One of the challenges of software architecture is to balance the trade-offs between different quality attributes, such as performance, security, scalability, and maintainability. One of these attributes that are often overlooked or underestimated is the cost of running the software system. The cost of running a software system can include the expenses of hardware, cloud services, licenses, energy consumption, and human resources. The cost of running a software system can have a significant impact on the profitability and sustainability of the business that owns or uses the system.
However, how can we measure and optimize the cost of running a software system? How can we ensure that the architectural decisions we make are aligned with the cost goals and constraints of the system? How can we compare different architectural alternatives in terms of their cost implications? These are some of the questions that motivate the idea of running cost as an architecture fitness function.
An architecture fitness function is a way of quantifying and evaluating how well an architecture satisfies a particular quality attribute or a set of quality attributes. An architecture fitness function can be used to guide the design and evolution of an architecture, as well as to monitor and verify its behaviour and performance. An architecture fitness function can be defined as a function that takes an architecture as input and returns a numerical value that represents how it fits the architecture for a given quality attribute or a set of quality attributes.
Running cost as an architecture fitness function means that we define a function that takes an architecture as input and returns a numerical value that represents how much it costs to run the software system based on that architecture. This function can be based on various factors, such as the number and type of components, the communication patterns, the deployment configuration, the resource consumption, and the operational activities. The function can also take into account different scenarios and workloads that affect the cost of running the system.
By defining and applying running cost as an architecture fitness function, we can achieve several benefits:
- We can make informed and rational decisions about the architecture based on its cost implications. For instance, we can choose between a monolithic or a microservices architecture based on their total cost of ownership (TCO) and return on investment (ROI).
- We can compare different architectural alternatives in terms of their cost-effectiveness and trade-offs with other quality attributes. For instance, we can evaluate whether adding more redundancy or caching improves the availability or performance of the system at an acceptable cost-benefit ratio.
- We can optimize the architecture for minimizing or maximizing the cost of running the system according to our goals and constraints. For instance, we can adjust the size and number of instances, the frequency and duration of backups, or the level of logging and monitoring to optimize the operational expenditure (OPEX) and capital expenditure (CAPEX) of the system.
- We can monitor and verify the actual cost of running the system and detect any deviations or anomalies from our expectations. For instance, we can use dashboards and alerts to track the cost metrics and identify any spikes or trends that indicate potential issues or opportunities for improvement.
- We can communicate and justify the architecture to stakeholders based on its cost-value proposition. For instance, we can use diagrams and reports to show how the architecture meets the cost requirements and delivers value to the business.
An Example of a low-latency, data-intensive service
Consider a scenario where we are building a low-latency, data-intensive service that deals with structured data. We have several architectural options at our disposal:
- Relational Database Management System (RDBMS): We could use a traditional RDBMS and apply strategies like partitioning and pre-compiled views to handle the data load.
- Online Analytical Processing (OLAP) Data Warehouse: Alternatively, we could use an OLAP data warehouse, which is designed to handle complex analytical queries efficiently.
- In-Memory Database: Finally, we could use an in-memory database for ultra-fast data access.
Each of these options has different implications for run cost.
RDBMS: While an RDBMS might be the most cost-effective option in terms of upfront costs, it could lead to higher run costs in the long run. The need for extensive optimization (like partitioning and pre-compiled views) can increase maintenance costs. Additionally, as data volume grows, we might face performance issues that require costly hardware upgrades or even a complete architectural overhaul.
OLAP Data Warehouse: An OLAP data warehouse, on the other hand, might have higher upfront costs due to licensing fees and the need for specialized skills. However, its ability to handle complex queries efficiently could result in lower run costs over time, especially for analytics-heavy applications.
In-Memory Database: An in-memory database offers the fastest data access, but it's also the most expensive option in terms of infrastructure costs. However, if the business value derived from ultra-low latency (e.g., improved user experience leading to higher customer retention) outweighs the higher run cost, this could be the best option.
In this scenario, using run cost as a fitness function would involve quantifying the costs associated with each option, considering both direct costs (like infrastructure and licensing fees) and indirect costs (like maintenance and opportunity costs). We would then use these cost estimates to guide our architectural decision-making process, always keeping in mind the need to balance cost efficiency with other system requirements like performance and scalability.
This example illustrates how running cost as a fitness function can lead to more informed, business-aligned architectural decisions. By considering the economic implications of our architectural choices, we can build systems that deliver maximum business value at the lowest possible cost.
A fixed budget is a common constraint in many projects and it certainly factors into the use of run cost as a fitness function. Here's how:
- Initial Architectural Decisions: If you have a fixed budget, it will directly influence your initial architectural decisions. You'll need to select technologies and design patterns that fit within your budget while still meeting your system requirements. For instance, in the example above, an in-memory database might be ruled out due to its high infrastructure costs, even if it offers the best performance.
- Trade-offs: A fixed budget often necessitates trade-offs. You might need to compromise on certain desirable features or performance characteristics to stay within budget. The key is to make these trade-offs in a strategic way, prioritizing aspects that deliver the most business value or are most critical to your system's functionality.
- Future-Proofing: When working with a fixed budget, it's particularly important to consider the future evolution of your system. You need to choose an architecture that not only fits within your current budget but can also accommodate future growth without incurring prohibitive costs. This might mean opting for a more scalable solution, even if it's slightly more expensive upfront.
- Monitoring and Optimization: Even with a fixed budget, run cost remains a crucial fitness function. You'll need to continuously monitor your run costs to ensure you're staying within budget, and proactively optimize your architecture to reduce costs wherever possible. This could involve techniques like resource optimization, efficient data management, and automating routine tasks.
In essence, a fixed budget doesn't change the fundamental principle of using run cost as a fitness function - it just adds an extra layer of constraint. The goal remains the same: to deliver the maximum business value at the lowest possible cost, within the boundaries of your budget.
automating the tracking and optimization of run costs is a key part of implementing this as a fitness function, and tools like InfraCost can be extremely helpful in this regard.
InfraCost is a tool that provides cost estimates for cloud infrastructure projects. It integrates with infrastructure as code (IaC) tools like Terraform and generates a breakdown of costs before you actually deploy your infrastructure. This allows you to understand the cost implications of different architectural decisions upfront, and make cost-optimized choices.
Here's how you can automate run cost as a fitness function using tools like InfraCost:
- Cost Estimation in CI/CD Pipeline: Integrate InfraCost into your continuous integration/continuous deployment (CI/CD) pipeline. This way, every time you make a change to your infrastructure code, you'll get an updated cost estimate. This helps you catch potential cost issues early before they make it into production.
- Cost Alerts: Set up cost alerts to notify you when estimated costs exceed certain thresholds. This can help you stay within budget and avoid cost overruns.
- Cost Optimization Recommendations: Use InfraCost's cost optimization recommendations to identify opportunities for cost savings. This could involve things like resizing over-provisioned resources or switching to a more cost-effective service.
- Cost Reporting: Regularly generate and review cost reports to understand where your money is going, and identify any unexpected cost increases.
- Integration with Architecture Decision Records (ADRs): When making significant architectural decisions, include the output from InfraCost in your Architecture Decision Records. This ensures that cost considerations are formally included in your decision-making process.
By automating the tracking and optimization of run costs, you can make cost awareness a built-in part of your architecture process, rather than an afterthought. Tools like InfraCost make this automation possible, helping you build cost-efficient systems without sacrificing other important architectural qualities.
In conclusion, running cost as an architecture fitness function is a useful and practical way of incorporating cost considerations into software architecture. By doing so, we can ensure that our architecture is not only technically sound but also economically viable.