ЁЯПв рдзрдбрд╛ 03 тАФ Layers: рдордЬрд▓реЗ, рдЖрдгрд┐ рдЬрд┐рдиреЗ рдХреЛрдгрддреНрдпрд╛ рджрд┐рд╢реЗрдиреЗ рдЬрд╛рддрд╛рдд
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 03 ┬╖ рдорд╛рдЧреЗ: lesson-02-modularity ┬╖ рдкреБрдвреЗ: lesson-04-hexagonal
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ02, рдЖрдгрд┐ рдПрдХ рдирд┐рдпрдо. рдкрд╛рд░рдВрдкрд░рд┐рдХ layered architecture code рдордЬрд▓реНрдпрд╛рдВрдордзреНрдпреЗ рд░рдЪрддреЗ тАФ
рд╕рдЧрд│реНрдпрд╛рдд рд╡рд░ web (presentation), рдордЧ app (use cases), рдордЧ domain (business rules),
рдЖрдгрд┐ рд╕рдЧрд│реНрдпрд╛рдд рдЦрд╛рд▓реА infra (database, email) тАФ рдЖрдгрд┐ рдПрдХрдЪ рдирд┐рдпрдо: рдПрдЦрд╛рджрд╛ рдордЬрд▓рд╛ рдлрдХреНрдд рддреНрдпрд╛рдЪреНрдпрд╛
рдЦрд╛рд▓рдЪреЗ рдордЬрд▓реЗ рд╡рд╛рдкрд░реВ рд╢рдХрддреЛ. Layer violations рдЖрдкреЛрдЖрдк рдХрд╕реЗ рд╢реЛрдзрд╛рдпрдЪреЗ, strict рд╡рд┐рд░реБрджреНрдз relaxed
layering, рдЖрдгрд┐ рд╣рд╛ рдзрдбрд╛ рдПрдХрд╛ рдЖрд╢реНрдЪрд░реНрдпрд╛рдиреЗ рдХрд╛ рд╕рдВрдкрддреЛ. arch/analyze.py рдордзреАрд▓
layer_violations() рдЖрдгрд┐ arch/demo.py рдордзреАрд▓ layers().
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рд╢рд╛рд│реЗрдЪреНрдпрд╛ рдЗрдорд╛рд░рддреАрд▓рд╛ рдЪрд╛рд░ рдордЬрд▓реЗ рдЖрд╣реЗрдд. ЁЯПв
- рд╕рдЧрд│реНрдпрд╛рдд рд╡рд░рдЪрд╛ рдордЬрд▓рд╛ тАФ рд╕реНрд╡рд╛рдЧрдд рдХрдХреНрд╖ (web): рдкрд╛рд▓рдХ рдЖрдд рдпреЗрддрд╛рдд рдЖрдгрд┐ рдкреНрд░рд╢реНрди рд╡рд┐рдЪрд╛рд░рддрд╛рдд.
- рджреБрд╕рд░рд╛ рдордЬрд▓рд╛ тАФ office (app): рдЧреЛрд╖реНрдЯреА рдХрд╢рд╛ рдХрд░рд╛рдпрдЪреНрдпрд╛ рд╣реЗ рдорд╛рд╣реАрдд рдЕрд╕рд▓реЗрд▓рд╛ рдХрд░реНрдордЪрд╛рд░реАрд╡рд░реНрдЧ тАФ рдореБрд▓рд╛рдЪрд╛ рдкреНрд░рд╡реЗрд╢ рдХрд░рдгреЗ, report card рдЫрд╛рдкрдгреЗ.
- рддрд┐рд╕рд░рд╛ рдордЬрд▓рд╛ тАФ рдирд┐рдпрдордкреБрд╕реНрддрд┐рдХрд╛ (domain): mark рдореНрд╣рдгрдЬреЗ рдХрд╛рдп, рд╕рд░рд╛рд╕рд░реА рдХрд╢реА рдХрд╛рдврд╛рдпрдЪреА.
- рддрд│рдордЬрд▓рд╛ тАФ рднрд╛рдВрдбрд╛рд░ рдЖрдгрд┐ рдЯрдкрд╛рд▓ рдЦреЛрд▓реА (infra): рдХрд╛рдЧрджрдкрддреНрд░рд╛рдВрдЪреА рдХрдкрд╛рдЯреЗ рдЖрдгрд┐ рдкрддреНрд░реЗ.
рдирд┐рдпрдо: рддреБрдореНрд╣реА рдЬрд┐рдиреНрдпрд╛рдиреЗ рдЦрд╛рд▓реА рдЬрд╛рдК рд╢рдХрддрд╛, рд╡рд░ рдХрдзреАрдЪ рдирд╛рд╣реА. Office рдирд┐рдпрдордкреБрд╕реНрддрд┐рдХрд╛ рдкрд╛рд╣реВ рд╢рдХрддреЗ. рдирд┐рдпрдордкреБрд╕реНрддрд┐рдХрд╛ рджрд┐рд╡рд╕рд╛рдЪреЗ рдирд╛рд╡ рдХрд╕реЗ рдЫрд╛рдкрд╛рдпрдЪреЗ рд╣реЗ рд╡рд┐рдЪрд╛рд░рд╛рдпрд▓рд╛ рд╕реНрд╡рд╛рдЧрдд рдХрдХреНрд╖рд╛рд▓рд╛ рдлреЛрди рдХрд░реВ рд╢рдХрдд рдирд╛рд╣реА.
рдРрд╢реНрд╡рд░реНрдпрд╛ clipboard рдШреЗрдКрди рдкреНрд░рддреНрдпреЗрдХ рдорд╛рд░реНрдЧрд┐рдХреЗрддреВрди рдлрд┐рд░рддреЗ рдЖрдгрд┐ рдЬрд┐рдиреНрдпрд╛рдиреЗ рд╡рд░ рдЬрд╛рдгрд╛рд░реА рдкреНрд░рддреНрдпреЗрдХ рдорд╛рд░реНрдЧрд┐рдХрд╛ рд▓рд┐рд╣реВрди рдареЗрд╡рддреЗ. рддреА рдпрд╛рджреА рдореНрд╣рдгрдЬреЗ layer violations.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart TB
web["ЁЯЦея╕П web тАФ reception (top floor)"]
app["ЁЯзСтАНЁЯПл app тАФ the office"]
domain["ЁЯУЪ domain тАФ the rule book"]
infra["ЁЯФМ infra тАФ store room + post room (ground floor)"]
web -->|"ok: down"| app
app -->|"ok: down"| domain
domain -->|"ok: down"| infra
domain -.->|"тЭМ upward: timetable тЖТ web.format"| web
infra -.->|"тЭМ upward ├Ч3: db тЖТ grades, db тЖТ ports, email тЖТ ports"| domain
app -.->|"strict only: skips a floor (enrol тЖТ email)"| infra
ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/software-architecture/lesson-diagrams.html#l03
тЭУ рдХрд╛рдп
- Layered architecture (n-tier) тАФ code рдХрд╛рдорд╛рдЪреНрдпрд╛ рдкреНрд░рдХрд╛рд░рд╛рдиреБрд╕рд╛рд░ рдЖрдбрд╡реНрдпрд╛ layers рдордзреНрдпреЗ рд╡рд┐рднрд╛рдЧрд▓рд╛ рдЬрд╛рддреЛ. Eric Evans рдпрд╛рдВрдЪреЗ Domain-Driven Design (2003) рдЪрд╛рд░ рдирд╛рд╡реЗ рджреЗрддреЗ: user interface, application, domain, infrastructure. рдЕрдиреЗрдХ web apps presentation, business, persistence, database рд╡рд╛рдкрд░рддрд╛рдд.
- Layering рдЪрд╛ рдирд┐рдпрдо тАФ рдПрдЦрд╛рджрд╛ layer рдлрдХреНрдд рддреНрдпрд╛рдЪреНрдпрд╛ рдЦрд╛рд▓рдЪреНрдпрд╛ layers рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рд░рд╛рд╣реВ рд╢рдХрддреЛ. рдЦрд╛рд▓рдЪреНрдпрд╛ рдХреЛрдгрд╛рд▓рд╛рд╣реА рд╡рд░рдЪреЗ рдХрд╛рд╣реА рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдЖрд╣реЗ рд╣реЗ рдорд╛рд╣реАрдд рдирд╕рддреЗ. рдордЧ рддрд│рд╛рд▓рд╛ рд╣рд╛рдд рди рд▓рд╛рд╡рддрд╛ рддреБрдореНрд╣реА рд╡рд░рдЪрд╛ рднрд╛рдЧ (рдирд╡реАрди mobile screen) рдмрджрд▓реВ рд╢рдХрддрд╛.
- Relaxed (open) layering тАФ рдЦрд╛рд▓рдЪрд╛ рдХреЛрдгрддрд╛рд╣реА layer рдЪрд╛рд▓рддреЛ; web рдордЬрд▓рд╛ рдереЗрдЯ domain рдХрдбреЗ рдЬрд╛рдК рд╢рдХрддреЛ.
- Strict (closed) layering тАФ рдлрдХреНрдд рд▓рдЧреЗрдЪ рдЦрд╛рд▓рдЪрд╛ layer. рдкреНрд░рддреНрдпреЗрдХ request рдкреНрд░рддреНрдпреЗрдХ рдордЬрд▓реНрдпрд╛рддреВрди рдЬрд╛рддреЗ. рдЬрд╛рд╕реНрдд рд╕реНрд╡рдЪреНрдЫ, рдкрдг рдпрд╛рддреВрди architecture sinkhole anti-pattern (Mark Richards рдпрд╛рдВрдиреА рджрд┐рд▓реЗрд▓реЗ рдирд╛рд╡) рддрдпрд╛рд░ рд╣реЛрдК рд╢рдХрддреЛ: рдХрд╛рд╣реАрд╣реА рди рдЬреЛрдбрддрд╛ рдлрдХреНрдд calls рдкреБрдвреЗ рдврдХрд▓рдгрд╛рд░реЗ layers.
- Layer violation тАФ рдирд┐рдпрдо рдореЛрдбрдгрд╛рд░рд╛ import: рд╡рд░ рдЬрд╛рдгрд╛рд░рд╛ (рдЦрд╛рд▓рдЪрд╛ рд╡рд░рдЪреНрдпрд╛рд▓рд╛ import рдХрд░рддреЛ) рдХрд┐рдВрд╡рд╛, strict layering рдордзреНрдпреЗ, рдПрдЦрд╛рджрд╛ рдордЬрд▓рд╛ рд╡рдЧрд│рдгрд╛рд░рд╛.
- Dependency rule тАФ "source code dependencies рдлрдХреНрдд рдЖрддрд▓реНрдпрд╛ рджрд┐рд╢реЗрдиреЗ, policies рдХрдбреЗ рдЬрд╛рддрд╛рдд" рдпрд╛рд▓рд╛ Robert C. Martin рдпрд╛рдВрдиреА (Clean Architecture) рджрд┐рд▓реЗрд▓реЗ рдирд╛рд╡. рдкреБрдврдЪрд╛ рдзрдбрд╛ рджрд╛рдЦрд╡рддреЛ рдХреА "рдЖрдд" рдЖрдгрд┐ "рдЦрд╛рд▓реА" рд╣реЗ рдПрдХрдЪ рдирд╛рд╣реАрдд тАФ рдЖрдгрд┐ рдиреЗрдордХреЗ рддреЗрдЪ рдпрд╛ рдзрдбреНрдпрд╛рдЪреЗ рдЖрд╢реНрдЪрд░реНрдп рдЖрд╣реЗ.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг рджреЛрдиреНрд╣реА рджрд┐рд╢рд╛рдВрдиреА рдЬрд┐рдиреЗ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдЗрдорд╛рд░рддреАрдЪреНрдпрд╛ рдирдХрд╛рд╢рд╛рд▓рд╛ рд╡рд░ рдирд╛рд╣реА рдЖрдгрд┐ рдЦрд╛рд▓реА рдирд╛рд╣реА: рднрд╛рдВрдбрд╛рд░ рддрдкрд╛рд╕рд▓реНрдпрд╛рд╢рд┐рд╡рд╛рдп рддреБрдореНрд╣реА рд╕реНрд╡рд╛рдЧрдд рдХрдХреНрд╖ рдмрджрд▓реВ рд╢рдХрдд рдирд╛рд╣реА, рдЖрдгрд┐ рддрд╛рд░рдЦрд╛ рдХрд╢рд╛ рдЫрд╛рдкрд╛рдпрдЪреНрдпрд╛ рдпрд╛рддрд▓рд╛ рдмрджрд▓ timetable рдЪреЗ рдирд┐рдпрдо рдореЛрдбрддреЛ. Layer рдЪрд╛ рдирд┐рдпрдо рдЗрддрдХрд╛ рд╕реЛрдкрд╛ рдЖрд╣реЗ рдХреА machine рдкреНрд░рддреНрдпреЗрдХ push рд╡рд░ рдкреНрд░рддреНрдпреЗрдХ import рддрдкрд╛рд╕реВ рд╢рдХрддреЗ тАФ рдореНрд╣рдгрдЬреЗ рддреБрдореНрд╣реА рдХрд╛рдврд▓реЗрд▓реА рд░рдЪрдирд╛ рд╣реАрдЪ рддреБрдордЪреНрдпрд╛рдХрдбрдЪреА рд░рдЪрдирд╛ рд░рд╛рд╣рддреЗ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
arch/analyze.py рдордзреАрд▓ layer_violations(g, order, strict) рдкреНрд░рддреНрдпреЗрдХ
рдордЬрд▓реНрдпрд╛рд▓рд╛ order рдордзреВрди рдХреНрд░рдорд╛рдВрдХ рджреЗрддреЛ (рд╡рд░рдЪрд╛ рдЖрдзреА; default FLOORS = ["web", "app", "domain", "infra"]). рджреЛрди рд╡реЗрдЧрд╡реЗрдЧрд│реНрдпрд╛ рдордЬрд▓реНрдпрд╛рдВрдордзреАрд▓ рдкреНрд░рддреНрдпреЗрдХ рдорд╛рд░реНрдЧрд┐рдХреЗрд╕рд╛рдареА: рдЦрд╛рд▓рдЪрд╛ рдордЬрд▓рд╛ рд╡рд░рдЪреНрдпрд╛рд▓рд╛
import рдХрд░рдд рдЕрд╕реЗрд▓ рддрд░ рддреА upward; strict=True рдЕрд╕рддрд╛рдирд╛ рдПрдХрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдордЬрд▓реЗ рдЦрд╛рд▓реА рдЬрд╛рдгреЗ рдореНрд╣рдгрдЬреЗ
skips a floor. рдХреЛрдгрддреНрдпрд╛рд╣реА рдордЬрд▓реНрдпрд╛рд╡рд░ рдирд╕рд▓реЗрд▓реНрдпрд╛ рдЦреЛрд▓реНрдпрд╛ (main, composition root) рджреБрд░реНрд▓рдХреНрд╖рд┐рдд рдХреЗрд▓реНрдпрд╛
рдЬрд╛рддрд╛рдд тАФ рд╕рдЧрд│реНрдпрд╛рдВрдирд╛ рдУрд│рдЦрдгреНрдпрд╛рдЪреА рдкрд░рд╡рд╛рдирдЧреА рдЕрд╕рд▓реЗрд▓реА рддреА рдПрдХрдореЗрд╡ рдЦреЛрд▓реА рдЖрд╣реЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 arch/demo.py layers
python3 - <<'EOF'
import sys; sys.path.insert(0, "arch"); from analyze import scan, layer_violations
g = scan().imports
for order in (["web", "app", "domain", "infra"], ["web", "app", "infra", "domain"], ["web", "infra", "app", "domain"]):
for strict in (False, True):
v = layer_violations(g, order, strict)
print(f"{' тЖТ '.join(order):<30} {'strict ' if strict else 'relaxed'} {len(v)} violation(s)")
EOF
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
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)
рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:
web тЖТ app тЖТ domain тЖТ infra relaxed 4 violation(s)
web тЖТ app тЖТ domain тЖТ infra strict 5 violation(s)
web тЖТ app тЖТ infra тЖТ domain relaxed 2 violation(s)
web тЖТ app тЖТ infra тЖТ domain strict 8 violation(s)
web тЖТ infra тЖТ app тЖТ domain relaxed 3 violation(s)
web тЖТ infra тЖТ app тЖТ domain strict 9 violation(s)
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рдкрд╛рд░рдВрдкрд░рд┐рдХ рдХреНрд░рдорд╛рдиреЗ (database рд╕рдЧрд│реНрдпрд╛рдд рдЦрд╛рд▓реА) рдРрд╢реНрд╡рд░реНрдпрд╛рд▓рд╛ 4 рд╡рд░ рдЬрд╛рдгрд╛рд▒реНрдпрд╛ рдорд╛рд░реНрдЧрд┐рдХрд╛ рд╕рд╛рдкрдбрддрд╛рдд тАФ
рдкрдг рддреНрдпрд╛ рдиреАрдЯ рдкрд╛рд╣рд╛. рддреНрдпрд╛рддрд▓реНрдпрд╛ рддреАрди рдореНрд╣рдгрдЬреЗ infra.db рдЖрдгрд┐ infra.email, рдЬреЗ рддреНрдпрд╛рдВрдирд╛ implement
рдХрд░рд╛рдпрдЪреЗ рдЕрд╕рд▓реЗрд▓реЗ ports рдЖрдгрд┐ рдкрд░рдд рджреНрдпрд╛рдпрдЪрд╛ рдЕрд╕рд▓реЗрд▓рд╛ Mark class import рдХрд░рддрд╛рдд. рд╣рд╛ рдЧреЛрдВрдзрд│ рдирд╛рд╣реА; рд╣рд╛
adapter рдЖрдкрд▓реЗ рдХрд╛рдо рдХрд░рддреЛ рдЖрд╣реЗ. рдкрд╛рд░рдВрдкрд░рд┐рдХ рд░рдЪрдирд╛ domain рд▓рд╛ database рдЪреНрдпрд╛ рд╡рд░ рдмрд╕рд╛рдпрд▓рд╛ рднрд╛рдЧ рдкрд╛рдбрддреЗ, рдореНрд╣рдгреВрди
рдкреНрд░рддреНрдпреЗрдХ adapter "рдЪреБрдХреАрдЪрд╛" рджрд┐рд╕рддреЛ. Domain рд╕рдЧрд│реНрдпрд╛рдд рдЦрд╛рд▓реА рдареЗрд╡рд╛ (web тЖТ app тЖТ infra тЖТ domain)
рдЖрдгрд┐ relaxed violations 2 рд╡рд░ рдпреЗрддрд╛рдд тАФ рдЦрд░реЛрдЦрд░ рдЪреБрдХреАрдЪреНрдпрд╛ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рджреЛрди рдорд╛рд░реНрдЧрд┐рдХрд╛
(domain.timetable тЖТ web.format рдЖрдгрд┐ domain.grades тЖТ infra.db). рдордЧ strict layering
8 рдЖрдгрд┐ 9 рд╡рд░ рдЙрдбреА рдорд╛рд░рддреЗ: domain рд╕рдЧрд│реНрдпрд╛рдд рдЦрд╛рд▓реА рдЕрд╕рд▓реНрдпрд╛рдореБрд│реЗ рдкреНрд░рддреНрдпреЗрдХ use case рд▓рд╛ рддрд┐рдереЗ рдкреЛрд╣реЛрдЪрдгреНрдпрд╛рд╕рд╛рдареА
infra рдордЬрд▓рд╛ "рд╡рдЧрд│рд╛рд╡рд╛" рд▓рд╛рдЧрддреЛ. Core рддрд│рд╛рд╢реА рдЧреЗрд▓рд╛ рдХреА strict рд░рдЪрдирд╛ рдиреАрдЯ рдмрд╕рдд рдирд╛рд╣реА. рдордЬрд▓реНрдпрд╛рдВрдЪрд╛ рдХреНрд░рдо
рд╣рд╛рдЪ design рдирд┐рд░реНрдгрдп рдЖрд╣реЗ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- database рд╕рдЧрд│реНрдпрд╛рдд рдЦрд╛рд▓реА рдареЗрд╡рдгреЗ рдЖрдгрд┐ рдордЧ business rules рдирд╛ ORM рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рдареЗрд╡рдгреЗ
- рдкреНрд░рддреНрдпреЗрдХ technology рд╕рд╛рдареА рдПрдХ "layer" (controllers, services, repositories), рдЖрдгрд┐ business rules рддрд┐рдиреНрд╣реАрдВрдордзреНрдпреЗ рдкрд╕рд░рд▓реЗрд▓реЗ
- рд╕рдЧрд│реАрдХрдбреЗ strict layering тЖТ рдХрд╛рд╣реАрд╣реА рди рдЬреЛрдбрдгрд╛рд▒реНрдпрд╛ pass-through methods (sinkhole)
- core import рдХрд░рддреЛ рдЕрд╕реЗ рд╡рд░рдЪреНрдпрд╛ рдордЬрд▓реНрдпрд╛рд╡рд░рдЪреЗ рд╕рд╛рдорд╛рдпрд┐рдХ "helpers" (рдЗрдерд▓рд╛
day_nameрд╕рд╛рд░рдЦреЗ) - wiki рд╡рд░ рд▓рд┐рд╣рд┐рд▓реЗрд▓рд╛ рдЖрдгрд┐ рдХреЛрдгреАрд╣реА рди рддрдкрд╛рд╕рд▓реЗрд▓рд╛ layer рдЪрд╛ рдирд┐рдпрдо
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
On a real project тАФ import-linter (Python) рдкреНрд░рддреНрдпреЗрдХ run рд╡рд░ layers contract рддрдкрд╛рд╕рддреЛ.
.importlinter рдордзреНрдпреЗ (рдХрд┐рдВрд╡рд╛ pyproject.toml рдордзреАрд▓ [tool.importlinter] table рдордзреНрдпреЗ):
[importlinter]
root_package = schoolapp
[importlinter:contract:floors]
name = Floors only use the floors below
type = layers
layers =
schoolapp.web
schoolapp.app
schoolapp.domain
schoolapp.infra
pip install import-linter
lint-imports # exits non-zero and lists each illegal import chain
ArchUnit (Java) рд╣реЗрдЪ рдПрдХрд╛ unit test рдордзреНрдпреЗ рд╕рд╛рдВрдЧрддреЛ:
@ArchTest
static final ArchRule floors = layeredArchitecture().consideringAllDependencies()
.layer("Web").definedBy("..web..")
.layer("App").definedBy("..app..")
.layer("Domain").definedBy("..domain..")
.layer("Infra").definedBy("..infra..")
.whereLayer("Web").mayNotBeAccessedByAnyLayer()
.whereLayer("App").mayOnlyBeAccessedByLayers("Web")
.whereLayer("Domain").mayOnlyBeAccessedByLayers("App", "Web")
.whereLayer("Infra").mayOnlyBeAccessedByLayers("Domain", "App", "Web");
JavaScript рдЖрдгрд┐ TypeScript рд╕рд╛рдареА dependency-cruiser рд╣реЗ forbidden рдирд┐рдпрдорд╛рдВрдиреА рдХрд░рддреЛ;
.NET рд╕рд╛рдареА NetArchTest.
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдордЬрд▓реНрдпрд╛рдВрдЪрд╛ рдХреНрд░рдо рд╣реЗрддреБрдкреВрд░реНрд╡рдХ рдирд┐рд╡рдбрд╛ тАФ рдЖрдгрд┐ database рдХреБрдареЗ рдареЗрд╡рддрд╛ рддреЗ рд▓рдХреНрд╖рд╛рдд рдШреНрдпрд╛. Adapters рд╕рддрдд violations рдореНрд╣рдгреВрди рджрд┐рд╕рдд рдЕрд╕рддреАрд▓, рддрд░ рддреБрдордЪрд╛ рдирд┐рдпрдо рддреБрдордЪреНрдпрд╛ design рд╢реА рд▓рдврддреЛ рдЖрд╣реЗ. рдкреБрдврдЪрд╛ рдзрдбрд╛ рдЗрдорд╛рд░рдд рдЖрддреВрди рдмрд╛рд╣реЗрд░ рдЙрд▓рдЯрд╡рддреЛ.
тПня╕П рдкреБрдвреЗ
рдирд┐рдпрдордкреБрд╕реНрддрд┐рдХрд╛ рдордЬрд▓рд╛рдЪ рдирд╕реВрди рдЗрдорд╛рд░рддреАрдЪрд╛ рдордзреНрдпрднрд╛рдЧ рдЕрд╕рддреА, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ рджрд╛рд░ рдмрд╛рд╣реЗрд░рдЪреНрдпрд╛ рджрд┐рд╢реЗрдиреЗ рдЙрдШрдбрдд рдЕрд╕рддреЗ, рддрд░? Ports and adapters.
git checkout lesson-04-hexagonal