Files
Joseph Doherty 604bfe919c refactor: address code review findings across all projects
Apply comprehensive fixes from code reviews including:
- Extract shared utilities (SqlFormatHelper, CellValueConverter, DbDestinationBase)
- Add interface abstractions (IAuthenticationService, IDatabaseMigrator, IMisQueryBuilder)
- Implement SecureStore for encrypted secrets storage
- Fix error handling with proper HTTP status codes and logging
- Optimize double enumeration in DevEtlRegistry
- Add DataSync.Dev README for developer onboarding
- Extract filter panel base classes to reduce duplication
- Update code review docs to mark all issues as fixed
2026-01-19 11:05:36 -05:00

202 lines
6.0 KiB
Markdown

# Code Review: JdeScoping.Core
**Project Path:** `NEW/src/JdeScoping.Core`
**Layer:** Domain
**Purpose:** Core models, DTOs, interfaces
---
## Executive Summary
The JdeScoping.Core project is the domain layer containing core models, DTOs, interfaces, and shared contracts. The codebase demonstrates **good architectural practices** with clear separation of concerns, proper use of nullable reference types, and consistent documentation.
**Overall Grade: B+**
| Category | Rating | Notes |
|----------|--------|-------|
| SOLID Principles | Good | Minor ISP violation |
| Clean Architecture | Excellent | No inappropriate dependencies |
| Code Organization | Excellent | Well-organized structure |
| Error Handling | Good | `TryGetCriteria` method with logging support |
| Testability | Excellent | Interface-based design |
| Code Duplication | Fair | Repeated JDE date conversion pattern |
| Async Patterns | Good | Consistent naming, CancellationToken support |
| Null Safety | Good | Nullable enabled with proper annotations |
| Documentation | Excellent | Comprehensive XML documentation |
---
## 1. SOLID Principles
### Single Responsibility Principle (SRP)
**Positive:** Most classes adhere well to SRP - each model represents a single domain concept.
### Interface Segregation Principle (ISP)
~~**Issue: IExcelExportService uses `object` parameter**~~ ✅ FIXED
~~```csharp
public interface IExcelExportService
{
Task<byte[]> GenerateAsync(object search, CancellationToken cancellationToken = default);
}
```~~
~~**Recommendation:** Change to use strongly-typed `SearchModel` parameter.~~
**Resolution:** Changed `IExcelExportService.GenerateAsync` to accept `Core.Models.SearchResults.SearchModel` instead of `object`. The `ExcelExportService` implementation maps to its internal `ExcelIO.Models.Reporting.SearchModel` for Excel generation.
### Dependency Inversion Principle (DIP)
**Positive:** Service interfaces properly defined in Core layer with clean abstractions.
---
## 2. Clean Architecture
### Layer Separation
**Excellent:** Core project maintains proper architectural boundaries:
- No references to infrastructure concerns
- Only depends on abstraction packages
- Defines contracts that outer layers implement
### ApiContracts Placement
The `ApiContracts` folder containing API client interfaces is appropriately placed in Core.
---
## 3. Code Organization
### Folder Structure
**Excellent:**
```
JdeScoping.Core/
├── ApiContracts/Results/
├── Helpers/
├── Interfaces/
├── Models/
│ ├── Auth/, Enums/, Infrastructure/
│ ├── Inventory/, Lookup/, Organization/
│ ├── Pipelines/, Quality/, Search/
│ ├── SearchResults/, WorkOrders/
├── Options/
└── ViewModels/
```
### Partial Classes for Repository
Using partial classes to split `ILotFinderRepository` by functional area is a good organizational choice.
### Issues
**Issue: Inconsistent Record/Class Usage**
The codebase mixes classes and records inconsistently for DTOs.
**Recommendation:** Establish consistent pattern - use records for immutable DTOs.
---
## 4. Error Handling
~~**Issue: Silent Deserialization Failure**~~ ✅ FIXED
**Resolution:** Added `TryGetCriteria(out SearchCriteria? criteria, ILogger? logger = null)` method that:
- Returns `true` if deserialization succeeded or JSON was empty
- Returns `false` if deserialization failed
- Logs at Warning level when logger is provided
- Property getter uses the method without logging for backwards compatibility
- Services that need logging can call `TryGetCriteria` directly with their logger
---
## 5. Testability
**Excellent:** Interface-based design with all services defined as interfaces, enabling easy mocking.
---
## 6. Code Duplication
### DRY Violation in Domain Models
Multiple domain models contain identical patterns for JDE date/time conversion:
```csharp
private int LastUpdateDate { get; set; }
private int LastUpdateTime { get; set; }
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
```
Pattern repeated in 13+ files.
**Recommendation:** Document why this pattern is intentionally repeated (e.g., for Dapper mapping compatibility).
### Duplicate ViewModel Classes
`LotViewModel` and `ComponentLotViewModel` have identical properties.
**Recommendation:** Consolidate or have `ComponentLotViewModel` inherit from `LotViewModel`.
---
## 7. Async Patterns
**Good:** Consistent `Async` suffix naming, all async interface methods include `CancellationToken` parameters with defaults.
---
## 8. Null Safety
**Good:** Nullable reference types enabled with proper annotations.
**Issue: Inconsistent Null Guard in Constructor**
```csharp
public SearchViewModel(Search search)
{
if (search == null) return; // Silent return on null
}
```
**Recommendation:** Throw `ArgumentNullException` or use factory method pattern.
---
## 9. Documentation
**Excellent:** Nearly all public members have XML documentation with `<summary>`, `<param>`, and `<returns>` tags.
---
## 10. Additional Observations
### Well-Designed API Result Pattern
The `ApiResult<T>` discriminated union using OneOf provides compile-time safety for error handling.
### Data Type Mismatch
`AddressNumber` is `long` in `JdeUser` but `int` in `OperatorViewModel` - potential data loss.
**Recommendation:** Change `OperatorViewModel.AddressNumber` to `long`.
---
## Recommendations Summary
### Important
1. ~~Fix `IExcelExportService` interface to use strongly-typed parameter~~ ✅ FIXED
2. Consolidate duplicate ViewModels
3. Fix `AddressNumber` type mismatch
4. ~~Add logging to `Search.Criteria` deserialization~~ ✅ FIXED - Added `TryGetCriteria` method with logging support
### Suggestions
1. Document JDE date pattern rationale
2. Establish guideline for records vs classes for DTOs
3. Fix null guard in `SearchViewModel` constructor