Nate Meyvis

Some failures of encapsulation

Here my previous post about encapsulation, the primary purpose of which is to argue for the importance of the concept.

Here are some realistic, important violations of encapsulation:

  1. Using a system that requires the properties or attributes of a runtime object to correspond one-to-one with the columns or fields of persisted objects. (E.g., DynamoDBMapper or Django models.) These extra dependencies between subsystems cause all sorts of problems. So, for example, your code-level objects often become hard to reason about, and you can cause performance problems by making innocuous-seeming code changes.)
  2. Decoding an API response directly in a React component and feeding something like response.hats to a sub-component. This kind of dependence between the over-the-wire representation and component mechanics can cause a lot of trouble,1 and commonly does.2
  3. Having a function that says (in its name, a docstring, or anywhere else) it returns all objects meeting criterion X, but silently dropping ones that aren't used by any of that function's consumers.3

Some general lessons emerge:

  1. These are all controversial, in the sense that many colleagues (even respected and/or senior-level ones) will do the opposite or even recommend the opposite. Enforcing encapsulation will often put you against "best practices," or at least actual practice.
  2. There's a lot of leverage in simply remembering this: data producers should be accurate and should not lie to their consumers; be liberal about making helper functions to transform data for consumers.
  3. Failures of encapsulation often manifest as bad names. What makes a bad name bad often involves a failure of encapsulation.

  1. I have no objection to doing a lot of heavy lifting in parsing and transforming API responses on the front end. In fact, I think it is an underrated family of techniques. But it needs to be done in a repository layer or other well-isolated subsystem, whether that subsystem is on the front or the back end.

  2. I once got a stern reprimand for renaming a variable on the front end: all the tests (including integration tests!) passed, but it turns out that the object was serialized, the resulting dict was sent to the back end, and the back end wrote its fields directly to the (schemaless) database. So, by renaming a variable, I'd caused us to stop writing the correct field and start writing another, irrelevant-to-the-rest-of-the-system field.

  3. This often happens when some of the X objects are empty or otherwise degenerate (e.g., when a function reporting lists of events drops empty lists because the existing callers are only operating on properties of the events that actually happened).

#encapsulation #sociology of software #software