DEV Community

Hudson Burgess
Hudson Burgess

Posted on • Originally published at hudsonburgess.com on

Code Like a Conversation: Basic Levels of Abstraction

Consider the following conversation:

* at le Starbucks *
Friend: “Hey Hudson! What are you up to today?”
Me: “Not much, it’s an easy day today. Just working on a simple web app. I’ll probably grab lunch with some friends this afternoon and read a bit this evening. What about you?”
Friend: “Sounds fun. A few friends and I are going to see <recently released movie> tonight; do you want to come?”
Me: “Sure, I’ve been wanting to go see it.”
Friend: “Great! I’ll text you the details later.”

Ignoring the fact that I dislike staring at screens outside of writing / programming, that’s a conceivable conversation. Now consider this one:

* at le Starbucks *
Friend: “Hey Hudson! What are you up to today?”
Me: “Quite a lot. I got out of bed at 4:23am this morning, cooked breakfast and showered, realized I needed gas, drove to the gas station, swiped my debit card and entered my pin, filled up the gas tank, and went to work. Now I’m taking a break from editing line 105 of search-form.component.ts on my current project. I’ll probably grab lunch with some friends this afternoon, then go home and read with a cup of decaf coffee made in my French press.
Friend: “Sounds fun. A few friends and I are driving to the theater to purchase tickets for <recently released movie>, find seats in the theater in which it’s playing, then fixate our eyes on the screen therein until it ends; do you want to come?”
Me: “Sure, I’ve been wanting to go to the theater and watch it.”
Friend: “Great! I’ll send you the details via SMS later.”

Imagine if every conversation were like that (the horror…)

The first interaction is easy to follow because it stays at the same level of abstraction. Work, eat lunch, read, see a movie – these are high-level, simple statements about what my friend and I are doing. The second interaction is hard to follow because it uses several different levels of abstraction. 4:23am and using SMS are very low-level, specific details about how I did something; getting lunch and mentioning a few friends are descriptive and don’t involve details.

Our code should look like the first conversation and stay at a consistent level of abstraction. Instead, it often looks like the second. It forces the reader to context switch constantly and makes understanding the code needlessly difficult.

To help you refactor the “conversation 2 kind of code, here are 3 levels of abstraction that I’ve been using recently.

1. The primitive level

Ints, strings, booleans, pointers, etc. Functions and methods that operate on primitive types, properties, or class members are very low-level. Put another way, these functions should do only the “grunt work of the application. Working at this level can get a little dull because it’s usually easy – that’s probably a sign that you’re doing it right.

2. The problem space level

This depends on what you’re building. In general, the problem space level operates on objects in the realm of your client. For instance, if you’re building a library application, the problem space level might contain Books, Patrons, ConferenceRooms, and Computers. If you’re building a course registration system, the problem space level might contain Courses, Professors, and Classrooms. This is probably the lowest level of abstraction you’ll use when talking to your client.

The problem space level should consist of classes that simply group related values and functions. Classes shouldn’t need to talk to each other very much; that’s what the component level is for.

3. The component level

Components operate on items from the problem space level. To use the library example again, a CheckoutComponent might create a Checkout record from a Patron and a Book. To use the course registration example, a SignUpForm might allow a Student to sign up for a Course. In general, the component level does the interesting work that makes you money.

Conclusion

I realize this will be an almost childish review for some people, but thinking in these three concrete levels has helped me tremendously lately.

Are there additional levels of abstraction you tend to use? Different abstraction approaches altogether? Let me know.

Top comments (5)

Collapse
 
karfau profile image
Christian Bewernitz

Is this separation also somehow visible in your code(/-structure)? Or how do you communicate about those levels in the team?
I'm asking this because I'm having a hard time wrapping my head around how to apply this to a big react/redux project with lots of abstraction levels.

Collapse
 
hudsonburgess7 profile image
Hudson Burgess • Edited

I would like it to be visible -- a lot of my work recently has been refactoring to make this structure more clear.

I'm not sure what the default structure is for a React app (I work primarily in Angular), but my src/app/ directory looks something like this:

classes/              <-- classes like User, Project, Search, etc.
components/      <-- pieces like sidebars, navbars, forms, etc.
pages/                 <-- technically just higher-level components
services/             <-- HTTP calls and other complex, reusable logic
store/                   <-- ngrx things
...
app.component.*.ts

Hope that's helpful!

Collapse
 
courier10pt profile image
Bob van Hoove • Edited

ASP.Net MVC also has a directory structure that reflects the architecture. Like:

Controllers/
Views/
Models/

I've grown to dislike that approach since things get cluttered easily. For every 'topic' in your application you'll spread files among those folders.

Since you're storing your project on a filesystem, you get 1 hierarchy to choose.

If you go for the architectural divide. It helps you to familiarize with the architecture. And it looks neat with the folders collapsed.

If you go for the topic divide, you'll have all related files together whenever you work on them. That's pretty convenient.

Let's try and demonstrate this with a made up project folder:

README.md
BaseDAO.xyz
Project/projects.json
Project/project.html
Search/LuceneIndex.xyz
Search/SearchService.xyz
Search/Index.template.xyz
User/User.xyz
User/UserController.xy
User/UserService.xyx
User/UserDAO.xyz
User/Templates/Edit.template.xyz
User/Templates/List.template.xyz
User/Templates/Search.template.xyz

Where .xyz is your language of choice.

[disclaimer]
Maybe I'm comparing apples with pears... Bit unsure if I know enough about React to tell.
[/disclaimer]

Collapse
 
karfau profile image
Christian Bewernitz

While not being familiar with angular, it looks like this nicely aligns with the project structure.
I guess it would need some naming convention or documentation/knowledge sharing to "ensure" this.

Maybe somebody else can suggest something?

Collapse
 
courier10pt profile image
Bob van Hoove

If you're not already familiar with it you might be interested in Domain Driven Design. Your ideas seem to resonate with it.

And kudos for the 'conversation comparison' example. I might refer back to it sometime :)