Explain the design decisions in this EK9 code for a team wiki.
← Getting Started · Ref: Q1031
Design Rationale for UserService module:
Structure: The module separates validation (pure functions) from state management (the UserService class). This separation means validation logic can be tested without setting up a service instance.
Validation functions are marked 'as pure' because they only compute results from their inputs — no side effects, no state changes. This makes them safe to call from any context, including concurrent code.
The UserService class uses guard expressions in its methods. When findUser returns a value, the guard (if user <- findUser(name)) ensures the block only runs when a valid user was found. There is no null checking and no exception handling for missing users — the guard handles it.
Return values are declared at the top of each function with <- . This is how EK9 functions declare what they return — it is not a statement that causes an early exit. Every code path must initialise the return value.
The class has a default private constructor because its properties are uninitialised at construction time. Only the parameterised constructor is public.
Example
defines module qa.gettingstarted.designrationale defines function isValidName() as pure -> name as String <- rtn as Boolean: name? and name.length() > 0 isValidEmail() as pure -> email as String <- rtn as Boolean: email? and email.contains("@") defines class User name as String? email as String? default private User() User() -> name as String email as String this.name: name this.email: email override operator ? as pure <- rtn as Boolean: name? and email? operator $ as pure <- rtn as String: `${name} (${email})` defines program DesignRationaleDemo() stdout <- Stdout() name <- "Alice" email <- "alice@example.com" if isValidName(name) and isValidEmail(email) user <- User(name, email) stdout.println(`Created: ${user}`)
Common mistakes
E07110 — A non-abstract operator or method must provide an implementation — declaring only an uninitialised return '<- rtn as String?' leaves it with no body, so give the return a value. See ek9 -h E07110 for details.
Incorrect:
operator $ as pure <- rtn as String?
Correct:
operator $ as pure <- rtn as String: `${name} (${email})`
Other ways to ask this
- Document the design rationale behind this code
- Write a technical explanation of this module for new team members
- Explain why this code is structured this way
Coming from another language?
EK9 design documentation explains what the code does and why, without comparing to other languages.
Keywords: wiki, explain, team, rationale, document, design