The Keys to Making Important Technical Decisions
The Keys to Making Important Technical Decisions
Decisions, decisions, decisions...
Join the DZone community and get the full member experience.Join For Free
When a Technical Decision (TD) Becomes Important (ITD)
I like Mike Whitaker's metaphor saying that "decisions are forks in the road." Choosing the right "road" is hard, and it's even harder to know if the choice was good or bad until we walk on this "road" for a while. Sometimes we know that the decision is important, other times we barely realize it based on its effects at the end of the "road."
Whether we are talking about a multi-billion software company or a small one with 3 best friends, Technical Decisions are invariable in daily work. Some of them are important while others are less important (not unimportant, there is no such thing).
But, how do you to identify technical decisions that are important and shape the success or failure of a software product? Well, we can differentiate an important technical decision by several characteristics:
- Independent of being good or bad its effects in time are important. I like to say that ITD effects are viral, meaning that they will propagate further in the product with no effort.
- When it's a good decision, it shapes the product personality and differentiates it from the competition.
- When it's a bad decision, it may compromise other good ITD and induces significant extra-costs (time and money); worse scenario: it compromises the product itself.
- It's very (sometimes extremely) costly and time-consuming to replace it or revert it.
- Usually, it sticks with the product for the entire lifespan of that product.
- It's close to the product core and is heavily exploited in the product.
- Usually, it takes time to see its effects (positive or negative) and this is why long-term vision is mandatory.
For example, if you want to build a house, there are several important decisions to undertake:
- Decide if the terrain under the house and the foundation can sustain the weight of the house.
- Decide the resistance structure of the house.
- Decide the materials from which the house will be built.
- Decide the needed tools to build the house.
All these are important decisions, and having a bad decision at this moment may compromise the future of the house. On the other hand, it's less important if we decide to go with square windows or round windows. Notice how the important decisions behave synergistically (e.g., if the terrain cannot sustain the house weight or the chosen materials are not compatible with the resistance structure metrics then the results will be disastrous even if the rest of important decisions are correct).
Choosing or designing the right architecture for a product is an ITD (e.g., relying on a monolith architecture, a micro-kernel, a microservices, etc). Deciding the database that will be used by the product is another ITD. Choosing the proper data structure for storing 50 million records in memory is another ITD.
Categories Of ITDs
From my experience most ITDs fall into one of the following four categories:
This is the highest level of abstraction and is the point when we decide the proper architecture for the product — by analogy, this is the terrain under the house and the foundation of the house. The architecture must be capable to sustain the product during its entire lifespan exactly as the foundation sustain the house (for example, we know very well how bad it is to go with a monolith architecture instead of a microservices one or vice versa, or more precisely to miss the point when a monolith should be migrated to microservices in order you avoid The Big Ball of Mud). Implementing a bunch of functional requirements can be accomplished under almost any architecture, but architecture comes into play in the case of successful products and starts to affect so-called non-functional requirements, quality attributes and quality of service. A small house can have almost any foundation, while this is not true for a big house. Typically, such decisions are specific to startups, but they can occur in existing products as well (e.g., introducing a layer of abstraction between new code and legacy code can be considered an architectural decision). Keep in mind that the first version of the product doesn't have the issues that the right architecture for it can solve.
Once we have the architecture in place, it's time to choose the proper databases, frameworks, libraries, services, and so on (technology stack), that give life to the architecture. By analogy, this is the resistance structure of the house. The chosen technologies must be capable to accompany the product over time, it must be capable to accompany the evolution of the product. They must be chosen in such a way to anticipate the product evolution on different levels but avoid being over-engineering. Replacing a bad decision here is not impossible, but usually implies a lot of work and money depending on the moment in time when the issue is discovered. This can be a major dilemma for startups, where the biggest problem is usually how to rapidly evolve the business model and accompanying application.
Data Structures Decisions
Data structures are the building blocks (the bricks) of the product; they store our in motion data and they are usually part of the solutions to certain problems that should be solved. By analogy, data structures are the materials from which the house will be built, so they must be reliable and they should outperform other choices for specific problems. All of our code interacts with and manipulates data, so we must rely on our data structures for a long time and they should be the perfect fit for specific use cases. We should strive to pick up the data structures that provide the best performance and robustness to the product. This means that knowing the data structures exist is not enough. You need to understand the data structures well enough to use the right one for the problem. But, don't fall in into the extreme of trying to daily play the role of a Data Scientist, but don't eliminate this role from your list.
Data structures and algorithms shouldn't make a good team, they should make a perfect team — this is their aim! Because together they represent your tools for building solutions to complex problems, and this is your aim!. By analogy, algorithms represent the needed tools to build the house. Without algorithms, we have only the data structures as a useless pile of boards. Now algorithms do the magic! Fortunately, in most of the cases, we don't need to reinvent the wheel, since as in the case of data structures, there are plenty of existing algorithms dedicated to solving problems. Strive for the proven and fast algorithms. Strive for patterns or algorithms that are pattern-able (prone to become patterns soon) and join (or orchestrate) them to solve complex problems. Add your know-how and use the tools wisely; if it is needed, innovate around proven algorithms. Most of the time it's about choosing the right one or the right combination, rather than inventing/researching an algorithm. So, don't fall in into the extreme of trying to daily play the role of a Computer Scientist, but don't eliminate this role from your list.
Do you want to be the maestro? Well, edge cases, cutting concerns, and challenging problems of your products will be always there for you. Think innovatively, but avoid experiments on production code as much as possible, especially if you are not in a Continuous Delivery environment or any other environment that allows you to loop a Risk-Fail Fast-Learn flow. Experiments are not innovation, they are just part of the road to innovation. And don't confuse innovation with improvisation.
In conclusion, your architectural decisions should sustain the product, your technological decisions should accompany the product, your data structures decisions should be reliable and performant, your algorithms decisions should be proven and fast. And on top of this add your footprint, that something that makes your ITDs fabulous.
Who Is Responsible For Making Important Technical Decisions?
Beyond titles, an ITD maker is a person with long-term vision, deep technical knowledge, and common sense.
In small software companies, this is usually accomplished by the Team Leader. In medium/large software companies these tasks are covered by Chief Architects or (VP) Technical Product Managers (focused on defining the technical solution for a particular feature). People that are IT Consultants are also responsible to take this kind of decisions. Even if we have a job description for each of these roles, you know that there is always a requirement that mentions that these roles should be prepared to wear different hats during product development.
Can a Bad Less Important Technical Decision Ruin A Good Important Technical Decision?
Only one, probably not. But, several less important technical/coding decisions can!
Let's take an example: an important technical decision from the technologies decisions category can point the usage of Hibernate as the ORM of the product. This is the perfect fit for the product and is a great ITD. But, this great decision should be empowered by dozens of less important decisions taken by the developers, who will actually exploit Hibernate at the code level. If you don't come from the Java ecosystem, then it is important to know that Hibernate is a great ORM, if it is used correctly. Otherwise, Hibernate can look/act really slow, clumsy and heavy. If the developers are not aware of the best practices of using Hibernate and databases (SQL) then the product will barely roll.
Mainly, a chosen technology is not giving its goodies for free, most of the time goodies are like achievements that should be unlocked via skills and knowledge. This means that behind ITDs is a must to have seniors developers with high skills in the chosen technologies. Mainly these seniors should be on Plateau of Productivity for the technology stack. The persons that are responsible to take ITDs cannot sit behind the developers or perform code reviews because this is simply not their job. While a part of the bad less-important technical decisions will be materialized in bugs and will be fixed, or will be intercepted in code review (less probably), another part will become silent killers of the ITD.
The main idea is that a bunch of less important technical decisions may downgrade an important technical decision.
How To Make An ITD?
Making Decisions Is Always About Balancing Trade-Offs.
Trying to define a dream team of technology or to join the fanciest and trendies technologies (sources of buzzwords) is the aim or the dream of a junior in this field, and theoretically, there are no juniors here. In the software engineering area, as we already know from Fred Brooks, nothing is a silver bullet and no magic formula will fit more products. This is why we have such a large number of technologies dedicated to the same segment of problems.
From my experience, I have gathered a few criteria for choosing technology for a product that I use somehow as a methodology:
- First, rely on mature technologies that have been tested in battles, have comprehensive documentation and strong communities (many "newcomers" libraries disappear before going in production).
- If no mature technology is available, go with "newcomers" provided by serious vendors which most likely will maintain and evolve the technology.
- Avoid as much as possible "anonymous", untested and unmaintained technologies (in case of issues, it will be very hard to obtain help or bug fixes).
- Avoid obsolete frameworks and deprecated solutions.
Rely on Versus Decisions Tables (e.g., MySQL vs. PostgreSQL) in order to decide between multiple technologies dedicated to the same segment of activity (such tables should contain head-to-head pros and cons, benchmarks, metrics, feedbacks, etc). Commonly, a technology is defined by comparison with its competitors, so there are plenty of technical resources on the Internet.
- For large companies with a lot of products using Versus Decisions Tables will be a slow process, so start building a Decision Support System (DSS). For example, a VP-Expert Technical Decision System application (the effective structuring of knowledge bases is most important for knowledge-based expert-system design) - use this system to nominate technologies and this will increase your metrics drastically; is a hard work but with amazing and constantly increasing results.
- Strive for high-compatibility between the technologies that should interact.
- Strive for choosing the technology that fits like a glove in the product context, not the most mighty or fancy technology on the market.
- Especially when the evolution of the product is unclear, rely on versatile technologies that cover a large range of features, but pay attention to not exaggerate (for example, don't recommend Apache Kafka as a messaging system for a University Campus Chat because probably later the product will need streaming analysis capabilities and trillions of messages; most probably this will never happen)
- Ask a second opinion whenever you have doubts; doubts are good, it means that you are still objective and open listening.
- Once you manage to nominate a set of technologies (preferably via a VP-Expert Technical Decision System) use your skills and knowledge about the product to decide which one is the proper choice for your specific case (basically, apply a decremental granularity process).
Note: These bullets apply to all ITDs categories (architecture, technologies, data structure, and algorithms), not only to the Technological Decisions category.
How To Express/Write an Important Technical Decision
In order to express an ITD you have to pass the following check-in list or quality bar:
- The ITD should be crystal clear and concise
- The ITD should explain what you decided and why you did it this way
- The ITD should be purely technical
- The ITD should be 100% focused on the problem to solve
- The ITD should not collide other ITDs
The way you effectively deliver this is company specific. Commonly, you write it as a document generated by specific tools.
Are You Planning To Become An ITDs Maker?
Well, then there are a few things to keep in mind:
- Accept that, sooner or later, you will make bad decisions and follow Deepak Chopra's advice: "Take responsibility for your last bad decision, and then let it go. Don't blame others or make excuses for yourself. "
- Typically, ITDs don't produce effects or feedback immediately, so keep in mind that objective vision should be your highest skill. It will sit right behind your long-term quality metric!
- Keep yourself constantly up to date no matter how hard is it. Read, read, read, learn, learn, learn, test, test, test. If you are used to constantly starting your argumentation with "in my opinion..." then you definitely have a lack of knowledge and it is time to fix it. Usually, lack of knowledge is replaced with personal opinions that are generally not proven (of course, is not always the case).
- Strive to become a technical influencer
- Strive to avoid tl;dr reaction for your ITD! Be concise!
- Most of the time the key to success is perseverance. As Markus Biel states in this tweet, lack of perseverance is an impediment for success.
- Don't forget how to code even if you don't have to (this is how the ivory tower begins)
- Don't try to be fancy just for the sake of being, stay classical (e.g., don't be functional or reactive just because you saw some YouTube talks about it). In other words, recommend things only if you can harvest real value from it, not just because is a new toy in town and you didn't try it out.
- Learn what and how to ask! Sounds simple and silly, but is not! As Claude Levi-Strauss said: "The key to wisdom is knowing all the right questions." If you don't ask the key questions that you may not get the key answers and quickly fall in the "wrong screwdriver" trap.
- Love, seek, and use feedback!
- Adaptation to changes is the survival key. Usually, you will change products like socks, so is major to adapt quickly, read between the lines, isolate the relevant things and do your job.
- Don't lose yourself in details! An ITD is not meant to be Saint Graal so it cannot solve everything!
- Don't act as a Google Technical Gathering Tool and think twice on each decision
- Don't start to believe that what you do is art! Is NOT! Is just hard-work, extremely hard!
Things That You Should Never Do As An ITDs Maker
Provide a Complex Codebase
Follow Albert Einstein quote: "Everything should be made as simple as possible, but not simpler."
Most people that are responsible for dealing with ITDs will not write code anymore. But, it is possible that an ITDs person should write the base code of the product and the development team will evolve it further. If you find yourself in such case then avoid introducing an overwhelming complexity at code level right from the start. This way the base code is hard to understand and developers will struggle to make changes correctly with a poor rate of success. This is bad!
Write "Clever" Code
Follow Andy Hunt's and Venkat Subramaniam's advice: "Write clear code, not clever code."
Once you've been asked to write some code you will have the feeling that your code should stand out from the crowd. After all, you are not a regular developer and this is something that should be obvious from your code which must be minimalist and do a lot of things. You spent hours to shrink your code. Don't do this, consider the next person who’s going to be looking at your code. If people are constantly coming to you and asking, "What does this code do?" then it's possible that you wrote some "clever" code. Usually, nobody wants to touch it because is hard to understand. This is not the way to win respect!
Blame the Technology
Kate Summers said, "If you are looking to inspire people then blaming is the last thing you want to do."
Don't put yourself in such an embarrassing situation: decide to use a technology and afterward blame it and evangelize that it should be avoided like the plague. Maybe you just have to remember that the adoption of a technology usually follows the Gartner Hype Cycle, so don't give up at the Trough of Disillusionment phase:
Have you ever decided to use a NoSQL as MongoDB and afterwards to realize that there is a heavy-transactional environment?
Or to design a REST API and afterwards to realize that you needed persistent connections not thousands of request-response cycles, or to choose O(n2) algorithm instead of O(n) because it performs better for a small amount of data and afterwards to realize that actually there are thousands of records to process? Then, you have experienced the "wrong screwdriver" scenario.
These are really bad ITDs! Apparently, they look as amazing decisions, but it turns out to be the opposite. Causes? Well, typically two causes are shaping this kind of disaster: first, lack of communication between the ITD maker and PCAs, CAs, development team; second, you asked the wrong or incomplete questions and you just couldn't intuit this situation from their answers, which is also a lack of communication. So, choose your questions wisely! Lack of communication can be caused by large teams as well. And, as Melvin Conway says, "Organizations which design systems…are constrained to produce designs which are copies of the communication structures of these organizations."
I should probably say something smart or at least motivational...still looking for it...
Opinions expressed by DZone contributors are their own.