SOLID
#программирование

SOLID. Что значит S

Давайте поговорим о том, что такое SOLID? Наверняка вы читали книгу «Чистый Код» Роберта Мартина (как это не читали???) и вам уже давно известно, что это такое. Да и в интернете есть множество статей на эту тему. Однако же, мне, как и большинству других разработчиков, постоянно приходится работать с грязным кодом, который можно улучшить. Возникает парадокс – если все знают правила написания хорошего кода, откуда берется код плохой? В следующем блоке постов я хочу кратко рассказать, как я понимаю каждый из принципов SOLID, и, что самое главное – как мне это помогает писать более понятный и чистый код. Никаких научно-занудных объяснений. Все максимально просто, кратко и на примерах. Сегодня поговорим о том, что значит S в аббревиатуре SOLID.

S значит SRP

А SRP значит Single-Responsibility Principle. Что, в свою очередь, переводится как «принцип единой ответственности». Занудное и чисто теоретическое (но более полное) описание этого принципа можете прочитать на википедии.

SRP на примере. Аркадий в деле

Итак, у нас есть класс Employee:

public class Employee {}

Разработчик Аркадий смотрит-смотрит на этот класс и не понимает, а чего он пустой-то? Ну и решает он добавить метод writeCode() (реализация опущена):

public void writeCode() {
  // ...
}

Немного подумав и почесав затылок, Аркадий исправляет название метода на writeGoodCode(). Потому что Аркадий — хороший разработчик!

Иннокентий негодует

Тестировщик Иннокентий, проходя мимо рабочего стола Аркадия, бросает быстрый взгляд на его монитор и замечает, что Employee только пишет код и совсем не тестирует его.

«Ну ты, Аркаша, и растяпа», – замечает Иннокентий и просит последнего исправить ситуацию. Аркадий соглашается и добавляет соответствующий метод (реализация снова опущена):

public void test() {
  // ...
}

Довольный Иннокентий с чувством выполненного долга уходит в закат. И вроде бы все хорошо, но тут…

Появляется Савелий Петрович

А Савелий Петрович, между прочим, менеджер проекта. И, как оно обычно и бывает, он коршуном налетает на бедного Аркадия и просит его «добавить фичку для клиента» в обход спринта. Внезапно Савелий Петрович замечает, что класс Employee совсем не занимается управлением командой, и просит добавить аж ТРИ метода.

Вспотевший Аркадий добавляет в класс Employee:

public void planSprint() {
  // ...
}

public void addLittleFeature() {
  // ...
}

public void manage() {
  // ...
}

Савелий Петрович вдруг замечает тестировщика Иннокентия, и фокус его внимания быстро съезжает с нашего бедного Аркадия. Казалось бы, можно передохнуть, но внезапно…

Приходит Люська из аналитики

И вот в класс Employee добавляется Люськин метод:

public void analyze() {
  // ...
}
А затем…

Появилась ОНА. Аксинья Всеволодовна из отдела уборки. «А полы мыть кто будет?» – Грозно прорычала она, отобрала у Аркадия компьютер и самовольно добавила:

public Garbage cleanUp() {
  // …
}

Аркадий, слегка придя в себя, робко спросил: «А зачем метод уборки что-то возвращает? Почему он не void?». Аксинья Всеволодовна будто ждала этого вопроса и гаркнула еще громче: «Да чтоб вы свой мусор все обратно получили, собаки вы сутулые!»

Что в итоге?

А в итоге класс Employee выглядит следующим образом:

public class Employee {

  public void writeGoodCode() {
    // ...
  }

  public void test() {
    // ...
  }

  public void planSprint() {
    // ...
  }

  public void addLittleFeature() {
    // ...
  }

  public void manage() {
    // ...
  }

  public void analyze() {
    // ...
  }

  public Garbage cleanUp() {
    // ...
  }

}

Похоже на SOLID? Как вам SRP?

Кто-то скажет, что Employee – типичный fullstack, который умеет делать все на свете. Однако, задумайтесь, нужен ли вам такой fullstack?

Чем это чревато?

Допустим, уборщица Аксинья Всеволодовна прошла курсы по повышению квалификации, и теперь ей доступна тряпка более высокого уровня. Вследствие этого, мы с вами идем в класс Employee и меняем реализацию метода cleanUp().

А затем наш разработчик Аркадий резко встал со своего места, воскликнул: «Да ну нах*р!» и удалился восвояси. Заместо него пришел другой разработчик, Акакий, который уже не такой опытный и пишет не такой хороший код. Поэтому мы снова идем в класс Employee и меняем название метода writeGoodCode() на writeCode().

А ведь у нас есть еще тестировщик Иннокентий, аналитик Люська и менеджер проектов Савелий Петрович – помните? Если хоть что-то деталях их работы изменится, нам снова нужно будет идти в класс Employee.

В общем, ребята, наш супер-класс на самом деле является вонючей помойкой, куда не навалил всякой логики только лентяй. Надо ли нам поменять метод уборки помещения или же метод написания кода – мы лезем в этот класс. Поменять метод тестирования? Снова в этот класс. 

Представьте, что Employee – это вы, и ваш основной профиль – разработка. Вот вы сидите, пишете код, и тут приходит менеджер проектов и говорит: «Спланируй спринт на следующую неделю». Потом приходит аналитик и говорит: «Сделай спеку по такой-то задаче, а потом сам по ней напиши код». И под конец рабочего дня приходит уборщица: «Там унитаз засорился, а у тебя пальцы-то гибкие, иди прочисть».

И вы просто не понимаете, зачем вы должны все это делать, ведь у вас конкретный и узкий профиль. Так же и Employee не понимает, зачем вы пихаете в него все, что не лень.

Как итог – у этого класса нет единой области ответственности, и он берет на себя слишком много. SOLID и особенно SRP тихонько негодуют в сторонке. Задачи (методы), описанные в этом классе, по-хорошему должны быть распределены на весь отдел. Давайте теперь посмотрим, как все должно быть по уму.

И тут приходит Здравый Смысл

И тут же падает в обморок от увиденного. Но уборщица Аксинья Всеволодовна выливает на него ушат холодной и грязной воды, и Здравый Смысл приходит в себя.

Он говорит: «Ребята, у вас тут не соблюдается принцип единой ответственности, также известный как SRP» и тут же начинает исправлять ситуацию и делать код более SOLID.

Метод, который отвечает за написание кода, он выносит в класс Developer:

public class Developer {
  public void writeCode() {}
}

Немного подумав, Здравый Смысл замечает, что Developer должен еще и фиксить баги, поэтому он добавляет новый метод в тот же класс Developer:

public class Developer {
  public void writeCode() {}
  public void fixBug() {}
}

«Отлично!», – восклицает Савелий Петрович, – «Теперь вся логика по разработке и багфиксу сосредоточена в одном месте!»

Здравый Смысл согласно кивает и создает класс ProjectManager:

public class ProjectManager {
  public void planSprint() {}
  public void addLittleFeature() {}
  public void manage() {}
}

Немного погодя, он удаляет метод addLittleFeature(), и Савелий Петрович в слезах удаляется. Но это уже тема для отдельного разговора.

Здравый Смысл, тем временем, не отдыхает и создает новые классы:

public class Tester {
  public void test() {}
}

public class Analyst {
  public void analyze() {}
}

public class Cleaner {
  public void cleanUp() {}
}
Что стало лучше?

Здравый Смысл сажает всех вокруг себя и говорит следующие золотые слова:

Теперь у каждого из вас есть своя зона ответственности. Акакий, если тебе нужно будет добавить новый метод или изменить существующий, ты пойдешь в класс Developer. И тебя больше не будут просить прочистить унитаз! Иннокентий, ты у нас теперь только тестируешь, и твой класс называется Tester. Люська сидит в Analyst, поэтому для изменений в ее работе вам следует отправиться именно туда. Савелий Петрович, ваша работа теперь заключена в классе ProjectManager, и никаких больше маленьких фич! Ну а вы, уважаемая Аксинья Всеволодовна, теперь сосредоточены в Cleaner, и не смейте больше свои обязанности скидывать на бедного Акакия! Давайте соблюдать SRP! У каждого из вас теперь своя зона ответственности!

Все встают и отправляются заниматься своей работой.

И это далеко не все

Представьте, что Здравый Смысл не приходил, и наш класс Employee по-прежнему выглядит ужасающе. 

И вдруг случается так, что уборщица в офисе этажом выше приболела, и они попросили на время нашу Аксинью Всеволодовну. А она, на самом-то деле, добрейшей души бабка, и не может отказать людям в беде. 

А так как она часть Epmloyee, то она заодно хватает с собой всех остальных: Акакия, Иннокентия, Люську и Савелия Петровича. И вот они приходят в офис этажом выше. Аксинья Всеволодовна приступает к работе, а остальные стоят вдоль стены и молча смотрят.

А теперь давайте перейдем к коду. Допустим, есть класс Office, и ему необходим только один метод: cleanUp().

Выглядит он как-то так:

public class Office {
  private final Employee employee;

  public Office(Employee employee) {
    this.employee = employee;
  }

  public void cleanUp() {
    employee.cleanUp();
  }
}

Возникает вопрос – если классу нужен лишь один метод cleanUp(), зачем ему объект, который, кроме этого метода, содержит еще кучу других, никак с уборкой не связанных? Иными словами, руководство офиса недоуменно смотрит на Акакия, Иннокентия, Люську и Савелия Петровича, которые как идиоты стоят у стены и смотрят, как Аксинья Всеволодовна убирается.

Вот как бы выглядел класс Office после визита Здравого Смысла:

public class Office {
  private final Cleaner cleaner;

  public Office(Cleaner cleaner) {
    this.cleaner = cleaner;
  }

  public void cleanUp() {
    cleaner.cleanUp();
  }
}

Просили уборщицу – пришла уборщица. Одна. Без кучи лишних зависимостей. Все ясно и понятно.

Вывод

Следуй здравому смыслу. Не нарушай SRP.

Понравилось? Подписывайтесь на меня в соцсетях!

 
Twitter
VK

guest
0 Комментариев
Inline Feedbacks
View all comments
Social media & sharing icons powered by UltimatelySocial
0
Нравится? Оставьте комментарий!x
()
x