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
6.0 KiB
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 ✅ FIXEDobject parameter
~~```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
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
Fix✅ FIXEDIExcelExportServiceinterface to use strongly-typed parameter- Consolidate duplicate ViewModels
- Fix
AddressNumbertype mismatch Add logging to✅ FIXED - AddedSearch.CriteriadeserializationTryGetCriteriamethod with logging support
Suggestions
- Document JDE date pattern rationale
- Establish guideline for records vs classes for DTOs
- Fix null guard in
SearchViewModelconstructor