Among the decisions a team makes early in a project are the technologies to use. Sometimes these decisions are given too much significance – especially in cases where a good architecture would trivialize the outcome; and sometimes the choices made can have a lasting and deep impact on the project. Either way, one of the worst thing a team can do is to make a decision by default, or without enough information. I’ve seen a few different approaches, so these are some of my thoughts on what has and hasn’t worked in my experiences.
What not to do!
The phenomenon of “resumé-driven-development” is fairly well known, and can be particularly dangerous. This is often seen when there are individuals in decision making positions who are new to these types of roles, whose judgement can be clouded. Quite simply, the choice of technologies is being made for personal gain, normally on the basis that learning a technology, normally new and shiny, would be desirable to the individuals. In this anti-pattern, there is often very little objective analysis of the technology, or of its suitability for the business need. I’ve seen projects be jeopardized from day one by this many times, and the damage is often hard to reverse.
While “resumé-driven-development” often comes from developers making subjective decisions, a related anti-pattern can come from non-practicing people, often highly ranked in an organisations hierarchy, encouraging the use of particular technologies. This can come about from things like the individuals having been “sold” the technology, and being a little more distant from the day-to-day of the project they are unable to make a fully qualified assessment of how suitable the approach will be in reality. One example I’ve seen a few times is where a non-practicing architect or CTO has attended presentations that on one level are about a methodology – service oriented architecture or document databases for example – but are delivered by a representative of a vendor, who merges together the methodology and their product or doesn’t fully disclose their position.
However a technology choice is made, a sound engineering and architectural principle is to try to avoid over-committing, and to keep the decision in its proper place. The “ports and adapters”, “hexagonal”, and “onion” architectures are all about this concept, which values a core domain that is free from frameworks or infrastructure – which will also normally make it less brittle, easier to test and more maintainable. One of the challenges in applying this principal is that many technologies offer quite enticing “easy routes”, that lead to excessive dependencies on their product. Sometimes this can be cynical – it creates vendor lock-in, and makes it easy to retain a customer because the sheer effort of switching is more difficult and costly – but normally it’s an honest attempt to provide a gentle learning curve or smooth integration. One of the key distinctions is between a “library” and a “framework” – where a library is a component that you use on your own terms within your own architecture, that will make very few demands about how it is used, and a framework is a much more opinionated product that will do many more things for you, but opposes constraints in the process. My preference is for libraries where possible, but there is nothing wrong with frameworks provided they are recognized for their costs as well as benefits, and kept to the boundaries of the system rather than allowed to permeate the whole solution. One example I’ve seen recently that demonstrates this quite well is a document database that offers unique constraints on indexes, by decorating properties with an attribute. This is a great functionality to offer and can be very useful in rapidly prototyping, but comes at a cost because it means that the entities – which could and should be isolated inside the core domain with no dependencies – end up having a knowledge of an infrastructure concern. Many frameworks offer 2 modes – an easy to use default that imposes more constraints, and an often less documented approach that gives the framework less influence and turns it effectively into a set of libraries; in the long term the latter is often preferable. Some frameworks go out of their way to be as unobtrusive as possible, and this is a quality I value very highly. A contemporary example of this is Rob Eisenberg’s Aurelia framework, which places a high importance on models that are completely decoupled from the other concerns of the application, in contrast to Angular where framework concepts tend to spread.
A better way?
Before committing to a decision over a technology, a couple of things I think are really important are to a) try actually using it(!) and b) compare it with some of its main competitors. I’ll often start by getting external opinions; there are plenty of people out there who write about comparisons of different technologies. I always try to take these with a pinch of salt however for a number of reasons. Firstly, the writer is not me, she’ll have her own perceptions and preferences. Secondly, the writer’s team are not my team; they will have their own experiences and knowledge that might mean one approach is a better fit for their needs. Thirdly, context is king; the writer’s requirements and project may be different, such that the relative values change. That said, if I read 5 people’s comparisons and they all reach the same outcome, I can probably save some time by taking that into strong consideration!
The thing for me that makes the biggest difference is to construct a simple side-by-side test and put two or more competitors through their paces. I’ll try to set aside one or two days, and come up with a simple toy project that should showcase some of the requirements of the real project. For example if I’m building a back-office data entry system, and comparing front-end frameworks, I’d want to see things like two-way data binding, some simple and more complex validation, some routing or navigation, and of course a testing story. I like to involve as many of the team as possible in these initial comparisons, so that they are engaged in the outcome rather than feeling disenfranchised by having someone else’s preferences imposed on them! One way to do this is by pairing or mobbing, another is to have each team member investigate a technology each, and to pitch it with demonstrations to the rest of the group. What normally happens is that within a couple of days the team will naturally form an affinity for one over the other, and that is probably the one to go with. Another nice side effect is that the team are exposed to the differences between the technologies, and are able to implement things in such a way that they are not painted into a corner, so could potentially switch later if the first choice doesn’t work out in practice.
One last thing I like to do for my own satisfaction is before using a particular type of library for the first time – something like a dependency resolver is a good example, I’ll sometimes take a few hours and try and implement my own. It would be absolutely senseless to actually use this for real of course, because the sheer number of man-hours of testing and proving robustness will never be there. What this does give me though is a deeper understanding of how this thing actually works, and some of the design decisions that go into this component. This often means that when I encounter something unexpected when trying to use an off the shelf library, I have a better intuition of what the problem might be, and an empathy for the design trade-offs that might be done differently in a competitor.
The key thing however is to try to be mindful whenever making a choice, and to make an effort to isolate the choice as much as possible. It’s ok to make a wrong choice, after all we are probably always making these choices with the least information we’ll ever have, and will learn new factors as the project evolves. If we’ve done a good job in the architecture around the choice, we can probably adapt and change track with relatively little pain – there’s nothing worse than being stuck!