Technical Solution Selection
published: ⏰ 7
A short article about how you can describe the selection of technical solutions within a project or any other activities that require decision-making with justification.
Introduction
Often, during the course of project work or when determining external solutions for implementation, it is not enough to simply choose what seems appealing based on personal preference. It is necessary to justify your choice so that other project participants or target clients, for whom the work is being done, understand the motivation and reasons behind this decision.
Depending on the size of the project and the complexity of the task, different approaches can be used to justify the choice. More complex cases require a detailed analysis of all dependencies and an assessment of the consequences of the choice, a full technical and economic justification document, stages of approval, defense of the decision, etc.
In this article, we will provide an example of a simple justification for selecting a solution, which is more aligned with everyday project work or early-stage express pre-sales. This approach is probably somewhat similar to what is described in ADRs (Architectural Decision Records).
General Approach
I think everything here is quite straightforward and obvious, but still, the steps are as follows:
- Define the problem that needs to be solved. Or the goals being pursued.
- Describe possible solution options.
- Evaluate each option based on predefined criteria.
- Draw conclusions and select the best option.
- Finalize the decision in a formalized form.
Goals
When defining a problem, it is important to consider various factors — both technical and organizational. It’s crucial to take into account the context in which the need arises. For example, the problem might be that the team cannot work efficiently with a certain service or programming language, or that the company lacks a clear understanding of what technologies are used in projects and where they are heading.
Example of a simplified statement for choosing a development language
Programming Language
The primary business need is to develop a robust, scalable, and maintainable software platform to support the core functionality of the NovaPlay platform to enable seamless integration with existing systems and support future growth. The platform should be built using a modern programming language that supports these requirements.
1.1. Objectives
1.1.1. Cross-platform compatibility
The system must be able to run on multiple platforms (Windows, macOS, Linux) without significant modifications and maintain consistent performance. This cross-platform capability is critical for ensuring accessibility on the different platforms and ease of maintenance. The chosen language should support cross-platform development capabilities, allowing for a single codebase to be deployed across different environments. This approach minimizes development overhead and maximizes code reusability.
1.1.2. Ecosystem maturity
The programming language should have a mature ecosystem with extensive libraries and tools to support rapid development and enhanced productivity. A mature ecosystem provides access to a wide range of pre-built solutions, reducing development time and ensuring that best practices are followed. It also ensures that the language has been battle-tested in real-world applications, which is essential for long-term project success and stability.
Variants
Having understood the need and defined the goals along with possible constraints, we can now move on to describing the solution options. In fact, it’s precisely this first stage that narrows down the spectrum of options to a more or less acceptable list.
Usually, the comparison is performed in the form of a table where the options are listed horizontally and the criteria vertically.
| Criteria | Java SE/EE | Go | Scala |
|---|---|---|---|
| Overview | |||
| Website | www.oracle.com | golang.org | scala-lang.org |
| License | GPLv2+CPE | BSD 3-Clause | Apache 2.0 |
| Release Date | 1995 | 2009 | 2003 |
| Developer | Sun / Oracle | EPFL / Lightbend | |
| Community Size | + + + + Very Large | + + + Large | + + Medium |
| Ecosystem Maturity | + + + + Mature | + + + + Mature | + + + + Mature |
| Features | |||
| Primary Purpose | Enterprise, Android, Backend | Cloud, microservices, CLI | Functional + OOP, Big Data |
| Key Features | JVM, GC, OOP | Goroutines, channels, simplicity | Functional + OOP, Pattern Matching |
| Platform | Linux: ARM64, Unix: ARM64, Linux: PPC64LE, Linux: s390x, Windows: x86-64, Linux: x86-64, macOS: x86-64, Unix: x86-64, Windows: ARM64, macOS: ARM64, AIX: PPC64, Plan 9: x86-64, Plan 9: ARM64 [13] | Linux: ARM64, Unix: ARM64, Linux: PPC64LE, Linux: s390x, Windows: x86-64, Linux: x86-64, macOS: x86-64, Unix: x86-64, Windows: ARM64, macOS: ARM64, AIX: PPC64, Plan 9: x86-64, Plan 9: ARM64 [13] | macOS: x86-64, Unix: x86-64, Linux: ARM64, Windows: ARM64, Unix: ARM64, Linux: PPC64LE, Linux: s390x, macOS: ARM64, Plan 9: x86-64, Windows: x86-64, Plan 9: ARM64, Linux: x86-64 [12] |
| Integration Capabilities | + + + Extensive (JARs, Maven) | + + gRPC, HTTP, CLI | + + + Akka, Spark |
| Extensibility | + + + + High (libraries) | + + Moderate | + + + + Very High (implicits) |
| Realtime Capabilities | + Fair (GC pauses) | + + + Good | + Fair |
| Scalability Support | + + + + High | + + + + High (goroutines) | + + + + High |
| Technical Evaluation | |||
| Architecture Style | OOP, modular | Concurrent, procedural | OOP, Functional |
| Performance | + + + Medium-High | + + + + High | + + Medium |
| Memory Usage | + Med-High (JVM) | + + + + Low-Med | + + High (JVM) |
| Concurrency Support | Threads, Executors | Goroutines, CSP | Akka, Futures |
| Security Features | + + + Good (sandbox) | + + Moderate | + + + Good |
| Debugging & Tooling | IntelliJ, Eclipse | Delve, VS Code | IntelliJ |
| Learning & Development Experience | |||
| Learning Curve | + + Moderate | + + + + Gentle | + Steep |
| Documentation Quality | + + + + + Excellent | + + + + + Excellent | + + + Good |
| Tutorials & Examples | + + + Abundant | + + + Abundant | + + + Abundant |
| Community Support | + + + + Very Large | + + + Large | + + Medium |
| IDE/Editor Support | + + + + + Excellent | + + + Strong | + + + Good |
| Development Speed | + + Medium | + + + + Fast | + Slow |
| Score | 10.3 | 10.6 | 8.5 |
| Consequences score | 1.5 | 1 | 1.4 |
Example of defining additional conditions.
1.2.1. Rewriting legacy systems in Java
Score: -1
1.2.2. Leave legacy systems as is
This approach does not require additional costs for rewriting old systems. However, it requires to organize migration between old and new systems. This is a complex task and requires a lot of time and resources.
Score: 0
With this table, you can assess how well a solution fits the specific task. For example, if the solution has a high score across all criteria, it may be a good choice. If it has a low score on one of the criteria, that could be an issue.
It is important to note, however, that evaluation ultimately depends on the particular situation, project,
customer, and so on. You cannot simply compare scores in absolute terms. For instance, in the table, the Score row
represents an abstract total score across all criteria, while the Consequences score represents the assessment of
implementation consequences (details below), and it is more important.
Evaluation
Once the list of options has been defined, they can be assessed taking into account the constraints and requirements.
This is most often described as a text Option 1 vs Option 2 with justifications. Or it can be in the form of a table with pros and cons, the sum of which will give the assessment.
| Variant | Pros | Cons |
|---|---|---|
| Java SE/EE | +2 Compatibility with multiple OS +1 Maturity of ecosystem | -1 Bad performance of the system -0.5 High memory consumption |
| Go | +1 Compatibility with multiple OS +0.5 Maturity of ecosystem | -0.5 Required manual memory management |
| Scala | +2 Compatibility with multiple OS +0.7 Maturity of ecosystem | -0.8 Bad performance of the system -0.5 High memory consumption |
| Rewriting legacy systems in Java | +2 Unified ecosystem and approaches to development | -3 Very high rewriting effort |
| Leave legacy systems as is | +1 No additional costs for rewriting old systems | -1 It is necessary to organize migration between old and new systems |
Choice and consequences
At this stage, the results are already summed up and the final choice with subsequent actions is described. The format depends on the situation and may include an implementation plan, a description of risks, etc.
1.4. Outcomes Selected: Java SE/EE Solutions: Leave legacy systems as is
The decision to use Java as the main development language is based on the following factors:
- Java is a mature and stable language with a large community and extensive documentation.
- Java is a good choice for developing large-scale applications.
- Java is a good choice for developing web applications with Spring Boot.
1.4.1. Cross-platform compatibility
Java provides excellent cross-platform compatibility through its virtual machine (JVM). It is a good choice for developing NovaPlay, as it allows the application to run on any platform that supports the JVM.
Objective: Cross-platform compatibility
1.4.2. Ecosystem maturity
Java has a mature ecosystem with many libraries and frameworks that can be used to develop NovaPlay. Spring Boot, in particular, provides a great foundation for building web applications.
Objective: Ecosystem maturity
1.5. Conclusion
Java is the best choice for NovaPlay due to its cross-platform compatibility, extensive ecosystem, and strong community support.
Conclusion
Such documents can be used as a basis for making decisions on the choice of technologies and as historical documentation for the project (analogous to ADR).
In tekBlueprint.specs (Architectural solutions) the preparation of such documents is possible using templates, automatic comparison by parameters and calculation of general estimates, which allows to speed up the process.
Additionally, for preliminary comparison of components it is possible to use tekBlueprint.kbase.