From Requirements to Architecture: A Hydroponic System Case Study (Part 2)

In Part 1, we translated product-level needs into structured engineering requirements using the EARS (Easy Approach to Requirements Syntax) methodology.In Part 2, we move forward: from requirements to architecture. This post introduces how we apply the “Data Dictates Design” principle to shape our hydroponic system’s software architecture in a modular, scalable, and testable way.
From Requirements to Architecture: Data Dictates Design
Instead of starting from functions or classes, we began by identifying the data our system needs to handle. This approach ensures the architecture is centered around real-world behavior and that components are designed around how they interact with that data.
Step 1: Identify the Data
From our requirements, we extracted the following key data points:
- Sensor Readings: Air humidity, water level, air temperature, water temperature, DO (Dissolved Oxygen), EC (Electrical Conductivity), pH value.
- Control Outputs: Pump control signals (for water, oxygen, nutrients, and pH adjustment).
- User Interaction: Configuration changes and UI outputs.
- Persistent Configuration: Parameters stored and retrieved from non-volatile memory, as configuration is present.
Each of these data points becomes an interface—either to publish/subscribe or read/write—defining how components communicate.
Step 2: Architecture Around the Data
From these interfaces, we designed the high-level architecture of the hydroponic system:
Figure: High-level component diagram based on data-driven design
Architectural Highlights
- Sensor Drivers read sensor data every 1000ms and publish values.
- The Control System subscribes to relevant data and publishes control decisions.
- Pump Drivers receive actuation commands and drive the hardware.
- The Configuration Manager handles persistent and live parameters.
- The UI System presents system state and enables user inputs.
Each component’s responsibility is defined entirely by its data interfaces, making the system modular, testable, and simulation-ready.
Step 3: From Structure to Behavior
With this architectural “big picture,” we now begin modeling system behavior through sequence diagrams. These diagrams illustrate how components interact over time during key workflows.Here are two examples of behavioral flows we are modeling:
Shows pH correction flow
Captures how a user updates configuration via the UI System, which then passes data to the Configuration Manager.
These behavioral models bring clarity to interactions and prepare the ground for what comes next: statecharts. Note that at the end we will have a bunch of sequence diagrams as we want to define all the intended behavior of the system but also the behavior that deals with exceptional conditions or mistakes made by the user. So in this post we have made some toy examples but a bunch of them should be made.
Bonus Insight: Simulate Before You Build
Powered by the Dependency Inversion Principle
A powerful byproduct of this architecture is the ability to simulate the entire system before any hardware is available.This is possible thanks to applying the Dependency Inversion Principle, a core element of SOLID design. In our design:
- High-level components (e.g., the Control System) do not depend on low-level hardware drivers.
- Low-level drivers do not depend on application logic.
- Instead, both depend on shared interfaces—exactly the kind we've structured around our core data points.
Because hardware-specific logic (e.g., ADC, I2C, UART) is confined to driver implementations of abstract interfaces, we can easily swap in mock components during development and simulation. This simulation can be fully automated for tests or manually driven via a dashboard, enabling interactive validation.
Why Simulation Is Critical
This simulation approach gives us:
- Early validation of business logic
- Faster iteration without hardware delays
- Reliable testing, even before sensor or pump hardware is finalized
- Greater resilience when hardware is unavailable or blocked (e.g., shipping delays, supply issues, shared lab access)
By abstracting all hardware dependencies, our architecture allows host-PC simulation of:
- Sensor readings (realistic, randomized, or edge-case)
- Control decisions and actuator responses
- UI interaction with mock inputs
- Full end-to-end workflows
With this setup, the core application can be verified long before any electronics are in place.
One Last Note
It is very important to highlight that this architecture maintains traceability with the requirements and is designed to co-evolve alongside them. As new insights emerge or requirements change—whether due to technical constraints, user feedback, or market shifts—this structure allows the architecture to adapt without collapsing.
Nobody said it would be easy. It won’t be. But it will be worth it.
This alignment ensures that engineering decisions stay connected to the product's core intent.
What’s Next?
With our architecture defined and behavior modeled through key sequence diagrams, we're now ready to move into detailed design.In Part 3, we’ll use the interaction flows captured here to design statecharts for individual components. These state machines will drive the internal logic of each module and guide us through the implementation phase with confidence and clarity.