Chapter 3: Refuse the 'Universal Field'
2026.08.10"Simplicity is about subtracting the obvious and adding the meaningful." — John Maeda, The Laws of Simplicity
Beneath the grand blueprints of system architecture lie countless tiny, concrete implementation details. And a system's decay rarely begins with the collapse of its architecture; it begins with the "corruption" of a single field. Just as one drop of ink can stain a glass of clear water, a single abused field can pollute an entire module -- or even the clarity of the whole system.
In this part, we focus on the most microscopic unit of a system: the field. We will learn to recognize fields that have been "conceptually compressed" and to refactor them with a powerful technique called "Dimension Decomposition." Our goal is to turn "ciphers" that depend on comments and "human memory" into self-explanatory, unmistakable business facts.
This is a journey from the "alchemy" of code back to the "chemistry" of data. We will no longer try to dissolve every substance in a single "universal solvent." Instead, we will learn how to separate and purify each element so that, along its own dimension, it clearly reveals its properties.
Prologue: That Summer, the Straw That Broke the Order System's Back
(This case -- the "Starfish E-commerce" 618 incident -- is a synthetic example; its characters and plot are constructed for teaching purposes, not a record of a real company.)
It was a Friday afternoon in June. The sun was bright, and the office hummed with the easygoing mood of an approaching weekend. Wang Ting, a core development engineer on the "Starfish E-commerce" platform, was making final preparations for the upcoming "618 Mid-Year Sale." The campaign's mechanics were genuinely intricate: the marketing team had designed pre-sales, group buying, the "billions subsidy," internal employee pricing, and several other models.
To support these mechanics, Wang Ting and Xiao Chen, the product manager, "extended" the order system's core field, order_type. The field had existed since the system's earliest days, holding just a few simple values: 1 for regular orders, 2 for virtual product orders. As the business grew, it behaved like a magnet, silently absorbing one new business meaning after another. By the eve of 618, the comment attached to the order_type column in the t_order table had become an intimidating "treasure map":
-- t_order.order_type (smallint)
-- 1: General physical order
-- 2: Virtual product order (e.g., phone top-up)
--
-- -- 2022 Q1: Added B2B business --
-- 10: Enterprise customer order (monthly billing)
--
-- -- 2022 Q4: Added pre-sale model --
-- 20: Pre-sale order (deposit)
-- 21: Pre-sale order (balance payment)
--
-- -- 2023 Q2: Added for the 618 sale --
-- 30: Billions subsidy order (platform-funded)
-- 40: Group buying order (awaiting group formation)
-- 41: Group buying order (group formed)
-- 50: Internal employee void test order (excluded from GMV, not shipped)
At five o'clock on Friday afternoon, the promotion went live on schedule. Traffic surged in, the system held steady, and within the first ten minutes GMV had already broken last year's record. The team was ecstatic; people started ordering bubble tea to celebrate.
At 5:30, the nightmare began.
The customer service phones were swamped. A large number of users reported that, after paying for their "billions subsidy" items, their order status had flipped straight to "Canceled." Meanwhile, the financial monitoring system began to alarm over a stream of mismatched bad debts. More bizarrely still, some internal employees discovered that their test orders had been picked up by the warehouse system and were being packed and shipped.
The entire engineering department snapped to full alert. Wang Ting's heart sank. Her gaze was locked on the screen, fixed on the code she and her colleagues had "stacked" together -- the processNewOrder method in OrderProcessingService. The method was more than two hundred lines long, riddled with a maze of if/else if/else structures whose branches were almost all decided by the same variable: order.getType().
// OrderProcessingService.java
public void processNewOrder(Order order) {
// ...
// Step 1: Compute price and discounts
if (order.getType() == 30) { // Billions subsidy
applySubsidy(order);
} else if (order.getType() == 10) { // Enterprise monthly billing
applyCorporateDiscount(order);
}
// ... other pricing logic
// Step 2: Advance status and inventory
if (order.getType() == 20 || order.getType() == 40) { // Pre-sale or group buying awaiting formation
order.setStatus(OrderStatus.PENDING_FULFILLMENT);
inventoryService.freezeStock(order);
} else if (order.getType() != 50) { // Not an internal test order
order.setStatus(OrderStatus.PAID);
inventoryService.decreaseStock(order);
} else {
// Internal test order, do nothing
}
// Step 3: Trigger shipment and notifications
if (order.getType() != 50 && order.getType() != 40 && order.getType() != 20 && order.getType() != 2) {
// Not test, not group buy, not pre-sale, not virtual => trigger physical shipment
shippingService.createShipment(order);
}
// ... more such judgments
}
As the team waded through the chaos, the problems gradually surfaced.
- Subsidy orders canceled: The colleague handling payment callbacks, hoping to prevent duplicate processing, had added a guard:
if (order.getType() != 1) return;. He assumed only regular orders needed handling and had no idea that30(billions subsidy) was also a physical order requiring payment. - Financial bad debts: Enterprise customer orders (
10) were on monthly billing and should not have been booked as receivables immediately. But the new report developer, when computing the day's GMV, naively ran aSUM(amount) WHERE status = 'PAID'. He didn't realize that whiletype=10orders were also in the PAID state, their billing model was entirely different. - Test orders shipped: In Step 2's inventory logic, the
else if (order.getType() != 50)check was correct. But in Step 3, a different colleague responsible for the shipment module wrote an independent condition and omitted the50type, so test orders were erroneously sent to the warehouse.
The root cause of this incident was not any single developer's oversight, but the order_type field itself -- a textbook "universal field." It was like an overcrowded intersection where traffic converges from every direction yet shares a single traffic light. Finance, marketing, warehousing, risk control -- every business function's logic changes funneled into this one tiny smallint. Each modification was a game of Russian roulette, no one knowing which unrelated business logic might be accidentally triggered.
That afternoon, the string that was order_type, stretched taut over and over again, finally snapped under the immense pressure of "618." It brought not only hours of downtime and incalculable financial loss, but also a heavy blow to the team's technical confidence.
From this rubble, we begin this chapter's reconstruction. We will learn how to dismantle "design-time bombs" like order_type completely, and how to build a clear, robust, and evolvable data model through a new, dimension-based way of thinking.
Section 1: "Dimension Decomposition" -- Finding an Independent Home for Each Concept
In the previous chapter, we defined "conceptual compression" as forcibly binding together things that change at different rhythms. So how do we systematically "decompress"? The answer is this chapter's core methodology: "Dimension Decomposition."
In the context of data modeling, a dimension refers to a set of mutually independent attributes or classifications of a business object along a particular facet. Each dimension answers a "what" or "how" question about that object.
- "What color is this car?" -> Color dimension (red, white, black)
- "What fuel does this car use?" -> Energy dimension (gasoline, diesel, electric)
- "Which country produced this car?" -> Origin dimension (Germany, Japan, USA)
A Car object can simultaneously carry attributes such as color=red, energy_type=electric, and origin=USA. We would never be foolish enough to design a car_type field and then define:
1: Red gasoline German car2: White electric American car- ...
Because we intuitively know that color, energy, and origin are three orthogonal dimensions. Each changes independently. An automaker can release a new color without touching its energy systems, or roll out a new electric platform across models of every origin. Had we compressed them into a single car_type, any change in one dimension would cause a combinatorial explosion of type values and render the code consuming those values extremely fragile.
Remarkably, this "dimensional" thinking we take for granted in the physical world is all too often forgotten in the software world. The tragedy of order_type stems precisely from its attempt to force multiple independent dimensions of an order into a single one.
Now, let us play system physician and perform a "pathological dissection" of order_type to see which independent dimensions it has squeezed together.
Dissecting order_type
Let's re-examine the "treasure map" and the code that consumes it:
1(general),2(virtual),10(enterprise monthly billing),30(billions subsidy)- These values mainly affect money. They determine how the order is priced, who pays (user, enterprise, platform), and when settlement occurs.
- We call this -> the Billing Dimension
20(pre-sale),40(group buy)- These values mainly affect the process. They determine whether, after payment, an order immediately enters fulfillment or must wait on an external condition (pre-sale period ending, group formation).
- We call this -> the Process Dimension
50(internal test order)- This value mainly affects visibility and permissions. It determines whether the order is visible to real users and whether it should be processed by downstream systems such as the warehouse and finance.
- We call this -> the Permission/Visibility Dimension
1(general),30(billions subsidy),40(group buy)- These values also carry another layer of meaning: which business scenario or marketing campaign they belong to. The marketing team and data analysts rely on these tags to measure the ROI of each campaign.
- We call this -> the Statistical Dimension
There it is -- the heart of the problem! A seemingly simple order_type field is in fact an "illegal cohabitation" of four independent dimensions:
- Billing Dimension: answers "how is the money settled?"
- Process Dimension: answers "what happens next?"
- Permission Dimension: answers "who can see it? who can act on it?"
- Statistical Dimension: answers "what category is this?"
These four dimensions are driven to change by completely different forces:
- The billing dimension changes at the behest of finance and business development.
- The process dimension changes at the behest of product and operations.
- The permission dimension changes at the behest of risk control and internal management.
- The statistical dimension changes at the behest of marketing and data analytics.
Compressing them together means that a minor billing-model tweak from the finance department can accidentally break the marketing team's campaign report. This is the "organizational coupling" that "conceptual compression" inevitably produces.
Performing the Decomposition: Assign a Dedicated Field to Each Dimension
The surgical procedure of "Dimension Decomposition" is straightforward: identify the compressed dimensions, then create an independent, semantically explicit field for each one.
Let's refactor the t_order table:
t_order before refactoring (partial fields):
| Field | Type | Meaning |
|---|---|---|
id | bigint | Primary key |
order_type | smallint | Universal field (God Field) |
status | smallint | Order status |
amount | decimal | Amount |
| ... | ... | ... |
t_order after refactoring (dimension decomposition):
| Field | Type | Meaning | Corresponding dimension | Notes |
|---|---|---|---|---|
id | bigint | Primary key | ||
billing_model | enum | Billing model | Billing dimension | USER_PAY, CORPORATE_MONTHLY, PLATFORM_SUBSIDY |
flow_type | enum | Flow type | Process dimension | IMMEDIATE, PRE_SALE, GROUP_BUY |
visibility | enum | Visibility | Permission dimension | NORMAL, INTERNAL_TEST, DELETED |
business_tag | varchar | Business tag | Statistical dimension | 618_PROMO, NEW_USER_GIFT (nullable) |
status | smallint | Order status | ||
amount | decimal | Amount | ||
| ... | ... | ... |
We have replaced an order_type that required a "codebook" to read with four self-explanatory fields. Now the data itself tells the business story. Let's see how those chaotic order_type values map cleanly onto the new dimensional model:
Old order_type | Description | billing_model | flow_type | visibility | business_tag |
|---|---|---|---|---|---|
| 1 | General physical order | USER_PAY | IMMEDIATE | NORMAL | null |
| 10 | Enterprise customer order | CORPORATE_MONTHLY | IMMEDIATE | NORMAL | null |
| 20 | Pre-sale order | USER_PAY | PRE_SALE | NORMAL | null |
| 30 | Billions subsidy order | PLATFORM_SUBSIDY | IMMEDIATE | NORMAL | 618_SUBSIDY |
| 40 | Group buying order | USER_PAY | GROUP_BUY | NORMAL | GROUPON_PROMO |
| 50 | Internal test order | USER_PAY | IMMEDIATE | INTERNAL_TEST | null |
This mapping reveals a startling truth: the old order_type was an incomplete, irregular subset of the Cartesian product of these four dimensions' values. That is precisely why it was so hard to maintain -- it tried to render a four-dimensional space as a linear sequence of numbers.
The Power of the New Model: Embracing Change
The decomposed model's greatest advantage is orthogonality. Each dimension can evolve independently without disturbing the others.
New requirement 1: Finance proposes a new "installment payment" billing model.
- Response: we simply add a value
INSTALLMENT_PAYto thebilling_modelenum. All existing process, permission, and statistical logic is completely unaffected.
- Response: we simply add a value
New requirement 2: Marketing wants to try a new "mystery box" mechanic, where users pay first and must wait for a unified draw to learn which product they receive before shipment.
- Response: we simply add
BLIND_BOX_RAFFLEtoflow_type. Billing and statistics are untouched.
- Response: we simply add
New requirement 3: We need a "stress test." These orders must not be shipped, yet must still be counted as "virtual GMV" by the finance system.
- Response: we simply add
STRESS_TESTtovisibility. Any code can now checkvisibilityto decide whether to process the order "for real."
- Response: we simply add
See it? "Dimension Decomposition" breaks a tangled "big ball of mud" into separately pluggable, freely combinable "Lego bricks." We sacrificed the superficial "simplicity" of a single order_type field and gained, in return, enormous flexibility and extensibility across the whole system as future requirements arrive.
This is the essence of refactoring at the micro level. In the next section, we will see how this "decompression" of the data model magically dissolves that headache-inducing, two-hundred-line if/else maze into nothing.
Section 2: Evolving from Fifty Lines of Nested Conditionals to One Line of Table Lookup
The ultimate purpose of refactoring a data model is to simplify code logic. A good data model should resemble a well-designed circuit board, where current (the business flow) moves smoothly without the need for intricate jumpers and switches (if/else).
Now let us return to the OrderProcessingService that drove Wang Ting to despair, and watch how it is transformed once "Dimension Decomposition" is applied.
Evolution, Stage One: Direct Replacement -- From Cipher to Plaintext
The first and most direct step of the refactor is to replace every judgment on order.getType() in the code with judgments on the new dimensional fields.
processNewOrder before refactoring (fragment):
// Step 3: Trigger shipment and notifications
if (order.getType() != 50 && order.getType() != 40 && order.getType() != 20 && order.getType() != 2) {
// Not test, not group buy, not pre-sale, not virtual => trigger physical shipment
shippingService.createShipment(order);
}
This code is nearly unreadable. A newcomer has to cross-reference the comments to decode the magic numbers 50, 40, 20, 2. Worse, every time the system gains a new "do not ship" order type (say, "mystery box"), someone must remember to come here and tack on another && order.getType() != NEW_TYPE.
processNewOrder after refactoring (fragment):
// Step 3: Trigger shipment and notifications
// We now express intent in clear business dimensions
boolean shouldShipImmediately =
order.getFlowType() == FlowType.IMMEDIATE &&
order.getVisibility() == Visibility.NORMAL;
if (shouldShipImmediately) {
shippingService.createShipment(order);
}
Notice the shift. Our judgment logic moved from a blacklist of exclusions (!= 50 && != 40 ...) to a whitelist of definitions (== IMMEDIATE && == NORMAL).
- Blacklist logic is fragile. It rests on the assumption that "everything I don't know about should be shipped" -- an assumption the system's evolution is all too ready to break.
- Whitelist logic is robust. It crisply defines the necessary and sufficient conditions for "should ship immediately." No matter how many new
flow_typeorvisibilityvalues we add in the future, so long as they don't satisfy this condition, they can never wrongly enter the shipping flow.
With this single replacement, the code's readability and safety improve by an order of magnitude. We have gone from fifty lines of baffling nested conditionals to a few clean combinations of logic rooted in business dimensions.
But this is not the end. Although the code is clearer, the processNewOrder method still has judgments on billing_model, flow_type, and so on scattered throughout. Can we make it even more "foolproof"?
Evolution, Stage Two: Logic Elevation -- The Strategy Pattern and Configuration
We observe that processNewOrder is, in essence, performing strategy dispatch. Depending on the order's dimensional attributes, it selects a processing strategy (billing, inventory, shipping). if/else and switch/case are the crudest forms of dispatch, and they become unmaintainable once the conditions grow complex.
Object-oriented design offers us a better alternative: the Strategy Pattern. We can encapsulate each distinct processing logic into its own strategy class.
Define the Strategy Interface
public interface OrderProcessingStrategy {
void applyBillingRule(Order order);
void handleInventory(Order order);
void triggerShipment(Order order);
}
Implement Concrete Strategy Classes
// Regular order processing strategy
public class ImmediateFlowStrategy implements OrderProcessingStrategy {
// ... implement the concrete billing, inventory, and shipping logic
@Override
public void triggerShipment(Order order) {
if (order.getVisibility() == Visibility.NORMAL) {
shippingService.createShipment(order);
}
}
}
// Pre-sale order processing strategy
public class PreSaleFlowStrategy implements OrderProcessingStrategy {
// ...
@Override
public void handleInventory(Order order) {
inventoryService.freezeStock(order); // Pre-sale only freezes stock
}
@Override
public void triggerShipment(Order order) {
// Pre-sale does not ship immediately; do nothing
}
}
Select the Strategy in the Main Flow
// OrderProcessingService.java
public class OrderProcessingService {
private Map<FlowType, OrderProcessingStrategy> strategies;
// ... (strategies Map initialized via dependency injection)
public void processNewOrder(Order order) {
OrderProcessingStrategy strategy = strategies.get(order.getFlowType());
if (strategy == null) {
throw new IllegalStateException("No processing strategy found for flow type: " + order.getFlowType());
}
strategy.applyBillingRule(order);
strategy.handleInventory(order);
strategy.triggerShipment(order);
}
}
Through the Strategy Pattern, we have successfully turned the branching logic of if/else into a Map lookup. The main flow of processNewOrder becomes remarkably concise and stable: it is responsible only for looking up the right strategy by order.getFlowType() and handing off execution, without ever caring about the strategy's internal implementation. When we need to support a new flow type (say, "mystery box"), we simply add a new class implementing OrderProcessingStrategy and register it in the strategies map -- OrderProcessingService itself never needs to change. This is the Open/Closed Principle in its purest form: open for extension, closed for modification.
We have made great strides. The code logic is now cleanly organized, easy to understand and extend. But can we go further?
Look closely, and you'll notice that even inside the strategy classes there are still if checks, such as if (order.getVisibility() == Visibility.NORMAL) in ImmediateFlowStrategy. Moreover, the billing logic (applyBillingRule) has little to do with the flow (FlowType); it is tied instead to BillingModel. The current strategy split still carries a trace of conceptual coupling.
Our ultimate ambition: can we make the code completely "forget" the business rules? Can we expunge every "judgment" from the code and move it wholesale into pure data?
Evolution, Stage Three: Ultimate Decompression -- Turning Business Rules into a "Configuration Table"
This is the book's core idea at its most extreme: data is the boundary; logic is a table lookup.
We will create a new database table that stores not business entities (orders, users) but the business rules themselves. We'll call it the "order processing capability matrix."
The t_order_capability_matrix table:
id | billing_model | flow_type | visibility | action_type | is_enabled | handler_bean_name |
|---|---|---|---|---|---|---|
| 1 | USER_PAY | IMMEDIATE | NORMAL | DECREASE_STOCK | true | defaultStockHandler |
| 2 | USER_PAY | IMMEDIATE | NORMAL | CREATE_SHIPMENT | true | physicalShipmentHandler |
| 3 | ANY | PRE_SALE | ANY | FREEZE_STOCK | true | defaultStockHandler |
| 4 | ANY | PRE_SALE | ANY | CREATE_SHIPMENT | false | null |
| 5 | CORPORATE_MONTHLY | ANY | ANY | GENERATE_BILL | true | corporateBillingHandler |
| 6 | ANY | ANY | INTERNAL_TEST | DECREASE_STOCK | false | null |
| 7 | ANY | ANY | INTERNAL_TEST | CREATE_SHIPMENT | false | null |
| ... | ... | ... | ... | ... | ... | ... |
The design philosophy of this table is revolutionary:
- Input dimensions: the columns
billing_model,flow_type, andvisibilitydefine the conditions under which a rule applies. They are combinations of order attributes.ANYis a wildcard meaning "all values in this dimension." - Output capabilities: the
action_typecolumn defines the kind of operation the order may undergo -- "decrease stock," "create shipment," "generate monthly billing statement," and so on. - Switch and handler: the
is_enabledfield is a simple boolean toggle deciding whether the capability is active.handler_bean_namepoints to the concrete code component that executes thisaction(in Spring, a bean name).
Now let's see what OrderProcessingService becomes. It goes completely "amnesiac," holding no concrete business rules at all.
Refactored OrderProcessingService (final form):
public class OrderProcessingService {
@Autowired
private CapabilityMatrixRepository capabilityRepo;
@Autowired
private ApplicationContext appContext; // Spring's ApplicationContext, for resolving beans
public void processNewOrder(Order order) {
// 1. Fetch all actions this order should execute
List<CapabilityRule> rules = capabilityRepo.findEnabledRulesFor(
order.getBillingModel(),
order.getFlowType(),
order.getVisibility()
);
// 2. Iterate and execute
for (CapabilityRule rule : rules) {
String handlerName = rule.getHandlerBeanName();
ActionHandler handler = (ActionHandler) appContext.getBean(handlerName);
handler.execute(order);
}
}
}
// ActionHandler interface
public interface ActionHandler {
void execute(Order order);
}
Take a moment to savor this code. It is short, sharp, and extraordinarily stable. It no longer contains a single if/else to decide business type. All it does is this:
- Query: it asks the capability matrix, "For an order with this combination of dimensions, what should I do?"
- Execute: it resolves the matching handler from the query result and runs it.
We have evolved fifty-plus tangled lines of if/else into a single, simple database query: capabilityRepo.findEnabledRulesFor(...).
This is the ultimate power "conceptual decompression" can deliver. We have stripped every business judgment out of imperative code and converted it into declarative data.
The Enormous Payoff of Making Rules into Data
Turning rules into data yields transformative benefits:
Extreme code stability:
OrderProcessingServiceis now a pure, business-agnostic "rule execution engine." No matter how business rules churn -- new billing models, new order flows, adjusted combinations -- we will almost never need to touch this core code again. Code stability is guaranteed to the maximum degree.Business agility:
- Scenario: on the eve of a big promotion, the product manager rushes in and says, "We've just decided that 'billions subsidy' orders (
billing_model = PLATFORM_SUBSIDY) should not ship for now. Hold them all until 8 AM tomorrow!" - Response under the old model: developers must urgently patch the shipping logic in code -- add
&& order.getBillingModel() != PLATFORM_SUBSIDYto theif-- then run the full gauntlet of testing, packaging, and deployment. The process is risky and can take hours. - Response under the new model: an operations person (possibly with no developer involvement) logs into the database console, locates the rule where
billing_model = PLATFORM_SUBSIDYandaction_type = CREATE_SHIPMENT, and flipsis_enabledfromtruetofalse. The whole operation takes under thirty seconds: zero code changes, no release process needed (though such direct data edits should themselves carry access control and audit logging, to guard against mistakes). At 8 AM, it flips back totrue. - That is agility. We place the ability to tune rules dynamically into the hands of the business itself; technology is no longer the bottleneck.
- Scenario: on the eve of a big promotion, the product manager rushes in and says, "We've just decided that 'billions subsidy' orders (
Rule explainability:
- When a tester finds an order behaving oddly -- "Why didn't this internal test order decrease stock?" -- we no longer have to
debugline by line through two hundred lines of code. - We just query
t_order_capability_matrix:WHERE visibility = 'INTERNAL_TEST' AND action_type = 'DECREASE_STOCK'. The result tells us plainly that this rule'sis_enabledisfalse. The database result is the final, authoritative explanation of system behavior. - The table itself becomes a living system design document, forever in sync with the implementation.
- When a tester finds an order behaving oddly -- "Why didn't this internal test order decrease stock?" -- we no longer have to
Complexity isolation:
- We have not eliminated business complexity, because business is inherently complex. We have simply relocated it -- out of code logic, which is hard to test and reason about, and into data, which is easy to query and manage.
- The code's job is reduced to pure "execution," while the data's job is "decision." This is a beautiful separation of concerns.
Chapter Summary: Be a "Data Modeler," Not a "Logic Coder"
In this chapter, we followed engineer Wang Ting through a production incident triggered by the "universal field" order_type (a synthetic case) -- a textbook example of the havoc "conceptual compression" wreaks in the real world.
To address such problems, we introduced this chapter's core methodology, "Dimension Decomposition." We learned to dissect a "universal field" the way a pathologist examines a specimen, identifying the independent dimensions -- billing, process, permission, and statistics -- that had been crushed together. We stressed that each dimension deserves its own dedicated, self-explanatory field, so the data model can reflect business reality cleanly and orthogonally.
Then we embarked on an invigorating journey of code evolution, watching that fifty-line maze of magic-numbered if/else refactored step by step:
- Stage one: we replaced magic numbers with dimensional fields, turning "cipher" into "plaintext" and dramatically improving readability and safety.
- Stage two: we introduced the Strategy Pattern, gathering scattered
iflogic into dedicated strategy classes and substituting aMaplookup for branching judgments -- thereby honoring the Open/Closed Principle. - Stage three, the decisive leap: we stripped the business rules out of the code entirely, data-ifying them into a "capability matrix" configuration table. The core code withered into a pure "rule execution engine," and complex business judgments collapsed into a single database query.
This evolution is a perfect enactment of the book's central philosophy: excellent software design is an ongoing process of "moving" logic out of code and into data.
The next time you encounter a field like type, status, or kind in a project, stay on guard. Ask yourself:
- Are the different values of this field driven by different departments or business scenarios?
- Is the logic that depends on this field scattered across the system?
- Are the
if/elsejudgments surrounding this field growing longer and longer?
If the answer is yes, you have found an excellent candidate for "conceptual decompression." Don't settle for being a mere "logic coder," stacking ever more else if. Try thinking like a "data modeler": can you eliminate this logic outright by adding a field or a table?
In the next chapter, we continue our work at the micro level, examining another common bad smell -- the "special case" logic lurking in code. We will learn how to apply this same data-driven mindset to eradicate those hard-coded "except for..." branches, making our systems more general and more elegant.