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



Книга Компилируем меньше с 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. Мы регулярно применяем их по несколько раз, не замечая этого. Несмотря на то, что они глубоко укоренились у нас в голове, им стоит уделять особое внимание. Ведь они не ограничены лишь архитектурой системы. 


855   0  

Comments

    Ничего не найдено.