Я видел множество статей об использовании различных библиотек и фреймворков, чистом коде и методах программирования, но почти ни одной об организации работы разработчика по реализации функции. Поэтому я решил поделиться тем, что работает для меня, и надеюсь, что это поможет кому-то улучшить свой процесс.
Я расскажу, как я анализирую пользовательскую историю, проектирую и реализую решение, а также готовлю запрос на слияние.
В настоящее время я работаю над проектом Android, который следует за вариантом чистой архитектуры с подмодулями Gradle, содержащими функции. Все примеры в статье будут основаны на этом проекте.
Я начинаю с чтения всей истории и просмотра дизайна, чтобы загрузить весь контекст в мою голову. Затем я снова просматриваю историю, но на этот раз перечисляю все, что нужно сделать.
И я имею в виду все , а не только детали реализации.
Нужно добавить копию в инструмент перевода - перечислите ее. Нед, чтобы поговорить с другими командами о некоторых деталях интеграции - перечислите их.
Записи типа «загрузить данные» пока подходят. Позже я буду беспокоиться обо всех деталях (получение данных из API, локальное кеширование, обработка ошибок и т. Д.).
В идеальном мире пользовательские истории, над которыми мы работаем, должны быть достаточно маленькими, чтобы приводить только к нескольким пунктам в списке. К сожалению, в реальном мире это не всегда так.
Затем, со всеми перечисленными высокоуровневыми требованиями, я выбираю некоторые общие детали решения.
Здесь я выбираю, какие компоненты навигации я хочу использовать (в текущем проекте Android мы используем Activity или Fragment, в зависимости от случая) или в какой модуль должен входить код (в нашем случае модули Gradle).
Я заранее принимаю только важные решения, а остальные откладываю как можно дольше. Таким образом, я могу принимать более обоснованные решения, учитывая все дополнительные детали, которые я нахожу по пути .
Если я не уверен, какой подход выбрать, я прошу других членов команды высказать свое мнение - лучше обсудить это сейчас, чем во время проверки кода, когда кодирование завершено.
Другой вариант - быстро запрограммировать грубую реализацию и обсудить «незавершенную работу» пул-реквест - наличие конкретного примера облегчает обсуждение.
Приняв все необходимые решения, я создаю функциональную ветку для всей истории. Я называю его «OA-5» (мы используем ключи задач JIRA в качестве имен веток).
Затем я выбираю ОДИН элемент (т. Е. Загружаю данные) из списка и создаю подветвь для размещения реализации, например «OA-5_load_data».
Как мне решить, какой элемент реализовать? В общем, я сосредотачиваюсь на том, чтобы сначала получить рабочий MVP, а затем расширить его более сложными потоками. Чем быстрее я смогу что-то протестировать, тем лучше.
Второй критерий, который я использую, - начать с архитектурного уровня, который диктует правила:
Я бы начал со слоя, который формирует другие интерфейсы (в нашем случае - уровень домена), или
если мне нужно интегрироваться с неизвестным API, который уже реализован, я бы начал с него (примечание: написание исследовательских тестов - отличный способ познакомиться с API).
Помимо этого, я выбираю то, что хочу реализовать в данный момент.
В другом списке (назовем его подсписком) я отмечаю более мелкие шаги, которые необходимо сделать для завершения пункта «загрузка данных». Подсписок пока не обязательно должен быть полным.
Когда появляются новые вещи, я записываю их, чтобы разобраться с ними позже. Таким образом, я всегда могу сосредоточиться на работе над одним конкретным элементом подсписка.
Я стараюсь, чтобы эти элементы были достаточно маленькими, чтобы их было легко реализовать. Например, «загрузить данные в модель просмотра» на данный момент охватывает только получение записей из интерактора.
Не нужно беспокоиться об обработке ошибок, отображении прогресса или способе отображения данных пользователю. Все это будет рассмотрено в отдельных шагах.
Использование TDD помогает мне эффективно работать с такими мелкими элементами, потому что я могу тестировать их изолированно, не запуская все приложение.
При написании кода я стараюсь сделать его максимально простым, сосредотачиваясь на текущих требованиях и расширяя их по мере необходимости.
Такой подход помогает мне избежать чрезмерной инженерии.
Когда требуется рефакторинг для соответствия дополнительным требованиям, это безопасно и приятно благодаря широкому охвату модульными тестами.
Каждый раз, когда я подтверждаю, что что-то работает, я совершаю коммит. Когда я завершаю элемент, я перехожу к другому в подсписке.
Я следую этому шаблону, пока у меня не закончатся элементы в подсписке.
Затем я готовлю запрос на перенос из подчиненной ветви в функциональную ветку: «OA-5_load_data» -> «OA-5». Таким образом, рецензенты могут просмотреть весь код небольшими частями, которые легче усвоить.
Прежде чем фактически создать запрос на перенос, я прочитал все изменения. Такой этап предварительной проверки упрощает процесс проверки кода. Здесь обнаруживается большинство опечаток и проблем со стилем, и другим разработчикам не нужно на них указывать.
После объединения всех частей я создаю еще один запрос на перенос - на этот раз в ветку разработки: «OA-5» -> «develop». В этом случае рецензенты могут только бегло просматривать код, в основном ища оставшиеся настройки разработчика (ненужные журналы, ярлыки навигации и т. Д.), Поскольку они уже видели весь код раньше.
После объединения этого пул-реквеста функция готова для контроля качества.
Это полная версия процесса, которая помогает мне реализовывать сложные функции за конечное время. Разделение больших функций на мелкие и четко определенные задачи помогает бороться с параличом принятия решений.
К счастью, некоторые истории разбиты на собраниях по уточнению, и полная версия процесса не требуется. В таких случаях я использую его части, например, пропускаю создание подсписок или пул-реквестов WIP.
Как вы могли заметить, этот процесс основан на TDD, описанном Кентом Беком в статье «Разработка через тестирование: на примере». Эта книга, которую я очень рекомендую, определенно изменила мой стиль работы, хотя прошли годы, прежде чем я начал писать тесты.
Если вы узнали что-то интересное, прочитав эту статью, или у вас есть совершенно другой подход к реализации функций, не стесняйтесь делиться в комментариях.