Tax Hurdle — Technical Architecture & Code Analysis

Deep dive into design patterns, implementation details, and code quality assessment.


📑 Quick Navigation


📐 System Architecture

Component Diagram

┌─────────────────────────────────────────────────────┐
│       InvestingHurdleBootstrapper (Singleton)        │
│         • main() - entry point                       │
│         • getInstance() - singleton instance         │
│         • reporterTesting() - output generation      │
└─────────────┬───────────────────────────┬───────────┘
              │                           │
        ┌─────▼──────┐  ┌───▼────────┐  ┌─▼──────────┐
        │WorkbookLoader│  │EquityLoader│  │HurdleLogger│
        │  • loadBuys() │  │•calculateSTC│  │•getLogger()│
        │  • loadSells()│  │•returnQtr() │  │•setupLog() │
        └─────┬────────┘  └───┬────────┘  └────────────┘
              │                │
              └────────┬───────┘
                       │
              ┌────────▼────────┐
              │  Security DAO   │
              │  • getter/setter│
              │  • P&L compute  │
              └─────────────────┘
              
    ConcurrentHashMap<String, Queue<Security>>

🏛️ Design Patterns

1. Singleton Pattern — InvestingHurdleBootstrapper

Purpose: Single application instance throughout lifecycle

Benefits: ✅ Single state ✅ Global access ✅ Thread-safe
Drawbacks: ⚠️ Hard to test ⚠️ Global state ⚠️ Difficult to mock


2. Factory Pattern — Security Object Creation

Purpose: Encapsulate creation of trade records

Benefits: ✅ Centralized creation ✅ Validation in one place ✅ Easy changes


3. Queue Pattern — FIFO Trade Processing

Purpose: Process buy/sell transactions chronologically

Implementation:

ConcurrentHashMap<String, Queue<Security>> securityMap

Benefits: ✅ Order preserved ✅ Natural FIFO matching ✅ Thread-safe


4. Strategy Pattern — Tax Calculation

Purpose: Different strategies for STCG vs. intraday

Recommendation: Create explicit strategy interface for clarity


🔍 Code Quality Analysis

Strengths ✅

Aspect Evidence
Error Handling Custom InvalidSecurityException for validation
Logging Comprehensive Log4j2 setup with rotation
Thread Safety ConcurrentHashMap + ConcurrentLinkedQueue
Encapsulation Private members, public getters/setters
Organization Logical package structure
Constants Dedicated HurdleConstant class

Weaknesses ⚠️

Issue Severity Impact
Hardcoded Quarter Dates 🔴 HIGH Only works for one FY
Empty setAveragePrices() 🔴 HIGH Cost basis not calculated
No Unit Tests 🔴 HIGH No test coverage
Exception Swallowing 🟡 MEDIUM Errors lost in catch blocks
Static File Paths 🟡 MEDIUM No configuration flexibility
String Comparisons 🟡 MEDIUM Locale-dependent, fragile

🔐 Thread Safety Analysis

Current Implementation:

private ConcurrentHashMap<String, Queue<Security>> securityMap = 
    new ConcurrentHashMap<>();

Thread-Safe Operations:

  • computeIfAbsent() — atomic
  • ConcurrentLinkedQueue.offer() — thread-safe
  • Multiple threads can add to different queues

Potential Issues: ⚠️

  • Check-then-act patterns need synchronization
  • Complex multi-operation sequences may need coordination

📈 Performance Considerations

Time Complexity

Operation Complexity Notes
Load buys O(n) n = buy rows
Load sells O(n) n = sell rows
Calculate STCG O(m) m = equity rows
Find quarter O(1) Fixed 5 comparisons
Overall O(n + m) Linear

Space Complexity

  • securityMap: O(n) where n = transactions
  • Quarter buckets: O(5) — fixed
  • Overall: O(n) — linear

🧪 Testing Strategy

Unit Tests Needed

@Test
public void testReturnQuarter_Q1() {
    LocalDate q1Date = LocalDate.of(2021, 5, 15);
    assertEquals(1, equityLoader.returnQuarter(q1Date));
}

@Test(expected = InvalidSecurityException.class)
public void testLoadBuys_NullSecurityName() {
    loader.loadBuys();
}

@Test
public void testCalculateSTCG_Sum() {
    Map<Integer, Double> result = equityLoader.calculateSTCG();
    double totalSTCG = result.values().stream()
        .mapToDouble(Double::doubleValue).sum();
    assertTrue(totalSTCG > 0);
}

@Test
public void testSecurityCalculatesPLCorrectly() {
    Security security = new Security("TCS", new Date(), 100, 10, 110);
    assertEquals((110 - 100) * 10, security.calculatePL(), 0.01);
}

Integration Tests

@Test
public void testEndToEndTaxCalculation() {
    // Create test Excel files, run workflow
    InvestingHurdleBootstrapper app = InvestingHurdleBootstrapper.getInstance();
    app.loadAndCalculate();
    
    // Verify STCG matches expected
    assertEquals(expectedTotal, app.getTotalSTCG(), 0.01);
}
  • ✅ 80%+ code coverage target
  • ✅ All edge cases (boundary dates, zero values, negative P&L)
  • ✅ Exception paths
  • ✅ Thread safety scenarios

🎯 Recommendations Summary

Priority 1: Critical

  1. Add Unit Tests — Target 80%+ coverage
  2. Fix Hardcoded Quarter Dates — Support multi-year, use LocalDate
  3. Implement setAveragePrices() — Critical for cost basis

Priority 2: Important

  1. Improve Exception Handling — Specific exceptions, proper logging
  2. Parameterize File Paths — Command-line args or config file
  3. Add Input Validation — Type checks, range validation

Priority 3: Enhancements

  1. Export Functionality — CSV, JSON, PDF formats
  2. Migrate to Java 8+ — Stream API, java.time package
  3. Database Integration — Persistence and queries
  4. Web UI — Spring Boot API + React/Vue frontend

Document Version: 1.0
Last Updated: December 31, 2025

Back to Hub Next: Refactoring Guide →