Balancing the present and the future of your solution
One of the most important aspects of software engineering is technical decision-making. Making decisions is agnostic to your role and is something that you have already experienced or will experience as part of your journey in software development. Technical advice is abundant, and there is no shortage of SaaS and Open Source offerings to overwhelm you with knowledge and best practices.
Technical decision-making is the art of choosing a technology, tool, framework, programming language, service, architecture, or pattern to solve a problem scientifically. A decision can go a long way in making your life easier, simpler, fast or slow, complex, and miserable in the future.
Spending time, resources, and energy on getting this right is significant to your future success. Additionally, the technology landscape iterates and moves exponentially, increasing the confusion and complexity of choosing the right solution. I don’t have a silver bullet for you or a decision-making flowchart that would work in all situations.
Being part of this process numerous times, I have gained learnings that have helped me decide on the solution objectively with one eye on the present and the other on the future.
A problem well understood is half solved and will always solicit better solutions. However, almost every time, I have seen scope creep. Yes, it’s essential to think about the future implications, but at the same time, increasing the scope of your problem will only end up in choosing an over-engineered solution or solving challenges that you don’t currently have.
“If I had an hour to solve a problem, I’d spend 55 minutes thinking about the problem and 5 minutes thinking about solutions.” ― Albert Einstein
Whenever people get into a room to solve a problem, they talk about the nice haves before the must-haves. It’s great to have heated seats in your car, but how about we talk about building the engine first. My favourite lot is those who offer a solution before looking at the problem, eventually retrofitting the issue to the solution, resulting in wasted time, effort, and insurmountable tech debt.
The learning to be had here is to ensure everyone agrees on the problem statement, the scope, and the objectives before indulging in resolution.
Companies hire people with similar experiences to their problems so that they can apply their past learnings. It’s a double-edged sword because you want people with relevant knowledge and skills to share their wisdom to make an informed tech decision. Still, it mostly ends up copying and pasting the solution without due diligence.
The problems may appear identical, but they are hardly the same in the two organizations. Pattern-matching is the easiest thing to do, and newer hires tend to do it more often to assert their knowledge and experience in the relevant field.
I support getting people with the relevant experience to share their learnings from the past, especially when the problem you are trying to solve overlaps with something they have already solved. As they say, the devil is in the details, so it is better to address challenges from your previous solution and design something relevant to the problem rather than just copying the last answer.
Humans are emotional beings, and as technologists, it’s common to get attached to technology, language, framework, or pattern. Also, it is easy to get attracted to the latest offering in tech. I like to be updated with what’s new in the industry and evaluate the upcoming trends, but at the same time, I don’t get attached to it.
Multiple conversations I have had with people who propose something because they are too attached or comfortable with it.
Let’s use React because it is excellent. I have used it in the past and really like developing applications with it.
That’s not a valid argument and pretty naive for making decisions. There’s no apparent reason for preference, and it is more emotional than logical. Instead, we should support choices that stem from analytical discussion and data.
Making slanted choices leads to tech debt, non-performant solutions, decreased adoption, and reliance on the single person who proposed it. Neither is this intelligent nor is this viable for solving problems.
Always ask for data-based evaluations to remove the emotional aspect from it. Multiple ways to solve the same problem, but evaluating each option logically will only support your cause. As a developer, what’s favourable for you might not be for your organization.
Quick, dirty, and hacky evaluation is far better than no early evaluation of your solution choices. An innovation from Extreme Programming (XP), spikes have become a norm with agile teams to evaluate technologies, frameworks, and design before committing them for production.
Failing fast provides an overview of the shortcomings of your technology preference, allowing you to either move on or live with it without the blind spot. Knowing the limitations beforehand is always advisable rather than hitting roadblocks later.
I have been part of implementations that skipped this due to tight timelines, and they ended up becoming showstoppers. If you fail early on without investing too many resources, you can miss the Spike.
For larger projects or programs, it might be challenging to do a Proof of Concept for each part; it’s helpful to identify the most important aspects and then call out that we need to focus on these more than others.
The most neglected part of technical discussions is usability, scalability & maintainability. A tech decision with low adoption is not a good decision. The ease of usability of your tool, framework, or language is as vital as any other feature it provides. The development experience shouldn’t suffer as it directly affects the team morale.
Intelligent decisions will set you up for a bright tomorrow, assuming you balance your current wants with future requirements. You are designing a system for a current load of 1,000 users/sec. Take the scale points into account so you can manage the extra burden on your system. However, engineering a solution to cater to 1 billion users/sec will only make it a costly and inefficient use of resources. It’s a good problem to have in the future, so your service is popular.
“What works at scale may be different from scaling what works. Pilots often succeed, while scale-up often fails when the context changes.” — Rohini Nilekani
Nobody likes to wake up at 3 a.m. to triage and solve an incident. Here is where the maintainability of your solution comes into play. Spend time evaluating the NFRs for your choices. “Are you introducing risk? Is this solution optimized? Is it self-healing?” are the questions to be assessed.
Evaluating your current tech stack and its components helps drive a better technical decision. If your tech stack is already using Python, there is no point in introducing a new programming language unless you are migrating. Similarly, if your team is already skilled in a framework or technology, consider its impact on your solution.
“The best part is no part. The best process is no process.” — Elon Musk
Reusing existing patterns and behaviours is a brilliant and quick way to deliver value faster. Don’t confuse this with copy-paste, which conveys a message on the approach of problem-solving.
Instead, don’t reinvent the wheel; leverage existing knowledge, technology, and processes to find innovative solutions to your problems. Adding unnecessary components to your solution means increasing complexity and reducing maintainability in the long run.
Once you have taken a decision, spread it and socialize it with the stakeholders. The most common trap among organizations is reaching a solution and not sharing it. Eventually, it comes as a shock to affected members, causing distrust and disharmony. On the contrary, if you share it well in advance, you earn their trust, loyalty, and feedback, making them feel part of the process.
Early feedback helps eliminate potential issues and gain an acceptance of the decision. Don’t forget that implementing is as crucial as making the decision. The parties calling the shots may not be implementing it. Early on, involving all the stakeholders will stop blame games and create a sense of ownership among them. In the end, create an ADR of your decision to make sure the future members can understand its rationale.
Technical decision-making is a complex process every organization takes to deliver value consistently and coherently. It is challenging yet rewarding in nature for individuals and teams. Balancing the past, present, and future is not an easy feat to deliver and requires patience, understanding, and a positive attitude to problem-solving. Decide wisely.
“You can’t make decisions based on fear and the possibility of what might happen.” ― Michelle Obama