Компилируем меньше с SOLID

Привет всем Android-разработчикам! Давайте разберем принципы SOLID, вернее, один из них. 

Недавно я углубился в SOLID и нашел один скрытый потенциал. Теперь хочу рассказать про него вам, не углубляясь в теорию.

Вернемся в недалекое прошлое и с нуля создадим проект с помощью Gradle на языке Java без дополнительной конфигурации сборки. Структура сборки приведена ниже.

На момент написания статьи версия Gradle v6.8.3. С плагином Java функция инкрементной компиляции включена по умолчанию.

Теперь представим, что Client1 использует только метод m1, Client2 —  только метод m2, а Client3 метод m3 класса Service. Как вы думаете, что произойдет, если мы изменим тело m3 и еще раз скомпилируем проект?

Можно предположить, что если мы внесли бинарное совместимое изменение в тело метода, то скомпилироваться должен только Service. Но в действительности компилируется весь проект.

Чтобы вывести результат сразу в Gradle, воспользуемся опцией listFiles для Java компиляции. Она записывает все компилируемые файлы.

tasks.withType(JavaCompile) {
 options.listFiles = true
}

Скомпилируем исходные Java-файлы с помощью JDK компилятора, вызвав задачу compileJava. Как правило, ее запускают с задачей build или assemble .

./gradlew compileJava

Наконец, можем увидеть все скомпилированные файлы:


> 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

Почему так происходит?

Дело не в Gradle и его работе. Полученный результат  —  ожидаемое поведение Java. Ведь двоичная совместимость не влияет на список компилируемых исходных файлов.

Все объявления, которые должны быть импортированы в исходный код, создают зависимость кода. Таким образом, исходный код Client1 зависит от метода m2 и m3, хоть он и не вызывает их. Поэтому, изменяя код m2 или m3 в классе Service, Client1 будет еще раз скомпилирован, несмотря на то, что он не менялся.

Принцип разделения интерфейса спешит на помощь

Принцип разделения интерфейса следующий: ни один клиент не должен вынужденно зависеть от методов, которые он не использует.

Применим его и создадим для каждого метода отдельный интерфейс, который предоставит определенному клиенту только то, что ему нужно. Ниже проиллюстрирована структура:

Теперь еще раз внесем бинарное совместимое изменение в тело m3 класса Service и скомпилируем проект.

./gradlew compileJava

Вот оно!

> Task :compileJavaSource files to be compiled:/ISP_java/src/main/java/com/jurcik/ivet/service/Service.java

Скомпилировался только Service.

Что насчет Kotlin?

Компилятор Kotlin достаточно умный. Отслеживая изменения с помощью двоичного интерфейса приложений, он перекомпилирует только измененные файлы. Однако он не отменяет принцип SOLID, а лишь упрощает его выполнение.

Заключение

Каждый разработчик, знакомый с ООП наверняка слышал о принципах SOLID. Мы регулярно применяем их по несколько раз, не замечая этого. Несмотря на то, что они глубоко укоренились у нас в голове, им стоит уделять особое внимание. Ведь они не ограничены лишь архитектурой системы. 

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Iveta Jurčíková: Compile less with SOLID

Предыдущая статья5 советов о браузерных инструментах разработчика
Следующая статья5 полезных функций JavaScript, которые знакомы не всем