Из меня вышел чертовски ленивый блогер. В начале января читал Фаулера "Рефакторинг. Улучшение существующего кода", что повлекло немало мыслей в моей голове. В общем и целом Фаулер повествует о том как некрасивый код делать удобным и красивым. Как менять дизайн в лучшую сторону если он не так хорош как мог бы быть. Книжка составлена как сборник рецептов на подобии если видите "это", то надо сделать "то". Пока читал книжку делал заметки, как минимум себе на память как максимум как исходник для статьи. Прошло пол года, а написать написать статью мне все лень. Посему выложу слегка отформатированные заметки.
Мысли по первым двум главам.
О Производительности:
Улучшение существующего кода - это палка о двух концах и если на одной стороне улучшение производительности кода(мы делаем его более удобным для машины), то на другой стороне рефакторинг(мы приводим код к виду удобному для чтения и понимания человеком).
Почти всегда? если вы боретесь за производительность пострадает понятность кода. И наоборот.
Как бы то ни было до появления проблем с производительностью, проведения профилирования, не всегда можно сказать какой участок кода тормозит. Даже если и кажется, что узкое место в цикле - то есть много НО. Мы не знаем как часто выполняется цикл, сколько обычно в нем итераций происходит и сколько времени каждая итерация занимает.
О Проектировании:
При проектировании и написании кода стоит писать код реализующий только требуемую функциональность, не надо предполагать еще 50 возможностей которые могли бы быть полезны заказчику. Проектируем и реализуем только то, что требуется для выполнения требуемых функций. Важно чтоб все возложенные на разрабатываемую систему обязанности были формализованы, например в UML или в любой другой, понятной(!) для всех участников проекта, форме. Вот и причина формализовать юз кейсы, чтоб не реализовывать лишнего, не загружать архитектуру потенциальными возможностями, которые ,возможно, никогда не будут реализованы.
О Формализация требований к системе:
Вообще, думаю оптимизации нужно вносить как отдельный этап процесса разработки. Вносить вместе с формализацией требований к производительности и скорости работы системы.
Если всерьез задумывать о требованиях к создаваемой системе, то нужно рассматривать все виды требований как функциональные, так и не функциональные. Подробнее тут.
О предварительном подробном проектировании архитектуры:
Можно придумывать дизайн(в смысле проектирования, а не графического представления) системы так, чтоб ее архитектура легко переживала изменения требований. Это будет очень гибкая архитектура. Но ее реализация будет крайне запутана, потому что архитектура построена не только для того, чтоб выполнить требуемую функциональность, но и для того чтоб предоставить возможность быстро достичь гипотетических целей, которые могут появится в дальнейшем, а могут и не появится. Обычно такая гибкость лишняя, все равно потребуется только малая часть потенциальной функциональности. Малая часть потенциальной энергии системы перейдет в кинетическую. Система умеет петь, плясать и строить дома. А нужно чтоб она просто прошла из пункта А в пункт Б.
О процессе разработки:
Если планировать рефакторинг системы как часть процесса разработки, можно выбрать самый простой дизайн, который просто отвечает требованиям системы и который легко рефакторить, а не раздувать архитектуру кучей потенциальных возможностей. В дальнейшем, если потребуется - проводить рефакторинг и менять дизайн в нужную сторону. В первом случае риски изменений требований к системе закрывались за счет раздутого дизайна, во втором случае за счет запланированного рефакторинга.
Этап рефакторинга может быть совмещен с код ревью(когда кто то другой читает твой код, проверяет тебя) и применен как применение замечаний ревьюера. Должен согласовываться с требованиями к культуре кода.
Оптимизацию стоит выделить в отдельный этап, этот этап должен быть после рефакторинга(а этот после написания компонента подсистемы) и согласовываться с требованиями к производительности.
Хозяйкам на заметку. Примеры рефакторинга:
Когда ты реализуешь конструкцию switch она должен основываться на твоих данных(на данных класса в котором этот switch используется), а не а чужих. Если используются чужие данные - стоит переместить метод со swith в другой класс, если метод не только делает switch, тогда можно выделить switch в отдельный метод который будет вызываться на его месте. Если в свиче используются данные, то часть из них лучше передавать параметром, так свич будет меньше расепухать если будет меняться логика
Сегодня мы узнали много нового:
Рефакторинг - это улучшение архитектуры. Архитектура хороша когда классы слабо связанны и повторно применимы. Copy-Paste исключен! Каждый раз, когда читаешь какой либо запутанный код - думай, как улучшить архитектуру, т.е. провести Рефактонинг. Так ты не просто разберешься в этом коде, но и сделаешь его понятней для следующих читателей. Слабая связанность кода достигается декомпозицией. Декомпозиция, так или иначе заключается в делегировании обязанностей класса или части метода другому классу или методу. Вообще, мне кажется, что каждый класс и метод должны предоставлять атомарные операции, ели это не так - выделять их в отдельные классы... Хотя если много мелких классов можно получить проблему организацией взаимодействия классов и передачи данных между ними.
Определение:
Рефактонинг - это управляемое и эффективное приведение кода в порядок.
Цель:
Упростить понимание и модификацию программы. Антипод рефакторинга - оптимизация.
Прочее:
- Когда планируется архитектура программы на заданные требования к функциональности, стоит предполагать как могут изменится требования и планировать архитектуру так, чтоб рефакторить было удобно.
- Когда разбираешься в чужом коде, пытаешься понять как он работает,, лучше всего сразу рисовать структурные и поведенческие диаграммы UML, вы все равно занимаетесь реверс инженирингом, так хоть оставляйте хоть какой-то след от проделанной работы. В этом случае другие угробят меньше времени на понимание программы и ее модификацию. А еще лучше сразу рефакторить плохо написанные куски кода. При подобном применении рефакторинга возникает проблема с отсутствием тестов. Значит нужно сразу писать и тесты на прочитанный кусок системы. А для этого придется понять все требования к данной подсистеме и осмыслить, что система должна делать (! Это самый ответственный участок). Тесты должны проверять корректность выполнения требований и быть согласованными с архитектурой системы у плане интерфейсов.
- Публичный разбор, превью кода и дизайна может быть хорошей практикой. Море критики из которой будет выбрана конструктивная. Возможно, разбирать код сам по себе смысла нет, но разбирать подробный дизайн подсистем реализующих функциональность полезно.
- Час времени на рассказ требований и дизайна который их реализует - это приемлемые затраты для команды разработчиков. Выигрыш очевиден - все участники становятся в курсе новых подсистем в проекте и особенностей их реализации.
- Единственная причина почему систему нужно переписывать с нуля, а не рефакторить - это неработоспособность системы. При рефакторинге предполагается, что система работает.
40802f89-8492-4408-b5ae-b3241a9304d3|1|4.0
Refactoring, Architecture
архитектура, процесс разработки, refactiring, deploiment