Skip to content

Latest commit

 

History

History
200 lines (139 loc) · 7.77 KB

File metadata and controls

200 lines (139 loc) · 7.77 KB

Lab 1: Running and Assessing the Sample Code

Overview

In this lab, you'll get familiar with the sample application, run tests, and analyze the "Spaghetti Code" pattern implementation in the 01_Spaghetti folder. This will help you understand the problems that cross-cutting concerns can create when mixed with business logic, setting the stage for learning better patterns in subsequent labs.

Learning Objectives

By the end of this lab, you will be able to:

  • Clone and set up the project
  • Build and run tests successfully
  • Identify cross-cutting concerns in code
  • Understand the problems with mixing concerns in a single service
  • Analyze code complexity and maintainability issues
  • Create endpoints following the pattern-based routing convention

Prerequisites

  • .NET 10.0 SDK or later (Download here)
  • Git
  • A code editor (Visual Studio, VS Code, Rider, etc.)
  • Basic understanding of C# and ASP.NET Core

Part 1: Getting the Code

Clone the Repository

git clone https://github.com/NimblePros/RefactorToPipelineArchitecture
cd RefactorToPipelineArchitecture

Verify Prerequisites

Check that you have the correct .NET SDK installed:

dotnet --version

You should see version 10.0 or later.

Part 2: Building and Running Tests

Running the tests will restore and build.

dotnet test

This runs all integration tests in the solution. You should see output indicating which tests passed or failed.

Understanding the Test Structure

The tests use [Theory] and [InlineData] to test all patterns with the same test logic:

[Theory]
[InlineData("Spaghetti")]  // Lab 1 (current)
[InlineData("Template")]    // Lab 2
[InlineData("Decorator")]   // Lab 3  
[InlineData("Pipeline")]    // Lab 4
[InlineData("PipelineAttributes")] // Lab 4
public async Task GetRoles_AsGuest_ReturnsForbidden(string pattern)
{
  var response = await Client.GetAsync($"/{pattern}/Roles");
  Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}

For Lab 1, focus on the tests that use the "Spaghetti" pattern. The other tests will mostly fail until those labs have been completed.

Part 3: Understanding the Project Structure

Folder Organization

The project demonstrates multiple patterns for managing cross-cutting concerns:

src/NimblePros.DAB.Web/
├── 01_Spaghetti/         ← Focus on this for Lab 1
│   ├── Services/
│   │   └── RoleManagerService.cs
│   ├── Endpoints/
│   │   ├── List.cs       (GET /Spaghetti/Roles)
│   │   └── AddRole.cs    (POST /Spaghetti/Roles)
│   └── Abstractions/
│       └── IRoleManagerService.cs
├── 02_Template/          ← For Lab 2
├── 03_Decorator/         ← For Lab 3
├── 04_Chain/             ← For Lab 4
├── Data/                 ← Database context
└── Model/                ← Domain models

Routing Convention

All endpoints follow the pattern /PatternName/Resource:

  • Spaghetti: /Spaghetti/Roles
  • Template: /Template/Roles
  • Decorator: /Decorator/Roles
  • Pipeline: /Pipeline/Roles
  • PipelineAttributes: /PipelineAttributes/Roles

This makes it easy to compare the behavior of different patterns for the same operation.

Key Files to Review

  1. 01_Spaghetti/Services/RoleManagerService.cs - The main service with all concerns mixed in
  2. 01_Spaghetti/Endpoints/List.cs - GET endpoint at /Spaghetti/Roles
  3. 01_Spaghetti/Endpoints/AddRole.cs - POST endpoint at /Spaghetti/Roles
  4. 01_Spaghetti/Abstractions/IRoleManagerService.cs - Service interface
  5. tests/NimblePros.DAB.IntegrationTests/Endpoints/ListRolesEndpointTests.cs - Parameterized integration tests

Part 4: Inspecting and Assessing the Spaghetti Code

You can do this later if you run out of time during the workshop.

What is "Spaghetti Code"?

The term "spaghetti code" refers to code where different concerns are tangled together, making it hard to understand, maintain, and test. In this example, the RoleManagerService class mixes:

  • Business Logic (data access)
  • Authorization (role checks)
  • Logging (diagnostic messages)
  • Caching (performance optimization)
  • Error Handling (try-catch blocks)
  • Validation (input checking)

Exercise 1: Analyze the ListAsync Method

Open src/NimblePros.DAB.Web/01_Spaghetti/Services/RoleManagerService.cs and examine the ListAsync() method (lines 24-55).

Questions to consider:

  1. How many different responsibilities does this method have?

    • Count the distinct concerns (hint: look for authorization checks, logging calls, caching logic, error handling, and data access)
  2. What is the core business logic?

    • Try to identify the single line that represents the actual business purpose of this method
  3. What percentage of the code is cross-cutting concerns vs. core logic?

    • Count lines dedicated to logging, caching, authorization, and error handling vs. the actual data retrieval

Exercise 2: Analyze the AddAsync Method

Now examine the AddAsync() method (lines 57-117).

Questions to consider:

  1. How many concerns are mixed in this method?

    • Identify authorization, logging, validation, error handling, caching, and business logic
  2. What makes this method difficult to test?

    • Think about what you'd need to mock or setup to test just the validation logic, or just the authorization

Key Takeaways

Problems with the Spaghetti Pattern:

  1. Violation of Single Responsibility Principle: The service does too many things
  2. High Coupling: Changes to one concern (e.g., caching) require editing the service
  3. Low Cohesion: Unrelated concerns (logging, authorization, caching) are mixed together
  4. Difficult to Test: Must mock multiple dependencies to test one aspect
  5. Code Duplication: Same patterns repeated in every method
  6. Hard to Maintain: Business logic is obscured by infrastructure code
  7. Inflexible: Can't easily add/remove concerns or change their order

What's Next?

In Lab 2, you'll learn about the Template Method Pattern - a common approach for separating concerns. You'll refactor the code to extract cross-cutting concerns into a base class, making the business logic clearer while still keeping concerns together in an inheritance hierarchy.

You'll create endpoints at /Template/Roles that behave identically to /Spaghetti/Roles but use a cleaner implementation.

Self-Assessment Questions

Before moving to Lab 2, make sure you can answer:

  1. What are cross-cutting concerns?
  2. What are at least 5 problems with the spaghetti code pattern?
  3. How many lines of code in ListAsync() are core business logic vs. cross-cutting concerns?
  4. Why is the spaghetti pattern difficult to test?
  5. What would happen if you needed to add a new cross-cutting concern (e.g., performance monitoring)?
  6. How does the routing convention help organize and compare different patterns?
  7. Why use parameterized tests with [Theory] instead of separate test classes?

Additional Resources

  • Ardalis.Result Pattern: Used for clean result handling - GitHub
  • FastEndpoints: Lightweight alternative to MVC controllers - Docs
  • Single Responsibility Principle: Martin Fowler
  • xUnit Theory and InlineData: xUnit Documentation

Next Steps

When you're ready, proceed to Lab 2 where you'll explore the Template Method Pattern as a first step toward better code organization.


Questions or Issues? Open an issue in the GitHub repository or ask your instructor for clarification.