Objects Should Make Decisions, Not Confess State
One code smell I have learned to pay attention to is when an object exposes its state and expects everyone else to decide what that state means. If you find yourself reading a field off an object and immediately writing an if statement, there is a good chance a decision has escaped from where it belongs. The object should expose isAtLimit(), not expose count and trust every caller to implement the rule correctly. Today there may be one caller. Next year there may be ten. The rule changes, one gets updated, three are forgotten, and the bugs begin.
I learned this the hard way in a pricing system. There was a service responsible for calculating the price of an item. At some point, a marketplace-specific plugin was introduced that read the computed values and tweaked them outside the original pricing logic. It worked perfectly at the time. Then the business evolved. Pricing rules changed. Vendor-specific exceptions were added. Two years later a vendor reported incorrect pricing and nobody could immediately explain why. The logic had become fragmented across multiple places. Debugging took far longer than fixing the actual issue. The problem was not the pricing rule. The problem was that the decision about what a price meant no longer belonged to the pricing service.
Tenet #4 — Make Assumptions Explicit. Every time you expose raw state, you are making an assumption that every future caller will interpret it correctly. Most of the time, that assumption is invisible until it breaks. The habit I try to build is simple: when I ask, “What is this value?”, I immediately follow with another question—“Who should be deciding what this value means?” More often than not, the answer is the object itself.
Comments
Post a Comment