01 logo

Why is Software Architecture Important?

Cost versus quality is counterintuitive

By Nitin KhaitanPublished 2 years ago 10 min read
Like
Cost versus quality is counterintuitive

Software Architecture reflects the internal quality of the product as compared to the user interface that reflects the external quality.

I have been in the software industry for more than 15 years and I got a chance to work on various applications and the architecture/building blocks that empower those applications. A few of them were enterprise applications while the others were greenfield or applications to empower tech startups.

Every application/feature that exists, is financed by its business stakeholders and is targeted at a certain consumer base and is developed by a team of architects, developers and testers. All stakeholders have their priorities. From the perspective of business stakeholders, time to market is important. For consumers, the application must be able to solve the purpose easily and intuitively. And if I think from the perspective of the development team who are owning the application from a development perspective, it is important to deliver the product/feature with the best quality possible in the agreed-upon time.

What is visible to the consumer of the application is the user interface. They look at the application from the perspective of user experience, possible use-cases they want to use it for, how intuitive the UI is, and the usability aspects of the application but what is invisible or hidden is the architecture or the code that is running in the background to empower this intuitive interface. Let me try to put forward different aspects of the good or bad quality of the code and its relevant impact on the business or consumer stakeholders.

When can we say a code is a good quality code?

Self-documenting code

The name of the package/folder, class, method and variables should be well defined and should be able to give a real sense of what that is meant for. While reading, we should be able to relate it to the real-world entity or the purpose or attribute. Comments should be added wherever required as well to support the logical flow and better readability.

Easy to read and understand

A few techniques that we should use to write an easy-to-read and understand code are:

  • A class or a script should cater to one single purpose
  • a long method should be broken down into smaller method
  • method(s) should have a logical name
  • an argument should have a logical name and logically the same name should be used along the path the argument has to traverse to reach this particular method

Modularisation

This is about dividing the code into a proper structure so that looking at the folder/package structure, we should be able to understand what to expect from that piece of code. We should try to write the code in the right place. i.e.- if the customer’s module is doing the payment-related stuff or the payment module is doing purchase-related stuff, it is not correct.

Reusability

When we break a long method into smaller logical methods, we will discover that quite a few of them are reusable. The reusability of the code might happen at the same class level or across different classes. At times, we might feel like shifting the common reusable code to another layer like framework or utils as well. It all depends upon if the common code is implicit to the feature in development or its common and should be moved towards framework/boilerplate.

Easy to enhance

An application’s inherent nature is to enhance and evolve as per the input from the business use case and consumer behaviour. It is very important that whatever we have written today, should be written in a way that we should be able to enhance the logical flow of the code later with the minimum rewrite. This is only possible if the code is well written and not too clumsy and cluttered.

Single Responsibility

A method, function or class should always solve one purpose at a time. If we get a feel while enhancing or writing, that its scope is increasing and it might cater to more than one purpose, we should refactor and break it down. This will help us in retaining the code quality and will avoid jumbled-up code.

Well-defined method/API signature or contract

One of the most costly parts is, changing the signature/definition of the method or the API, as it might already be in consumption by other flows of the application. We should think from a futuristic approach to ensure the signature we are finalising would not require any change.

Domain objects should be in line with the organisational current state and future vision

Applications/features are developed to empower businesses to achieve their goals and for the consumers to fulfil their needs, as desired by the product. An application is a mimic of the offline or manual workflow that in most cases exists. So, the class, script, method, variables, API signature and entities should all follow the semantics of the domain and the business it exists for. While designing an application, the more our code structure is in line with the business's current and future state, the more scalable it would be with the least effort.

Data structure

A well tough upon data structure might require a bit of high effort in the initial phase but it pays off in long term. It can be considered a key building block in the overall architecture.

Readily scalable

In most cases, the load on the application keeps on increasing either because of the scale in the business territory or due to adoption by the consumers. With new features coming in, a product moves towards maturity and tends to solve more and more use-cases for which a consumer might use that. A good application is always ready for that scale. It can be only achieved by:

  • iterative refactoring of the code
  • giving equal priority to technical debt
  • doing regular load benchmarking for 2X & 5X load
  • Low cost to change

    A good attribute to gauge the quality of the code and the architecture is, the cost incurred in the enhancement of an existing feature. A good quality code incurs less cost and is more agile.

    Fewer bugs

    A well-written code undergoes unit test cases, integration testing, static code review and code coverage check and is expected to be maintained as part of the development life cycle. It ensures the code quality at the development as well as the deployment stage (CD/CI).

    Indicators of poor code quality

    Hard to understand code

    A code should always be written from the perspective that anyone else in the team who has a fair business context, should be able to read and understand the code and the logic behind it. A code tends to lose its quality semantic when we try to publish code without a proper review cycle or the code is not self-documented.

    High bug rates

    Chances are high that with a poor quality code, the probability of bugs surfacing goes high with every release or change that is induced.

    Poor performance

    A slow API or a flow is another indicator of poor code quality. The slowness might be due to:

    • missed or wrong indexes at the DB level
    • poorly handled compute or memory consumption due to the way the code is written
    • or may be due to an external component in the pipeline i.e. — Redis, etc.

    High maintenance cost

    The maintenance cost of an application goes high with time if we ignore to do:

    • regular cleanup
    • work on technical debt
    • code refactoring
    • re-modelling wherever required

    It leads to bulky, unused and slow code.

    How can we avoid poor code quality?

    Code review

    This should be treated as an important step in the development life cycle. We should ensure that whatever a developer is doing should be done as part of the feature branch, and should get merged into the release branch only post 2 review cycles and the bug fixes are done for the same. Also, we should ensure that the build on the server should happen via the release branch only.

    Code cleanup

    As we move ahead with the new releases, at times, we are left with unused/legacy code for which the newer version has been released. We should regularly plan for the cleanup of this code. A way to do this can be, by creating cleanup tickets with relevant comments and aligning them with either future releases or as part of the backlog.

    Business agility should not compromise code quality

    At times, we have to deliver in time constraints. We should think from the perspective that both times to market as well code quality is important. We can achieve this by thinking from the perspective that not everything is important to be developed and delivered as part of the first launch. We can develop the feature/product into phases, by well defining the scope which will help us in achieving the same along with the quality.

    Keep track of technical debt

    Technical debts are unavoidable. They will always exist in the system. Important thing is, that we should not ignore or lose track of them. We should keep them adding to the backlog with proper details and should prioritise them as part of the product roadmap along with the features as part of the sprint.

    Monitoring and Alerts

    We should publish success, error, audit and action logs to either in-house or third-party tools concerning:

    • touchpoints
    • intermittent flows (capturing traceability)

    Create a dashboard to analyse trends for different:

  • feature
  • flow
  • sub-systems
  • systems
  • It should be analysed from different aspects like:

    • business aspects
    • behavioural aspects
    • technical aspects

    In case of deviations in trend or error scenarios or unusual behaviours, this system should raise alerts for the respective audience as well.

    Start with MVP

    While planning for a new feature, we should always start with an MVP (Minimal Viable Product):

    • do a soft launch
    • build observation around the consumer behaviour
    • looks at the usability patterns
    • generate insight from the matrix
    • evaluate success/failure criteria
    • plan the next set of enhancements

    What should we do to ensure good quality code?

    Invest in bootstrap/framework code

    More time and effort we will invest in the initial phase of the development to carve the building blocks of the architecture, mostly around NFRs, the faster and smoother the application development would be at the later stage of the development

    A balance between time to market versus code quality

    We should not compromise on time to market to achieve the best possible product and vice-versa. It is very important to keep a balance between the two as if we just focus on the quality of the product, we might get delayed with the delivery timelines and if we just focus on the timeline, we might compromise on the code quality. A mix of both is a good approach to move ahead with.

    Domain knowledge

    What might look technically correct might not be correct when we look at it from the perspective of business or domain. Domain knowledge adds its own level of refinement to the application architecture.

    Current and future state, knowledge of roadmap

    The better understanding a team has about the current and the future state of the product/organisation and the goals that we want to achieve, the better we would be aligned to achieve those targets. A solution is not just right or wrong. Whether it is right or wrong changes is very subjective, based on the requirement we have and goals that we want to achieve. What might be right today might become not that correct in the future scenario.

    Think ahead of time

    We should think ahead of time, it's a world full of uncertainty, and we should zero down on assumptions as much as possible. The reality is, as we move ahead with the development lifecycle, many things unfold on the way and at times, they are big enough to put in question, a critical solution that we all agreed upon earlier.

    The cost incurred in developing a feature versus its quality is counterintuitive. A good quality code can’t be achieved with a compromised timeline/cost in delivery.

    Read this to know more about Architectural building blocks.

    how to
    Like

    About the Creator

    Nitin Khaitan

    Strategic thinker, a technically astute developer/architect with 15+ years of experience owning engineering, backend, and frontend from infancy to successful progression via the utilization of tools, technologies, and methodologies.

    Reader insights

    Be the first to share your insights about this piece.

    How does it work?

    Add your insights

    Comments

    There are no comments for this story

    Be the first to respond and start the conversation.

    Sign in to comment

      Find us on social media

      Miscellaneous links

      • Explore
      • Contact
      • Privacy Policy
      • Terms of Use
      • Support

      © 2024 Creatd, Inc. All Rights Reserved.