# code-organization > Structure projects for maintainability and scalability with clean architecture, separation of concerns, and consistent project layouts. - Author: Piyush Jain - Repository: premaarya/AgentX-Test - Version: 20260122062115 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-08 - Source: https://github.com/premaarya/AgentX-Test - Web: https://mule.run/skillshub/@@premaarya/AgentX-Test~code-organization:20260122062115 --- --- name: code-organization description: 'Structure projects for maintainability and scalability with clean architecture, separation of concerns, and consistent project layouts.' --- # Code Organization > **Purpose**: Structure projects for maintainability, scalability, and team collaboration. --- ## Project Structure ### C# (.NET Solution) ``` Solution/ ├── src/ │ ├── MyProject.Api/ # Web API project │ │ ├── Controllers/ │ │ │ ├── UsersController.cs │ │ │ ├── ProductsController.cs │ │ │ └── OrdersController.cs │ │ ├── Middleware/ │ │ │ ├── AuthenticationMiddleware.cs │ │ │ ├── LoggingMiddleware.cs │ │ │ └── RateLimitingMiddleware.cs │ │ ├── Filters/ │ │ │ ├── ValidationFilter.cs │ │ │ └── ExceptionFilter.cs │ │ ├── Program.cs │ │ ├── Startup.cs # or configure in Program.cs │ │ ├── appsettings.json │ │ └── appsettings.Development.json │ ├── MyProject.Core/ # Domain/Business logic │ │ ├── Entities/ │ │ │ ├── User.cs │ │ │ ├── Product.cs │ │ │ └── Order.cs │ │ ├── Interfaces/ │ │ │ ├── IUserRepository.cs │ │ │ ├── IEmailService.cs │ │ │ └── IPaymentService.cs │ │ ├── Services/ │ │ │ ├── UserService.cs │ │ │ ├── PaymentService.cs │ │ │ └── EmailService.cs │ │ ├── DTOs/ │ │ │ ├── UserDto.cs │ │ │ └── ProductDto.cs │ │ └── Exceptions/ │ │ ├── UserNotFoundException.cs │ │ └── DuplicateEmailException.cs │ ├── MyProject.Infrastructure/ # Data access & external services │ │ ├── Data/ │ │ │ ├── ApplicationDbContext.cs │ │ │ └── Migrations/ │ │ ├── Repositories/ │ │ │ ├── UserRepository.cs │ │ │ └── OrderRepository.cs │ │ └── Services/ │ │ ├── EmailService.cs │ │ └── BlobStorageService.cs │ └── MyProject.Shared/ # Shared utilities │ ├── Constants/ │ │ └── AppConstants.cs │ ├── Helpers/ │ │ └── StringHelper.cs │ └── Validators/ │ └── EmailValidator.cs ├── tests/ │ ├── MyProject.UnitTests/ │ ├── MyProject.IntegrationTests/ │ └── MyProject.E2ETests/ ├── docs/ ├── scripts/ ├── .gitignore ├── MyProject.sln └── README.md ``` --- ## Separation of Concerns ### Layered Architecture ```csharp // ❌ Bad: Everything in one place [HttpGet("users/{userId}")] public IActionResult GetUser(int userId) { using var conn = new NpgsqlConnection("Host=localhost;Database=mydb;Username=user;Password=pass"); conn.Open(); var cmd = new NpgsqlCommand("SELECT * FROM Users WHERE Id = @id", conn); cmd.Parameters.AddWithValue("id", userId); var reader = cmd.ExecuteReader(); if (!reader.Read()) return NotFound(new { error = "Not found" }); var user = new { /* map reader */ }; // Send email var smtp = new SmtpClient("smtp.gmail.com"); smtp.Send("from@example.com", user.Email, "Subject", "Body"); return Ok(user); } ``` ```csharp // ✅ Good: Separated layers // 1. Repository Layer (Data Access) public interface IUserRepository { Task FindByIdAsync(int userId); Task FindByEmailAsync(string email); Task CreateAsync(User user); } public class UserRepository : IUserRepository { private readonly ApplicationDbContext _context; public UserRepository(ApplicationDbContext context) { _context = context; } public async Task FindByIdAsync(int userId) { return await _context.Users .FirstOrDefaultAsync(u => u.Id == userId); } public async Task FindByEmailAsync(string email) { return await _context.Users .FirstOrDefaultAsync(u => u.Email == email); } public async Task CreateAsync(User user) { _context.Users.Add(user); await _context.SaveChangesAsync(); return user; } } // 2. Service Layer (Business Logic) public interface IUserService { Task GetUserProfileAsync(int userId); Task RegisterUserAsync(RegisterDto data); } public class UserService : IUserService { private readonly IUserRepository _userRepository; private readonly IEmailService _emailService; private readonly IPasswordHasher _passwordHasher; public UserService( IUserRepository userRepository, IEmailService emailService, IPasswordHasher passwordHasher) { _userRepository = userRepository; _emailService = emailService; _passwordHasher = passwordHasher; } public async Task GetUserProfileAsync(int userId) { var user = await _userRepository.FindByIdAsync(userId); if (user == null) throw new UserNotFoundException($"User {userId} not found"); return user.ToDto(); } public async Task RegisterUserAsync(RegisterDto data) { // Business validation var existingUser = await _userRepository.FindByEmailAsync(data.Email); if (existingUser != null) throw new DuplicateEmailException("Email already exists"); // Create user var user = new User { Email = data.Email, Name = data.Name }; user.PasswordHash = _passwordHasher.HashPassword(user, data.Password); user = await _userRepository.CreateAsync(user); // Send welcome email await _emailService.SendWelcomeEmailAsync(user); return user; } } // 3. API Layer (Presentation) [ApiController] [Route("api/[controller]")] public class UsersController : ControllerBase { private readonly IUserService _userService; private readonly ILogger _logger; public UsersController(IUserService userService, ILogger logger) { _userService = userService; _logger = logger; } /// /// Get user profile by ID /// [HttpGet("{userId}")] [ProducesResponseType(typeof(UserDto), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetUser(int userId) { try { var profile = await _userService.GetUserProfileAsync(userId); return Ok(profile); } catch (UserNotFoundException) { return NotFound(new { error = "User not found" }); } catch (Exception ex) { _logger.LogError(ex, "Error fetching user {UserId}", userId); return StatusCode(500, new { error = "Internal server error" }); } } } ``` --- ## Dependency Injection ```csharp // Define interfaces public interface IUserRepository { Task FindByIdAsync(int userId); Task CreateAsync(User user); } public interface IEmailService { Task SendWelcomeEmailAsync(User user); } // Service depends on abstractions, not concrete implementations public class UserService { private readonly IUserRepository _userRepository; private readonly IEmailService _emailService; public UserService(IUserRepository userRepository, IEmailService emailService) { _userRepository = userRepository; _emailService = emailService; } public async Task RegisterUserAsync(RegisterDto data) { var user = new User { Email = data.Email, Name = data.Name }; user = await _userRepository.CreateAsync(user); await _emailService.SendWelcomeEmailAsync(user); return user; } } // Dependency injection configuration in Program.cs var builder = WebApplication.CreateBuilder(args); // Register DbContext builder.Services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); // Register repositories builder.Services.AddScoped(); builder.Services.AddScoped(); // Register services builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Register other dependencies builder.Services.AddMemoryCache(); builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("Redis"); }); var app = builder.Build(); // Usage - ASP.NET Core automatically injects dependencies [ApiController] [Route("api/[controller]")] public class UsersController : ControllerBase { private readonly IUserService _userService; // Constructor injection public UsersController(IUserService userService) { _userService = userService; } [HttpPost("register")] public async Task Register([FromBody] RegisterDto request) { var user = await _userService.RegisterUserAsync(request); return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user); } } ``` --- ## Module Organization ### Feature-Based Structure ``` src/ ├── Features/ │ ├── Users/ │ │ ├── UsersController.cs │ │ ├── User.cs # Entity │ │ ├── UserDto.cs │ │ ├── UserRepository.cs │ │ ├── IUserRepository.cs │ │ ├── UserService.cs │ │ └── IUserService.cs │ ├── Products/ │ │ ├── ProductsController.cs │ │ ├── Product.cs │ │ ├── ProductDto.cs │ │ ├── ProductRepository.cs │ │ └── ProductService.cs │ └── Orders/ │ ├── OrdersController.cs │ ├── Order.cs │ ├── OrderDto.cs │ ├── OrderRepository.cs │ └── OrderService.cs ``` --- ## Best Practices ### 1. Single Responsibility Principle ```csharp // ❌ Bad: Class does too much public class User { public void SaveToDatabase() { } public void SendEmail() { } public void GenerateReport() { } } // ✅ Good: Separate concerns public class User { // Just data and behavior public int Id { get; set; } public string Email { get; set; } public string Name { get; set; } } public class UserRepository { public async Task SaveAsync(User user) { } } public class EmailService { public async Task SendToUserAsync(User user, string message) { } } public class ReportGenerator { public async Task GenerateUserReportAsync(User user) { } } ``` ### 2. Keep Files Small - Max 300-400 lines per file - Split large files into smaller classes - Group related functionality ### 3. Clear Naming ```csharp // ✅ Good naming conventions // Files: PascalCase.cs // Classes: PascalCase // Interfaces: IPascalCase // Methods: PascalCase // Variables/parameters: camelCase // Constants: PascalCase or UPPER_SNAKE_CASE // UserService.cs public class UserService { private const int MaxLoginAttempts = 3; public async Task AuthenticateUserAsync(string email, string password) { // Implementation } } ``` ### 4. Use Namespaces Properly ```csharp // Organize by feature or layer namespace MyProject.Core.Services { public class UserService { } } namespace MyProject.Core.Entities { public class User { } } namespace MyProject.Infrastructure.Repositories { public class UserRepository { } } namespace MyProject.Api.Controllers { public class UsersController { } } ``` --- **Related Skills**: - [Core Principles](01-core-principles.md) - [Scalability](07-scalability.md)