Lattix Blog | Software Architecture, DevOps, Systems Engineering
CodeClinic, a provider of innovative solutions for software organizations in safety-critical embedded systems, received the Embedded World Award 2022 in the Safety & Security Category for Traci. This tracing solution is a traceability matrix used to identify gaps in the design and verification of requirements as required by standards such as ISO 26262, DO-178 B/C, IEC 62304, IEC 61508, and more. With Traci, functional safety teams can eliminate the manual error-prone process of conducting tracing analysis.
Success (or failure) is mostly about “small” decisions
For some, architecture is all about decisions. Once the biggest and the most important decisions are made, architectural work is considered done. Sadly, the success of your project rarely hinges on those “big” decisions. It is the “small” decisions, the ones we often ignore, where a project’s success lies. The biggest decisions are static; once made they will rarely change. It is the small decisions, the ones we make every day, that will actually determine how easy it is to support new functionality and how productive the team can remain as software evolves.
Out of the box, Android Studio provides one module: the app module. Because of this, most developers write their entire application in this one module. This is fine for small teams and small applications. But, as an application grows, more team members are added and the application becomes more complex, build times can increase – with Gradle builds sometimes taking up to 10-15 minutes – and developer productivity goes down.
One way to solve this problem for complex android applications is to modularize. Modularization means to divide a program into separate sub-programs (or modules) based on features. Each feature will be its own module.
Some advantages of modularization are:
- Ease of incremental builds and deliveries
- Smaller modules are easier to unit test
- Modules can be added, modified, or removed without any impact on another module
- Modules can be reused
- Reused modules can lead to smaller APKs
- Easily pluggable into Instant Apps
- Increased developer productivity, as one person can have sole responsibility of a module
How do we split up a monolithic application into modules?
For business critical applications, discarding the current application and rewriting it from scratch is not an option. Therefore, the only option for critical apps is an iterative approach where you figure out the features that can be separated from the main application and do it in an orderly sequence with the ultimate goal being a set of feature modules.
The key to splitting up a monolithic application into modules is understanding the dependencies between features. This is the software’s architecture. Knowing this will allow you to make decisions on which modules can be split apart and how much work that will entail.
Here are the steps to follow:
- Understand what will be shared. This might seem counterintuitive, but if we didn’t do this we end up duplicating large amounts of code. Many modules share resources such as activities, fragments, and layout files. Looking at the application’s architecture can help identify the utilities that will be shared across the various modules. Looking at the “as-is” architecture can even identify where these utilities have incorrect dependencies.
- Understand how to split what isn’t shared. Modules can end up with definitions of objects that are partial views of the real object. For instance, a shipping module may not need the order history of the customer but does need to know the address where a product will be shipped. By understanding the dependencies from the shipping code, we can understand the actual dependencies that code has on different parts of our domain objects. This can help determine the code needed to interoperate between modules.
- Understand how to split up the data. Splitting up a database means understanding the dependencies within the database. The first thing to think about is foreign key-primary key relationships between tables. But what about stored procedures that access parts of the database? Are there embedded triggers in one of the tables that have dependencies on another table within the database? Again, looking at the architecture of the database (all the dependencies) can help you plan how you will split up the database
- Manage the evolution. Refactoring is never done in isolation. The business still needs new functionality and bug fixes. You need to be able to both add new features and fix bugs at the same time. This is where incremental refactoring can be beneficial. Update a few pieces of the architecture and see how the application is affected by the changes.
There are many benefits to modularizing (refactoring) your Android application: improved maintenance, improved quality, faster builds, and improved developer efficiency. Modularizing your architecture does not have to be a risky, error prone process that requires a massive rewriting the entire application. Instead, it can be accomplished in an orderly and incremental way that minimizes risk while bringing the benefits of modularization.
The Aerospace and Defense industry has a large problem with increasing cost and complexity in their projects. This is the result of Aerospace and Defense projects becoming larger and more sophisticated. To solve this problem, the complexity that has been introduced has to be identified, reduced, and managed. This will lower the overall cost and keep projects on schedule. As an example, Tesla puts a strong emphasis on modularity (reduced complexity) across all their hardware. So during the recent chip shortage, they were able to quickly switch to chips that were available and continue to make and sell cars with minimal disruptions. One technology that can be used to reduce complexity (and increase modularity) is the Dependency Structure Matrix (DSM).