codebases च्या आत आणि त्यांच्या दरम्यानची रचना, शाळेच्या इमारतीचा नकाशा म्हणून शिकवलेली: modules म्हणजे खोल्या, imports म्हणजे मार्गिका आणि दारे, layers म्हणजे मजले, आणि bounded contexts म्हणजे विभाग. प्रत्येक धडा ही शाळेची एक गोष्ट आहे — काढलेल्या आकृतीसह आणि एका lab सह — आणि इमारत repo मध्येच आहे: एक छोटे sample school app आणि pure Python मधील एक analyzer (arch/analyze.py, शून्य dependencies) जो ast ने त्याचे imports वाचतो आणि coupling, cycles, layer व ring नियम, विभाग आणि fitness functions मोजतो.
# the 60-second wow — the floor plan, inspected:
git clone https://github.com/BaluRaut/learn-software-architecture-school.git && cd learn-software-architecture-school
python3 arch/demo.py # 12 lessons: blast radius, layers, the hexagon, fitness functions, C4
python3 arch/analyze.py check # the architecture tests — exit code 1 on the planted problems
python3 arch/test_arch.py # 12 checks across the lessons
तुम्हाला काय दिसायला हवे (छाटलेले — यश असे दिसते):
═══ decisions ═══
── the building: arch/sample/schoolapp has 13 rooms (modules) and 24 corridors (imports), 187 lines
blast radius = the rooms a change can ripple into (every room that reaches it through corridors):
domain.admissions 8 of 12 rooms
domain.ports 8 of 12 rooms
domain.grades 4 of 12 rooms
domain.timetable 0 of 12 rooms
main 0 of 12 rooms
repainting a room (a local variable) touches 1 room · moving a load-bearing wall (a port) touches 8 — THAT is architecture
── Katrina's three driving characteristics (the -ilities), each with a scenario and a price:
modifiability 'a new department (the library) goes live within a term' · price: costs up-front structure
testability 'the marks rules run in a test without a database' · price: needs ports and adapters (more types)
availability 'report cards open on results day' · price: spare capacity, and fewer moving parts
every characteristic you add costs another; pick the few that decide success
═══ modularity ═══
── per floor (component): N rooms, R corridors inside, H = (R+1)/N, Ca in, Ce out, I = Ce/(Ca+Ce), A abstract, D = |A+I-1|
app N=3 R=0 H=0.33 · Ca=2 Ce=3 I=0.60 · A=0.00 D=0.40
domain N=5 R=2 H=0.60 · Ca=5 Ce=2 I=0.29 · A=0.33 D=0.38
infra N=2 R=0 H=0.50 · Ca=3 Ce=2 I=0.40 · A=0.00 D=0.60
main N=1 R=0 H=1.00 · Ca=0 Ce=1 I=1.00 · A=0.00 D=0.00
web N=2 R=1 H=1.00 · Ca=2 Ce=1 I=0.33 · A=0.00 D=0.67
domain is stable (I=0.29): 5 rooms outside lean on it · main is fully unstable (I=1.00): nobody imports it — both are fine
app has H=0.33: its 3 rooms never talk to each other — a floor, not a department
web has D=0.67: fairly stable but fully concrete — hard to change, nothing abstract to extend
═══ layers ═══
── floors, top to bottom: web → app → domain → infra · a room may import its own floor or any floor BELOW
relaxed layering: 4 violations
domain.timetable → web.format (upward)
infra.db → domain.grades (upward)
infra.db → domain.ports (upward)
infra.email → domain.ports (upward)
strict layering (only the floor directly below): 5 violations — adds app.enrol → infra.email (skips a floor)
3 of the 4 are adapters importing the ports they implement — the classic stack calls that wrong; lesson 04 flips it
═══ hexagonal ═══
── rings: domain (core) ← app ← web + infra (adapters) · dependencies point INWARD only
outward: app.enrol → infra.email
outward: domain.grades → infra.db
outward: domain.timetable → web.format
the domain imports outside itself 2 times · outside libraries per room: domain.ports ['abc', 'typing'], infra.db ['sqlite3'], infra.email ['smtplib']
to test domain.grades you must load 3 other rooms ['domain.admissions', 'domain.ports', 'infra.db']
remove the 3 outward corridors (use the ports) → 1 ['domain.admissions'] · outward left: 0
classic layers flagged infra → domain; the hexagon allows it and flags domain → infra instead
═══ ddd ═══
── departments (bounded contexts): admissions · grades · fees · timetable — each with its own meaning of 'student'
in admissions a student is a form number, a name and a status
in grades a student is a roll number with marks in subjects
in fees a student is an account that owes money
── the context map, read from the code: 2 cross-department corridors
fees → admissions: domain.fees imports Student from domain.admissions
grades → admissions: domain.grades imports Student from domain.admissions
grades → admissions: conformist today → an anti-corruption layer translates at the door
fees → admissions: customer–supplier · both would break if admissions renamed Student.name
═══ styles ═══
── the same 4 departments in three styles (teaching assumptions: 1 ms and 1-in-1000 failure per network hop)
monolith 1 deployable unit(s) · own deploys: no · boundaries enforced by nothing (any room may import any room)
report card 0 hop(s) +0 ms 100.0% · pay fees 0 hop(s) +0 ms 100.0% · enrol 0 hop(s) +0 ms 100.0% · enrol needs one database transaction
modular monolith 1 deployable unit(s) · own deploys: no · boundaries enforced by a build-time check (lesson 09)
report card 0 hop(s) +0 ms 100.0% · pay fees 0 hop(s) +0 ms 100.0% · enrol 0 hop(s) +0 ms 100.0% · enrol needs one database transaction
microservices 4 deployable unit(s) · own deploys: yes · boundaries enforced by the network (separate processes)
report card 2 hop(s) +2 ms 99.8% · pay fees 1 hop(s) +1 ms 99.9% · enrol 3 hop(s) +3 ms 99.7% · enrol needs a saga across services
microservices buy independent deploys with hops, partial failure and sagas — the modular monolith keeps the boundaries without the network
═══ events ═══
── admissions publishes StudentAdmitted(Dipika, 5A) on the notice board → grades opens a mark sheet · fees opens an account · timetable assigns a class
direct calls: admissions imports 3 departments · events: it imports 0 of them (only the event's shape) — a 4th listener needs no change to admissions
── CQRS: 3 marks written (72, 85, 90); the read model has applied 2 → average 78.5
after catch-up it has applied 3 → average 82.33 · reads are fast, and eventually consistent
═══ data ═══
── fees needs a student's name 20 times; at tick 5 admissions renames name → full_name; ticks 10–12 admissions is down
shared database failed reads 15 · stale reads 0 · other teams' code broken by the rename 2
API failed reads 3 · stale reads 0 · other teams' code broken by the rename 0
events failed reads 0 · stale reads 2 · other teams' code broken by the rename 0
shared DB: no call to admissions at run time, but total schema coupling · API: contract, but runtime coupling · events: own copy, but stale
═══ fitness ═══
── the fitness functions run on every push (python3 arch/analyze.py check)
FAIL no import cycles 1 cycle(s): domain.grades ↔ infra.db
FAIL dependencies point inward 3 outward import(s)
FAIL the domain imports only the domain 2 leak(s)
FAIL departments do not import each other 2 cross-context import(s)
PASS fan-out ≤ 5 per room (main excluded) max 4 (web.views)
PASS domain instability ≤ 0.5 I = 0.29
after removing the 5 planted corridors: 6/6 pass · CI exit code 0
═══ c4 ═══
── a C4 model as text (Structurizr DSL), 31 lines — the component arrows come from the code:
app -> domain "imports (6)"
app -> infra "imports (1)"
domain -> infra "imports (1)"
domain -> web "imports (1)"
infra -> domain "imports (3)"
web -> app "imports (3)"
the wiki drawing is out of date: 3 arrows in the code are not on it: app → infra, domain → infra, domain → web
after the fixes: 0 drift · generate the drawing from the code, or check it in CI
═══ adr ═══
── ATAM-lite: 5 scenarios, weight 1–3, each option scored 1–5 by the team
modifiability w=3 'add the library department within a term'
operability w=3 'run it with a team of 3'
performance w=2 'a report card in < 300 ms on results day'
deployability w=1 'release grades without redeploying fees'
scalability w=1 'survive 20× traffic on results day'
modular monolith [4, 5, 5, 2, 3] → 42
monolith [2, 5, 5, 1, 3] → 35
microservices [4, 2, 3, 5, 5] → 34
weights matter: microservices would win if deployability weighed 4 (not 1), or scalability 6 (not 1)
── the decision, written down as ADR-0007 (14 lines):
# ADR-0007: A modular monolith for the school app
Status: Accepted
- one database transaction per request
- no independent deploys yet
- revisit if deployability weight reaches 4
═══ evolve ═══
── the building over four terms: rooms · corridors · cycles (largest) · propagation cost · outward imports · floors tangled
term 1 · the first plan 13 · 19 · 0 (0) · 24.3% · 0 · floors tangled 0
term 2 · as shipped 13 · 24 · 1 (2) · 31.4% · 3 · floors tangled 4
term 3 · exam rush 13 · 29 · 4 (3) · 49.7% · 3 · floors tangled 4
term 4 · checks + a library wing 15 · 24 · 0 (0) · 22.2% · 0 · floors tangled 0
── the strangler fig: a facade sends each route to the old building or the new wing, one route at a time
step 1: /admin → 1/6 routes, 2% of traffic on the new wing
step 2: /timetable → 2/6 routes, 27% of traffic on the new wing
step 3: /fees → 3/6 routes, 42% of traffic on the new wing
step 4: /enrol → 4/6 routes, 47% of traffic on the new wing
step 5: /marks/upload → 5/6 routes, 55% of traffic on the new wing
step 6: /report-card → 6/6 routes, 100% of traffic on the new wing
── the whole picture: decide what is costly → rooms with few corridors → floors point one way → the core in the middle → departments with their own words → pick a style → notices, not calls → own your data → inspect every push → draw from the code → write the why → grow, don't rot
✅ done — the floor plan holds
arch/sample/schoolapp) ast ने वाचतो; style, event, data आणि trade-off models हे सांगितलेल्या गृहीतकांसह शिकवण्याचे models आहेत. खरी tools प्रत्येक धड्यात येतात: import-linter, ArchUnit, dependency-cruiser, Structurizr, adr-tools. ही शाळा कुठे बसते: System Design शाळा distributed systems (caches, queues, sharding) design करते; ही शाळा codebases च्या आतील आणि त्यांच्या दरम्यानच्या रचनेबद्दल आहे.संपूर्ण कोर्स एका कॅनव्हासवर. 4K आवृत्तीसाठी क्लिक करा.
एक git branch = एक कल्पना; branch 04 मध्ये धडे 01–04 आहेत. arch/analyze.py sample चे imports वाचतो — प्रत्येक run तेच आकडे छापतो.
lesson-01-what-is-architectureधडा वाचा →आकृती पहा ↗lesson-02-modularityधडा वाचा →आकृती पहा ↗lesson-03-layersधडा वाचा →आकृती पहा ↗lesson-04-hexagonalधडा वाचा →आकृती पहा ↗भागांमधील रेषा कुठे काढायच्या, किती deployable units ठेवायची, आणि विभाग events व data कसे वाटून घेतात.
lesson-05-dddधडा वाचा →आकृती पहा ↗lesson-06-stylesधडा वाचा →आकृती पहा ↗lesson-07-events-cqrsधडा वाचा →आकृती पहा ↗lesson-08-data-ownershipधडा वाचा →आकृती पहा ↗खरी राहणारी architecture: ती लागू करणाऱ्या tests, तिच्यापासून तयार होणारी आकृती, लिहून ठेवलेले निर्णय, आणि big-bang rewrite शिवाय बदल.
lesson-09-fitness-functionsधडा वाचा →आकृती पहा ↗lesson-10-c4धडा वाचा →आकृती पहा ↗lesson-11-adrsधडा वाचा →आकृती पहा ↗lesson-12-evolutionधडा वाचा →आकृती पहा ↗प्रत्येक धडा एका क्रमांकित बॉक्स-आणि-बाण आकृतीत — स्वतंत्र पानावरही.
जिना, रंग नव्हे — बदलायला महाग असलेले निर्णय, त्यांनी मिळणाऱ्या -ilities, आणि त्यांची किंमत.
कतरिना नव्या शाळेच्या इमारतीचा आराखडा बनवते. रंग नंतर सहज बदलता येतो. जिना नाही. तो हलवायचा म्हणजे अर्धी शाळा बंद. Sample app मध्ये ports नावाची एक room इतर 12 पैकी 8 rooms ना आधार देते. असा निर्णय म्हणजे architecture. कतरिना सर्वात महत्त्वाचे थोडे गुण निवडते, आणि त्यांची किंमत स्वीकारते.
टीम प्रत्येक निर्णय सारखाच मानत असे: variable चे नाव आणि सगळ्यांचा port सारख्याच काळजीने, किंवा बेफिकिरीने बदलले जात.
Architecture म्हणजे जिना, रंग नव्हे: जे निर्णय नंतर बदलणे महाग असते, जसे sample मधील domain.ports.
Analyzer 13 rooms आणि 24 corridors वाचतो: domain.ports मधला बदल 12 पैकी 8 rooms पर्यंत पोहोचतो, timetable चा 0.
कतरिना 3 driving characteristics निवडते, प्रत्येकासोबत scenario आणि किंमत, कारण प्रत्येक गुण दुसऱ्या कशाची तरी किंमत घेतो.
पुढचा धडा rooms मोजतो: प्रत्येक मजल्याला किती corridors आहेत, आणि त्याचा बदलावर काय परिणाम होतो.
कमी मार्गिका असलेल्या खोल्या, मोजून — cohesion, coupling, Ca, Ce, instability, abstractness आणि distance.
चांगल्या room चे एकच काम असते. Test tubes विज्ञान प्रयोगशाळेत असतात, library मध्ये नाही. चांगल्या room ला कमी दारे असतात. दीपिका प्रत्येक मजल्याची दारे मोजते. Rule book च्या मजल्याला आत येणारी 5 दारे आणि बाहेर जाणारी 2 आहेत. अनेक जण त्यावर अवलंबून आहेत, म्हणून तो हळूहळू बदलायला हवा. त्याची instability 0.29 आहे.
Code अंदाजाने तपासला जाई: 'हे module गोंधळलेले दिसते'. एखादा भाग किती coupled आहे, आणि ते वाईट आहे का, कोणी सांगू शकत नसे.
Cohesion आणि coupling आकड्यांत: Ca आत येणारी दारे, Ce बाहेर जाणारी, instability I = Ce/(Ca+Ce), आणि distance D = |A+I-1|.
दीपिका प्रत्येक मजला मोजते: domain चे Ca=5, Ce=2, म्हणून I=0.29; main चे I=1.00; web चे D=0.67 आणि app चे H=0.33.
ज्यांच्यावर अनेक जण अवलंबून आहेत ते स्थिर भाग abstract असावेत; web स्थिर पण पूर्ण concrete आहे, म्हणून बदलायला अवघड.
पुढचा धडा rooms मजल्यांवर रचतो आणि विचारतो जिना कोणत्या दिशेने जावा: फक्त खाली, कधीच वर नाही.
मजले, आणि जिने कोणत्या दिशेने जातात — layer नियम, strict विरुद्ध relaxed, आणि उल्लंघने शोधणे.
शाळेला चार मजले आहेत. वर reception, मग office, मग rule book, आणि खाली store room. नियम सोपा: जिन्याने खाली जा, कधीच वर नाही. कतरिना प्रत्येक corridor तपासते. तिला वर जाणारे 4 सापडतात. पण त्यातले 3 म्हणजे store room चे कर्मचारी rule book वाचत आहेत, जे खरे तर चूक नाही.
Screens, rules आणि SQL एकाच files मध्ये होते, म्हणून database बदलला की business rules लाही हात लावावा लागे.
Layers म्हणजे मजले: web, app, domain, infra. एखादी room स्वतःच्या किंवा खालच्या मजल्याला import करू शकते, वरच्याला कधीच नाही.
Check ला relaxed mode मध्ये 4 वर जाणारे corridors सापडतात, आणि strict मध्ये 5, कारण enrol थेट infra.email ला जातो.
मजल्यांचा नियम जिना एकाच दिशेने ठेवतो; पण 4 पैकी 3 violations हे adapters आहेत, जे स्वतः implement करत असलेले ports import करतात.
पुढचा धडा चित्र उलटवतो: rule book मध्यभागी जाते आणि प्रत्येक दार बाहेरच्या दिशेने उघडते.
मध्यभागी नियमपुस्तिका, बाहेर उघडणारी दारे — domain कोणतेही infrastructure import करत नाही.
आता rule book मधल्या staff room मध्ये आहे. प्रत्येक दारावर पाटी आहे: 'मला marks आणणारे कोणीतरी हवे.' आज store room चा कर्मचारी येतो. Test मध्ये दीपिका कागद घेऊन येते. दोघेही त्या दाराला बसतात. तीन दारे चुकीने बाहेर उघडत होती. ती दुरुस्त केल्यावर grades च्या test ला फक्त 1 दुसरी room लागते.
Domain database वर बसलेले होते, म्हणून marks चा नियम test करायला SQLite सुरू करून store room load करावी लागे.
Ports and adapters: core ports ठरवतो (GradeStore, Mailer, Ledger) आणि बाहेरचे adapters त्यांना जोडले जातात.
Ring check ला 3 बाहेर जाणारे corridors सापडतात; ते काढल्यावर domain.grades च्या test ला load कराव्या लागणाऱ्या rooms 3 वरून 1 होतात.
आतल्या दिशेने जाणाऱ्या dependencies मुळे मौल्यवान नियम SQL आणि SMTP पासून मुक्त राहतात, आणि fakes सोबत काही ms मध्ये test होतात.
पुढचा धडा core ला विभागांमध्ये वाटतो, प्रत्येकाचा 'student' या शब्दाचा स्वतःचा अर्थ असतो.
स्वतःचे शब्द असलेले विभाग — bounded contexts, ubiquitous language आणि code मधून वाचलेला context map.
तीन offices ना विचारा student म्हणजे काय. Admissions म्हणते form number आणि नाव. Exam cell म्हणते marks सह roll number. Accounts म्हणते fees देणे असलेले खाते. तिघीही आपल्या office मध्ये बरोबर आहेत. पण grades आणि fees admissions ची कल्पना उसनी घेतात. Admissions ने नावाचा रकाना बदलला, तर 2 offices बिघडतात.
एकच मोठा Student class प्रत्येक office वापरत असे, म्हणून admissions साठी नवे field आले की report cards गुपचूप बिघडू शकत.
Bounded contexts म्हणजे विभाग: admissions, grades, fees, timetable, प्रत्येकाचे एक model आणि स्वतःचे शब्द.
Code मधून वाचलेला context map 2 विभाग-ओलांडणारे corridors दाखवतो: grades आणि fees दोघेही admissions चा Student import करतात.
Admissions ने Student.name बदलले तर काहीही न बदलता 2 विभाग बिघडतात; ACL तो बदल दारातच थांबवतो.
पुढचा धडा विचारतो विभाग कुठे ठेवायचे: एक मोठा हॉल, भिंती असलेली एक इमारत, की campus.
एक इमारत, भिंती असलेली एक इमारत, की कॅम्पस — आणि प्रत्येक शैलीची किंमत काय.
कतरिना चार विभाग तीन प्रकारे ठेवू शकते. एक मोठा हॉल सोपा, पण कागद मिसळतात. भिंती असलेली एक इमारत प्रत्येक office चे कागद वेगळे ठेवते. वेगळ्या इमारती प्रत्येक office ला आपल्या दिवशी बदल करू देतात. पण प्रत्येक प्रश्न म्हणजे campus ओलांडून फेरी. विद्यार्थिनीच्या प्रवेशासाठी 3 फेऱ्या लागतात, आणि काही निरोप पोहोचतच नाहीत.
टीम गोंधळलेल्या monolith मधून थेट microservices कडे गेल्या, आणि गुंतलेल्या imports ऐवजी गुंतलेले network calls आले.
तीन शैली: monolith, build-time check असलेल्या भिंतींचा modular monolith, आणि network वरचे microservices.
Microservices मध्ये enrol 3 hops चालतो: +3 ms आणि 99.7% यशस्वी; report card 2 hops, 99.8%; दोन्ही monoliths 100.0% वर.
Microservices 4 स्वतंत्र deploys देतात, पण hops, partial failure आणि sagas घेऊन; modular monolith भिंती फुकट ठेवतो.
पुढचा धडा offices मधल्या फेऱ्यांऐवजी board वर एक सूचना लावतो: events, आणि थोडे मागे राहणारे read model.
सूचना फलक आणि display फलक — एकदाच publish करा, थोडे मागे असलेले model वाचा.
पूर्वी admissions नव्या विद्यार्थिनीबद्दल सांगायला तीन offices मध्ये जात असे. आता ती board वर एक सूचना लावते: 'दीपिका 5A मध्ये आली.' प्रत्येक office board वाचते आणि आपले काम करते. Library सुरू झाली की तीही board वाचते. हॉलमधील marks board थोड्या वेळाने अद्ययावत होतो, म्हणून तो 82.33 आधी 78.5 दाखवू शकतो.
नवीन विद्यार्थिनी आली की admissions प्रत्येक office मध्ये जाऊन सांगत असे, आणि नवी library म्हणजे admissions मध्ये पुन्हा बदल.
सूचना फलकावर events, आणि CQRS: लिखाण नोंदवहीत जाते, वाचन display board वरून होते जो नंतर अद्ययावत होतो.
StudentAdmitted(Dipika, 5A) 3 listeners पर्यंत पोहोचते; marks 72, 85, 90 लिहिले, 2 applied → 78.5, नंतर 82.33.
Events मुळे admissions 0 विभाग import करते आणि 4था listener काहीही न बदलता जोडला जातो; किंमत म्हणजे मागे राहणारे read model.
पुढचा धडा विचारतो data कोणाच्या मालकीचा: सामायिक कपाट, खिडकी, की copy केलेली सूचना.
सामायिक कपाट, एक खिडकी, की नोटिशीची प्रत — shared DB विरुद्ध API विरुद्ध events.
Fee पावत्यांसाठी accounts ला प्रत्येक विद्यार्थिनीचे नाव हवे. ती थेट admissions चे कपाट वाचू शकते, पण column चे नाव बदलल्याने 15 वेळा अडचण येते. ती admissions च्या खिडकीवर विचारू शकते, पण office बंद असताना 3 वेळा उत्तर मिळत नाही. किंवा प्रत्येक सूचना आपल्या वहीत copy करू शकते, जी 2 वेळा थोडी मागे असते.
प्रत्येक application त्याच tables वाचत आणि लिहित असे, म्हणून column चे नाव बदलायची कोणाची हिंमत होत नसे.
Data ownership: प्रत्येक table ची मालकी एका विभागाकडे; इतरांना तो shared database, API किंवा events मधून मिळतो.
20 वाचनांत, tick 5 ला rename आणि 10–12 ला बंद: shared DB 15 वेळा अपयशी, API 3 वेळा, events 2 वेळा जुने.
Shared DB ने 2 इतर टीमचा code देखील मोडला; API runtime ला जोडते, आणि events ताजेपणाच्या बदल्यात स्वातंत्र्य देतात.
पुढचा धडा एक inspector नेमतो जी प्रत्येक push वर आराखडा तपासते, कोणतेही नवे दार राहण्याआधी.
कधीही सुट्टी न घेणारा निरीक्षक — build fail करणाऱ्या architecture tests.
कतरिनाने सुंदर आराखडा काढला. मग घाईत असलेल्या एका बांधकाम कामगाराने भिंतीत दार पाडले. म्हणून ऐश्वर्या इमारत निरीक्षक बनते. ती प्रत्येक push वर 6 नियम तपासते. आज 4 fail होतात, आणि नवे दार स्वीकारले जात नाही. 5 चुकीची दारे बंद केल्यावर सगळे 6 pass होतात आणि build हिरवा होतो.
Architecture चे नियम wiki page वर आणि एका senior engineer च्या डोक्यात होते, आणि इमारत आराखड्यापासून दूर जात राहिली.
Fitness functions म्हणजे CI मधील architecture tests: cycles नाहीत, आतल्या दिशेची dependencies, leaks नाहीत, विभाग-ओलांडणारे imports नाहीत.
ऐश्वर्याचा check sample वर 6 पैकी 4 नियमांत fail होतो, exit code 1; 5 planted corridors काढल्यावर: 6/6, exit 0.
Build fail करणारा नियम drift त्याच दिवशी पकडतो, जसे grades ↔ db cycle, सहा महिन्यांनी नाही.
पुढचा धडा इमारत चार zoom levels वर काढतो, आणि drawing code मधूनच बनवतो म्हणजे ते खोटे बोलू शकत नाही.
कॅम्पसचा नकाशा, इमारतीचा आराखडा, मजल्याचा नकाशा — code मधून तयार होणारे text C4 model, आणि drift.
ऐश्वर्या ही नवी शिक्षिका शाळेत येते. कतरिना आधी तिला campus चा नकाशा दाखवते. मग इमारतीचा आराखडा, मग एका मजल्याचा आराखडा. तिने विचारले तरच, एका room मधली बाके. पण भिंतीवरचा आराखडा जुना आहे: त्यात बांधकामात नंतर आलेले 3 corridors नाहीत. म्हणून कतरिना इमारतीवरूनच नवा आराखडा छापते.
Wiki वरचा हाताने काढलेला box diagram दोन वर्षांपूर्वीचा आराखडा दाखवत होता, आणि नवीन लोक त्यावर विश्वास ठेवत.
C4 model: context, containers, components आणि code, Structurizr DSL text file म्हणून लिहिलेले.
Analyzer 31 ओळींचा DSL लिहितो, ज्याचे component arrows imports मधून येतात, जसे app -> domain (6).
Wiki drawing मध्ये code मधले 3 arrows नाहीत: app → infra, domain → infra, domain → web; fixes नंतर 0 drift.
पुढचा धडा निर्णय का घेतला ते लिहून ठेवतो, आणि पर्यायांना गुण देतो म्हणजे trade-off दिसतो.
मुख्याध्यापिकेची नोंदवही — decision records आणि weight check सह ATAM-lite गुणांकन.
कतरिना मुख्याध्यापिकेच्या office मध्ये एक नोंदवही सुरू करते. प्रत्येक मोठ्या निर्णयासाठी ती परिस्थिती, निवड आणि त्याची किंमत लिहिते. टीम तीन पर्यायांना गुण देते: भिंती असलेल्या इमारतीला 42, एका हॉलला 35, campus ला 34. पुन्हा कधी विचार करायचा तेही ती लिहिते: वेगळे releases खूप महत्त्वाचे झाले तर.
मोठे निर्णय meeting मध्ये घेतले जात आणि विसरले जात; एका वर्षाने एकच इमारत का आहे हे कोणालाच माहीत नसे.
ADR संदर्भ, निर्णय आणि परिणाम नोंदवतो; ATAM-lite पर्यायांना weighted quality scenarios नुसार गुण देते.
5 scenarios, weights 1–3: modular monolith ला 42, monolith ला 35, microservices ला 34; ADR-0007 14 ओळींचा आहे.
Weights महत्त्वाचे: deployability चे weight 4 झाले तर microservices जिंकतील, म्हणून ADR नेमके तिथेच पुन्हा पाहायला सांगतो.
पुढचा धडा चार terms मध्ये इमारत पाहतो: ती कशी बिघडते, कशी सुधारते, आणि route by route कशी बदलायची.
वाढा, सडू नका — काळानुसार cycles आणि propagation cost, strangler fig, आणि संपूर्ण नकाशा.
Exam च्या गडबडीत बांधकाम करणारे shortcuts टाकतात. इमारत गुंतते: corridors चे 4 फेरे तयार होतात. पुढच्या term ला निरीक्षिकेचे checks ते सगळे काढतात. मग शाळा नवीन wing बांधते. ती जुनी इमारत बंद करत नाही. द्वारपाल एका वेळी एका प्रकारच्या पाहुण्यांना नवीन wing कडे पाठवतो, सगळे तिथे जाईपर्यंत.
जुन्या systems गोठवून एकाच big bang मध्ये पुन्हा लिहिल्या जात, महिनोनमहिने features शिवाय आणि धोकादायक weekend cutover सह.
Evolutionary architecture: प्रत्येक term ला झीज मोजा, आणि strangler fig ने जुने भाग एका वेळी एक route बदला.
Propagation cost 24.3% → 31.4% → exam rush मध्ये 49.7%, नंतर checks सह 22.2%; routes 2% → 100% हलतात.
Checks झीज थांबवतात, 4 cycles पुन्हा 0 होतात, आणि लहान उलटवता येणाऱ्या पायऱ्यांमुळे शाळा चालू असताना नवीन wing वाढते.
पुढे, scan() तुमच्या ओळखीच्या खऱ्या codebase वर चालवा: मजले मोजा, cycles शोधा आणि पहिला ADR लिहा.