Я - не разработчик игр и с Unity не знаком, но меня зацепил один момент в статье, где архитектура "сражается" с некрасивым, но работающим кодом.
Когда-то в начале своего профессионального пути сильно страдал от того, что голова была забита всякими представлениями о том, как должно быть хорошо (SOLID and etc.) и как можно сразу сделать хорошо (книжка банды четырех).
Каждый раз, когда я садился что-то сотворить новое в коде я городил монстра. Я тратил время, много времени на то, чтобы продумать всё и учесть, как могут развиваться требования в дальнейшем. Код, который получался, был сложным для большинства остальных его читателей, и он частенько был к тому же и избыточным, решал те задачи, которых и не было на самом деле.
В моём окружении часто витала красивая фраза "рефакторинг". Часто кто-то говорил "давайте порефакторим вот это" и иногда в результате этого садились писать рядом ещё одну новую версию того, как обрабатывается какая-то фича в продукте. Я примерно понимал, что значит рефакторинг, но не понимал, является ли это чем-то особым (это просто переписать код, или всё же есть какая-то особая церемония?).
Открытием стала книжка Фаулера про рефакторинг. Дико повезло, что не прошёл мимо неё. Увы, после её прочтения я узнал, что почти никто никогда не занимается честным рефакторингом, даже какое-то время воевал с этим (да и сейчас агитацию за это веду в своём комментарие :) ).
То, что узнал в книжке, я возвёл в некий абсолют, стал использовать непрерывно (да, я ещё и поклонник идей из XP и люблю пробовать идеи проверять в их экстремуме).
И я заметил, что в результате (а я проверял буквально постоянно и на разных проектах, и на пет-проектах, и на рабочем коде, и на katas), идеальная архитектура рождалась самая собой.
Буквально то, как я стал работать, выглядит так:
Есть текущий код (хороший или кривой - не важно)
Есть новое требование/задача
Если хочу, покрываю тестом текущий код (если боюсь его менять, если считаю его хрупким или мутным). По рабочему коду покрыть его тестами несложно, особенно если код понятный. Если код непонятный, то тест будет больше похож на тестирование чёрного ящика, если понятный - то я могу позволить себе более детальные тесты, либо могу позволить себе их не писать. В общем тут стараюсь действовать так: чем дешевле - тем я довольнее, ведь новые тесты - это такой же новый код, я им займусь в пункте 5
Я вкорячиваю новую реализацию минимальными усилиями. Буквально иногда через 100 место в цепочку функций могу спокойно прокинуть доп. флажочек, если так быстрее. Цель: лишь бы это заработало. Если так проще - могу сперва сделать минимальный рефакторинг кода, если это действительно дёшево.
Окунаюсь в рефакторинг. Тут я нахожусь до тех пор, пока не буду полностью удовлетворён, пока не почувствую, что больше не знаю, что тут сделать, либо знаю, что то, что осталось ну уж слишком дорогое и оставит меня на этом месте на час или больше. Возможный критерий останова тут - ощущение, что теперь тест на этот код написать тривиально.
Если хочу (если боюсь, что кто-то сломает написанный код) или того требует долг (обычный процесс разработки), покрываю тестом то, что я только что написал. Как писал выше, теперь это легко сделать.
Да, это звучит во многом похоже на TDD :) Но акцент на том, что ключевое - не тесты, ключевое - не рефакторинг даже, а результат: я не чувствую никаких преград взять и добавить любую новую фичу. Я всегда уверен, что как бы коряво я её не воткнул бы, сам код подскажет мне, а как фича должна в итоге выглядеть с т.зр. архитектуры и качество кода будет на высоте (и читаться будет, и тесты будут).
Кажется, осознанно в подавляющем числе случаев не пишу тесты сначала. Я чувствую, что они обычно сильно фокусируют меня на реализации, на том, как фича должна выглядеть в коде. А этого я в начале не знаю. Поэтому и не TDD.
Поразительно, но в рефакторинге появляются изначально совсем неочевидные (но при этом совершенно логичные) абстракции, которые сходу ты бы не стал предлагать при проектировании.
Сверх этого потом наложились и сплавились воедино другие знания (например, я также позаимствовал себе из Чистого кода Мартина идеи про минимальное возможное число параметров у функций и возводя в абсолют добиваюсь того, чтобы 90% функций не имели бы параметров, а ещё и чтобы 90% функций не имели бы сайдэффектов).
Подход, которым я пользуюсь, смело можно называть "рефакторинг ради рефакторинга" :) Ничуть не стыдно за это, поскольку я вижу, что если преодолеть эту психологическую стену "это ведь не нужно больше рефакторить" и довести до абсолюта, то начинаешь получать пользу. Структура кода адаптируется под то, что нужно в конкретных требованиях и он становится всё более и более выразительным.
Со временем тот новый код, который ты добавляешь становится всё менее и менее корявым (он просто напросто хорошо вкладывается в получаемый доменный язык). Внезапно то, что обычно называют сложной фичей оказывается простым упражнением, да и количество требуемого рефакторинга радикально снижается (ведь основное сделано ранее).
Интересное последствие (как у автора статьи, но наоборот):
К этому подходу я сильно привык. Перестал ощущать, что есть нерешаемые с точки зрения архитектуры задачки вне зависимости от объёма, но при этом архитектуру отвык проектировать. Я скорее стал наблюдать, как она рождается в ходе изменений. И как-то раз, сменив работу, ощутил, что мне просто напросто некомфортно и больно описывать какую-то гипотетическую архитектуру в каком-то документе (это требовалось во многих задачках на новом месте). Ощущение, что топчишься на месте, а не творишь. (Но это стало для меня ценным наблюдением, тоже извлёк для себя выводы и чуть иначе стал относиться к своему подходу).
Ну а если сделать вывод к статье, то думаю, что такой вот любительский геймдев - это отличный полигон для быстрого прототипирования в связке с последующим рефакторингом. Советую пробовать этот поход (и советую почитать Фаулера + потестировать его применять в абсолюте на каком либо петпроекте)
Я - не разработчик игр и с Unity не знаком, но меня зацепил один момент в статье, где архитектура "сражается" с некрасивым, но работающим кодом.
Когда-то в начале своего профессионального пути сильно страдал от того, что голова была забита всякими представлениями о том, как должно быть хорошо (SOLID and etc.) и как можно сразу сделать хорошо (книжка банды четырех).
Каждый раз, когда я садился что-то сотворить новое в коде я городил монстра. Я тратил время, много времени на то, чтобы продумать всё и учесть, как могут развиваться требования в дальнейшем. Код, который получался, был сложным для большинства остальных его читателей, и он частенько был к тому же и избыточным, решал те задачи, которых и не было на самом деле.
В моём окружении часто витала красивая фраза "рефакторинг". Часто кто-то говорил "давайте порефакторим вот это" и иногда в результате этого садились писать рядом ещё одну новую версию того, как обрабатывается какая-то фича в продукте. Я примерно понимал, что значит рефакторинг, но не понимал, является ли это чем-то особым (это просто переписать код, или всё же есть какая-то особая церемония?).
Открытием стала книжка Фаулера про рефакторинг. Дико повезло, что не прошёл мимо неё. Увы, после её прочтения я узнал, что почти никто никогда не занимается честным рефакторингом, даже какое-то время воевал с этим (да и сейчас агитацию за это веду в своём комментарие :) ).
То, что узнал в книжке, я возвёл в некий абсолют, стал использовать непрерывно (да, я ещё и поклонник идей из XP и люблю пробовать идеи проверять в их экстремуме).
И я заметил, что в результате (а я проверял буквально постоянно и на разных проектах, и на пет-проектах, и на рабочем коде, и на katas), идеальная архитектура рождалась самая собой.
Буквально то, как я стал работать, выглядит так:
Есть текущий код (хороший или кривой - не важно)
Есть новое требование/задача
Если хочу, покрываю тестом текущий код (если боюсь его менять, если считаю его хрупким или мутным). По рабочему коду покрыть его тестами несложно, особенно если код понятный. Если код непонятный, то тест будет больше похож на тестирование чёрного ящика, если понятный - то я могу позволить себе более детальные тесты, либо могу позволить себе их не писать. В общем тут стараюсь действовать так: чем дешевле - тем я довольнее, ведь новые тесты - это такой же новый код, я им займусь в пункте 5
Я вкорячиваю новую реализацию минимальными усилиями. Буквально иногда через 100 место в цепочку функций могу спокойно прокинуть доп. флажочек, если так быстрее. Цель: лишь бы это заработало. Если так проще - могу сперва сделать минимальный рефакторинг кода, если это действительно дёшево.
Окунаюсь в рефакторинг. Тут я нахожусь до тех пор, пока не буду полностью удовлетворён, пока не почувствую, что больше не знаю, что тут сделать, либо знаю, что то, что осталось ну уж слишком дорогое и оставит меня на этом месте на час или больше. Возможный критерий останова тут - ощущение, что теперь тест на этот код написать тривиально.
Если хочу (если боюсь, что кто-то сломает написанный код) или того требует долг (обычный процесс разработки), покрываю тестом то, что я только что написал. Как писал выше, теперь это легко сделать.
Да, это звучит во многом похоже на TDD :) Но акцент на том, что ключевое - не тесты, ключевое - не рефакторинг даже, а результат: я не чувствую никаких преград взять и добавить любую новую фичу. Я всегда уверен, что как бы коряво я её не воткнул бы, сам код подскажет мне, а как фича должна в итоге выглядеть с т.зр. архитектуры и качество кода будет на высоте (и читаться будет, и тесты будут).
Кажется, осознанно в подавляющем числе случаев не пишу тесты сначала. Я чувствую, что они обычно сильно фокусируют меня на реализации, на том, как фича должна выглядеть в коде. А этого я в начале не знаю. Поэтому и не TDD.
Поразительно, но в рефакторинге появляются изначально совсем неочевидные (но при этом совершенно логичные) абстракции, которые сходу ты бы не стал предлагать при проектировании.
Сверх этого потом наложились и сплавились воедино другие знания (например, я также позаимствовал себе из Чистого кода Мартина идеи про минимальное возможное число параметров у функций и возводя в абсолют добиваюсь того, чтобы 90% функций не имели бы параметров, а ещё и чтобы 90% функций не имели бы сайдэффектов).
Подход, которым я пользуюсь, смело можно называть "рефакторинг ради рефакторинга" :) Ничуть не стыдно за это, поскольку я вижу, что если преодолеть эту психологическую стену "это ведь не нужно больше рефакторить" и довести до абсолюта, то начинаешь получать пользу. Структура кода адаптируется под то, что нужно в конкретных требованиях и он становится всё более и более выразительным.
Со временем тот новый код, который ты добавляешь становится всё менее и менее корявым (он просто напросто хорошо вкладывается в получаемый доменный язык). Внезапно то, что обычно называют сложной фичей оказывается простым упражнением, да и количество требуемого рефакторинга радикально снижается (ведь основное сделано ранее).
Интересное последствие (как у автора статьи, но наоборот):
К этому подходу я сильно привык. Перестал ощущать, что есть нерешаемые с точки зрения архитектуры задачки вне зависимости от объёма, но при этом архитектуру отвык проектировать. Я скорее стал наблюдать, как она рождается в ходе изменений. И как-то раз, сменив работу, ощутил, что мне просто напросто некомфортно и больно описывать какую-то гипотетическую архитектуру в каком-то документе (это требовалось во многих задачках на новом месте). Ощущение, что топчишься на месте, а не творишь. (Но это стало для меня ценным наблюдением, тоже извлёк для себя выводы и чуть иначе стал относиться к своему подходу).
Ну а если сделать вывод к статье, то думаю, что такой вот любительский геймдев - это отличный полигон для быстрого прототипирования в связке с последующим рефакторингом. Советую пробовать этот поход (и советую почитать Фаулера + потестировать его применять в абсолюте на каком либо петпроекте)