Designing the System
Reviewing and Revising a Technical Design
আপনি একটি free preview lesson দেখছেন।
আমরা এখন পর্যন্ত:
- requirements analyse করেছি
- domain entities identify করেছি
- responsibilities define করেছি
- initial architecture design করেছি
- RFC-001 লিখেছি
- major decisions ADR-এ record করেছি
এখন একটি critical step বাকি:
Design review.
একটি technical design author-এর কাছে reasonable মনে হলেই সেটি implementation-ready হয়ে যায় না।
আরেকজন engineer যখন design পড়ে, সে এমন assumption, ambiguity, risk, বা contradiction দেখতে পারে যা author miss করেছে।
Design review-এর goal হলো design-কে attack করা নয়।
Goal:
Implementation শুরু হওয়ার আগে ভুল assumptions, unclear decisions, এবং unnecessary complexity খুঁজে বের করা।
Why Review Before Implementation?
Suppose design-এ একটি ভুল assumption আছে।
RFC stage-এ fix করতে হলে:
edit document
update diagram
clarify decision
কিন্তু একই issue implementation-এর পরে ধরা পড়লে:
change domain model
change database schema
change API
rewrite tests
update migrations
rewrite integration code
লাগতে পারে।
So:
Earlier feedback
=
cheaper feedback
Technical Design Review Is Not Approval Theatre
Bad process:
Author writes RFC
Reviewer says:
"Looks good"
RFC accepted
without actually evaluating anything।
Useful review asks:
Does the design satisfy requirements?
Which assumptions are hidden?
Which failure modes are missing?
Are responsibilities clear?
Are we solving problems we don't have?
Are important decisions still unresolved?
Can this actually be implemented safely?
Reviewer Mindset
A good reviewer does not ask:
How would I personally design this?
Instead:
Given the agreed requirements and engineering context, is this proposal correct, understandable, and appropriately simple?
There may be several valid designs।
Reviewer should distinguish:
incorrect
risky
unclear
different personal preference
These are not the same thing।
Review Against Requirements First
Architecture exists to satisfy requirements।
So first review question:
Does RFC-001 cover every important v1 behaviour?
Our major requirements:
browse products
manage products
manage inventory
create orders
view order history
cancel unpaid orders
pay orders
customer ownership
admin permissions
RFC covers all of them conceptually।
Good।
But review should go deeper।
Review Acceptance Criteria
For Order creation, agreed behaviour includes:
at least one item
product exists
product appears at most once
quantity positive
product orderable
inventory sufficient
backend determines price
backend calculates total
historical price preserved
invalid item fails whole request
order belongs to customer
Now reviewer checks:
Does architecture provide a place
for every one of these rules?
Mostly yes।
But one issue appears:
Where exactly is duplicate-product validation owned?
This is worth clarifying।
Review Comment 1 — Duplicate Products
Reviewer:
RFC says a product may appear only once in an order request,
but responsibility for enforcing this rule is unclear.
Is this transport validation,
CreateOrder workflow validation,
or an Order invariant?
This is a good review comment।
Analyse the Feedback
Request:
{
"items": [
{
"productId": 10,
"quantity": 2
},
{
"productId": 10,
"quantity": 3
}
]
}
Structurally valid।
But business rule says duplicate Product entries are not allowed।
This rule involves the collection of requested items।
A reasonable place is:
CreateOrder workflow
or Order construction boundary
rather than an individual OrderItem।
Revision 1
We update design:
CreateOrdermust reject a request containing the same Product more than once before persistence. Order construction must receive a valid unique Product set.
This keeps responsibility explicit।
We do not need a new architectural layer।
Small clarification, meaningful improvement।
Review Comment 2 — What Does "Available Product" Mean?
Reviewer:
Product browsing says "available products."
Does this mean:
1. Product is ACTIVE,
2. Inventory > 0,
or
3. both?
Excellent comment।
Earlier requirements used "available" broadly।
Our domain design separated:
Product ordering state
from:
Inventory quantity
But API behaviour still needs explicit meaning।
Analyse the Requirement
We already established:
- only orderable products should be returned
- inactive products should not be returned as orderable
- inventory constrains ordering
For browsing intended to show products that can currently be ordered, the most coherent v1 interpretation is:
Product is active/orderable
AND
Inventory quantity > 0
This is not introducing a new feature।
It resolves an ambiguity already present in the requirement।
Revision 2
RFC Product Browsing section becomes:
A product is returned as currently available for ordering only when its Product state permits ordering and its available Inventory quantity is greater than zero.
Important:
This does not mean inventory becomes Product state।
It is a read/use-case decision combining two facts।
Requirement Clarification vs Architecture Decision
Notice this feedback is partly product behaviour clarification।
If business stakeholders had not agreed on what "available" means, engineer should not silently decide it।
In our simulated project, we now clarify the intended v1 meaning based on the existing acceptance criteria।
In a real company, this might require:
Product Manager confirmation
before RFC acceptance।
Review Comment 3 — Customer Model Is Still Vague
Reviewer:
RFC says existing identity capability authenticates users,
but it is unclear whether Order Management Backend
stores a local Customer record.
This is also valid।
Our earlier design intentionally avoided inventing customer-account functionality।
But implementation needs to know whether:
orders.customer_id
references:
a local customers table
or simply stores:
external authenticated identity ID
Do We Need a Local Customer Table?
Current requirements need:
stable customer identity
order ownership
They do not require:
customer profile management
shipping address
customer preferences
password/account state
Therefore a local Customer entity/table would add state without current need।
The simpler design:
Order stores authenticated external customer identifier.
Revision 3
We make this explicit:
v1 will not maintain a separate Customer aggregate solely for ordering. Orders will store the stable customer identifier supplied by the existing authenticated identity context.
This may later change if ordering-specific customer data is introduced।
Why This Is Better Than "Maybe Customer Entity"
The earlier design correctly avoided overcommitting।
But before implementation, some uncertainty must become concrete।
Otherwise one engineer may create:
customers table
while another assumes external IDs only।
Design review is where such ambiguity should be removed।
Review Comment 4 — Order Total Source of Truth
Reviewer:
RFC says Order total is calculated by the backend,
but still lists whether total is stored or derived as open.
Can implementation proceed without deciding this?
Good question।
This decision affects:
database schema
Order model
queries
consistency rules
So before persistence implementation, we should resolve it।
Option A — Derive Order Total
Conceptually:
total
=
sum(unitPrice × quantity)
Advantages:
one underlying source of truth
no stored derived field drift
Cost:
calculation required when needed
For our small Order aggregate, calculation is trivial।
Option B — Persist Order Total
Advantages:
simple summary reads
no repeated calculation
Costs:
must guarantee stored total
matches Order Items
Current Requirement
Our v1 has:
- no tax
- no discounts
- no shipping cost
- no multiple currencies
- no complex pricing breakdown
Total is simply:
sum of item price × quantity
So derived total is straightforward।
Revision 4
Decision:
For v1, Order total will be derived from the Order Items' recorded purchase-time unit prices and quantities rather than treated as an independently mutable value.
Persistence may later optimize summary reads if evidence requires it, but domain source of truth remains the items।
This removes a significant open question।
Should This Be an ADR?
Probably not yet।
It is a useful domain/persistence decision, but current trade-off is simple and localized।
We can record it in RFC/domain design।
If later architecture changes to persisted totals with more pricing components, a dedicated ADR may become useful।
Review Comment 5 — Product Price Validation Is Missing
Reviewer:
Product has a current price,
but RFC does not say what constitutes a valid price.
Can a Product have a negative price?
This exposes an invariant we should reasonably define।
A negative product price would violate basic ordering semantics।
We don't need arbitrary pricing limits, but:
price >= 0
or perhaps:
price > 0
requires a business decision।
Should Zero Price Be Allowed?
Zero-price products could be legitimate:
free sample
promotion
but promotions are outside scope।
Still, banning zero without a requirement would also be arbitrary।
Safer minimum domain invariant:
price cannot be negative
This preserves technical validity without inventing that free products cannot exist।
Revision 5
Add Product invariant:
Product price must not be negative.
We still do not invent:
maximum price
minimum €0.01
without requirement।
Review Comment 6 — Inventory Adjustment Semantics
Reviewer:
Admin can "adjust inventory."
Does API set absolute quantity,
or apply a delta?
This is an implementation/API ambiguity।
Examples:
Absolute:
set quantity to 10
Delta:
add +5
They have different concurrency and audit semantics।
Do We Need to Decide It in Initial Architecture?
Yes, before designing the API।
But not necessarily in the high-level architecture RFC if it belongs to feature/API design।
Still, backlog ticket must not remain ambiguous before implementation।
For our current v1, the simplest explicit behaviour can be:
administrator sets the current available quantity
with validation:
quantity >= 0
We don't need inventory movement history or reason codes।
Revision 6
Clarify v1:
Administrative inventory management sets the current available quantity to a non-negative value. Inventory adjustments are not modeled as an audit ledger in v1.
This is bounded and implementable।
Review Comment 7 — Product Deactivation and Existing Unpaid Orders
Reviewer:
If a Product is deactivated after an unpaid Order
was already created, can that existing Order still be paid?
This is an excellent state/lifecycle question।
Order creation has already:
- validated Product
- captured purchase-time price
- reduced inventory
- created a historical Order
Product state may change later।
Should payment re-check Product active status?
Reason About Ownership
Once Order is successfully created, Product's current state should not rewrite Order eligibility unless requirement explicitly says so।
Otherwise:
Order created validly
↓
Admin deactivates Product
↓
Customer suddenly cannot pay existing Order
This behaviour was never requested।
Order lifecycle should govern existing Order payment eligibility।
Revision 7
Clarify:
Product activation state is evaluated during creation of new Orders. Deactivating a Product does not invalidate an already-created Order. Existing eligible unpaid Orders may still be paid.
This reinforces historical boundary between Product and Order।
Review Comment 8 — Inventory Restoration After Product Deactivation
Reviewer:
If an unpaid Order is cancelled after its Product
has been deactivated, do we still restore Inventory?
Yes।
Why?
Cancellation requirement says inventory consumed by the Order is restored।
Product deactivation affects future orderability, not whether inventory state exists।
So:
Inactive Product
+
Inventory quantity
can still coexist।
Revision 8
Clarify:
Cancelling an eligible Order restores its Inventory regardless of the Product's current activation state.
The Product remains inactive and therefore still cannot be used for new Orders until reactivated।
Review Comment 9 — Order History Pagination Is Too Vague
Reviewer:
RFC says order history is bounded/paginated,
but no pagination mechanism is selected.
Is this design blocked?
Not necessarily।
Exact REST pagination mechanism belongs to the API design module।
The architectural requirement is:
do not load/return unbounded history
Page-based vs cursor-based pagination is implementation/API contract detail।
We can keep this open until Module 5।
No Revision Needed Yet
This is a good example where review identifies an open detail but not an architecture blocker।
Response:
Confirmed. RFC intentionally requires bounded retrieval but defers exact pagination semantics to REST API design.
Not every review comment requires design change।
Sometimes clarification is enough।
Review Comment 10 — Payment Failure Model Is Not Implementable Yet
Reviewer:
Payment section identifies partial-failure risk,
but the design does not define how we prevent
duplicate payment or recover when provider succeeds
and local state update fails.
Can RFC be Accepted while this remains open?
This is the most serious comment so far।
Is Payment Design a Blocking Issue?
For implementing:
Product
Inventory
Order creation
No।
For implementing:
Payment
Yes।
The exact provider capabilities are not yet defined।
We should not invent provider idempotency semantics।
Therefore RFC can accept the overall architecture while making payment implementation explicitly blocked on provider-specific integration design।
Revision 9
Update RFC:
Payment capability follows the approved architectural boundary, but payment execution implementation is not considered design-complete until provider idempotency, timeout, and payment-reference semantics are confirmed.
And backlog:
BACKEND-117
Implement Payment Provider Client
remains not-ready until those questions are resolved।
This is disciplined planning।
Design Can Be Partially Ready
This is common in real engineering।
We do not need every future feature fully designed before:
BACKEND-101
can start।
We need sufficient design for the work currently being implemented।
Conceptually:
Overall Architecture
→ Ready
Product design
→ Ready
Order foundation
→ Ready
Payment provider semantics
→ Not yet ready
This is better than pretending everything is equally resolved।
Review Comment 11 — Inventory Concurrency Still Has No Mechanism
Reviewer:
Inventory concurrency is a correctness risk.
Shouldn't locking strategy be decided before RFC acceptance?
Answer depends on design level।
High-level architecture has established required property:
concurrent ordering must not oversell inventory
Exact PostgreSQL/JPA mechanism depends on persistence implementation choices।
However, before BACKEND-112 Order Creation Workflow is implemented, mechanism must be selected and tested।
So it is a deferred implementation decision, but not optional।
Add a Decision Gate
Revision:
Order creation implementation cannot be considered Done
until a concurrency-safe Inventory persistence strategy
has been selected, documented, and tested.
This creates accountability without prematurely choosing a technique।
Why This Is Better Than Choosing Pessimistic Locking Immediately
Suppose we arbitrarily choose:
SELECT ... FOR UPDATE
before evaluating actual JPA/persistence design।
Maybe correct।
Maybe unnecessary।
Maybe an atomic SQL update would be simpler।
Design should first state the invariant and decision deadline।
Mechanism follows evidence।
Review Comment 12 — Repository Boundaries Are Inconsistent
Reviewer:
RFC says repository boundaries are pragmatic,
but that could lead to each capability using
a completely different persistence style.
Should we standardize?
This is a trade-off question।
We want consistency but not ceremony।
Reasonable Convention
We can establish:
Application workflows should not contain raw SQL
or EntityManager-level persistence mechanics.
and:
Persistence concerns remain behind repository components
owned by the relevant capability.
Whether the repository is:
direct Spring Data interface
or:
custom repository implementation
can depend on capability complexity।
This is sufficient architecture consistency।
Revision 10
Add repository convention:
Every capability keeps database-specific query and persistence mechanics inside its persistence boundary. Application workflows may depend on repository-level operations but will not contain direct JPA/SQL implementation logic.
This provides consistency without PortAdapterFactoryImpl explosion।
Review Comment 13 — shared/ Is Dangerous
Reviewer:
The proposed `shared/` package may become a dumping ground.
What is allowed there?
Valid concern।
Revision 11
Clarify:
shared/ may contain only genuinely application-wide technical concepts, such as:
consistent API error representation
if such sharing becomes useful।
Domain-specific code must stay with its capability।
We will not create shared/ content before a real shared responsibility exists।
In fact, the package itself does not need to exist at bootstrap if empty।
Good Review Can Remove Architecture
Notice review is not only:
add more components
Good review can say:
don't create this yet
Often the best revision is removing speculative structure।
Review Comment 14 — Does Payment Need Its Own Domain?
Reviewer:
Payment package includes a `domain` area,
but exact Payment entity is still unknown.
Are we creating structure before the model exists?
Correct।
Earlier architecture diagram showed:
payment/
├── application/
├── domain/
└── integration/
But if Payment currently only needs:
PayOrder workflow
PaymentGateway
Provider client
PaymentResult
a dedicated domain/ package may be unnecessary initially।
Revision 12
Simplify:
payment/
├── application/
└── integration/
with provider-independent result/value types placed where they naturally belong।
If a real persistent Payment domain model emerges later, then introduce payment/domain/।
Architecture should grow from real responsibilities।
This Is an Important Design Lesson
Before review:
We thought a domain package might be useful.
After review:
No current domain model needs it.
Remove it.
Changing the design before code is cheap।
That's the point।
Review Comment 15 — Are Product and Inventory Truly Separate Modules?
Reviewer:
Product and Inventory are separate concepts,
but product browsing often reads both.
Will strict module isolation make simple reads awkward?
Good concern।
Our modular boundaries are logical, not isolation walls।
Read workflows can compose:
Product
+
Inventory
inside the same application।
We are not enforcing:
Product module cannot know Inventory exists.
The key restriction is ownership of mutation and responsibility।
Clarification
Architecture principle:
Capability boundaries define ownership and organization, not network-style isolation inside the monolith.
Product browsing can query Product and Inventory through appropriate persistence/application boundaries।
No internal REST calls।
No duplicated read database।
Review Comment 16 — Is OrderStatus Enough for Payment?
Reviewer:
If Order status is only UNPAID, PAID, CANCELLED,
how will payment attempts be represented?
Important distinction:
Order lifecycle
and:
Payment attempt lifecycle
are not necessarily the same thing।
An Order can remain:
UNPAID
while:
payment attempt failed
or:
provider timeout occurred
Therefore we should not inflate OrderStatus with provider attempt states like:
PAYMENT_TIMEOUT
PAYMENT_RETRYING
before payment model is designed।
Revision 13
Clarify:
OrderStatusrepresents the Order lifecycle only. Payment-attempt state, if required, will be modeled separately and must not be encoded as Order lifecycle states unless the product behaviour actually requires it.
This protects domain clarity।
Review Comment 17 — Does Order Store Customer Role?
Reviewer:
If customer identity comes externally,
does Order also store the customer's role?
No。
Order ownership needs:
customer identifier
Role is current authorization context, not historical Order ownership data।
Admin/customer authority may change over time।
Order does not need to preserve it।
Revision 14
Clarify:
Order stores owner customer identifier.
Authorization roles remain part of
authenticated request context.
This avoids mixing security metadata with business ownership।
Review Comment 18 — Should Order Creation Recheck Price After Inventory?
Reviewer:
What happens if Product price changes concurrently
while an order is being created?
This introduces concurrency beyond Inventory।
Important question।
We need a coherent price snapshot for the transaction।
The Order should use the Product price observed as part of the successful creation operation।
We do not need to promise price locking behaviour beyond that unless business says quoted prices must remain valid across earlier client browsing।
Client never supplies trusted price।
So:
price at successful order creation
is authoritative।
Revision 15
Clarify:
Order Item captures the server-side Product price read during the successful Order creation operation. Product price shown during earlier browsing is not a guaranteed quote for a later Order request.
This is a useful API/business semantic clarification।
Why This Matters
Customer may browse:
10:00
Product = €20
Admin changes price:
10:05
Product = €25
Customer submits Order:
10:06
Backend uses:
€25
unless business later introduces quote/price-lock functionality।
We will not invent that system now।
Review Comment 19 — What Does "All-or-Nothing" Include?
Reviewer:
For Order creation, does all-or-nothing include
multiple inventory rows and all order items?
Yes।
This should be explicit।
If request contains:
Product A × 2
Product B × 3
Product C × 1
and C cannot be fulfilled:
no Order
no Order Items
no Inventory reduction for A or B
Revision 16
RFC now explicitly states:
The complete Order creation request is one local atomic operation. Validation or persistence failure for any requested item causes the full operation to fail without partially consuming Inventory or creating a partial Order.
This matches acceptance criteria more precisely।
Review Comment 20 — Are Database Constraints Part of the Design?
Reviewer:
RFC says database constraints may protect invariants,
but does not define which critical invariants
must have database-level protection.
Some exact constraints depend on schema design।
But we can establish policy:
Critical persisted structural invariants should be enforced in PostgreSQL where practical।
Examples:
required foreign relationships
non-null required fields
inventory quantity >= 0
Business lifecycle rules remain primarily in application/domain logic।
Revision 17
Add persistence principle:
PostgreSQL constraints will reinforce critical structural/data-integrity invariants where they can be expressed clearly, while behavioural lifecycle rules remain in application/domain logic.
This guides later schema work without prematurely writing DDL।
What Makes Feedback "Actionable"?
Good review comment points to:
a requirement
an ambiguity
a risk
a trade-off
a contradiction
Weak comment:
I don't like this.
Better:
This component mixes provider-specific HTTP behaviour
with Order lifecycle rules, which makes the Order workflow
depend on an external protocol.
Now author knows what problem to evaluate।
Author Response Matters Too
Bad response:
That's just my style.
or:
This is how I've always done it.
Good response:
The concern is valid.
Given requirement X,
I'll change the design to Y.
Or:
I don't think we should change this because
the proposed alternative would introduce Z,
and our current requirement does not justify it.
Design review is technical reasoning, not obedience।
You Do Not Have to Accept Every Review Comment
Suppose reviewer says:
We should use Kafka so payment can be more scalable.
We ask:
Which current requirement requires Kafka?
None।
What new complexity?
broker operation
async semantics
delivery guarantees
consumer failure
event schema
Current design has no need for it।
Response:
Rejected for v1. No current workflow requires asynchronous messaging, and introducing Kafka would add operational and consistency complexity without solving a confirmed requirement.
This is a valid review outcome।
Review Comment: Split Into Microservices Now
Another reviewer:
Product and Order clearly have different responsibilities. They should be separate microservices.
Responsibility separation does not imply network separation।
Current architecture intentionally benefits from:
local transaction
simple deployment
in-process calls
No independent scaling or ownership requirement exists।
So ADR-001 still holds।
No revision।
Review Comment: Add Redis for Product Browsing
Reviewer:
Product browsing will probably be read-heavy. Let's add Redis now.
"Probably" is not enough।
We have:
no measured load
no latency target requiring cache
no database bottleneck
Caching would introduce consistency complexity।
No revision।
If production metrics later show need, architecture evolves।
Review Comment: Separate Read Database
Same reasoning।
No requirement yet।
PostgreSQL is sufficient for current read/write workload assumption because no scale target says otherwise।
Don't solve imaginary bottlenecks।
Review Comment: Add Event History to Every Entity
No requirement.
We need Order history, not universal audit/event sourcing।
No revision।
Design Review Should Remove Hidden Assumptions
Let's list assumptions that review made explicit:
Before:
"available Product"
After:
Product active AND Inventory > 0
Before:
"Customer"
After:
external authenticated customer ID;
no local Customer aggregate in v1
Before:
"Order total"
After:
derived from historical Order Items
Before:
"admin adjusts inventory"
After:
admin sets non-negative current available quantity
This is exactly what review should accomplish।
Revised Core Design Decisions
After review, our design is more concrete।
Product
Product owns:
stable identity
current product data
current price
active/inactive state
Invariant:
price >= 0
A Product is currently available for customer browsing when:
Product permits ordering
AND
Inventory quantity > 0
Inventory
Inventory is separate from Product।
Owns:
current available quantity
Invariant:
quantity >= 0
Admin v1 behaviour:
set current available quantity
to a non-negative value
Order creation consumes Inventory।
Eligible cancellation restores Inventory।
Customer Context
v1 does not create a local Customer aggregate solely for ordering।
Order stores:
authenticated external customer identifier
Security roles remain request/security context।
Order
Order owns:
owner customer ID
Order Items
Order lifecycle
States:
UNPAID
PAID
CANCELLED
Total:
derived from Order Item
unitPrice × quantity
Order Item
Contains:
Product reference
positive quantity
purchase-time Product price
The same Product cannot appear more than once in one Order creation request।
Product Changes After Order Creation
Current Product price/status changes do not rewrite existing Order meaning।
Therefore:
Product deactivated
does not invalidate already-created unpaid Orders।
They can still be paid if otherwise eligible।
Cancellation still restores Inventory even if Product is inactive।
Payment
Order state and Payment attempt state remain separate concepts।
Payment implementation remains gated on confirmation of:
provider idempotency behaviour
provider payment reference semantics
timeout behaviour
No fake solution will be invented before provider context exists।
Revised Order Creation Semantics
A successful Order creation operation:
1. receives at least one item
2. rejects duplicate Products
3. validates positive quantities
4. loads Products
5. verifies Product ordering state
6. loads relevant Inventory
7. verifies sufficient Inventory
8. uses current server-side Product price
9. constructs Order Items
10. derives Order total from those Items
11. decreases Inventory
12. persists the complete Order
13. commits all local changes together
Any failure:
no partial Order
no partial Order Items
no partial Inventory consumption
Revised Cancellation Semantics
Cancellation:
load Order
verify ownership
verify Order is UNPAID
transition to CANCELLED
restore Inventory
persist both atomically
Current Product activation state does not change the restoration rule।
Revised Payment Semantics
Payment:
load Order
verify ownership
verify Order is UNPAID
invoke provider boundary
process provider result
On confirmed safe success:
UNPAID → PAID
A Product becoming inactive after Order creation does not make existing Order unpayable।
Design Readiness
Now ask:
Is the design ready to implement?
Not every imaginable detail is resolved।
But implementation does not require every future decision upfront।
We need sufficient clarity for the next engineering work։
Ready for Early Implementation
These are sufficiently designed:
BACKEND-101
Bootstrap Application
BACKEND-102
PostgreSQL + Flyway Foundation
BACKEND-103
Product Domain
BACKEND-104
Product Persistence
Product API foundations
Inventory domain foundations
Order domain foundations
Requires Further Implementation-Level Design
Before Order creation persistence is complete:
Inventory concurrency strategy
must be resolved।
Before Payment implementation:
provider idempotency
timeouts
provider reference behaviour
must be resolved।
Before public API contracts finalize:
pagination details
error representation
exact endpoint models
will be designed in the REST module।
This is acceptable।
Design Readiness Is Not "No Open Questions"
A useful distinction:
Bad:
We cannot code until every possible question is answered.
Also bad:
We'll figure everything out while coding.
Better:
Resolve questions before the work that depends on them begins.
This is progressive design with explicit decision gates।
When Is an RFC Ready to Accept?
For our purposes, RFC is ready when:
core requirements are represented
main domain boundaries are clear
responsibilities are clear
architecture direction is clear
major workflows are understandable
important transaction boundaries are known
system boundaries are explicit
major risks are identified
important non-goals are explicit
remaining open questions have clear resolution points
RFC does not need exact method names or SQL।
Updated RFC Status
After incorporating review feedback:
RFC-001
Status: Accepted
Meaning:
The team agrees this is the architecture direction for the initial implementation.
It does not mean:
nothing can ever change.
What Happens to Review Comments?
Useful final design review should leave a record of outcomes।
For example:
Comment:
Clarify Customer persistence.
Resolution:
No local Customer aggregate in v1.
Order stores external customer identity.
Comment:
Inventory concurrency mechanism unresolved.
Resolution:
Accepted as implementation decision gate;
must be resolved before Order creation is Done.
This helps reviewers know comments were considered rather than ignored।
Revision Does Not Always Require a New RFC
Minor clarification:
define available Product
can update RFC-001।
Major architecture reversal:
split Order and Inventory into services
might require:
new RFC
+
new ADR
The size of documentation should match the size of the decision।
Design Review and ADRs
Review may also change ADR candidates।
Our existing ADRs still hold:
ADR-001
Modular Monolith
ADR-002
Separate Inventory from Product
ADR-003
Preserve Purchase-Time Price
ADR-004
Isolate Payment Provider
None were invalidated।
Review actually strengthened their reasoning।
What If Review Invalidates an ADR?
Suppose review proves a proposed ADR is wrong before implementation।
If status was:
Proposed
we can reject it।
No need to preserve a rejected proposal as accepted history unless team process values that record।
If already Accepted and later evidence changes it:
supersede
rather than silently rewrite history।
Design Review vs Code Review
Now the distinction is clear।
Design Review
Focus:
problem
boundaries
responsibilities
trade-offs
failure modes
risks
Code Review
Later focus:
does implementation match the design?
is behaviour correct?
are tests adequate?
is code maintainable?
did implementation introduce new risk?
Both matter।
Design Review Does Not Guarantee Correctness
Even a strong RFC review cannot prove:
no bugs
no incidents
perfect performance
Implementation and production will reveal new information।
Design review reduces avoidable mistakes।
It does not eliminate uncertainty।
A Senior Engineer's Review Questions
When reviewing future technical designs, useful questions include:
What requirement drives this decision?
What happens when this dependency fails?
What state can become inconsistent?
Who owns this data?
Who is allowed to mutate it?
Is this historical or current state?
Where is the transaction boundary?
What happens under concurrent requests?
Are we trusting client-controlled data?
Which assumptions are not confirmed?
Which complexity is required today?
What becomes difficult to change later?
How will we know this fails in production?
These questions generalize far beyond this course project।
Avoid Reviewing Only Diagrams
A beautiful architecture diagram can hide:
unclear ownership
missing failure behaviour
incorrect transactions
unconfirmed assumptions
Review behaviour and invariants first।
Boxes and arrows are supporting tools।
Avoid Reviewing Only Technologies
Weak review:
Why PostgreSQL instead of MongoDB?
Why Spring Boot instead of framework X?
when those are established context।
Better review:
Does the proposed PostgreSQL transaction
cover all local state changes that must be atomic?
Focus effort on real decisions।
Avoid Premature Performance Review
Without scale targets, reviewer should not demand:
Redis
read replicas
sharding
But reviewer can still identify obvious unbounded behaviour।
For example:
load every Order in history
would be clearly risky even without precise traffic numbers।
That's why we already require bounded retrieval।
Review the Failure Path
For every major workflow, ask:
What if step 1 succeeds and step 2 fails?
Order creation:
Inventory updated
but Order persistence fails?
Transaction protects it।
Cancellation:
Order cancelled
but inventory restore fails?
Transaction protects it।
Payment:
Provider succeeds
but local DB update fails?
Still unresolved external consistency problem, intentionally flagged।
Failure-path review exposes architecture quality quickly।
Review the Ownership Path
Ask:
Which component is authoritative for this fact?
Examples:
Current Product price:
Product
Historical purchase price:
Order Item
Current available quantity:
Inventory
Order lifecycle:
Order
Authentication identity:
External identity capability
Customer resource ownership enforcement:
Application workflow
If two components both think they own the same mutable fact, architecture often becomes fragile।
Review the Trust Boundary
Ask:
Which values come from the client, and which values does the backend trust?
Client supplies:
Product ID
Quantity
Backend determines:
Product existence
Product orderability
Inventory
Price
Order total
Customer identity
Client should not determine:
authoritative price
order owner
payment success
order status
This is a useful security and correctness review habit।
Review the Temporal Boundary
Ask:
Is this fact current state or historical state?
Current:
Product price
Product activation
Inventory quantity
Historical:
Order Item purchase-time price
Stable ownership reference:
Order customer ID
Confusing current and historical state causes subtle bugs।
Review the Scope Boundary
Ask:
Did we accidentally design something the requirement never requested?
Examples we avoided:
Cart
Warehouse
Refund
Shipment
Inventory Reservation Entity
Payment Plugin Framework
Kafka
Redis
Design review should actively remove speculative scope।
Final Revised Architecture Snapshot
After review:
Order Management Backend
=
one modular Spring Boot application
Capabilities:
Product
Inventory
Order
Payment Integration
Security Context
Persistent application state:
PostgreSQL
Customer:
external authenticated identity
stored on Order as owner ID
Order total:
derived from historical Order Items
Product browsing availability:
active/orderable Product
+
Inventory > 0
Local atomic workflows:
Order creation
Order cancellation
Payment:
external integration boundary
with provider-specific consistency design pending
Module 2 Deliverables
We have now produced:
Domain model
Responsibility map
Initial architecture
RFC-001
ADR-001 through ADR-004
Design review revisions
This is enough to start building the application foundation deliberately।
What Comes Next?
Module 2 is now complete।
We move into:
Module 3 — Building the Spring Boot Application
The first implementation ticket is:
BACKEND-101
Bootstrap Order Management Backend
We will finally start creating the application।
But now when we create packages, components, and dependencies, we know why they exist।
We are not starting from:
What annotation should I learn first?
We are starting from:
We have an agreed system to build.
Spring Boot is the tool we will use to build it.
Engineering Principle
The core principle from this lesson:
A technical design is not ready because the author finished writing it; it is ready when important assumptions, trade-offs, risks, and responsibilities have survived meaningful review.
Another:
Accept feedback based on the problem it reveals, not because every reviewer preference must become architecture.
And:
Leave uncertainty explicit, but resolve each uncertainty before the implementation that depends on it begins.
Summary
In this lesson, we learned that:
- Design review happens before implementation to reduce expensive mistakes.
- Review should evaluate requirements, ownership, boundaries, failures, and risks.
- Design review is not approval theatre.
- Reviewer preference and actual design problem are different things.
- Duplicate Product validation now has an explicit responsibility.
- "Available Product" now means Product is orderable and Inventory is greater than zero.
- v1 does not require a local Customer aggregate.
- Order stores the authenticated external customer identifier.
- Order total will be derived from historical Order Items.
- Product price cannot be negative.
- v1 admin Inventory management sets a non-negative current quantity.
- Product deactivation does not invalidate already-created Orders.
- Cancellation restores Inventory even when Product is currently inactive.
- Order creation uses current server-side Product pricing at successful creation time.
- The entire multi-item Order creation operation is atomic.
- Order lifecycle state and Payment attempt state remain separate.
- Payment implementation remains blocked on actual provider idempotency and failure semantics.
- Inventory concurrency remains a required decision before Order creation implementation is Done.
- Persistence mechanics remain inside capability-owned persistence boundaries.
shared/will not become a dumping ground and does not need to exist until truly needed.- Payment does not need a speculative domain package before a real Payment domain model exists.
- Some review comments result in changes, some in clarifications, and some should be rejected.
- RFC-001 can now be considered Accepted.
- Module 2 is complete.
Next lesson:
Creating a Spring Boot Application
We will begin BACKEND-101 — Bootstrap Order Management Backend and create the actual Java/Gradle/Spring Boot application that will evolve throughout the rest of the course.