Home/Low-level design/Recipe Manager

Recipe Manager

Permissions and immutable revision history

Ownership and transitions

A revision is immutable historical content; rollback appends copied historical content as a new revision rather than moving a pointer backwards. A current-name index must release renamed names while retaining old versions. Permissions are explicit, and write does not imply read. Copy nested lists at both ingress and egress. Simple name/ingredient scans cost O(recipes); history copies O(total returned content).

Java boundaries

Use the supplied nested records as immutable value carriers. A record is only shallowly immutable: copy every retained mutable input and every outward list/map, including lists inside records. Absence is null; validation failures use IllegalArgumentException, missing-key purchase errors use NoSuchElementException, and invalid transaction boundaries use IllegalStateException. Java primitive types already exclude booleans from numeric inputs. Numeric values use long where signatures say long and all computations must fit signed 64-bit values. Calls in these service exercises are serialized.

Rollback appends a selected historical revision; it does not erase the versions created after that history point:

java
import java.util.*;

class Example {
    public static void main(String[] args) {
        List<String> history = new ArrayList<>(List.of("v1: A", "v2: B"));
        String selectedContent = history.get(0).substring(4);
        history.add("v3: " + selectedContent);
        assert history.equals(List.of("v1: A", "v2: B", "v3: A"));
    }
}

The older content becomes the newest revision while the previous future remains auditable. Name collision checks must consider other recipes current names before appending that selected content.

Design boundary

Read and write permissions are independent: a writer may create or roll back without being allowed to read. Current-name uniqueness is separate from immutable historical names. Nested ingredient/step lists must be copied on both storage and retrieval so a caller cannot rewrite history through an alias.

Put it into practice

Implement the exercise in a full-screen workspace, then run its tests.

Open practice
Next lessonMessage Broker