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

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 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

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