Spoiled for choice: Dealing with dependencies in software development
Make or buy? Decisions to use frameworks or third-party software often lead to discussions about scope, quality and thus the sensible use of time and money. We show why it does not always make sense to rely on ready-made solutions and when in-house development is worthwhile.
Make-or-buy? Decisions to use frameworks or third-party software often lead to discussions about scope, quality and thus the sensible use of time and money. We show why it does not always make sense to rely on ready-made solutions and when in-house development is worthwhile.
Whether large frameworks or libraries or small tools or collections of useful functions: one has the impression that solutions already exist for all problems. For the most part, these are available free of charge as open source software (OSS). Sometimes they cost money, but the cost is often very low these days. A developer hour is significantly more expensive. Third-party software is quickly integrated thanks to Package Manager. This often pleases developers and project managers alike - when we can all save effort and money with it, too. So what's the catch?
The fallacy of cost
In most cases, costs in software development consist of almost 100% personnel costs. This creates a great incentive to save developer time. The promise of a tool to reduce developer time is therefore obvious. And also the conclusion to use ready-made software to buy in parts of the development is in principle correct, because only by less development effort time and thus money is saved in the end.
But this is also where the problem lies hidden. How exactly does one estimate whether a finished software can save time? It is not the initial implementation that is the cost driver, but the time required to solve problems and the constant maintenance of the software. These time expenditures depend primarily on whether the development team understands the software and is well versed in the code. In the case of third-party software, this is only possible after a long period of familiarization with a great deal of experience. In any case, the trade-off between using third-party software and writing your own software is not trivial, because the follow-up costs are very difficult to estimate.
There is often a tendency to overestimate the promises at the beginning, because the decision is made on the basis of incomplete data and the immediate positive effects outweigh the negative ones (less time for training and integration of the third-party software in the short term). Package managers such as NuGet or npm have taken this principle to the extreme and mercilessly simplified the search for and integration of third-party software.
So how do you weigh it?
The decision to develop a software in-house or to use a ready-made software is usually based on little experience. In addition, one may only know at a late stage whether there are functional differences that are not apparent at first glance. They only become apparent later in the implementation - a problem that cannot be completely eliminated.
So if you want to make a good decision, you need factors from which you can deduce with little knowledge whether make or buy is the better choice. The following tricks can simplify the decision.
This or something similar could be the argumentation if only a small part of the third-party software is needed. But what if only the small part is needed? Isn't it then easier to write the functionality yourself? Do I really need a component like leftpad?
It is useful to take a look at the scope of the needed solution. Sometimes real arguments for the more complex off-the-shelf solution don't exist at all and you still decide for a potential you won't use at all.
Future-proof
External components are independently maintained and updated
It is certainly true that components from other manufacturers often have updates and security updates that increase functionality and improve stability. It is the acquired maturity of a third-party component that provides insight into its future-proofing. Factors include:
- Commitment, popularity (for open source software).
- Software has a stable business model, with which the manufacturer earns money
- Enforcement in the market
These factors seem easy to evaluate, for example, the stars on GitHub give an indication of the popularity of the software. The assertion in the market or the question of the business model often remains only qualitatively evaluable.
The integration effort remains
Regardless of the previous factors, a certain integration effort always remains. In the case of in-house development, this is included. With third-party software, integration often consists of building understanding through documentation and trial and error. This structure tends to be larger with more extensive solutions. With smaller solutions, it can therefore make sense to develop them future-proof yourself, because with in-house development, your own development team knows the solution very well and can keep it stable.
Nothing is free
Neither is free of charge, because up-to-dateness always costs integration effort in any case, even if automated version management in the package managers and approaches such as semantic versioning are used to try to escape dependency hell (e.g. through many dependencies and dependency cascades).
A practical example - Caliburn.Micro
How easy an implementation can be can be seen in an example from one of our software teams who create software using WPF and .NET. For this they used the Caliburn.Micro framework. The primary reason was to use the MVVM pattern.
The decision was easy because Caliburn.Micro is free and very easy to use and integrate. By limiting themselves to the MVVM pattern, the team had chosen only a small isolated part that was important to them. Nevertheless, problems arose relatively early on that made development unnecessarily complicated:
- In the MVVM pattern, as implemented in Caliburn.Micro, the matching of view and view model happens via the name of the components.
- With the additional integration of DevExpress, this pattern could not be used in this way. Instead, the standard WPF pattern had to be used, consisting of XAML + code-behind.
- By using two patterns, the team kept falling into the WPF pattern because it was not clear at which point which pattern was now being used.
So first, the scope of the solution was considered. The MVVM pattern itself is a smaller isolated part. It can be easily separated out and solved by itself, without dependency on Caliburn.Micro. Integration and familiarization with the external framework was similarly complex.
Accordingly, the implementation of the in-house development included:
- Isolating the MVVM pattern matching via filename convention (instead of component names) and
- the integration into WPF
Own ideas can now be implemented easier and faster and the code is much clearer and leaner, because only those functions were implemented that we actually need. Our framework is now much easier to understand and therefore ready for any maintenance and extension. The use of our proprietary standard formats and standard structures simplify the handling of the software within the company. Thus, problems can be solved more easily by already existing solutions.
The fact that it does not require a lot of programming work is shown by the code we created ourselves, which reflects the advantages hoped for through Caliburn.Micro.
///
/// Searches for View models and views that match the name convention and adds them to the resource dictionary ///
/// The namespace in which will be searched for the view models ///Reference to Dictionary in which the template should be stored ///Array of types that contains among other types, the view model types and view types /// List that contains the imported templates public static List GenerateTemplateDictionary(String typeNamespace, ResourceDictionary res, Type[] relTypes) { // get names of namespaces for VMs and Views by convention String vmNs = $@"{typeNamespace}.ViewModels"; String viewNs = vmNs.Replace("Model", String.Empty); // getting types of VMs and Views from that namespaces var viewModelQuery = from t in relTypes where t != null && t.IsClass && !t.IsAbstract && t.Namespace != null && t.Namespace.StartsWith(vmNs) select t; var viewModelTypeList = viewModelQuery.Where(t => t != null).GroupBy(t => t.Name).Select(g => g.First()).ToDictionary(t => t.Name, t => t); var viewQuery = from t in relTypes where t != null && t.IsClass && !t.IsAbstract && t.Namespace != null && t.Namespace.StartsWith(viewNs) select t; var viewTypeList = viewQuery.Where(t => t != null).GroupBy(t => t.Name).Select(g => g.First()).ToDictionary(t => t.Name, t => t); var foundItems = new List(); // link the VM types to View types by convention into a datatemplate and add the datatemplate to app.resources foreach (var vmt in viewModelTypeList) { var viewKey = vmt.Key.Replace("Model", String.Empty); if (viewTypeList.ContainsKey(viewKey)) { var viewType = viewTypeList[viewKey]; var template = CreateTemplate(vmt.Value, viewType); if (!res.Contains(template.DataTemplateKey ?? throw new InvalidOperationException())) { res.Add(template.DataTemplateKey ?? throw new InvalidOperationException(), template); foundItems.Add($@"Found and add VM -> View: {viewType.FullName} -> {vmt.Value.FullName}"); } else foundItems.Add($@"Pair is already known VM -> View: {viewType.FullName} -> {vmt.Value.FullName}"); } } return foundItems; } private static DataTemplate CreateTemplate(Type viewModelType, Type viewType) { // The only way to get around some problems with binding later is this way of creating datatemplate objects // see www.ikriv.com/dev/wpf/DataTemplateCreation/ const String xamlTemplate = ""; var xaml = String.Format(xamlTemplate, viewModelType.Name, viewType.Name); var context = new ParserContext { XamlTypeMapper = new XamlTypeMapper(new String[0]) }; context.XamlTypeMapper.AddMappingProcessingInstruction("vm", viewModelType.Namespace ?? throw new InvalidOperationException(), viewModelType.Assembly.FullName); context.XamlTypeMapper.AddMappingProcessingInstruction("v", viewType.Namespace ?? throw new InvalidOperationException(), viewType.Assembly.FullName); caliburnmicro.com context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation"); context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml"); context.XmlnsDictionary.Add("vm", "vm"); context.XmlnsDictionary.Add("v", "v"); var template = (DataTemplate)XamlReader.Parse(xaml, context); return template; }
The reasons are often the same. There are few developers responsible for the project, the developers change their private or professional setup and can no longer maintain a development that is often done privately.
Conclusion
The example shows that decisions and considerations in this case meant that the investment was worthwhile. The freedom to make this decision in the development team characterizes the work at OHB Digital Services.
There is plenty of scope for making these decisions, people can contribute their own ideas and the project manager does not dictate which type of library is to be used. The fact that decisions are made as a team often results in better solutions.
For us, it has become clear over time that it is more often sensible to create our own solutions and develop a simple small framework ourselves, rather than using more complex third-party frameworks.
If you still decide to use a third-party library, you should always be aware that this is not a no-brainer. Instead of simply integrating and forgetting, a high level of care and maintenance is also important with third-party software. If the number of dependencies increases, one sometimes loses sight of hidden incompatibilities. Costly bug fixes can also be the result if the third-party software is not deeply understood. All this must not be forgotten.
In the end, of course, the best possible product should be available for the customer and the decision should be made according to this.
Your journey with OHB Digital Services
Benefit from the knowledge gained from space travel for your business. OHB Digital Services GmbH has been a reliable partner for secure & innovative IT solutions for many years. We are part of one of the most successful space and technology companies in Europe. With our products and services, we support you, among other things, in digitizing your business processes along the value chain and in all security-related issues. Please feel free to contact us.