liveBook · Manning

Design

As explained in Functional Design and Architecture: Examples in Haskell

The creative activity of selecting and organizing software structures and mechanisms to satisfy requirements while managing trade-offs.

Software design translates domain models and requirements into high-level code structures that achieve goals. Its central challenge is controlling accidental complexity: complexity introduced by unjustified difficult solutions, tricky code, or unnecessary abstractions. Design is therefore a creative balancing activity rather than a search for a universally perfect structure. section 1.2 section 1.3

Start with what the system must do and the properties it must have. Functional requirements describe user-facing capabilities; nonfunctional requirements describe qualities such as performance, stability, extensibility, availability, latency, security, and ease of operation. A workable design satisfies both while remaining understandable enough to change without a rewrite. section 1.2.1 section 1.2

Use design to make deliberate trade-offs:

  • Keep accidental complexity low, but do not remove useful abstractions merely to make code shorter; too little abstraction can create coupling and harm maintainability. section 1.3
  • Prefer simple, deterministic structures where possible, because complexity raises the cost and risk of maintenance. section 1.2 section 1.6
  • Organize large systems into independent parts, then refine high-level architecture into low-level implementation details. section 2.1.3
  • Use low coupling and high cohesion as general principles for keeping components manageable across design methodologies. section 1.6

Divide and conquer is a recurring design principle. An interface can define a component’s operations, inputs, outputs, and types independently of its implementation. Client code then depends on the contract rather than a concrete subsystem, allowing implementations to change or be substituted. This form of inversion of control improves robustness, readability, and testability while supporting modularity. section 1.3.2 section 1.6

Designing spaceship control

A spaceship-control system must support manual and automatic operation while remaining robust, fault-tolerant, secure, and compatible with varied components. Its design can model engine-control responsibilities through an interface, an engine implementation, and a control-panel client. When a high-accuracy thermometer reports Kelvin but the sensor contract expects Celsius, an Adapter converts the mismatched interface without forcing client code to change. section 1.2.1 section 1.3 section 1.4.2

Object-oriented design provides established patterns and UML diagrams for reasoning about large applications. Functional programming supplies different tools and trade-offs: higher-order functions, lambdas, and closures can provide functionality associated with patterns such as Command or Strategy, but functional code is not automatically simple or loosely coupled. Choose approaches consciously rather than treating a paradigm as a guarantee. section 1.4.2 section 1.2 section 1.6

Figure 1.4 Compromising between simplicity, goals, and requirements

Compare the competing pressures of simplicity, project goals, and requirements when judging whether a proposed structure is justified. section 1.2.1

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Defines design, analyzes accidental complexity and trade-offs, and outlines interfaces, patterns, and top-down iterative architecture rather than detailed implementation.
Examples
Uses spaceship control requirements, engine-control UML, thermometer adapters, interface-based sensors, and deliberately overcomplicated FizzBuzz structures.
What it assumes
Assumes prior functional-programming knowledge and benefits from some Haskell familiarity for following most examples.
What you can do after
Evaluate/understand design choices by balancing requirements, simplicity, abstractions, maintainability, and paradigm-specific techniques.
How it connects
Connects requirements, domain modeling, architecture, accidental complexity, modularity, interfaces, inversion of control, coupling, cohesion, UML, and functional programming.

Also explained in

Compare how 4 books explain design →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Design and Architecture: Examples in Haskell. The section links point to the parts of the book it draws on.