Wait, wait, don’t close the tab. Let me speak about just one of them. It’s not going to be theoretical or boring, I promise️! I recently bumped into SOLID again and I’d like to show you a hidden power, which I had not noticed before.
Let’s take one more step into the past and create a Gradle project from scratch, written in Java (sorry, Java). No additional build configuration is applied. The structure of the project is shown in the following diagram.
The Gradle version, at the time of writing this article, is v6.8.3
. The incremental compilation feature is enabled by default with the Java plugin.
Imagine that Client1
only uses method m1
, Client2
only uses method m2
, and Client3
only uses method m3
of Service
. What do you think will happen if we change the body of m3
and recompile the project?
You may think that once a change to the body of a method is a binary compatible change, only Service
would be recompiled. I get it... but you are wrong. The reality is, the whole project recompiles.
Those who got it right have gained my respect. You may close the tab now. :)
To see the result directly from Gradle, we take advantage of the listFiles
option for Java compilation that logs the files to be compiled.
tasks.withType(JavaCompile) {
options.listFiles = true
}
We run a compilation of Java source files using the JDK compiler by calling the compileJava
task that is normally executed with every build
or assemble
task.
./gradlew compileJava
Finally, we can see that all source files got recompiled!
> Task :compileJava
Source files to be compiled:
/ISP_java/src/main/java/com/jurcik/ivet/service/Service.java
/ISP_java/src/main/java/com/jurcik/ivet/client/Client1.java
/ISP_java/src/main/java/com/jurcik/ivet/client/Client2.java
/ISP_java/src/main/java/com/jurcik/ivet/client/Client3.java
Why is it like that?
There is nothing wrong with Gradle. The result we got is expected Java behavior. The binary compatibility has no impact on the list of the compiled source files.
All declarations that users must import
in source code create a source code dependency. The source code of Client1
then depends on methods m2
and m3
, even though it does not call them. This dependence means that a change to the source code of m2
or m3
in Service
will trigger a recompilation of Client1
, despite the fact that it does not care about the change.
The Interface Segregation Principle to the Rescue
The Interface Segregation Principle (ISP) states that no client should be forced to depend on methods it does not use.
Let’s follow it by creating a separate interface for each method. Every interface exposes to a particular Client
only what the client really needs. The structure is illustrated in the following diagram.
Now the same question, once again. What do you think will happen if we change the body of the m3
method of Service
class, which is a binary compatible change, and recompile the project?
./gradlew compileJava
Voila!
> Task :compileJava
Source files to be compiled:
/ISP_java/src/main/java/com/jurcik/ivet/service/Service.java
Only Service
got recompiled, thanks to introducing interfaces!
What about Kotlin?
Kotlin compiler is smart enough to only recompile affected files by tracking Application Binary Interface changes (“API” for the binaries — you can read more about the process here). However, this does not make the principle obsolete! The compiler just makes it a bit easier for you. Anyway, it is good to know that extra work has to be done.
Conclusion
Every developer familiar with OOP should have heard about SOLID principles. We follow them on a daily basis, many times without noticing. Even though we all have them rooted deep down in our minds, it is worth giving them special attention. SOLID principles matter. And their boundaries do not end with a system’s architecture.
Resources
- Martin, R.C. (2018). ‘ISP: The Interface Segregation Principle’, in Martin R.C. (ed.) Clean Architecture. Pearson Education, Inc., pp. 83–86.
- Andrey Breslav. The Dark Secrets of Fast Compilation for Kotlin.
Thank you to Alexander Kovalenko for adding a spark to the article and Tomas Mlynaric with Lubos Mudrak for consultations.