Skip to main content

EARS and Functional Thinking:

· 5 min read

EARS and Functional thinking is a Perfect Match for Requirements Engineering.

I first stumbled upon EARS (Easy Approach to Requirements Syntax) when trying to solve communication issues between business stakeholders and our development team. My experience with requirements had been a bit like my first ZX Spectrum 48k Phone Directory - technically correct but practically unusable. The business folks would write requirements that seemed clear to them, but developers would interpret them entirely differently, leading to a situation where we were constantly rebuilding features.

From Functional Programming to Better Requirements

"Functional programmers prefer data to calculations and prefer calculations to actions."

This principle from "Grokking Simplicity" struck me as fundamentally aligned with what makes EARS so effective. In both approaches, there's a clear separation of concerns and a focus on structure that makes complex systems more manageable.

Just as I adapted Robustness Diagrams by extending the controller symbol with letters 'e' for events and 'f' for functions, EARS provides templates that clearly separate different types of requirements:

  1. Ubiquitous Requirements (pure data) - For stuff that's always true

    • Template: The [ system ][ imperative ] [ system response ].
    • My example: The Data Entry Form shall display validation errors in red text.
  2. State-Driven Requirements (data with context) - For when the system is in a specific state

    • Template: While [ pre-condition(s) ], the \ [ system ] \ [ imperative ] \ [ system response ].
    • My example: While in Edit Mode, the Data Entry Form shall highlight changeable fields with a blue border.
  3. Event-Driven Requirements (calculations triggered by events) - For when something specific happens

    • Template: When [ trigger ], the \ [ system ] \ [ imperative ] \ [ system response ].
    • My example: When the user clicks Submit, the Data Entry Form shall validate all mandatory fields.
  4. Optional Feature Requirements (conditional functionality) - For those extra bells and whistles

    • Template: Where [ feature is included ], the \ [ system ] [ imperative ] \ [ system response ].
    • My example: Where voice input is enabled, the Data Entry Forxsm shall display a microphone icon next to text fields. xs
  5. Unwanted Behavior Requirements (error handling) - For when things go wrong

    • Template: If [ trigger ], then the \ [ system ] \ [ imperative ] [ system response ].
    • My example: If the server connection is lost, then the Data Entry Form shall automatically save data locally.

The Shared Philosophy

What connects my work with Robustness Diagrams, Grokking Simplicity's functional approach, and EARS is the common philosophy of classification and separation:

  • In Functional Programming: We separate data, calculations, and actions
  • In Robustness Diagrams: I extended notation to clearly indicate events ('e'), functions ('f'), and listeners ('l')
  • In EARS: We classify requirements as ubiquitous, state-driven, event-driven, optional, or handling unwanted behavior

Each of these approaches helps solve the same problem - making complex systems more understandable by imposing structure that maps to how humans think about problems.

Practical Application: A Password Visibility Toggle

Let's take my simple password visibility toggle example and show how it maps across all three approaches:

User Story

As a user, I want to be able to toggle the visibility of my password so that I can see what I am typing.

Functional Breakdown (Grokking Simplicity style)

  • Data: Password field, toggle checkbox state
  • Calculations: Determine field type based on checkbox state
  • Actions: Handle change events, update the DOM

EARS Requirement

When the show-password checkbox is clicked, the system shall change the password field type to match the checkbox state (text when checked, password when unchecked).

Robustness Diagram with My Extensions

My diagram would show:

  • A boundary object (password input) with listener ('l')
  • A controller object with event ('e') for change handling
  • A controller object with function ('f') for toggling password visibility
  • Connections showing the flow between these elements

Code Implementation

// Variables (Data)
const toggle = document.querySelector('#show-password');
const password = document.querySelector('#password');

// Functions (Calculations)
function togglePassword (checkbox, field) {
field.type = checkbox.checked ? 'text' : 'password';
}

function handleChange () {
togglePassword(this, password);
}

// Event Listeners (Actions)
toggle.addEventListener('change', handleChange);

Why This Combined Approach Works

My first ZX Spectrum program failed because it didn't separate concerns properly - there was no clear distinction between data storage, calculations, and user actions. The entire program was a monolithic block that only worked in the most ideal conditions.

By combining the principles from functional programming with the structured templates of EARS and enhanced visual notation of Robustness Diagrams, we create a comprehensive approach to requirements engineering that addresses the entire development lifecycle:

  1. Requirements gathering: EARS templates ensure clarity and completeness
  2. System design: Robustness Diagrams with my extensions provide visual representation
  3. Implementation: Functional programming principles guide clean code structure

Conclusion

The connection between EARS, functional programming as taught in Grokking Simplicity, and my adapted Robustness Diagrams isn't coincidental - they all stem from the same need to bring structure to complexity.

As my childhood experience with the Phone Directory program taught me, technical correctness doesn't guarantee usability. What matters is a system that maps to how humans actually think and work. That's exactly what these combined approaches provide - a way to translate human needs into structured requirements, clear designs, and clean implementations.

If you're struggling with the gap between business requirements and technical implementation, try this combined approach. It might just help you avoid creating your own version of my childhood Phone Directory program - technically impressive but practically unused.