Writing dirty code is painful, but it's even more painful to read it, especially by other people. The hardest part of programming is not writing code that works, but code that is understandable and makes sense. Fortunately, that's where code reviews come in.
Earlier this week, I received a remark from a fellow developer (Fabien HIEGEL), who gave me a code review on a project we're both working on and introduced me to the SLAP concept.
This principle of software design has enabled me to improve my code, and today I've decided to write an article on it to share this practice with you.
In this post, you'll learn what SLAP is, what its advantages are and a concrete example of its use in your code.
What is SLAP?
The Single Level of Abstraction Principle (SLAP) means that each method or function should operate at a single level of abstraction. This means that a method should perform either a high-level operation or a low-level detailed operation, but not mix both.
But, what is really an abstraction?
An abstraction is a fragment of code doing different things than other fragments within the same scope of code, or simply put, all elements in a function shall have the same level of detail β Nik Sumeiko
The SLAP in Practice
Letβs consider a scenario where we want to read data from a file, process the data and save the processed data into a database. Weβll start with a version of the code that does not follow SLAP and then refactor it to adhere to the principle.
Non-SLAP code
In the initial version of the code, the processData
method handles multiple levels of abstraction.
- Reading data from a file (low-level operation)
- Processing the data (medium-level operation)
- Saving the data to the database (high-level operation)
import java.io.*;
import java.nio.file.*;
import java.sql.*;
public class DataProcessor {
public void processData(String filePath) {
try {
// Low-level operation: Reading data from a file
String data = new String(Files.readAllBytes(Paths.get(filePath)));
// Medium-level operation: Processing the data
String processedData = data.toUpperCase(); // Example processing
// High-level operation: Saving data to the database
saveToDatabase(processedData);
} catch (IOException | SQLException exception) {
exception.printStackTrace();
}
}
private void saveToDatabase(String data) throws SQLException {
// Assume we have a JDBC connection
// Save data
}
public static void main(String[] args) {
DataProcessor processor = new DataProcessor();
processor.processData("data.txt");
}
}
Refactored code applying SLAP
We can refactor the code to apply the SLAP principle by separating the different levels of abstraction into their methods.
import java.io.*;
import java.nio.file.*;
import java.sql.*;
public class DataProcessor {
public void processData(String filePath) {
try {
String data = readFile(filePath); // High-level operation
String processedData = process(data); // High-level operation
saveToDatabase(processedData); // High-level operation
} catch (IOException | SQLException exception) {
exception.printStackTrace();
}
}
private String readFile(String filePath) throws IOException {
// Low-level operation: Reading data from a file
return new String(Files.readAllBytes(Paths.get(filePath)));
}
private String process(String data) {
// Medium-level operation: Processing the data
return data.toUpperCase(); // Example processing
}
private void saveToDatabase(String data) throws SQLException {
// High-level operation: Saving data to the database
// Save data
}
public static void main(String[] args) {
DataProcessor processor = new DataProcessor();
processor.processData("data.txt");
}
}
There may be borderline cases where you don't really need to extract bits of code to another abstraction level.
For example, when you find yourself in an if
statement with a fairly trivial condition, as in the code snippet below.
private void saveToDatabase(String data) throws SQLException {
if (Objects.isNull(data)) { // <- No need to refactor this condition
return
}
// ...
}
Objects.isNull(data)
is a low-level code mixed with high-level code in the saveToDatabase
. I don't think applying SLAP is a good idea, because we can rely on the intelligence of other developers to understand what condition we're trying to test.
Benefit of the SLAP
- Readability β By making your code adhering to SLAP, it becomes self-explanatory. Each method or component is focused on a specific task, making it easier for developers to understand its purpose.
- Maintainability β By separating concerns into distinct layers, it becomes easier to locate and modify a specific piece of code without affecting unrelated parts of the system.
- Testability β Methods with a single level of abstraction are generally easier to test, as they have clearly defined inputs and outputs.
- Reusability β The clear separation of concerns allow them to be extracted and reused in other parts of the system or even in different projects.
Related Resources
Single Level Of Abstraction (SLA) Principle In JavaScript
SLAP your code
I hope you enjoyed reading this, and I'm curious to hear if this tutorial helped you. Please let me know your thoughts below in the comments. Don't forget to subscribe to my newsletter to avoid missing my upcoming blog posts.
You can also find me here LinkedIn β’ Twitter β’ GitHub or Medium
End
In conclusion, the Single Level of Abstraction Principle (SLAP) is an essential concept in software design that promotes readability, maintainability, testability, and reusability of code.
By ensuring each function or method operates at a single level of abstraction, developers can create cleaner, more efficient code that's easier to understand and modify.
Whether you're writing in Java or another language, applying SLAP principles can significantly enhance your coding practices and the overall quality of your software.