Why this matters
Robert Martin coined the term "Screaming Architecture" from a simple observation: when you look at the blueprints of a library, the structure screams "Library". A hospital blueprint screams "Hospital". But when you look at most software projects, the top-level structure screams "Rails", "Spring", or "Django" — not the business it serves.
If your top-level directories are controllers/, models/, and views/, you are looking at an MVC application. You cannot tell from the folder names whether it manages patients, orders, invoices, or space shuttles. The framework has stolen the project's identity.
Good architecture makes the domain visible. The folder names should read like a conversation with a domain expert: billing/, patients/, appointments/. Frameworks are tools — they should live at the edges, not at the top. A good architecture lets you defer the framework decision and keeps it replaceable.
The problem
A top-level folder structure that reveals the framework, not the business — a new developer cannot tell what the system does without reading the code.
Bad
# Top-level structure screams "MVC framework", not "e-commerce"
# models/user.py
# models/order.py
# views/user_views.py
# controllers/order_controller.py
# A new developer sees: "This is an MVC app."
# They cannot tell what the business does from folder names alone.
# Is it e-commerce? Healthcare? Logistics? Impossible to know.
# The framework owns the structure — the domain is invisible.
// Top-level structure screams "Express app", not "healthcare system"
// controllers/
// appointmentController.ts
// patientController.ts
// models/
// appointment.model.ts
// patient.model.ts
// routes/
// appointments.ts
// patients.ts
// A new developer sees: "This is an Express app."
// The framework's naming conventions have colonized the architecture.
The solution
Organize by bounded context — each top-level folder is a business domain. The framework lives in infrastructure/ at the edge and can be swapped without touching domain code.
Good
# Top-level: "e-commerce system"
# catalog/ — products, categories, search
# ordering/ — cart, checkout, order lifecycle
# payments/ — payment methods, billing, invoices
# shipping/ — fulfillment, tracking, carriers
# infrastructure/ — framework wiring, DB adapters, HTTP controllers
# A new developer sees: "This is an e-commerce system."
# The framework (Django, FastAPI, Flask) lives in infrastructure/.
# If you swap frameworks, only infrastructure/ changes.
# Business logic in catalog/, ordering/, payments/ is untouched.
// Top-level: "healthcare system"
// patients/
// Patient.ts — domain entity
// PatientRepository.ts — abstract interface
// appointments/
// Appointment.ts
// ScheduleAppointmentUseCase.ts
// billing/
// Invoice.ts
// GenerateInvoiceUseCase.ts
// infrastructure/
// express/ — HTTP adapters, route wiring
// postgres/ — repository implementations
// A new developer sees: "This is a healthcare system."
// Express lives only in infrastructure/express — replaceable without
// touching any business logic.
Key takeaway
Your folder structure is the first thing every developer reads. If it screams the framework instead of the business, the domain is hidden behind a technical detail. Organize by bounded context, and push all framework wiring to the edges — then your architecture screams what the system actually does.