Modern & Enterprise
Patterns from everyday business applications: values, repositories, retries and events.
Business software has its own recurring problems: money and dates passed around as raw numbers and strings, SQL mixed into business rules, half-saved records after a failure, and services that keep calling a dependency that is clearly down.
The patterns here give those ideas a proper home: small immutable value types, repositories that speak in domain terms, a unit of work that saves everything or nothing, and policies for retries and circuit breaking.
You'll recognise it when
- Amounts are doubles, and rounding bugs appear in invoices.
- The same validation of an email or phone number is copied around.
- Services build query objects or SQL strings themselves.
- Optional collaborators are guarded by null checks everywhere.
Example
A travel app adds up trip distances. Some partners send kilometres, others miles.
double total = 0;
for (Leg leg : trip.legs()) {
total += leg.distance(); // km? miles? nobody knows
}
if (total > 500) offerRestStop();record Distance(long metres) {
static Distance km(double km) { return new Distance(Math.round(km * 1000)); }
static Distance miles(double miles) { return new Distance(Math.round(miles * 1609.344)); }
Distance plus(Distance other) { return new Distance(metres + other.metres); }
boolean isLongerThan(Distance d) { return metres > d.metres; }
}
Distance total = trip.legs().stream().map(Leg::distance).reduce(new Distance(0), Distance::plus);
if (total.isLongerThan(Distance.km(500))) offerRestStop();Why it's better: The unit is decided once, when a distance is created. Adding kilometres to miles by accident becomes impossible, and the comparison reads like the rule it implements.
Ideas you'll practise
Problems 16
- MD-09Money as a DoubleL1EasyFREE
- MD-02Service Locator EverywhereL2MediumComing soon
- MD-03SQL Inside the Checkout LogicL1MediumComing soon
- MD-04Repository Returning Query BuildersL2MediumComing soon
- MD-05Half-Saved OrdersL1HardComing soon
- MD-06Null Checks on Every LineL1EasyComing soon
- MD-07Guest User Special CasesL1MediumComing soon
- MD-08A New Finder for Every Filter CombinationL1MediumComing soon
- MD-10Emails and Phones as Plain StringsL1EasyComing soon
- MD-11Date Ranges Passed as PairsL1MediumComing soon
- MD-13A Central Switch for PluginsL1MediumComing soon
- MD-14The 300-Line Import MethodL1MediumComing soon
- MD-16Modules Calling Each Other to Announce EventsL1MediumComing soon
- MD-20Retry Loops Copy-PastedL1HardComing soon
- MD-21Hammering a Dead ServiceL1HardComing soon
- MD-23Plain Data Orders, Bloated Order ServiceL1MediumComing soon