architecture-principles
Skill0 starsChanged 30 days agoMITView on GitHub
Use when designing system structure, splitting modules/services, or when code changes in one place unexpectedly break another.
3 other projects use a version of this.
Adopted by
Most recently taken up by
- bolgovr/skillstheir own version, first seen Oct 31, 2026
- vospr/context-engineering-templatetheir own version, first seen Oct 1, 2026
- Mesteriis/Engineering-Bible-AItheir own version, first seen Jun 28, 2026
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- vospr/context-engineering-template★ 9same name
- bolgovr/skills★ 1same name
- Mesteriis/Engineering-Bible-AI★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository9 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .cursor/rules/clean-principles.mdcCursor rule
- clarify-before-buildSkill
- clean-codeSkill
- design-patternsSkill
- dry-kiss-yagniSkill
- solid-principlesSkill
- testing-principlesSkill
The file
We split this skill into the rules it gives an agent
1 rule. 0 are common, 1 is distinctive, and 0 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
1
Distinctive
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 92
Benefits: Read and write models evolve independently.
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Architecture Principles
Principles for structuring systems so they're easy to understand, change, and scale.
Separation of Concerns (SoC)
Each module has one clearly defined responsibility. Concerns don't bleed into each other.
❌ BAD — Everything in one layer:
route handler → validates input → runs business logic → queries DB → formats response
✅ GOOD — Each layer has one job:
Controller → validates HTTP input, delegates
Service → business logic, orchestrates
Repository → data access only
Serializer → formats outputBoundary test: Can you change the database without touching business logic? Can you change the API format without touching domain logic? If no → concerns are mixed.
Layered Architecture
Dependencies flow one way: outer layers depend on inner layers, never the reverse.
┌─────────────────────┐
│ Presentation │ HTTP, CLI, WebSocket
├─────────────────────┤
│ Application │ Use cases, orchestration
├─────────────────────┤
│ Domain │ Business rules, entities ← Core, no dependencies
├─────────────────────┤
│ Infrastructure │ DB, email, queues, APIs
└─────────────────────┘
Rule: Domain knows NOTHING about Infrastructure.
Infrastructure implements Domain interfaces.Hexagonal Architecture (Ports & Adapters)
Core business logic is isolated. External systems plug in via adapters.
[ HTTP API ] [ CLI ] [ Tests ]
↓ ↓ ↓
┌────────────────────────┐
│ Application │ ← Ports (interfaces)
│ (Business Logic) │
└────────────────────────┘
↓ ↓ ↓
[ PostgreSQL ] [ Redis ] [ SendGrid ]
(Adapters)Benefit: Swap any external system (DB, email provider) without changing business logic. Business logic is testable with no infrastructure.
CQRS — Command Query Responsibility Segregation
Separate write operations (Commands) from read operations (Queries).
# ❌ BAD: Mixed reads and writes — hard to optimize independently
class UserService:
def create_user(self, data): ... # command
def update_email(self, id, email): ... # command
def find_by_id(self, id): ... # query
def search_users(self, query): ... # query — often needs different optimization
# ✅ GOOD: Separated by intent
class UserCommandService:
def create(self, data: CreateUserDTO) -> None: ...
def update_email(self, id: int, email: str) -> None: ...
class UserQueryService:
def find_by_id(self, id: int) -> UserView: ...
def search(self, query: str) -> list[UserView]: ...Benefits: Read and write models evolve independently. Query side can use caching, denormalized views, or read replicas without affecting write logic.
Note: Full CQRS with separate databases is advanced. Even splitting command/query into separate classes in the same service is a meaningful step.
Event-Driven Architecture
Modules communicate by publishing events — not by calling each other directly.
# ❌ BAD: OrderService knows about every downstream service
class OrderService:
def place_order(self, order):
self.db.save(order)
self.email_service.send_confirmation(order) # tight coupling
self.inventory_service.reserve(order.items)
self.billing_service.charge(order)
# ✅ GOOD: OrderService publishes one event — knows nothing downstream
class OrderService:
def place_order(self, order):
self.db.save(order)
self.event_bus.publish("order.placed", order) # zero coupling
# Each service subscribes independently:
email_service.on("order.placed", send_confirmation)
inventory_service.on("order.placed", reserve_items)
billing_service.on("order.placed", charge_customer)
# Adding analytics? Zero changes to OrderService.Benefit: Adding a new reaction requires zero changes to the publisher.
Trade-off: Flow is harder to trace — invest in structured logging and observability.
High Cohesion, Low Coupling
| Concept | Goal | Smell |
| High Cohesion | Things that change together, live together | Feature spread across 10 files |
| Low Coupling | Modules communicate through narrow interfaces | One module importing 20 things from another |
# ❌ HIGH COUPLING: Order module reaches into User internals
class OrderService:
def place(self, user_id):
user = UserRepository().find(user_id)
address = user._private_address_data["street"] # Reaching in!
# ✅ LOW COUPLING: Order asks for what it needs through interface
class OrderService:
def place(self, user_id):
address = self.user_service.get_shipping_address(user_id) # Clean contractLaw of Demeter (Don't Talk to Strangers)
A method should only call methods on: itself, its parameters, objects it creates, its direct fields.
# ❌ BAD: Chain of knowledge (fragile)
total = order.get_customer().get_wallet().get_balance()
# ✅ GOOD: Ask the direct collaborator
total = order.get_customer_balance() # Customer encapsulates walletPackage / Module Organization
Two valid strategies — pick one, be consistent:
| Strategy | Structure | Best for |
| By Layer | controllers/, services/, repos/ | Small teams, simple CRUD apps |
| By Feature | orders/, users/, billing/ | Growing apps, team ownership |
By feature scales better — all order code lives in orders/, changes are contained.
Quick Architecture Checklist
- Can I describe each module's responsibility in one sentence?
- Does the domain layer have zero imports from infrastructure?
- Can I test business logic without a database or HTTP server?
- Does changing a database table require changes outside the repository?
- Are module boundaries obvious from the folder structure?
- Are commands (writes) separated from queries (reads)?
- Do modules communicate through events rather than direct calls where decoupling matters?
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

