<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ayman Atif</title>
    <description>The latest articles on DEV Community by Ayman Atif (@a95yman).</description>
    <link>https://dev.to/a95yman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3887349%2F44f7eb73-8509-408e-94a4-f2d98502a27d.jpg</url>
      <title>DEV Community: Ayman Atif</title>
      <link>https://dev.to/a95yman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/a95yman"/>
    <language>en</language>
    <item>
      <title>How I Structure Every .NET Project (Clean Architecture Breakdown)</title>
      <dc:creator>Ayman Atif</dc:creator>
      <pubDate>Sun, 19 Apr 2026 13:09:20 +0000</pubDate>
      <link>https://dev.to/a95yman/how-i-structure-every-net-project-clean-architecture-breakdown-4e8m</link>
      <guid>https://dev.to/a95yman/how-i-structure-every-net-project-clean-architecture-breakdown-4e8m</guid>
      <description>&lt;p&gt;Most .NET projects don’t fail because of bad code.&lt;br&gt;
They fail because of unclear structure.&lt;/p&gt;

&lt;p&gt;When everything is dumped into a single project or loosely organized folders, things feel fine at first — until the project grows. Then small changes start breaking unrelated parts, testing becomes painful, and onboarding new devs turns into a mess.&lt;/p&gt;

&lt;p&gt;Over time, I’ve converged on a simple structure that avoids most of these problems without overengineering.&lt;/p&gt;

&lt;p&gt;Here’s how I structure almost every .NET project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The core idea: separation of responsibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The goal isn’t “complex architecture.”&lt;br&gt;
It’s predictable boundaries.&lt;/p&gt;

&lt;p&gt;Each part of the system should have one reason to change.&lt;/p&gt;

&lt;p&gt;So I split my projects into 4 layers:&lt;/p&gt;

&lt;p&gt;API&lt;br&gt;
Application&lt;br&gt;
Domain&lt;br&gt;
Infrastructure&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Domain layer (the center of everything)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the core of the system.&lt;/p&gt;

&lt;p&gt;It contains:&lt;/p&gt;

&lt;p&gt;Entities&lt;br&gt;
Value objects&lt;br&gt;
Domain rules&lt;br&gt;
Core business logic&lt;/p&gt;

&lt;p&gt;No dependencies on anything external.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;User&lt;br&gt;
Order&lt;br&gt;
Invoice&lt;/p&gt;

&lt;p&gt;The rule here is simple:&lt;br&gt;
If you remove everything else, this should still make sense.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Application layer (use cases)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where the business workflows live.&lt;/p&gt;

&lt;p&gt;It contains:&lt;/p&gt;

&lt;p&gt;Use cases (CreateOrder, RegisterUser, etc.)&lt;br&gt;
Interfaces (contracts)&lt;br&gt;
DTOs&lt;br&gt;
Validation logic&lt;/p&gt;

&lt;p&gt;This layer defines what the system does, not how it does it.&lt;/p&gt;

&lt;p&gt;It depends on the Domain layer, but nothing else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Infrastructure layer (implementation details)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where external systems live:&lt;/p&gt;

&lt;p&gt;Database (EF Core, Dapper)&lt;br&gt;
Email services&lt;br&gt;
File storage&lt;br&gt;
External APIs&lt;/p&gt;

&lt;p&gt;This layer implements interfaces defined in Application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IEmailService → implemented here&lt;br&gt;
IUserRepository → EF Core implementation here&lt;/p&gt;

&lt;p&gt;This keeps your core logic independent from frameworks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. API layer (entry point)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the thin outer layer.&lt;/p&gt;

&lt;p&gt;It contains:&lt;/p&gt;

&lt;p&gt;Controllers / endpoints&lt;br&gt;
Dependency injection setup&lt;br&gt;
Request/response handling&lt;/p&gt;

&lt;p&gt;Its job is simple:&lt;/p&gt;

&lt;p&gt;Receive input → call Application → return output&lt;/p&gt;

&lt;p&gt;No business logic should live here.&lt;/p&gt;

&lt;p&gt;Why this structure works&lt;/p&gt;

&lt;p&gt;This setup gives you:&lt;/p&gt;

&lt;p&gt;Clear boundaries between concerns&lt;br&gt;
Easier testing (especially Application layer)&lt;br&gt;
Swap database or services without touching business logic&lt;br&gt;
Scalable structure for real projects&lt;/p&gt;

&lt;p&gt;But more importantly:&lt;/p&gt;

&lt;p&gt;You stop thinking about “where should this go?” every time you write code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The mistake most devs make&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They either:&lt;/p&gt;

&lt;p&gt;Overcomplicate architecture early&lt;br&gt;
or&lt;br&gt;
Put everything in one project until it breaks&lt;/p&gt;

&lt;p&gt;This sits in the middle:&lt;/p&gt;

&lt;p&gt;Simple enough to start fast, structured enough to scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I packaged this into a starter setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After rebuilding this structure across multiple projects, I turned it into a ready-to-use starter kit so I don’t repeat the setup every time.&lt;/p&gt;

&lt;p&gt;If you want a clean .NET foundation you can just clone and build on:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://yaman95.gumroad.com/l/clean-core-dot-net-starter-kit" rel="noopener noreferrer"&gt;https://yaman95.gumroad.com/l/clean-core-dot-net-starter-kit&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
