[Перевод] Мой подход к реализации крупных технических проектов

xhmpmy1afva52d05le7wt7ov0vq.jpeg

Источник

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

Нам всем знакомо это чувство восторга в начале нового проекта. Первые несколько недель тебе не терпится сесть за компьютер, чтобы приступить к работе. Затем постепенно начинают возникать различные отвлекающие факторы, или ты сам находишь причины для того, чтобы уделять проекту меньше времени. Если речь идёт о заказной работе, то ты с трудом всё же её завершаешь, но каждый очередной день вызывает боль. Если же это был просто хобби-проект ради развлечения, то ты оглядываешься на него спустя несколько лет и представляешь, чего мог бы тогда достичь.

Я понял, что когда я разбиваю собственные крупные задачи на части, которые позволяют видеть ощутимый прогресс, то с большей тягой иду к завершению проекта и сохраняю в течение всего этого времени интерес. Для разных людей требуются разные подходы к мотивации, так что в вашем случае такой метод может не сработать. Тем не менее, если говорить в общем, то я ещё не встречал ни одного инженера, которого бы не вдохновляло хорошее демо первых результатов его работы. Так что важной целью является регулярное получение таких удачных демо.

Я не стану преподносить содержание этой статьи как нечто новое. Мой опыт определённо несёт в себе различные аспекты хорошо известных практик разработки или менеджмента. Я лишь хочу поделиться тем подходом, который использую при реализации масштабных технических задач, и пояснить, почему следую именно ему.

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

Отдельно уточню, что не хочу кого-либо пристыдить за незавершение проектов. Если вы получаете удовольствие и чувствуете удовлетворённость (или вам просто пофиг), могу вас поздравить. Но эта статья нацелена на людей, которые хотят более эффективно продвигаться к завершению своих проектов или просто желают узнать, как это удаётся мне.


▍ Стартовая точка


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

В случае упомянутого эмулятора терминала я понимал, что есть ряд крупных компонентов, без которых проект никак не состоится: парсинг терминала, запуск процесса оболочки и управление им, отрисовка шрифтов, сетки, обработка ввода (клавиатура/мышь) и так далее. На пути к завершению изначального проекта присутствуют сотни относительно больших подпроектов.

Если бы моей изначальной целью было получение запускающегося терминала, способного выполнять Neovim, то у меня возникли бы существенные неприятности. Даже при неизвестных неизвестных эта цель звучит слишком масштабно. Я интуитивно осознаю, что на этом пути стоит множество компонентов: отрисовка GUI, запуск процессов, парсинг терминала и управление состояниями. Ввиду своей масштабности такая цель окажется неудачной, и по прошествии одного-двух месяцев я наверняка потеряю к ней интерес.

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

  • Парсинг VT — парсинг управляющих последовательностей терминала.
  • Отрисовка пустого окна — открытие окна и отрисовка пустого холста.
  • Запуск дочерних процессов — запуск дочерней оболочки вроде bash, zsh, fish, настройка подсистемы TTY и получение возможности считывать из неё вывод (то есть приглашение изначальной оболочки).


На этой стадии я не пытаюсь перечислить все крупные подпроекты — я просто получаю некоторое представление итоговой структуры проекта и нахожу такую, которую смогу создать отдельно, попутно наблюдая определённые результаты работы.

На этой фазе очень важен опыт. Наиболее опытные инженеры обычно способны более эффективно сформировать примерное представление итогового проекта. Они могут более точно определить различные подкомпоненты и увидеть, как они сочетаются друг с другом. Если же опыта не хватает, или приходится работать в незнакомой области, я просто строю догадки, и вероятность того, что в какой-то момент я заброшу проект, повышается.


▍ Первые результаты


В начале работы обычно трудно получить ощутимые видимые результаты. К примеру, если я решаю работать над парсингом VT для терминала, то не могу пронаблюдать результат, пока не прикручу какой-нибудь UI. Также в некоторых проектах бывает, что если я решаю работать над базой данных и минимальным API, то аналогичным образом не могу увидеть результаты приложенных усилий без написания клиента вместе с CLI или GUI.

Если изначальный выбранный вами подпроект представляет работу над UI, то вы, естественно, сможете пронаблюдать результаты быстро. Тем не менее по ряду причин я редко начинаю с фронтенда — обычно сначала берусь за серверную часть. И вы в любом случае в конечном итоге тоже доберётесь до бэкенда, столкнувшись с аналогичными сложностями.

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

Это даёт ещё один ориентир для выбора первых задач: если они не являются графическими, то лучше выбирать такие, которые можно будет без лишних хлопот протестировать и увидеть какие-то результаты.

Для своего терминала я решил начать с парсинга VT, так как он являлся частью терминала, когда я ещё мало о нём знал, и мне казалось, что результат можно будет легко протестировать — передать в качестве ввода пример строки в ожидании получить на выходе результат парсинга или событие.

Меня очень вдохновляет наблюдение прогресса в таком виде:»1 тест пройден»,»4 теста пройдено»,»13 тестов пройдено» и так далее. Я выполняю написанный код, и он работает. В итоге я понимаю, что продвигаюсь в создании некоего критического подкомпонента крупного проекта.

▍ Скорейшая реализация демо


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

Этот компромисс проявляется не только в функциональности. Он может быть проявлен в алгоритмических или структурных аспектах. К примеру, вы можете знать, что в будущем потребуется использовать что-то вроде реальной БД или особой структуры данных, либо поддерживать потоковую передачу данных. Но для начального объёма работы вы можете просто использовать содержимое памяти, встроенные структуры данных вроде словарей и требовать все входные/выходные данные заранее.

Я думаю, что это важный компромисс, поэтому повторю его: не позволяйте идеализму препятствовать прогрессу. Продвигаясь вперёд, не давайте будущим доработкам, которые вы предвидите, мешать вам перейти к очередной задаче. Ваша цель — получить демо.

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

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

Напомню, что для терминала в качестве первой задачи я выбрал парсинг VT. На ранних этапах я видел в работе только автоматизированные тесты. Для получения первого демо я создал скрипт оболочки, который должен был выполнять команду, получать её вывод, передавать его парсеру VT и выводить всё, что тому удавалось (или не удавалось) спарсить. С течением времени я доработал этот инструмент командной строки в качестве своего первого «UI» — сетку терминала я отрисовывал с использованием ASCII.

Это дало мне невероятное удовлетворение, поскольку я смог выполнять простые команды вроде man или ls, а также более сложные программы вроде vim и наблюдать, как мой парсер работал (или давал сбой, что по-своему тоже вдохновляет).

В этом сценарии создаваемый мной инструмент командной строки долго оставался относительно бесполезным (в итоге я его довольно быстро забросил). Но день или два, которые я потратил на создание его в качестве демо, дали мне важное чувство прогресса, а видимый результат работы помог мне сохранить мотивацию.

▍ Создавайте для себя


Эта часть будет больше применима к личным проектам, нежели к рабочим. Даже если вы собираетесь выпустить некое ПО для других, создавайте только то, что вам нужно по мере необходимости и вводите в эксплуатацию свои программы как можно быстрее.

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

В случае моего терминала это означало, что изначально мне нужно будет реализовать загрузку конфигурации оболочки (fish), и уже на основе этого реализовать возможность запускать и использовать Neovim. Поэтому я нацеливал всю свою работу на получение только необходимой для этого функциональности: только используемых этими программами управляющих последовательностей; отрисовки только того шрифта, который я использую постоянно, и так далее. В качестве примера функционала, который я изначально опускал, можно назвать прокрутку, выбор мышью, поиск и прочее.

Затем я начинал использовать свой терминал в повседневной работе. На этом этапе обычно присутствует несколько фальстартов. Вы осознаёте, что нуждаетесь в функционале, который опустили или забыли реализовать. Во время первых запусков терминала я понял, что не назначил для клавиш курсора никаких действий, увидел тонкие (но нарушающие рабочий поток) баги отрисовки и так далее. В итоге я перестал его использовать, но зато понял, какие конкретные задачи нужно реализовать далее.

Кроме того, я всегда чувствую гордость, используя программное обеспечение с написанным мной кодом, и это обычно помогает мне сохранять мотивацию для продолжения работы над ним.

▍ Подведём итоги


  1. Разбивайте большую задачу на меньшие. Здесь важно, чтобы для каждой подзадачи присутствовал отчётливый способ пронаблюдать результаты проделанной работы.
  2. Поочерёдно решайте небольшие задачи, которые позволят поэтапно получать демоверсии общей большой задачи.
  3. Решайте минимум небольших задач, необходимый для создания рабочих демо вашего ПО, после чего переходите к реализации дополнительной функциональности. Создавайте демо как можно чаще.
  4. Отдавайте приоритет функциональности, которая позволяет начать использовать собственное ПО, если это возможно (в личных проектах или рабочих, решающих и вашу задачу). Затем продолжайте в первую очередь реализовывать собственные задачи.
  5. При необходимости возвращайтесь и дорабатывайте каждый компонент.


▍ Заключение


Вот, собственно, и всё. Я следую этой общей схеме в личных, групповых, рабочих, школьных проектах и при реализации прочих процессов, благодаря чему мне удаётся долго сохранять мотивацию.

Заметьте, что я многое не упомянул. К примеру, я не говорил о поставке продукта. Я знаю многих людей, которые находят этот этап реализации мотивирующим. Не думаю, что вам необходимо поставлять продукт для того, чтобы он получился успешным. Лично я считаю поставку слишком крупным событием для долгосрочного поддерживания во мне мотивации. Я не говорю об инструментах (рабочих потоках Git, CI и так далее). Я использовал свой подход на многих должностях и подгонял его под любой устоявшийся рабочий поток.

Думаю, здесь очевидно, насколько личным является этот процесс. На мой взгляд, всем необходимо найти некий метод, который будет подкреплять их мотивацию. Я понял, что меня сильно мотивирует наблюдение реальных результатов и выработал на основе этого свой стиль, который до сих пор отлично мне помогает.

hc88sbzi7apcmcvqt2icby4azas.jpeg

© Habrahabr.ru