Introduction to fitness functions concept with simple examples
In this article, I’m going to introduce the fitness functions concept and provide a few simple examples. By the end of the article, you’ll get an idea of what these functions are used for. Hopefully, you’ll gather fresh ideas about testing your project’s requirements.
Fitness functions are used to measure how close the architecture comes to achieving a goal. They guide us through the evolution of the system.
The software architecture considers crucial requirements such as performance, reliability, security, operability, coding standards, etc.
For example, we can write tests or metrics to meet the required criteria. Consider a business requirement that states that all services should respond within X ms. We can write a test that measures the response time and fails if the result is greater than that value.
Each new service should pass these test criteria. This way, we constantly get feedback if the development goes according to the plan.
We should aim to identify the fitness functions from the software development's early stages. What are the most important criteria for your product? Usually, stakeholders and business analysts provide the specification. Depending on the industry, the requirements vary. For example, it’s crucial to have a stable performance and security in banking.
Architecture standards evolve constantly. The fitness functions help break a complex system into smaller pieces. This way, it’s safer to make any changes to the software and identify any issues in an early stage.
After collecting the necessary criteria from the key people, integrate them into a testing framework. Consider incorporating the tests in the CI/CD pipeline process.
You’re probably familiar with Unit tests that ensure the code quality is met. Let’s cover other non-functional requirements, such as scalability, performance, and other architectural aspects.
Architecture constraints tests
Let’s write a test to validate architecture constraints.
Consider a fitness function defined at the technical architecture level to control the dependencies between components. For example, for Java, there is a tool called ArchUnit. It analyzes the dependencies between packages and classes, layers and slices, checks for cyclic dependencies, and more.
The tests can be run as JUnit tests. They prevent developers from violating architectural design principles. If someone accidentally submits a non-compliant code, the build will fail, and the developer will find out the issue on time.
For instance, let’s verify that the controller class should call secured methods only:
Architecture design tests
If you’re applying the Layered Software Architecture, you can add ArchUnit tests to ensure the design is not broken:
This test ensures that only allowed layers can access the specified layers.
Architecture and operation tests
You can also measure a combination of architectural and operational qualities. For cloud environments, there is a tool called Chaos Monkey. The Netflix engineers invented it to test the resiliency of AWS.
It randomly creates chaos — latency goes up, processes get terminated, and so on. The exposure of the failure ensures that developers make the services resilient to instance failures. If you want to know more about chaos tools, check out my related article about Chaos Mesh:
For security, you can use Static Application Security Testing (SAST) or image scanning tools. You can prevent the usage of a container image with known vulnerabilities. For example, tools like JFrog Xray scan all of the layers in your container recursively.
Having fitness functions ensures the software meets the desired architecture standards. By breaking down the software into smaller units, it’s easier to implement new changes. Fitness functions constantly provide feedback about the development process.
I hope that you’ve learned something new today. Thanks for reading, and happy coding!