logo

Software Architecture for Daily Usage

Before worrying about architecture and design principles, it would be good to start here and define what we are looking for. Software Architecture is pointless without leveraging it to support our goals. And before we can leverage it, we need to know what good software is.
  • Good software is functional – If any piece of software can’t execute its core functionality, then it’s useless.
  • Good software is robust – What this means is that good software is resistant to changes around it and failures, it also means being able to recognize and deal with failures.
  • Good software is measurable – This trait has taken time to grow on me personally. It should be possible to see how well the code is doing outside of a test environment. Usually, the best measures are how the software can facilitate business needs. A good measure for a UI is how long it takes to load or react to an interaction.
  • Good software is debuggable – This doesn’t mean being able to log everything for the heck of it but being able to bulk dump debug on demand can be very handy.
  • Good software is maintainable – Software can be easy to maintain if it has consistent styling, good comments, is modular, etc. In fact, there is a lot of literature on good software design that just focuses on design principles that make it easy to make changes to parts of the software without breaking its functionality.
  • Good software is reusable – Generalizing a solution can be hard and time-consuming. Obviously, we are all on deadlines so unless you are absolutely sure that you are going to reuse this piece of functionality elsewhere, you can time-bound the effort of making it reusable.
  • Good software is extensible – Usually, the conversation starts with – β€œBut suppose that tomorrow somebody wants to add X here…” software should be written with extension in mind, these extensions should be thought of in the most general of fashion. Like the general copy command on all OSs, it doesn’t care where you’re copying to or from these are extensions to the original program, making it immeasurably more valuable.
Having clean software architecture and staying conform to pre-defined design principles from the start of the project is one of the best ways to avoid possible technical debt in the future of that software system. Clean Software Design is a key point for an effective software product.
Let us have a look at some important principles, rules, and guidelines that ensure a clean software design:
Principles:
  1. Loose Coupling β€” if classes use each other, they are coupled together. The fewer classes are coupled, the easier is to change them.
  1. High Cohesion β€” the degree to which elements of a whole belong together. The components of the class should be highly cohesive.
  1. Locality β€” Changes, maintenance, and extensions are only local. This leads to no harming the whole environment.
  1. Removeable β€” Software Components should be easily removable.
  1. Small Components β€” software system should be only of small components ideally each doing only one task.
Class Design:
  1. Single Responsibility Principle (SRP)β€Šβ€”β€Šclass should do only one task.
  1. Open Closed Principle (OCP)β€Šβ€”β€Šclass should be extended not modified.
  1. Liskov Substitution Principle (LSP) β€” child classes must be able to replace their superclasses.
  1. Dependency Inversion Principle (DIP) β€” dependency is reversed: high-level components are free of low-level components.
  1. Interface Segregation Principle (ISP) β€” The interface should be small: classes should not implement unnecessary methods.
Cohesion Principles:
  1. Release Reuse Equivalency Principle (RREP) β€” only together releasable components should be bundled together.
  1. Common Closure Principle (CCP) β€” classes that change together should be bundled together.
  1. Common Reuse Principle (CRP) β€” classes that are used together should be bundled together.
Coupling Principles:
  1. Acyclic Dependencies Principle (ADP) β€” no dependency cycles.
  1. Stable Dependencies Principle (SDP) β€” depends on the direction of stability.
  1. Stable Abstractions Principle (SAP) β€” the more abstract, the more stable.
High-Level Architecture:
  1. Keep Configurable Data at High Levels β€” constants or config data should be kept at a high level.
  1. Don’t Be Inconsistentβ€” have a convention, principle, rule, or guideline, and always follow them.
  1. Prefer Polymorphism to If/Else or Switch/Case.
  1. Separate Multi-Threading Code β€” isolate multi-thread from the rest of the code.
  1. Only one level of Abstraction per layer β€” stay conformed to existing abstraction layers.
  1. Fields Not Defining Stateβ€Šβ€”β€Šfields holding data that do not belong to the state of the instance but are to hold temporary data. Use local variables or extract to a class abstracting the performed action.
  1. Micro Layers β€” avoid unnecessary design layers.
  1. Singletons / Service Locator β€” Make use of dependency injection.
  1. Base Classes Depending on Their Derivatives β€” Base classes should work with any derived class.
  1. Feature Envy β€” The methods of a class should be interested in the variables and functions of the class they belong to, and not the variables and functions of other classes. Using accessors and mutators of some other object to manipulate its data, is envying the scope of the other object Β©.
  1. Unused Coupling β€” avoid unused dependencies, and be greedy.
  1. Hidden Coupling β€” make sure that order of calls to different methods is correct.
  1. Transitive Navigation β€” (Law of Demeter), write isolated code. Classes should have access to only their direct dependencies.
Environment:
  1. Project Build Requires Only One Step.
  1. Executing Tests Requires Only One Step.
  1. Source Control System β€” Always use a source control system.
  1. Continuous Integration β€” Assure integrity with Continuous Integration.
  1. Overridden Logsβ€” Do not override warnings, errors, exception handling
Share