Software Architectural Principles

In this post I would like to share some Architectural Principles that every Software Architect need to understand or be aware of. The architecture practise area is so broad, open and convoluted within Agile software development. Furthermore, the ephemeral nature of most modern applications (should I say Functions, micro-services, Lambda’s) as they iterate and become something else over years, delivering varied business value makes it even more interesting to apply these principles to systems and applications as they evolve in this era of Artificial Intelligence (ML, DL, API AIs) and Serverless.

ARCH 1: Single Responsibility principle

Screen Shot 2017-09-15 at 10.38.12 AM.png

Each component or module should only be responsible for a specific feature or functionality, or aggregation of cohesive functionality. Remember single responsibility – thanks to Serverless and Function as a Service!

ARCH 2: Separation of Concerns

Screen Shot 2017-09-15 at 2.51.49 PM.png

Divide application into distinct features with little or no overlap in functionality. The important factor is to minimise interaction points to achieve high cohesion and low coupling. Note: Separating functionality at wrong boundaries can result in high coupling and complexity even though the contained functionality within a feature does not significantly overlap.

ARCH 3: Principle of Least Knowledge (aka Law of Demeter)

demeter.jpg

A component or object should not know about internal details of other components or objects.

ARCH 4: Don’t repeat yourself (DRY)

You should only need to specify intent in one place. For example, in terms of application design, specific functionality should be implemented in only one component; the functionality should not be duplicated in any other component.

ARCH 5: YAGNI – You ain’t gonna need it (Minimize upfront design)

Screen Shot 2017-09-15 at 3.05.53 PM.pngOnly design what is necessary – sounds easy but isn’t simple in software architecture within Agile frameworks. In some cases, you may require upfront comprehensive design and testing if the cost of development or a failure in the design is very high. Especially for agile development, you can avoid big design upfront (BDUF). If your application requirements are unclear, or if there is a possibility of the design evolving over time, avoid making a large design effort prematurely. KISS and fail fast is my other favourite principles.

ARCH 6: Define clear contract for components

Components, modules, and functions should define a contract or interface specification that describes their usage and behaviour clearly. The contract should describe how other components can access the functionality of the component, module, or function; and the behaviour of that functionality in terms of pre-conditions, post-conditions, side effects, exceptions, performance characteristics, and other factors.

ARCH 7: Do not overload the functionality of a component

Overloaded components often have many functions and properties providing business functionality mixed with crosscutting functionality such as logging and exception handling. The result is a design that is very difficult to maintain and often error prone. Applying the single responsibility and separation of concerns principles will help you to avoid this.

ARCH 8: Do not mix different types of components in the same logical layer

Start by identifying different areas of concern, and then group components associated with each area of concern into logical layers. For example, the UI layer should not contain business processing components, instead should contain components used to handle user input and process user requests.

ARCH 9: a) Understand how layers communicate with each other b) Understand how components will communicate with each other

Allowing every layer in an application to communicate with or have dependencies on all other layers will result in a solution that is more challenging to understand and manage. Make explicit decisions about the dependencies between layers and the data flow between them. How components communicate warrants deep understanding of the deployment scenarios your application must support. You must determine if all components will run within the same process, same container, or if communication across physical or process boundaries must be supported – perhaps by implementing message-based interfaces.

ARCH 10: Keep the data format consistent within a layer or component.

Mixing data formats will make the application more difficult to implement, extend, and maintain. Every time you need to convert data from one format to another, you are required to implement translation code to perform the operation and incur a processing overhead.

ARCH 11: Keep crosscutting code abstracted from the application business logic

crosscutting.jpg

Crosscutting code refers to code related to security, communications, or operational management such as logging and instrumentation. Mixing the code that implements these functions with the business logic can lead to a design that is difficult to extend and maintain. Consider using frameworks and techniques (aspect oriented programming) that can help to manage crosscutting concerns.

You must consider when architecting your applications:

  • Instrumentation and Logging
  • Authentication
  • Authorization
  • Exception Management
  • Protocol and Communication
  • Caching

ARCH 12: Determine Deployment Strategy

Your application may be deployed in a variety of environments, each with its own specific set of constraints such as physical separation of components across different servers, a limitation on networking protocols, firewall and router configurations, and more. Think about diagnosable, recoverable, and others!

ARCH 13: Determine Appropriate Technologies

Your choice of technologies will also be governed by organization policies, infrastructure limitations, resource skills, and so on. You must compare the capabilities of the technologies you choose against your application requirements, taking into account all of these factors before making decisions.

ARCH 14: Determine Quality Attributes (Fitness functions)  

Every application design must consider security and performance, but not every design needs to consider interoperability or scalability. Understand your requirements and deployment scenarios first so that you know which quality attributes are important for your design. Keep in mind that quality attributes may conflict; for example, security often requires a tradeoff against performance or usability or debuggability as security checks (Auth & Authn) or constraints could cost performance.

Questions one should ask when considering quality attributes include:

  • What are the key quality attributes required for your application? Identify them as part of the design process.
  • What are the key requirements for addressing these attributes? Are they actually quantifiable?
  • What are the acceptance criteria that will indicate that you have met the requirements?

ARCH 15: Designing for Operation, Keep DevOps or SecDevOps in your thoughts 

Design for Operability & Supportability. Architecting for production is key to delivery of artefacts. Also total cost of ownership (TCO) is something that is critical to business – from a P&L perspective. I see operations (you build it, you own it) as an on-going nightmares given the scope of whats involved. At a very high level things such as security, pen test, data breaches, compliance, performance test, vendor support, SaaS HA / SLA, cloud & hybrid public cloud, etc is critical to business and operations team. At an application level failure handling, retry, 3rd party integrations, monitoring and alerting, etc evolves over time and operations tend to become complex.

Summary

These principles cover broad areas of software architecture addressing various aspects such as business architecture, software architecture & design, software development, hosting, operations & support, customer data & experience, software evolutions, re-factoring, re-architecting, and most importantly business value delivered from an architecture practise should be on the rise. I believe these principles stay relevant and valid even today and next foreseeable future.

Advertisements

Monolith vs Microservices

Tags

, , , ,

In this article I would like to cover industry’s hype on ‘Microservices vs Monolith’ debate and also try contemplate “how to make that hard decision” in this modern software era.

Monolith vs Microservices

Monolith vs Microservices

What is a Monolith? Is it Bad?

Monolith is not all that bad, don’t jump to any conclusions yet, read this post before you can reason out. Let us see how industry leaders define ‘Monolith’ as

A monolith is an architectural style or a software development pattern – see below common Monolithic style.

  • Compile Time, The Code Units and their Relationship
    If you have all of the code for a system in a single codebase that is compiled together and produces a single artifact. The code may still be well structured (classes and packages that are coherent and decoupled at a source level rather than a big-ball-of-mud) but it is not split into separate modules for compilation. This is called Module Monolith.
  • Software and its Environment.
    If you have all of the code shipped/deployed at the same time. In other words once the compiled code is ‘ready for release’ then a single version is shipped to all nodes/VMs. All running components have the same version of the software running at any given point in time. This is independent of whether the module structure is a monolith. This is called Allocation Monolith.
  • Component Structure and their interaction during Runtime
    If you have a single application or process performing the work of the system i.e multiple services under one umbrella service/system which may or may not have multiple external dependencies. Many applications have traditionally been built like this. This is called Runtime Monolith.

Martin Fowler described this quote in his blog about Monolith – makes sense yeah, agree?

…don’t even consider microservices unless you have a system that’s too complex to manage as a monolith. The majority of software systems should be built as a single monolithic application. Do pay attention to good modularity within that monolith, but don’t try to separate it into separate services.

Now lets look at microservices, yay!

Oh, wait…

What are the pros and cons of monoliths?

  • Limited Agility
  • Obstacles for CI/CD/Testing Automation
  • One Technology Stack – so boring, really?
  • Technical Debt – yup! big one for me!
  • and more… you know it already 🙂

moving on….

What are Microservices? Is it Good?

Microservices is nothing but an architectural style – an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and are independently deployable by a fully automated deployment machinery. There is bare minimum centralized management of these services, which may be written in different programming languages and use different data storage technologies.

Why someone would want to build Microservices?

  • Service Model is around business domain – package structure and runtime dependencies are around business domain. To build services for business functions/verticals rather than end-to-end system.
  • Testing and Automation (CI / CD / DevOps Culture) – easy because it is small to manage compared to those N-layers in ‘big-ball-of-mud’.
  • Abstraction (hiding implementation details) – nothing new here, as OOP we always define interfaces, abstract classes, classes, etc..
  • Decentralise everything – the services are still logically coupled, no matter how you split them.
  • Autonomy (deployed and monitored independently) – easy to benchmark and fine tune each services
  • Isolate blast radius / failures –  now that’s potentially a good thing. If one module “fails”, you can just display “sorry, this functionality isn’t available right now” and handle the failure.
  • Graceful degradation is another important aspect of microservices.

How does the above compare to monolithic world?

  • You can automate the deployment of any application. Blue-Green Deployment for Monolith.
  • Abstractions in the form of microservices brings network overhead whereas in monolith it is all in the same process/machine.
  • ‘Decentralized’ is just a thing that sounds good, but in practice means nothing in this particular context.
  • ‘Deployment Autonomy’ alone doesn’t give you anything over a monolith – where you can gather metrics (e.g. with statsd) or get profiling and performance information about each class or package or routine.
  • Graceful degradation can be handled by monoliths too, it would require a little bit of extra code – e.g. feature toggle in case of failures

Other benefits such as “easy to modify” and “easy to understand” were claimed and hyped. But again, a well written, structured and tested monolith can be as easy to understand and modify.  Software engineering, CI/CD, infrastructure management / Docker containers and other best practices are claimed to work very well with microservices, while in fact they work perfectly fine with a monolith.

Kewl, I’m not saying go and build monolith, read further.

But, why Microservices is also scary?

  • Coordination between services – most often asynchronous, message based, orchestration adds complexity
  • Sharing of Common Data – needs disciple, good architecture and engineering practise, and we can’t oversee the necessity to keep duplicated data in sync
  • Lack of Transactions – CAP Theorem, Consistency vs Eventual Consistency
  • Communication overhead – network overhead, all the serialization and deserialization, require reliable and fast network connections
  • Usually hosted on Docker Containers which has CPU overheads
  • Need for Service Discovery – The dynamic nature of a service’s endpoint address is handled by service registration and discovery.
  • Can’t do lift and shift of existing codebase or application – need to be re-architect and re-design which often requires new CAPEX.
  • Team communication overhead – updates in one team’s service does not break another’s team functionality
  • Formal documentation overhead – to keep updated schemas and interface documents all the time
  • Polygot technology stack – it leads to a problem of non uniform application design and architecture. It can increase maintenance costs in the long run.
  • DevOps complexity –  due to several moving parts of the application, it becomes complex and requires a level of expertise.
  • Network security – Inter service communication needs to be secured to avoid any security breach. Due to several moving parts, these applications are more prone to security vulnerabilities.
  • Testing of such applications is definitely harder in comparison to monolith applications. Plumbing all services, coordinating data store from production backup from production, configuration and coordinating testing efforts across various teams and their services will be a challenge.

So why choose Microservices? when to use?

There are real use cases for microservices, see below.

  • Multiple Teams – Geo-separation, component autonomy,
  • Team Skills – Technology Diversity, Multiple Programming Language, Framework
  • Reversibility of a component architecture – R&D, Innovation and embrace fail-fast
  • Short-lived, Spawned Workers – micro components, utility components
  • Memory or CPU Intensive Components/Services
  • To break synchronous, long running ‘Chain of Services’ (i.e. Service A ↔ Service B and Service B ↔ Service C) to a scalable asynchronous architecture.

Conclusion

Microservices architectural pattern has well-known advantages and can certainly help any business evolve faster as long as they can operate them efficiently. Consider the operational requirements of microservices in addition to the benefits before considering refactoring monolith to a microservices architecture. I think Architects need a take a middle ground – wisely choose monolith over microservices if your application isn’t complex, doesn’t churn drastically, doesn’t involve too many development teams. But let’s accept the fact that monoliths will stay with us for foreseeable future in this modern software era.

 

Why Architecture?

Tags

, , ,

If you ever asked someone or thinking aloud as to why a project initiative need an Architecture, then you should continue reading this post. Kewl, you are not alone.

Why Architecture? 

It is a tricky question that might have varied and complex answers. This was my first question too when i joined as a fresher but my curiosity didn’t stop there and below questions kept popping up and I decided to explore further.

Architecture

What is it?
What does Architecture really address?
What are those boxes and arrows?
What are the governing architecture principles?
Who reads it?
Who cares for it?

I’m here today who truly believes and appreciates the necessity of ‘Software Architecture’ for modern business to innovate.

Ok, let me try and answer ‘What is Architecture’ in this post.

What is Architecture?

Industry Definition: The fundamental organization of a system embodied in its components, their relationships to each other, and to the environment, and the principles guiding its design and evolution. Usually captured as diagram.

My Definition: 
A shared understanding among various team members (business, product, development, operations) about an application or a set of applications, more often observed as delivery platform, that drives business by innovating and delivering capabilities that are robust, built flexibly – open for extension, composable by nature, and can be orchestrated to produce an optimal solutions to deliver a software product for the end business users.

Two Kinds of Architecture

#1) Traditional Architecture (a.k.a Waterfall Software Architecture)
Main Features

  • Focus on big picture
  • Compliance-Oriented
  • Produces Blueprints
  • Not much hands-on experience

#2) Agile Architecture (a.k.a Modern / Capability or Enabler Platform / Service-Oriented / Microservices Architecture)
Main Features

  • Focus on big picture and now
  • Hands-on Experience
  • Produce reference-architecture (prototypes, if deemed necessary)
  • Focus on sustainability (Dev Team buy-in)

What does Architecture really address?

It really depends on the software product but below fitness functions are generally considered. Usually covers Cross-Cutting concerns such as error detection, data validation, persistence, transaction processing, information security, caching, logging, monitoring, business-domain optimization, and others.

  • High Throughput – Load, Max Req/Res, stateless vs stateful, TLS / TCP considerations, connection limits, etc..
  • High Availability – Scalability, Resilience, Disaster Recovery, etc..
  • Data Security – at rest and in transit
  • Compliance and Legal Requirements
  • Usability
  • Monitor-ability
  • Low Latency
  • Production Cost Factor – Maintenance and Operation
  • Configurability
  • Audit-ability
  • Deployment Platform
  • Composability Index
  • others

What are those boxes and arrows?

For a shared understanding we need a common language that everyone can understand hence diagrams which can capture the intent, problem being solved and the decision being made (tradeoffs / alternate solutions / technical debt).

What types of diagrams are used in Architecture? 

  • Usually block/component diagrams with arrows (subset of UML)
  • Occasionally ‘Sequence and Activity Diagrams are used to capture some high level and low level designs

What represents a block/component? why lines and arrows?

  • Block or component(boxes) generally represent a system/platform (software stack) that delivers business capabilities and features for one (or more) domain functions
  • Relationships and contracts between the components are defined by lines
  • Arrows represent the nature of relationships and/or data flow among components. want to learn more? read online about UML types

Governing Principles?

Very complex and a long list but below is my two de-facto standard principle what helps making decisions

  • KISS – Keep it Simple, Stupid
  • YAGNI – You Aren’t Gonna Need It

What these two principles try to enforce is to make us think if we really need a specific feature or decision at that very moment. If we can postpone making a decision to a later moment (a character of Agile Architecture), we will keep our architecture simple and hence easy to manage for a longer time. One common way software architectures become complex is by introducing abstractions – this could be a new fancy layer that copies data in one format and transforms it into another, or this could be creating many classes, interfaces, factories, etc., to ensure testability.

However, one pitfall when applying these two principles is that we tend to delay everything until the last possible moment. By then it may already have become too difficult to implement the required change. Instead our task is much more difficult, because

“we should take decisions not in the last possible moment, but rather in the most responsible one.”

What I usually do if I am about to make an architectural decision, is to do some small preparations that do not take much time, if the certainty of this decision is high.

Who should care? read?

Everyone (really? yes, at least PO, BA, Tech Leads, QA, Ops should) involved in project, both technical and non-technical, should care and empower software architecture in order to understand the business problem, solution and important decisions taken. Be involved in the process such as of product briefing, technical brainstorming sessions, whiteboard sessions and alternate solutions, decisions and its implications, documentations, Q&As, Dev & Operations Team sign-off, etc. Architecture empowers engineers, developers, business and product owners to collaborate better.

Coming up: My next post will introduce common architectural patterns that are widely adapted by current modern architecture community. Stay tuned!