Subscribe Us

Designing a Software Architecture Correctly

Architecture, Design, Design Patterns, etc. terms are widely used in literature and specific project communications. The goal of this write-up is to gain a better understanding of these terms with help of some examples.

Let’s start with the basics.

What is Software Architecture?

There are many definitions of Software Architecture.

Wikipedia says “Software architecture refers to the fundamental structures of a software system and the discipline of creating such structures and systems”

Martin Fowler has defined architecture as “the decisions you wish you could get right early in a project and Architecture is about the important stuff. Whatever that is.”

There will be many more definitions. They all are true, but I have found the description in Clean Architecture by Uncle Bob easier to start understanding the concept. Here is my explanation based on that:

There are two aspects (or “value” as Uncle Bob says) of software:

  1. Behavior: the reason for the software to exist like an email client to send and receive emails, a calculator to perform calculations, etc.
  2. Shape / Structure: it is the foundation on which features (that provide behavior) are built.

Behaviors will change with time as the software needs to adapt to the growing and changing user needs. A good architecture will provide a shape/structure that makes the evolution of behaviors easier, faster, and less expensive.

Architecture’s goals are to make it easy to understand (for a developer), develop, maintain (change), deploy and operate the software.

A lot has been said in a few lines! It will become clear as we go further.

What is Design?

The difference between Software Architecture and Design is confusing because they both are mixed and sometimes there is no clear differentiation. But still, let’s try to understand what is called Design.

Architecture is about shape/structure which is fundamental and difficult to change once done. Design is things that are built on the foundation and things that can be changed with relatively less difficulty.

Let’s try to understand with an example:

  • An application has default system settings and user settings. User settings override default system settings. Default system settings are configurable via database and environment variables. Environment variables take priority over database config.

  • To implement this requires deciding many things like:

    1. Configuration Parameter naming standardization
    2. Database schema to store configuration
    3. APIs / Interfaces used by other parts of the system to fetch and update configuration
    4. Classes and their relationships implementing the behavior required for configurations
  • #1, #2, and #3 are things that are more expensive to change once implemented and deployed. So they are Architectural Decisions. #4 can be changed relatively easily even after implementation so it can be considered a Design Decision.

Process of Architecting

  • Architecture in a way is a set of decisions taken in a given scenario.

  • Most of the time, something can be done in multiple ways, but the Architecture selects one option from that. That choice of one option is the Architectural Decision. E.g.,

    • There are multiple protocols to build an API: REST, GraphQL, and SOAP.
    • The decision to use GraphQL is the Architectural Decision.
  • So the next question should be how are these decisions made? Inputs to Architectural Decision Making:

    1. Requirements
    2. Architectural Characteristics (AC) (or Non-Functional Requirements) are derived based on requirements and business domain. E.g.,
      • For a stock trading platform, Performance and Reliability are important ACs.
      • For a news aggregation portal, Responsiveness is important – meaning immediately loads the first 5 stories and loads the remaining stories asynchronously, so the user doesn’t have to wait longer to start consuming the content.
    3. Implicit ACs: things that nobody will ask for but always expect like Security, Maintainability, etc.
    4. Available resources: budget (cost), skills, and time. Example:
      • It is identified that writing a serverless function (AWS Lambda) is a good choice to perform some background tasks.
      • NodeJS may be the right choice to write a serverless function but do we have the skills in the team to build it within the time we have to release the feature?
      • We don’t have NodeJS developers but we have Java developers, so is it possible to use Java to write a serverless function?
  • Most Architectural Decisions are trade-offs. They have some bad outcomes, but still, it may be the right decision for the given circumstances. If we can live with it, it is easier otherwise we have to try to mitigate its effects. E.g.,

    • Writing a serverless function (AWS Lambda) in Java has the problem of Cold Start because JVM takes at least a few hundred milliseconds to start up.

    • So we have the following options. Each has its negative impact but we have to select the one right for current circumstances:

      1. Since the functions will be used in background processing so we decide to live with a few milliseconds of a performance hit for now and revisit this later if it becomes a serious issue.
      2. In case we cannot afford a performance hit, we have to provision at least 1 (or more depending on load) Lambda instance to be active all the time. But this will add to the Cost.
      3. Train a developer on NodeJS and then write functions in NodeJS. But this will impact the timeline.
      4. Find an alternate to the serverless function.
  • The output of Architecting:

    • Documentation with reasoning and decisions. It can be diagrams, write-ups, specs, etc.
    • Common artifacts:
      • Components and relationships between them
      • Shared libraries and interfaces
      • Deployment view
      • Security scheme – authentication, authorization, secrets management
      • API Schema
      • DB Schema
      • Guidelines like naming conventions, exception handling practices, logging conventions, etc.

Case Study

Let’s walk through the journey of an application to understand these concepts with an example.

The product Manager (PM) and Engineering Team (ET) discuss requirements.

Stage: Building MVP

PM: We need to build a mobile app that will allow users to send SMS in bulk and check the status of the delivery. Users can manage a list of recipients by uploading a CSV or managing via the App.

ET: Do we need to send an SMS for each request immediately upon receiving the request?

PM: No, we don’t have to do that now. We put the request in the queue and we process requests one by one. The expectation is that we will process it at least within an hour of the user submitting the request. This is MVP so we will keep it simple.

ET: How will the user be on board and sign-in?

PM: They will use their mobile number. We will send an OTP and verify the number.

ET comes up with an architecture for MVP and produces artifacts.

Components

Deployment

The architecting process would produce other artefacts like Database Schema, Security Scheme, etc., but we are only including things relevant to the discussion.

1 month after the MVP release

PM: We have got an enterprise customer who is interested in using our services.

ET: That’s great!

PM: They right now use another provider. They generate a CSV file with requests at a scheduled frequency. This file is uploaded to a shared location and the service provider processes the file to send messages. They are interested in trying out our service if they do not have to make any changes to their implementation. Can we make it work?

ET: It should be possible. Let us think about it.

ET comes up with a solution that can be implemented quickly.

Components

A new component FileRequestService is added that will read files and create requests from them. This was possible because core domain logic to manage requests, recipients, etc. was implemented in BulkSenderDomainLib so it can be re-used easily from any part of the system.

Deployment

What went well?

Breaking down the system into modules allowed a new requirement to be accommodated very easily and quickly. This kind of requirement was not expected during MVP, but the Architecture was able to handle it.

6 months after the MVP

PM: There is a lot of interest in our service. Customers want to use it but we are getting a lot of complaints that the messages are delivered after hours.

ET: Because we are getting a lot of requests…

PM: But we need to fix this. We also want to introduce a quick delivery paid plan. We think we will get customers ready to pay for an immediate delivery commitment.

ET: That’s going to require a lot of work.

PM: Why..??

ET: We kept it simple for the MVP. We did not provision for scaling for the such load.

PM: We better do it right now!

What went wrong?

ET did not identify Scalability as AC\NFR in request processing in the original MVP architecture. That is now causing a problem when the solution needs to scale quickly. This lapse can be costly because it can either force a half-baked solution in hurry or delay business plans.

Should ET always design for scale even when they don’t know what is going to be the scale?

Its a trade-off:

a. Building for scalability will add complexity to the solution meaning more time to release.

b. On the other hand, there may be kind of problem we just went to through.

There is no right or wrong approach. If MVP doesn’t work, doing a quick release saved effort so (b) would be the right thing.

That’s where the Architectural Decision Making is required to find a balance between Long Term Goals and Short-term Needs working with all stakeholders.

In the end.

There is no universally accepted definition or scope of Software Architecture. It also evolves continuously with change in technology e.g., Cloud has added a lot of new possibilities that widen the scope of Architecture. We have tried to understand what can be considered Software Architecture. And now if you go back and read all definitions of Software Architecture, you may understand them better.

Instead of exactly defining what is Software Architecture, it is important to get a good understanding of the Process of Architecting and the Importance of making good architecture and design decisions.

This is a vast topic with various perspectives. A lot of the insights come with experience. I have presented my understanding. Please comment if there is anything you would like to add (or remove too :)). Thanks for reading!

References

Clean Architecture by Robert C. Martin

Fundamentals of Software Architecture: An Engineering Approach by Mark Richards, Neal Ford

C4 Model by Simon Brown – Component Diagram uses C4 template

Also Published here

L O A D I N G
. . . comments & more!



Designing a Software Architecture Correctly
Source: Trends Pinoy

Post a Comment

0 Comments