DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Master-Class: Understanding Database Replication (Single, Multi, and Leaderless)
  • Liquibase: Database Change Management and Automated Deployments
  • AWS Managed Database Observability: Monitoring DynamoDB, ElastiCache, and Redshift Beyond CloudWatch
  • Production Database Migration or Modernization: A Comprehensive Planning Guide [Part 2]

Trending

  • Java in a Container: Efficient Development and Deployment With Docker
  • Navigating the Complexities of AI-Driven Integration in Multi-Cloud Environments: A Veteran’s Insights
  • Building a Skill-Based Agentic Reviewer with Claude Code: A Practical Guide Using Skills.MD, MCP Servers, Tools, and Tasks
  • LLM-Powered Deep Parsing for Industrial Inventory Search
  1. DZone
  2. Data Engineering
  3. Databases
  4. SLAP Your Methods and Don't Make Me Think!

SLAP Your Methods and Don't Make Me Think!

The Single Level of Abstraction principle and obeying the Don't Make Me Think rule of coding.

By 
Grzegorz Ziemoński user avatar
Grzegorz Ziemoński
·
Aug. 16, 16 · Tutorial
Likes (55)
Comment
Save
Tweet
Share
18.0K Views

Join the DZone community and get the full member experience.

Join For Free

In my recent post about creating a blogging platform I posted a piece of code like this:

 public MarkdownPost(Resource resource) {
        try {
            this.parsedResource = parse(resource);
            this.metadata = extractMetadata(parsedResource);
            this.url = "/" + resource.getFilename().replace(EXTENSION, "");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

Never mind the smart constructor (which hasn't caused any problems so far!), there's an important rule that's been violated: the Single Level of Abstraction Principle.

Image title

The principle says that every statement in a method should be on the same level of abstraction. If we try to read this method top to bottom we get something like this:

  • Parsed resource is initialized by the result of parsing the resource (yay!).
  • Metadata is initialized by extracting metadata from the parsed resource.
  • URL is initialized by... STRING CONCATENATION WITH A REPLACE USING A CONSTANT AND A MAGIC EMPTY STRING.

That's not good. A method should read smoothly. Let's fix it:

public MarkdownPost(Resource resource) {
        try {
            this.parsedResource = parse(resource);
            this.metadata = extractMetadata(parsedResource);
            this.url = urlFor(resource);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private String urlFor(Resource resource) {
        return "/" + resource.getFilename().replace(EXTENSION, "");
    }

Not sure if urlFor is the best name, but at least the original method looks and reads much better. But we're not done with levels of abstraction yet.

When reading solutions for Sam Atkinson's code challenges, I noticed that in most of them there's a missing level of abstraction! Most solutions for chemical challenge have some kind of isValid method, that does String operations all way long.

You may ask what's wrong with this — it's like 10 lines of code. I'll tell you what — it's 10 lines of decoding. I don't want to do that. I don't want to sit and think "what the hell did you mean?". I want to read a method and know what's happening in there right away, what was the intention, what are the business rules behind it!

This is an adaptation of Don't Make Me Think rule to coding. In the case of methods, it can often be achieved by introducing another level of abstraction. Let's look at another example.

You want to validate a newly submitted user account. The criteria is simple:

  • Username is unique
  • Password contains special characters
  • Email is in correct format
  • User is/claims to be adult

Let's write a method for it:

public boolean isValid(User user) {
        ...
    }

What do you expect inside isValid? A database call to check uniqueness? A regexp check for the email? Date calculations? Hopefully none of these.

public boolean isValid(User user) {
        return isUnique(user.username)
            && containsSpecialCharacters(user.password)
            && hasCorrectFormat(user.email)
            && isAdult(user.birthdate);
    }

Of course, the database call and other checks will have to be done just below this method. But if someone wants to check how a user is validated, the first thing he sees are clearly defined rules, all on the same level of abstraction. He won't have to think.

Now it's your turn to do the thinking and SLAP your methods! Despite my unwillingness to think, I still have to correct mine too ;)

Database

Published at DZone with permission of Grzegorz Ziemoński. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Master-Class: Understanding Database Replication (Single, Multi, and Leaderless)
  • Liquibase: Database Change Management and Automated Deployments
  • AWS Managed Database Observability: Monitoring DynamoDB, ElastiCache, and Redshift Beyond CloudWatch
  • Production Database Migration or Modernization: A Comprehensive Planning Guide [Part 2]

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook