refactor: clean project based sesstion04 notes

This commit is contained in:
2025-07-18 11:33:54 +03:30
parent a611565777
commit ab1ec88779
2 changed files with 59 additions and 118 deletions
@@ -1,34 +1,24 @@
### 1. **Should I have an `IEntityService` and then `EntityService` for each of my entities?** ## *Should I have an `IEntityService` and then `EntityService` for each of my entities?**
Not necessarily **for _every_** entity — only if it **makes sense**. Not necessarily **for _every_** entity — only if it **makes sense**.
- The Application Layer should expose **use cases** — not just CRUD logic for each entity. - The Application Layer should expose **use cases** — not just CRUD logic for each entity.
- If an entity has business logic or interactions that need orchestration (e.g., validations, aggregations, calling repositories, etc.), then **yes**, create a service. - If an entity has business logic or interactions that need orchestration (e.g., validations, aggregations, calling repositories, etc.), then **yes**, create a service.
- Otherwise, for basic operations, **directly using a repository (via a unit of work or interface)** from the use case handler might be fine. - Otherwise, for basic operations, **directly using a repository (via a unit of work or interface)** from the use case handler might be fine.
### 2. **Is it OK to have services not related to a specific entity?** ## **Is it OK to have services not related to a specific entity?**
Absolutely, **yes**. In fact, thats expected in a Clean Architecture setup. Absolutely, **yes**. In fact, thats expected in a Clean Architecture setup.
Examples: Examples:
- A `ReportGenerationService` that combines bookings, customers, and payments. - A `ReportGenerationService` that combines bookings, customers, and payments.
- A `TokenService` for authentication tokens. - A `TokenService` for authentication tokens.
- A `CurrencyConversionService` that hits an external API. - A `CurrencyConversionService` that hits an external API.
- A `NotificationService` that sends emails or SMS. - A `NotificationService` that sends emails or SMS.
👉 As long as these services **live in the Application Layer** and follow **dependency inversion** (i.e., they depend only on interfaces, not implementations), youre doing great. 👉 As long as these services **live in the Application Layer** and follow **dependency inversion** (i.e., they depend only on interfaces, not implementations), youre doing great.
### 3. **Is it necessary to have an interface for each service?** ## **Is it necessary to have an interface for each service?**
## **Whats the Difference Between Services and Repositories?**
### 🔹 **Whats the Difference Between Services and Repositories?**
| Aspect | **Service** | **Repository** | | Aspect | **Service** | **Repository** |
| ------------------ | ---------------------------------------------------------------------- | --------------------------------------------------------------- | | ------------------ | ---------------------------------------------------------------------- | --------------------------------------------------------------- |
@@ -37,7 +27,7 @@ Examples:
| **Focus** | Coordinates multiple domain/repo operations, validation, business flow | Fetching/storing data for a specific entity | | **Focus** | Coordinates multiple domain/repo operations, validation, business flow | Fetching/storing data for a specific entity |
| **Example** | `PlaceOrderService`, `ReportService` | `ICustomerRepository`, `IOrderRepository` | | **Example** | `PlaceOrderService`, `ReportService` | `ICustomerRepository`, `IOrderRepository` |
### What does `init` mean? ## What does `init` mean?
`init` is an **access modifier for properties** that allows you to **set a property only during object initialization**, **but not after**. `init` is an **access modifier for properties** that allows you to **set a property only during object initialization**, **but not after**.
@@ -62,21 +52,15 @@ Examples:
### But when should you prefer `class`? ### But when should you prefer `class`?
Use `class` if your DTO or model: Use `class` if your DTO or model:
- Needs to be **mutable** after creation - Needs to be **mutable** after creation
- Has to **interact with legacy APIs/libraries** - Has to **interact with legacy APIs/libraries**
- Needs **inheritance or polymorphism** (not well supported in `record`) - Needs **inheritance or polymorphism** (not well supported in `record`)
- Has **rich behavior** (logic, methods, validation, etc.) - Has **rich behavior** (logic, methods, validation, etc.)
> For example, in the Domain Layer (Entities, ValueObjects), you'll usually stick to **`class`** — because that's where behavior lives. > For example, in the Domain Layer (Entities, ValueObjects), you'll usually stick to **`class`** — because that's where behavior lives.
## RESTful APIs: ## RESTful APIs:
https://aws.amazon.com/what-is/restful-api/#:~:text=RESTful%20API%20is%20an%20interface,applications%20to%20perform%20various%20tasks. [read more](https://aws.amazon.com/what-is/restful-api/#:~:text=RESTful%20API%20is%20an%20interface,applications%20to%20perform%20various%20tasks.)
## What Conditions Make an API RESTful? ## What Conditions Make an API RESTful?
### Key Principles of REST: ### Key Principles of REST:
@@ -140,23 +124,16 @@ public class CustomerController : ControllerBase {
## List-like stuff in `C#` ## List-like stuff in `C#`
Absolutely, lets go over the main “list-like” data types in C#. They all serve similar purposes—holding multiple items—but differ in functionality, performance, and use cases. Heres a detailed breakdown: They all serve similar purposes—holding multiple items—but differ in functionality, performance, and use cases. Heres a detailed breakdown:
🔷 1. `IEnumerable` 🔷 1. `IEnumerable`
- Namespace: System.Collections.Generic - Namespace: System.Collections.Generic
- Most basic "list-like" abstraction. - Most basic "list-like" abstraction.
- Read-only (forward-only iteration). - Read-only (forward-only iteration).
- You can use foreach on it. - You can use foreach on it.
- Doesnt support indexing (no .Count, no [i]). - Doesnt support indexing (no .Count, no [i]).
- Often used as the return type to expose a stream of data without giving full collection control. - Often used as the return type to expose a stream of data without giving full collection control.
Example: Example:
```csharp ```csharp
@@ -166,43 +143,29 @@ foreach (var num in numbers)
``` ```
💡 Ideal when: 💡 Ideal when:
- You want to return a sequence without exposing modification. - You want to return a sequence without exposing modification.
- Youre using LINQ chains. - Youre using LINQ chains.
- Youre returning data from a database query. - Youre returning data from a database query.
--- ---
🔷 2. ICollection 🔷 2. ICollection
- Extends IEnumerable. - Extends IEnumerable.
- Adds Count and Add/Remove/Clear methods. - Adds Count and Add/Remove/Clear methods.
- Still abstract—List and HashSet implement it. - Still abstract—List and HashSet implement it.
💡 Useful when: 💡 Useful when:
- You want to expose a collection that can be modified (e.g. Add or Remove). - You want to expose a collection that can be modified (e.g. Add or Remove).
- You care about the Count. - You care about the Count.
--- ---
🔷 3. IList 🔷 3. `IList`
- Extends `ICollection` and `IEnumerable`.
- Extends ICollection and IEnumerable. - Adds index access: `list[0]` etc.
- Adds index access: list[0] etc.
- Think of it like a mutable array with dynamic size. - Think of it like a mutable array with dynamic size.
💡 Use when: 💡 Use when:
- You want ordered collection with indexing. - You want ordered collection with indexing.
@@ -215,15 +178,10 @@ foreach (var num in numbers)
🔷 4. List 🔷 4. List
- A concrete class (not interface). - A concrete class (not interface).
- Implements `IList`, `ICollection`, `IEnumerable`.
- Implements IList, ICollection, IEnumerable.
- Backed by an array (auto-resizes). - Backed by an array (auto-resizes).
- Fast read and write. - Fast read and write.
- Supports `Add`, `Remove`, `Insert`, `IndexOf`, etc.
- Supports Add, Remove, Insert, IndexOf, etc.
Example: Example:
@@ -238,32 +196,23 @@ var second = list[1]; // "Two"
--- ---
🔷 5. IReadOnlyCollection & IReadOnlyList 🔷 5. `IReadOnlyCollection` & `IReadOnlyList`
- IReadOnlyCollection: Just Count and IEnumerable.
- IReadOnlyList: Adds indexing without modification.
- `IReadOnlyCollection`: Just Count and `IEnumerable`.
- `IReadOnlyList`: Adds indexing without modification.
- Used to expose lists safely (read-only). - Used to expose lists safely (read-only).
💡 Used when: 💡 Used when:
- You want to return a list, but prevent any changes. - You want to return a list, but prevent any changes.
--- ---
🔷 6. Array (T[]) 🔷 6. `Array(T[])`
- Fixed-size. - Fixed-size.
- Fastest for indexing. - Fastest for indexing.
- Cannot change size. - Cannot change size.
- Implements `IList` (via Array).
- Implements IList (via Array).
Example: Example:
@@ -276,28 +225,21 @@ numbers[0] = 42;
--- ---
🔷 7. ObservableCollection 🔷 7. `ObservableCollection`
- For WPF/Blazor/WinForms data-binding.
- For WPF/`Blazor`/WinForms data-binding.
- Notifies UI when items are added/removed. - Notifies UI when items are added/removed.
- Implements IList. - Implements IList.
💡 Use in UI apps when the view needs to react to collection changes. 💡 Use in UI apps when the view needs to react to collection changes.
--- ---
🔷 8. HashSet 🔷 8. HashSet
- Unordered, no duplicates. - Unordered, no duplicates.
- Implements `ICollection`, not `IList`.
- Implements ICollection, not IList.
- No index access. - No index access.
💡 Best for fast membership checking (contains x). 💡 Best for fast membership checking (contains x).
--- ---
@@ -315,6 +257,3 @@ numbers[0] = 42;
|ObservableCollection|✔️|✔️|✔️|✔️|UI binding for collections| |ObservableCollection|✔️|✔️|✔️|✔️|UI binding for collections|
|HashSet|❌|✔️|❌|❌|Fast lookup, uniqueness enforcement| |HashSet|❌|✔️|❌|❌|Fast lookup, uniqueness enforcement|
If you tell me the scenario (e.g. search results, modifying a cart, populating a drop-down), I can recommend the best type for it. Want that?
@@ -1,19 +1,20 @@
# Preparation:
# 🛠️ Task Checklist
## Preparation:
The unedited conversation with Chat GPT, concerning almost all of the aspects of this session: The unedited conversation with Chat GPT, concerning almost all of the aspects of this session:
(optional): read this to get a better understanding of the topic: (optional): read this to get a better understanding of the topic:
https://chatgpt.com/share/67f18460-1c1c-8010-bc57-9f3b683ec87a https://chatgpt.com/share/67f18460-1c1c-8010-bc57-9f3b683ec87a
# Branching ## 🚧Branching
- [ ]  Create the feature/transportation-search branch based on develop - [ ]  Create the feature/transportation-search branch based on develop
# DTO ## DTO
In order to develop transportation search flow, three DTOs need to be created in the application layer. In order to develop transportation search flow, three DTOs need to be created in the application layer.
- [ ]  Create DTOs related to transportation search flow - [ ]  Create DTOs related to transportation search flow
📂 Suggested Folder: Application/DTOs/City` 📂 Suggested Folder: Application/DTOs/City`
```cs ```cs
public class CityDto public class CityDto
{ {
@@ -23,34 +24,35 @@ public class CityDto
``` ```
📂 Suggested Folder: Application/DTOs/Transportation 📂 Suggested Folder: Application/DTOs/Transportation
```cs ```cs
public class TransportationSearchRequestDto public class TransportationSearchRequestDto
{ {
public short? VehicleTypeId { get; init; } public short? VehicleTypeId { get; init; }
public int? FromCityId { get; init; } public int? FromCityId { get; init; }
public int? ToCityId { get; init; } public int? ToCityId { get; init; }
public DateTime? StartDate { get; init; } public DateTime? StartDate { get; init; }
public DateTime? EndDate { get; init; } public DateTime? EndDate { get; init; }
}
``` ```
```cs ```cs
public class TransportationSearchResultDto public class TransportationSearchResultDto
{ {
public long Id { get; init; } public long Id { get; init; }
public required string CompanyTitle { get; init; } public int VehicleTypeId { get; init; }
public required string FromLocationTitle { get; init; } public string? VehicleTitle { get; init; }
public required string ToLocationTitle { get; init; } public required string CompanyTitle { get; init; }
public required string FromCityTitle { get; init; } public required string FromLocationTitle { get; init; }
public required string ToCityTitle { get; init; } public required string ToLocationTitle { get; init; }
public DateTime StartDateTime { get; init; } public required string FromCityTitle { get; init; }
public DateTime? EndDateTime { get; init; } public required string ToCityTitle { get; init; }
public decimal Price { get; init; } public DateTime StartDateTime { get; init; }
} public DateTime? EndDateTime { get; init; }
public decimal Price { get; init; }
public int RemainingCapacity { get; init; }
``` ```
# Repository ## Repository
There are a few things to be add to some repositories for transportation search flow. There are a few things to be add to some repositories for transportation search flow.
- [ ] Create DTOs related to transportation search flow - [ ] Create DTOs related to transportation search flow
@@ -108,7 +110,7 @@ public class TransportationRepository :
``` ```
# Auto Mapper ## Auto Mapper
Auto Mapper simplifies mapping between aggregates and DTOs in both directions. Auto Mapper simplifies mapping between aggregates and DTOs in both directions.
- [ ] Create a `MappingProfile` that inherits `Profile`, and use it to add configurations for mappings - [ ] Create a `MappingProfile` that inherits `Profile`, and use it to add configurations for mappings
@@ -157,7 +159,7 @@ public class MappingProfile : Profile
. .
``` ```
# Result & Result Status ## Result & Result Status
- [ ] Create `ResultStatus` enum and `Result` class - [ ] Create `ResultStatus` enum and `Result` class
📂 Suggested Folder: Application/Result 📂 Suggested Folder: Application/Result
@@ -220,22 +222,18 @@ public enum ResultStatus
You can read more about enums: [W3Schools](https://www.w3schools.com/cs/cs_enums.php) You can read more about enums: [W3Schools](https://www.w3schools.com/cs/cs_enums.php)
# `IService` & Service ## `IService` & Service
Now, use `I[Entity]Repositry` and `IUnitOfWork` in services to implement business logic Now, use `I[Entity]Repositry` and `IUnitOfWork` in services to implement business logic
- [ ] Create `I[Entity]Service` and `[Entity]Service` which implements it - [ ] Create `I[Entity]Service` and `[Entity]Service` which implements it
📂 Suggested Folder for `I[Entity]Service`: Application/Interfaces 📂 Suggested Folder for `I[Entity]Service`: Application/Interfaces
📂 Suggested Folder for Services: Application/Services 📂 Suggested Folder for Services: Application/Services
- existence of an interface for each service class is optional - existence of an interface for each service class is optional
- services can have multiple repositories in them -> logic-based structure - services can have multiple repositories in them -> logic-based structure
An example of `I[Entity]Service`: An example of `I[Entity]Service`:
```c# ```c#
public interface ITransportationService public interface ITransportationService
{ {
@@ -244,7 +242,6 @@ public interface ITransportationService
``` ```
An example of `[Entity]Service`: An example of `[Entity]Service`:
```cs ```cs
public class TransportationService : ITransportationService public class TransportationService : ITransportationService
{ {
@@ -291,7 +288,7 @@ builder.Services.AddScoped<ICityService, CityService>();
. .
``` ```
# Controller ## Controller
Now we're getting to endpoints, you should communicate with client side through web-api. So every controller uses Services in Application layer to receive requests and send responses with DTOs. Now we're getting to endpoints, you should communicate with client side through web-api. So every controller uses Services in Application layer to receive requests and send responses with DTOs.
- [ ] Create an APIController (right click on the folder, and then under Add, select Controller, and then make sure to select the APIController type) - [ ] Create an APIController (right click on the folder, and then under Add, select Controller, and then make sure to select the APIController type)
@@ -336,17 +333,16 @@ public class TransportationController : ControllerBase
} }
``` ```
- HttpGet: handles a GET request from client -> important for routing - `HttpGet`: handles a GET request from client -> important for routing
- Ok, BadRequest, NotFound and StatusCode are Json results to send through api - Ok, `BadRequest`, `NotFound` and `StatusCode` are json results to send through API
- Use TransportationService to communicate with Application - Use `TransportationService` to communicate with Application
# Inserting Sample Data ## Inserting Sample Data
For testing purposes, add some data into the related tables. For testing purposes, add some data into the related tables.
You are provided with a SQL script, that adds some sample data into the following tables You are provided with a SQL script, that adds some sample data into the following tables
**Important Notes:** Note that different database names, and different table names will produce errors while executing the script. Consider adjusting these names before executing the script **Important Notes:** Note that different database names, and different table names will produce errors while executing the script. Consider adjusting these names before executing the script
- Cities - Cities
- Companies - Companies
- LocationTypes - LocationTypes
@@ -356,8 +352,14 @@ You are provided with a SQL script, that adds some sample data into the followin
- Transportation - Transportation
- [ ] Open `TransportationRelatedSampleData.sql` with SSMS, and execute the query - [ ] Open `TransportationRelatedSampleData.sql` with SSMS, and execute the query
> Note: there has been changes in database structure since this note and this file has been written.
# Merge ## 🚧Merge
- [ ] Create a PR and merge the current branch with develop - [ ] Create a PR and merge the current branch with develop
# 🧠 Hints & Notes
# 🙌 Acknowledgements
- ChatGPT for snippet refinement and explanations
# 🔍 References