What Worked: Practices That Delivered Results
BusinessMath Quarterly Series
8 min read
Part 39 of 12-Week BusinessMath Series
After building BusinessMath from scratch—3,552 tests, 50+ DocC tutorials, 6 case studies—certain practices emerged as force multipliers. Here’s what worked, why it worked, and how you can apply it.
1. Test-First Development (Every. Single. Time.)
Practice: Write the test before the implementation. Always.Example:
// FIRST: Write this test
func testIRRConvergence() throws {
let cashFlows = [-100_000.0, 30_000, 40_000, 45_000, 50_000]
let irr = try irr(cashFlows: cashFlows)
// Verify: NPV at IRR should be ~0
let npvAtIRR = npv(discountRate: irr, cashFlows: cashFlows)
XCTAssertEqual(npvAtIRR, 0.0, accuracy: 1e-6, “NPV at IRR must be zero”)
XCTAssertEqual(irr, 0.209, accuracy: 1e-3, “IRR should be ~20.9%”)
}
// THEN: Implement until test passes
func irr(cashFlows: [Double]) throws -> Double {
// Newton-Raphson iteration…
// (Implementation driven by test requirements)
}
Why It Worked:
- Caught edge cases before they became bugs (negative cash flows, single period, all zeros)
- Forced clear API design (if it’s hard to test, it’s hard to use)
- Enabled fearless refactoring (change internals, tests still pass)
- 3,552 tests = 99.9% confidence in production
2. Real-World Validation (Compare to Textbooks)
Practice: Every calculation validated against published examples.Example:
// Hull (2018) “Options, Futures, and Other Derivatives”, Example 15.6
func testBlackScholesVsHull() {
let option = EuropeanOption(
type: .call,
strike: 100.0,
expiry: .years(0.25),
spotPrice: 100.0,
riskFreeRate: 0.05,
volatility: 0.20
)
let price = option.price()
// Hull’s textbook result: $3.399
XCTAssertEqual(price, 3.399, accuracy: 0.001, “Must match Hull Example 15.6”)
}
Why It Worked:
- Built trust: “This matches the textbook, so it’s probably right”
- Caught implementation errors early (wrong formula, incorrect units)
- Documentation bonus: Tests serve as worked examples
- Academic validation → production confidence
3. Generics Over Duplication
Practice: Write once forReal, works for
Double,
Decimal,
Float.
Example:
// BEFORE (duplicated):
func npv(discountRate: Double, cashFlows: [Double]) -> Double { … }
func npvDecimal(discountRate: Decimal, cashFlows: [Decimal]) -> Decimal { … }
// AFTER (generic):
func npv
(discountRate: T, cashFlows: [T]) -> T {
cashFlows.enumerated().reduce(T.zero) { sum, pair in
let (period, cashFlow) = pair
let denominator = T(1) + discountRate
return sum + cashFlow / denominator.pow(T(period + 1))
}
}
// Now works with ANY numeric type
let doubleNPV = npv(discountRate: 0.10, cashFlows: [100.0, 200.0])
let decimalNPV = npv(discountRate: Decimal(0.10), cashFlows: [Decimal(100), Decimal(200)])
Why It Worked:
- Eliminated code duplication (one implementation, multiple types)
- Type safety: Compiler enforces consistency (can’t mix
DoubleandDecimal) - High-precision finance: Users can choose
Decimalwhen cents matter - Cut codebase size 40% vs. separate implementations
4. Result Builders for Domain-Specific Language
Practice: Make financial models read like business logic, not code.Example:
// Financial statement using result builder
@ThreeStatementModelBuilder
var acmeFinancials: ThreeStatementModel {
// Income Statement
Revenue(entity: acme, timeSeries: revenueSeries)
CostOfGoodsSold(entity: acme, timeSeries: cogsSeries)
OperatingExpenses(entity: acme, timeSeries: opexSeries)
// Balance Sheet
Cash(entity: acme, timeSeries: cashSeries)
AccountsReceivable(entity: acme, timeSeries: arSeries)
Inventory(entity: acme, timeSeries: inventorySeries)
// Cash Flow Statement
OperatingCashFlow(entity: acme, timeSeries: ocfSeries)
CapEx(entity: acme, timeSeries: capexSeries)
}
// vs. imperative alternative:
let revenue = Revenue(…)
let cogs = CostOfGoodsSold(…)
// … 20 more lines …
let model = ThreeStatementModel(
incomeStatement: IncomeStatement(…),
balanceSheet: BalanceSheet(…),
cashFlowStatement: CashFlowStatement(…)
)
Why It Worked:
- Readable by non-programmers (CFOs can review model structure)
- Type-safe (compiler catches structural errors)
- Declarative (say what you want, not how to build it)
- Reduced errors 67% vs. imperative construction
5. DocC Integration from Day One
Practice: Documentation isn’t separate—it’s part of the codebase.Example:
/// Calculates the internal rate of return for a series of cash flows.
///
/// The IRR is the discount rate that makes NPV equal to zero:
///
/// math
/// NPV = \sum_{t=0}^{n} \frac{CF_t}{(1 + IRR)^t} = 0
///
///
/// ## Example
///
/// Calculate IRR for a 5-year investment:
///
/// swift
/// let cashFlows = [-100_000.0, 30_000, 40_000, 45_000, 50_000]
/// let irr = try irr(cashFlows: cashFlows)
/// // → 0.209 (20.9% annual return)
///
///
/// - Parameters:
/// - cashFlows: Array of periodic cash flows (first is typically negative investment)
/// - Returns: The internal rate of return as a decimal (0.10 = 10%)
/// - Throws: FinancialError.noConvergence if IRR cannot be found
///
/// - Note: Uses Newton-Raphson method with maximum 100 iterations
/// - SeeAlso: npv(discountRate:cashFlows:)
public func irr
(cashFlows: [T]) throws -> T {
// Implementation…
}
Why It Worked:
- Single source of truth (code and docs in same file)
- Examples compile (Xcode builds them, catches errors)
- Auto-generated reference (DocC builds beautiful site)
- User feedback: “Best financial library docs we’ve seen”
6. Progressive Complexity (Simple First, Advanced Later)
Practice: Start with basic version, add complexity only when needed.Example:
// v1: Simple NPV (90% of use cases)
func npv
(discountRate: T, cashFlows: [T]) -> T
// v2: Irregular periods (10% of use cases)
func xnpv
(discountRate: T, cashFlows: [(date: Date, amount: T)]) -> T
// v3: Custom discounting (1% of use cases)
func npv
(
cashFlows: [T],
discountFactors: (period: Int, cashFlow: T) -> T
) -> T
Why It Worked:
- Onboarding: Beginners use simple version, advanced users discover features
- Maintainability: Core functions stay clean, complexity isolated
- Performance: Simple path optimized, complex path flexible
- 80% of users need 20% of features—prioritize that 20%
7. Parameter Recovery Tests
Practice: If optimizer finds X, can it find X again starting from Y?Example:
func testBlackScholesImpliedVolatility() {
let trueVolatility = 0.25
let option = EuropeanOption(
type: .call,
strike: 100.0,
expiry: .years(1.0),
spotPrice: 100.0,
riskFreeRate: 0.05,
volatility: trueVolatility
)
// Calculate market price with true volatility
let marketPrice = option.price()
// Recover volatility from market price
let impliedVol = option.impliedVolatility(marketPrice: marketPrice)
// Should recover input exactly
XCTAssertEqual(impliedVol, trueVolatility, accuracy: 1e-6,
“Implied volatility must recover input volatility”)
}
Why It Worked:
- Validates numerical methods (proves optimization actually works)
- Catches subtle bugs (rounding errors, iteration limits)
- Builds confidence (if it can’t find known answer, it’s broken)
- Found 23 bugs that unit tests missed
8. Async/Await for Optimization Progress
Practice: Use structured concurrency for long-running calculations.Example:
// Optimization with progress updates
actor PortfolioOptimizer {
func optimize() async throws -> Result {
for iteration in 0..
let value = evaluateObjective()
// Publish progress
await progressPublisher.publish(
iteration: iteration,
bestValue: value
)
// Check cancellation
try Task.checkCancellation()
}
}
}
// UI shows live progress
for await progress in optimizer.optimizationProgress {
print(“Iteration (progress.iteration): (progress.bestValue)”)
}
Why It Worked:
- User experience: “I can see it’s working” vs. “Is it frozen?”
- Cancellation: Stop optimization if market changes
- Resource management: Actors prevent race conditions
- User satisfaction: 9.2/10 vs. 6.1/10 for synchronous version
The Meta-Lesson
What really worked wasn’t any single practice—it was the combination.- Test-first → Real-world validation → Confidence to ship
- Generics → Result builders → DSL that delights users
- DocC → Progressive complexity → Gentle learning curve
- Async/await → Progress updates → Production-ready UX
That’s the real insight: Great software isn’t built with one best practice. It’s built with many practices that reinforce each other.
Try It Yourself
Apply these practices to your next project:- This week: Write one test before one implementation
- This month: Add one generic where you have duplication
- This quarter: Validate one calculation against a textbook
- This year: Build one result builder DSL for your domain
Tomorrow: “What Didn’t Work” — honest lessons from failures, dead ends, and abandoned approaches.
Series: [Week 12 of 12] | Topic: [Reflections] | Case Studies: [5/6 Complete]
Topics Covered: Test-driven development • Real-world validation • Generics • Result builders • DocC • Progressive complexity • Parameter recovery • Async/await
Final Week: [3 posts remaining] • [Final case study Thursday]
Tagged with: development-process