Abstraction FTW

Posted by Aaron Parkening on July 5, 2019

I’ve been writing increasingly complicated code during my time at Flatiron. My classes and methods can do more, but I also notice that the code feels more brittle. My code does what I ask it to do, but I can’t reuse it to do similar tasks elsewhere.

The most useful thing I’ve learned to address this has been separating each individual task into its own reusable chunk. While I sometimes resist the process because it takes more initial work, abstracting my tasks always makes it easier to reuse and update my code, saving my future-self oodles of time.

One Class to Rule Them All

The way I had been approaching complicated code was to combine everything into a single wrapper, moving sequentially through each task. For example, if I was trying to make dinner, I could represent it with a Dinner class:

Class Dinner
	Decide what to eat
	Procure ingredients
	Determine task order to serve dishes at the right time (simultaneously, in courses, etc.)
	Gather ingredients
	Measure ingredients
	Cut/process ingredients
	Combine or cook until done
		Add ingredients until done
	Divide items into portions
	Transfer portions to dishes
	Serve dishes to consumers
	Clean preparation tools
	Clean tableware
	Put away tools
	Put away tableware
end

This approach will get food on the table, yay! But the overall process isn’t flexible:

  • What if I want to clean our preparation tools while dinner is cooking?
  • What about marinating or precooking any items ahead of time?
  • How do I add drinks, locations, or other variables to the mix?

And then I need to do all this again tomorrow? Ugh, this is way too complicated!

Abstract, Then Assemble

Instead, I can divide these tasks into chunks that can be mixed and reused by multiple Meal instances:

Class Meal 
	Plan
	Procure
	for each stored component part
		Prepare
		Cook
		Serve
	end
	Clean
end

Class Plan
	Determine amount of consumers
	Determine amount of processing people (cooks, cleaners, etc.)
	Identify component parts (courses, starches, vegetables, etc.)
	Scale component parts based on amount of consumers and processors
	Mark component order of operations
	Mark ingredients and tools on hand
	Mark external ingredients and tools to procure
	Determine procurement locations (garden, store, neighbor, etc.)
	Mark procurement locations for each item
end

Class Procure
	For each marked location, procure external ingredient and tool item
end

etc.

Each meal is now much simpler! I can:

  • Clean a few dishes in the middle by adding another instance of Clean before Serve.
  • Introduce marinades and drinks by adding them to Plan, and then automatically take advantage of Procure, Prepare, Cook, Serve, and Clean.
  • Divide our meal labor more efficiently. Cleaners don’t need to Cook, cooks don’t need to Procure, etc.

And beyond each specific meal, abstracting my steps means I improve the flexibility of all meals. Now I can:

  • Call Meal any time I need it, rather than just dinner time.
  • Inherit Meal into instances of Lunch, Elevensies, etc. if specific meals have individual needs.
  • Save effort by thinking about mulitple meals. Since Plan stores its results, I can both Plan and Procure for multiple Meals at once.

Abstracting tasks isn’t always easy, but the results are so much more versatile!

Try It Yourself

If you’ve been writing giant single-class programs and want to try abstracting more, here are two questions I ask to determine whether a task might be be abstractable:

  • Could this functionality be used again later? Preparing lunch uses the same steps as preparing dinner, for example.
  • Do I repeat this step multiple times throughout the process? Cleaning the cutting board between each type of ingredient, for example.

As a bonus, once you’ve abstracted into smaller chunks, it’s much easier to expand later. Smaller chunks are easier to understand, and there are fewer ripple effects when you make changes. When it’s time to update the Serve class to pour soup into a bowl (not a plate!), you’ll be glad you can make a discrete simple change to that class instead of the entire Dinner.