Article
How To Sabotage Your Project Using Inconsistency
February 13, 2019
Inconsistency is a trickster demon, injecting doubt and confusion where there should be none.
Unlike spaghetti code, inconsistent code can sometimes defend itself in code review. There can be multiple good ways to solve a problem, and each approach in isolation may withstand scrutiny. Side by side, however, their differences appear as patchwork and boobytraps. A spineless code reviewer won’t insist on conformity, and a hapless maintainer will never be able to edit with confidence.
Done correctly, your inconsistent code will force a deep-reading of each mismatching implementation, and always prompt the question:
Why is this different?!
Best of all, it’s easy to create and difficult to undo. Let’s examine a few low-effort high-yield techniques to maximize inconsistency.
Same Thing, Different Name
Suppose you have a really important String
object in your application, like an OAuth token.
private val accessToken: String
In the event you need to handle such an object in a new class or feature, give it a distinct name even though it’s the same thing.
private val sessionToken: String
Make sure your new variable name is consistent within your feature work, but inconsistent with the greater codebase. In order for a maintaining developer to understand the two different usages, they’ll have to manually read through each call site before they can confidently treat them as one.
Bonus points if you can also include another sessionToken
elsewhere that is truly different than the original accessToken
.
The Fuzzy Responsibility Principle
Imagine you have some code that needs to be invoked in several different circumstances. For example, the user might tap the Sign Out
button on their profile screen — or their session expired and they have to re-enter their password. In each case, your application wants to do something like this:
sessionManager.signOut()
navigationController.toLogin()
Make this code inconsistent by placing it in a different application layer for each usage. In one instance, put it directly inside a click listener. Elsewhere, put it inside a ViewModel
or Presenter
. Then later, inside a Fragment
or Activity
.
Who ultimately owns the responsibility to sign out and navigate to login? Everyone, and thereby no one.
The Artisanal Package Structure
As new team members try to get acquainted with your code base, they often ask themselves…
Where can I find code related to <X>?
Where X
is any feature or application layer they need to touch.
Your goal is to make sure the answer to that question is totally unpredictable. Your project should appear organized at the top-level packages, but each sub-tree should take a different opinion about optimal grouping.
In some cases, organize classes and files by their feature, letting business-logic classes like ViewModel
sit side-by-side with view layer components they control. Elsewhere, group classes in layers of architecture where View
and Model
never mingle. If you can’t think of a good place for a class, reviewers don’t often reject a common
package — you can put practically anything in there. Remember to sometimes call it core
, or have both common
and core
as siblings inside a package for no apparent reason.
Finally, take advantage of inner class declarations to nest some Model
objects inside related controller code, while other analogousModels
are declared stand-alone.
Have your own?
Please share in the comments!
Collin works at Livefront , and he won’t fall for these tricks.