Choosing Technologies
Are we really having the impact we expect, when we choose technologies for software products?
Despite growing up in a country where football (soccer, for my American readers) is the universal passion, I never understood the appeal, and I never shared it. However, I suspect it to be similar to the passion that a discussion on technology choices evokes among software engineers and architects: despite being otherwise excessively rational beings (at least according to everyone in a different profession), we favor technologies by faith instead of reason, and we get emotionally attached to them. I think I tend to adopt a more pragmatic approach than average, and sometimes find myself wondering to what extent it actually matters. I remember attending a Startup Grind event in Barcelona a few years back, where the speaker was the CTO of a very successful Spanish startup. Someone in the audience asked a question about the technology used, and his answer (to the best of my recollection) was:
As engineers we discuss technology choices a lot, but I suspect that if you look very closely, you will find that in any startup, the technology of choice happens to be whatever technology the first key technical person in the company was comfortable with.
I have thought of that answer many times since then, and every time it strikes me as the most accurate (as well as the most sincere) statement about how we pick technologies. I think a lot of the discussion about specific advantages and disadvantages amounts to what's effectively a posteriori rationalization of the decision, rather than an explanation of the causes of the decision. That being said, one has to ask: to what what extend do technology choices matter anyway? My belief is that most of the time there are no major differences that would compel the use of one technology over another, and the decision is really a matter of second order effects, such availability of talent, or the size of the community around the technology. The goal of this article is to lay out those second order effects, not only to bring technology choice discussions back on rational footing, but also to enable people to judge to what extend a decision makes a meaningful impact in their specific scenario.
Choosing A Programming Language
Counterintuitive as it may sound, I believe that the choice of programming language is, in some respects, the least relevant choice of all: all programming languages that one is likely to run into nowadays (including practically every form of assembly language) are Turing complete. In other words, any program you could write in any other language, you could also write in the target language (if it is Turing complete). If one's argument against language A and in favor of language B, is that there are programs one can write in B but not in A, the argument is most likely wrong. That is not to say that there aren't things that are easier in language A vs. language B. For example, if performance is so important that one would like to optimize the cache access patterns of the code (this is often the case in game engines and middleware), then one probably wants to pick a language with an explicit memory management model (such as C/C++), over a garbage-collected language such as Java. In general, however, such requirements are rare, and most languages look pretty similar. The one major exception I would make, is the distinction between strongly typed and untyped or weakly typed languages. These have fundamentally different cost characteristics over the software life-cycle; I plan to write a later article on specifically this impact.
In reality, the primary impact of language choice is in its second order effects:
- Availability of talent: This is by far the most important second order effect. A fellow entrepreneur was recently sharing his challenge finding an additional engineer for his team. The application is what I would describe as a fairly straightforward web application, but the core is written in Scala (incidentally, they picked Scala for the same reason described in the quote above). He can find many Java engineers, but the Scala talent pool is much smaller, and he has struggled to find a single engineer to fill the position.
- Reach of the ecosystem: in general, you don't want to write all the code yourself; you want to reuse as much as possible in libraries and frameworks, and certainly in tooling (as you are unlikely to write your own tools). Some languages are embedded in a much richer ecosystem than others.
- Maturity: This generally becomes important when the non-functional requirements (especially security and stability) become important. More mature technologies tend to have more of their bugs shaken out, so they tend to be more stable and secure. Note that this primarily applies to the ecosystems, rather than the languages themselves, but since the languages are often bound to their ecosystem, the language choice itself might be made on the basis of the maturity of its ecosystem.
- Vendor specificity / Open Source: if the language is owned by a single vendor, that often implies vendor lock-in. At the same time, single-vendor ecosystems tend to have parts that fit together better than open source.
Choosing a Framework Environment
First of all, let me explain what I mean by Framework Environment in this case, since I am using it in a non-standard way. Within some technology ecosystems there are frameworks that make fundamental decisions as to how your code should operate within the framework. Different such frameworks often make incompatible decisions, meaning you have to pick one or the other. In Java, I would list J2EE/EJB, Equinox, and Spring1 as such frameworks. Since they all three attempt to control the life-cycle of the components of your application, they are not really compatible with each other, and you need to pick one. Similarly, front-end teams generally end up using either Angular or React for each page or module, although it is possible to mix modules using different framework environments.
The primary difference between framework environments is in what the framework has chosen to make easy, versus what remains more complicated. Spring, for example, has focused a lot of energy on making dependency injection as easy as possible. If that is important to you, it might make sense to pick Spring. On the other hand, J2EE manages the interaction between your components and the application server in which they live more effectively. With each of these options you get some things for a very low cost, provided by the framework, but you have to pay the full price for others. By choosing which cost to defer to the framework, you can optimize how much you have to build for yourself, but the actual trade-off will always depend on what you are building, and therefore there is no option that is universally better than the others.
Note that there are many other second order factors to be taken into account as well:
- Availability of talent (it is a lot easier to find Spring or J2EE developers than it is to find Equinox developers, for example).
- Maturity
- Community Size
- Support for specific architecture philosophies (microservices, vs. SOA, vs. Web Services, etc.)
Choosing Specific Technologies
One level below framework environments, one is faced with the decision on choosing specific technologies. Consider, for example, messaging technologies: one could choose between ActiveMQ, Kafka, IBM MQ, RabbitMQ, and so on. Sometimes, the decision is actually a two-tier decision, with the first tier being a class of technologies. The classic example would be database technologies: the first tier is a choice of SQL vs. NoSQL, for example, and the second tier would contain specific database technologies such as MariaDB/MySQL, MS SQL Server, Oracle, or PostgreSQL for the SQL class, or MongoDB, Apache Ignite, Apache Giraph, and so on for the NoSQL class.
In the case of technologies, specific features matter. It is still not the case that something you wish to do will be impossible in a particular technology, but the difference in how hard it is if not supported by the technology is significantly higher. For example, you can implement schemaless functionality in an SQL database, but it requires you to do a lot more work in the application than if you simply used a schemaless database. That being said, most technologies of a certain reach and maturity tend to cover most common functionality, so it would take unusual requirements to make functionality be the major determinant in which technology you choose. The second order factors still count for a lot, in particular:
- Talent availability
- Compatibility with other technology choices (e.g., in the case of a message broker, is it compatible with JMS if you are using J2EE/EJB?)
- Flexibility
- Licensing Cost
- Non-functional requirements (performance, scalability, reliability)
- Maturity
- Active development and maintenance (you certainly do not want to commit yourself to a technology that is approaching End-of-Life, or does not have enough critical mass to create a reasonable expectation of support)
- Community size
- Vendor specificity / Open Source
- Resource consumption
Getting it wrong
Going back to the quote at the beginning of the article for a second, one has to ask: What if you make the wrong choice? In fact, given how we tend to make these decisions at a time where we know very little about the requirements that eventually will become relevant to the choice, we quite often make the “wrong” choice. What recourse do we have once we finally reach the point where the information becomes available, and we know the “right” choice? I think in a lot of respects, the answer depends on how you choose to think about the question. My particular answer is that you obviously have two choices:
- Live with the consequences of the choice: in most of the cases, you will realize that some of the things you wish to do are now more difficult than if you have made a different choice, but the cost is not high enough to warrant a major re-engineering effort to replace the technology in question. In effect, it is a source of technical debt just like any other, and you can continue to pay the interest on this debt for as long as you find it affordable.
- Change technologies: if the mismatch is great enough, the cost of continuing with the original technology choice can become prohibitive, and it may make more sense to re-engineer the system to replace the technology in question. How costly it is do do so will depend on the system architecture. Some architecture philosophies, such as the microservices style, make it really simple to replace technologies: one could simply re-implement an entire microservice in a new technology. In SOA and Web Services, it tends to be a bit more complicated, but can still be done without excessive cost if planned and executed properly. Also, if there is a standard interface anywhere between the bulk of your application and the technology you are trying to replace, it can be used to contain the impact, thus making the re-engineering much simpler. For example, consider the case of replacing the underlying data store in an application that uses JPA / Hibernate: most of the time all that has to change is the configuration of the data source.
That being said, I'd like to revisit one of the questions introduced at the beginning of this article: How much does it really matter? Based on the analysis above, I tend to think of getting a technology choice wrong as equivalent to a technical debt issue. By analyzing the factors above one could arrive at a decent estimate for the size of the corresponding technical debt. I would then treat it like any other decision that generates technical debt. If you think that the risk and/or impact of the decision is high enough, you could even architect some containment around it to contain the impact. At the end of the day, however, once engineers understand that it is merely an issue of technical debt, hopefully they will feel less inclined to make decisions on faith, or to fight religious wars over technology choices.
One last word
While I certainly believe that from the engineering perspective the impact can be easily contained and ameliorated, I have learned the hard way that technologies are inherently biased, and strongly condition how we think about engineering problems. The question of the impact on the team culture and ethos is much more complicated to analyze, and certainly a lot harder to contain or ameliorate. As a result, from the management and strategy perspective, I think that technology choices matter a lot more, and deserve much more attention. That being said, that particular rabbit hole is much deeper, and I do not yet feel I have enough clarity of thought to analyze it here.
-
Note that in the Java ecosystem, these would normally be called containers, but with that term now being in common use to mean something else, I opted to stay away from it. ↩︎