Table of Contents

Software Architecture

We can use AMMERSE for software design. Existing principles and methods have been designed, discovered or mined from existing code and experience. These are done by humans with values, and their observations are value-driven. Product Owners or others with no architecture knowledge can learn to communicate a little better about this important aspect of software development. In fact, they could even help reason about it.

Since AMMERSE is a value system, it should not be difficult to reason about software-oriented principles from an AMMERSE perspective.

What problems can AMMERSE help solve?

No matter your definition of Software Architecture, we all tend to agree that architecture is composed of decisions we make. It is ultimately a collection of trade-offs configured to create beneficial outcomes. Whether designing infrastructure, frameworks or web applications, you are creating a system that mirrors the team's values.

Problem: Knowing which designs are best

Problem: Remembering design choices

Problem: Implementing designs correctly according to envisioned tradeoffs

Problem: Knowing which architectural or design pattern to use

Problem: Vision, Leadership and Alignment

Problem: Mapping vision to code artefacts

Problem: Understanding the consequences of a design

Problem: Over vs Under engineering

Problem: Change and Complexity

Problem: Changing "hard-to-change" architectures

Problem: Knowledge transfer (especially of design)

Problem: Oversight or good decision-making by those that do not understand the design at the same level

Problem: Meta-architecture, meta-problems

Problem: Guidelines and rules

AMMERSE Design principles

Based on the AMMERSE value system and the Maturity Index, we can reason about design in a very practical way.

Reachable and Solvable (Level 1)

  • A design must be reachable and solve the problem

To reach, we must understand a reasonable amount about the requirements and what is needed. We need to understand the problem and solve it.

  • A design must be reachable for all actors

All actors involved should be able to reach the design. When a design is created, it is not merely some code for a feature, it must be reachable for the stakeholder, customer, developers and anyone else involved. ie. All actors of the system should be considered and balanced.

Reachable also pertains to 'ability to reach', such as reaching an understanding and learning curves.

  • A design must solve all conceptual layer problems as well as not introduce new problems

A design must solve the problem at each level from customer experience to operations. It should also not create problems. A design which creates problems while it is solving another is not Solving.

Solvable also pertains to how others can solve problems using the solution, or whether it creates problems for them. ie. Second Order thinking.

Minimal, Maintainable and Environmental (Level 2)

  • A design should be an elegant abstraction

You can solve problems in many ways, but each solution will have associated costs, design qualities and meta-problems. A minimal design is elegant while possibly solving more than one problem.

  • A design should be easily maintained

A design should be understood easily and maintained within suitable Reachable/Solving behaviour. Updating dependencies or fixing an issue should always be considered.

  • A design should be fit for purpose

There are many environments, from the developer's local machine to the cloud servers, to the code existing inside of an editor. Code should fit its runtime, platform, framework, coding conventions, user target runtime environments and required devices.

Agile (Level 3)

  • A design should be adaptable and changeable

A design should be adaptable and changeable to allow changing requirements to fit well. A design that allows the ultimate form of "design-time" change, without rewrites or large refactorings.

Extensible (Level 3.1)

  • A design should be extensible to solve future problems

A design should be extensible to solve future problems without modifying the existing code. Agile is "design-time", while extensible is "run-time". Without modifying the internals or any code, extensible code should be configured and running.

Design Maturity and GAP Analysis

Software can be divided into any segments, modules or architectures. Software can be divided into features, slices, layers or executable units. Each of these, however, you choose, can be measured against the Maturity Index.

A system could have a Maturity Index of 1 for feature x and a Maturity Index of 3.1 for feature y.

Practical Measurements

Any codebase can be examined and measured against the Maturity Index.

Note: Currently I am working on metrics for .NET based on AMMERSE which will provide a score for your code. If you are interested in coding on this, an opensource project can be created.

Visit a section of code that has a boundary of some kind, perhaps a module, a set of modules for a feature or similar.

Evaluate the code against the seven values. Here I will assume it is a Table of Contents generator.

  • Does the code reach all actors?
  • Does the code solve the problem?
  • Is the code minimal?
  • Is the code easily maintainable?
  • Does the code conform to it's environment?
  • Is the code agile?
  • Is the code extensible?

Further explanation

  • Does the code reach all actors?

Is it easy to install or do you need python and knowledge of package managers? Does the intended audience use python?

  • Does the code solve the problem?

Does it generate the Table of Contents? In which format? In the document?

  • Is the code minimal?

Even though the code is minimal, can it be styled? If it cannot be styled, does it actually solve the problem? Is this code efficient, low cyclomatic complexity, low dependencies?

  • Is the code easily maintainable?

Can you update the code easily since it is easy to read? Can any developer who has not seen it, be able to find their way easily, or do they need complex tools, packages and other setups?

  • Does the code conform to it's environment?

If it is a web application, is it isolated, using sandbox api? Does it use HTML/CSS and JavaScript? Does it use an out of process CLI that is not CGI or can cause issues running in process? Does the code abide by coding conventions for the language?

  • Is the code agile?

Can you style the table of contents, easily by adding a decorator or an event/callback function that can add styles. You did not plan to add styles, but it would be simple to add to existing code structure without refactoring and reworking the code?

  • Is the code extensible?

Can you create a different module, drop it into a folder and have it execute the new behaviour. Can you inherit, extend or add the styles by not changing existing code, but rather via an interface or api?

Software decision records

It is simple to store an AMMERSE Set in the design records to document the intended Maturity Index.

Implementation guidance and decision making

If a developer knows the intent of the design, for it could be decided that the Maturity Index 1 is satisfactory for this design or that we should do this to Level 3.1. The design and implementation would be vastly different.

As a design language

AMMERSE makes it easy to discuss designs and intentions.

  • Should we simply reach and solve or go for level 2?
  • When should I push to level 3.1 and build extensibility into this?

As gap analysis

Let us evaluate our codebase and create AMMERSE Sets for different features, sections and architecture. We can then have an idea of which sections are below standard.

Architectural guidance

We can stipulate our vision of quality. We do not release Level 1 code, we only release Level 2, and it will be evaluated by the team, and then QA.

Defect Analysis

Why are these features breaking often? Why do we have defects here or there? The AMMERSE maturity Index measured against the usage and expected operating behaviour is not aligned. Conduct a gap analysis and raise the level.

Which design pattern is best?

A Factory Method is good enough for level 1, but the Abstract Factory is best for Level 3 and 3.1. A Strategy pattern is overkill for Level 1. Liskov Substitution is only required for level 3. Open Closed Principle could be level 1 but it probably best suits the definition of Agile at level 3. A singleton is Level 1 while a composite falls into level 2. Single-Reponsibility or Interface segregation could well fall into Level 2 or 3. Microservices falls under Level 3.1. Pure fabrication is solidly a level 1. A god class is level 1 and so too is low cohesion. Low coupling could start at Level 2 but not really realised fully until level 3.1.

How do development practices affect this

Domain-driven design is Level 2, 3 and 3.1, with the more rigourous adoption will be level 3.

Behaviour-driven is arguably Level 2 code with Level 3.1 tooling and mindset. Whether the code is ultimately level 3.1 is dependent on the code itself, however many of the connected ideas lean code towards 3.1.

Test-Driven Development tends to produce Level 2 code with level 3.1 tooling and mindset. Whether the code is ultimately level 3.1 is dependent on the code itself, however many of the connected ideas lean code towards 3.1.

Waterfall tends to be Level 3, while Agile tends to be a level between 1 and 2.

Over-engineering vs Under-Engineering

Reason about the code/features and expected values.

If you are not reaching and solving minimally and maintainably in a section that requires extensibility, then you are under-engineering.

If you have a Level 3.1 extensible code base with all the agility required, for a feature that is not used often, or a large part of the product, you have over-engineered.

Goldilocks Maturity Index and code

Perfectly adequate code can remain at level 1. It is not a scale of importance or a scale where everything is best because it is at a higher level.

Complexity can be managed by implementing the correct levels for code that align with business and requirements. The goldilocks of AMMERSE is mathcing the correct values to each problem, where it is just right. Just right, is where you will find cost-effective, good working, not under or over engineered, good software.

If everything is level 3.1, you will most likely have an over-engineered solution. If everything is level 1, you will not have an adaptable product.

This will also depend on the business model, budgets and generally the environment in which the software runs.

Conclusion

AMMERSE can provide benefits for architects, designs, quality, code analysis and even selecting appropriate design patterns.

AMMERSE Sets can be easily constructed and done repeatedly over time to measure gaps and changes in code.

The metrics proposed by AMMERSE can be at any level you wish, as you can construct your questions for each value and measure it the same way each time. You can't measure lines of code or cyclomatic complexity to provide you with much insight, still can measure the problems it solves, the agility it has and ultimately what maturity the code is at.

AMMERSE offers a design language that will aid you in communication, governance, implementation and even quality.

Navigation

Substack Newsletter

Sign up to our newsletter and collaborate.

AMMERSE Levels

Level 1

7 Principles: Agile, Minimal, Maintainable, Environmental, Reachable, Solvable, Extensible.

Level 2

The AMMERSE Set has weights assigned to 7 Principles. eg. “Enterprise Strategy”.

Level 3

AMMERSE Sets in a grouping that work together for a purpose. eg. Modes.

Level 3.1

You can extend AMMERSE by creating your own Sets and Frameworks.

Our goal is to enable business strategy, implementation and the reaching of objectives by giving you the tools to design your own methods. 

Sign up for the occasional email