Соло-разработка проекта ПО — непростая задача. Никто не будет подталкивать тебя, проверять код и обеспечивать руководство, ты сам по себе путешествуешь в неизведанное.

Чаще всего неопытные разработчики попадают в одну из следующих ловушек:

  1. Пользуются этим как возможностью наплевать на стандарты качества кода и не уделять внимания формату кодинга.
  2. Делают совершенно противоположное и переусложняют всё намного сильнее необходимого.

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

Примечание: если вы ищете практические советы, то сразу переходите к разделу «Конкретные рекомендации».

Познай своих врагов


Вам нужно избегать двух врагов, и большинство своих взглядов я основываю на этом. Можно даже рассматривать этот раздел как TL;DR статьи.

  1. Сила воли: упрощаете процесс совершенствования

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

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

Вам должно быть «комфортно»


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


Небольшая помощь со стороны IDE запросто может сэкономить вам десятки минут в день

Обычно первым делом мы выбираем IDE (если у нас ещё нет любимой среды). Совершенно необходимо иметь должную поддержку IDE. Вот список наиболее полезных функций IDE, достаточно важных для всех разработчиков и абсолютно необходимых в соло-разработке:

  1. IntelliSense и проверка правописания
  2. Распознавание ошибок и предложения для быстрого исправления
  3. Автоматическая проверка соблюдения стандартов написания кода (linting)
  4. Автоматическая генерация и рефакторинг фрагментов кода
  5. Пошаговый отладчик (который может даже пошагово заходить в библиотеки)
  6. Горячие клавиши для быстрой навигации и изменения кода (быстрый поиск, переименование, документирование и т.п.)

Разумеется, реализовать готовую для продакшена кодовую базу можно даже в vim! Но, увы, только лет через десять.

Автоматизация, автоматизация, автоматизация


Если процесс можно автоматизировать за время, которое меньше, чем время на ручное выполнение процесса в течение трёх месяцев, то автоматизируйте его.

Позвольте продемонстрировать последнее предложение на примере. Если при каждом развёртывании вам нужно тестировать конкретный критический сценарий использования и для этого требуется 5 минут, а вы выполняете развёртывание по 10 раз в месяц, то это стоит 50 минут в месяц (если вы не пропускаете или не забываете этот этап). Значит, за 3 месяца это будет стоить 150 минут, то есть абсолютно приемлемо потратить до 150 минут своего времени на написание автоматизированного сквозного тестирования для этого конкретного сценария, даже если придётся приостановить работу над другими важными делами.

Из всех профессионалов разработчики больше всего должны максимально пользоваться автоматизацией!


Ты не потеряешь свою работу из-за автоматизации, если ты её и программируешь

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

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

В дополнение к правильно организованному тестированию у вас должна быть некая промежуточная среда, как можно более близкая к среде продакшена. Выпуск непосредственно в продакшен в условиях отсутствия бета-тестеров и наличия немногочисленных ценных пользователей может стать катастрофическим событием. Если правильно настроить конвейер CI/CD, то можно легко будет развёртывать в промежуточной среде ветки фич и отлавливать баги, возникающие только в продакшене (проблемы сертификации TLS, неправильной конфигурации, ошибки CORS и т.п.).

Уделяйте внимание безопасности


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

Поэтому убедитесь, что есть способ локального хранения паролей без их коммита в репозиторий. Конечно, их там никто не увидит, однако подчистка репозиториев, перепутанные хэши коммитов и метки версий — это совсем невесело. Кроме того, вдруг ваш сервис git когда-нибудь взломают? Что если вы случайно предоставите доступ тому, кто не должен видеть лишнего? Храните пароли на своей машине в среде, или файлах секретов, или даже в локальных переменных IDE.

Переусложняйте, но в правильную сторону


Учитывая то, что переусложнение (over-engineering) проекта всегда угрожает соло-разработчику, ведь никто его не контролирует, и оно манит количеством времени, которое можно потенциально сэкономить (основная причина всякого переусложнения), давайте подумаем, как смягчить его влияние. Для одиночного разработчика существует два типа переусложнения.

Плохой: всё, что добавляет многословия.

Хороший: всё, что снижает многословие.


Не создавайте подающего масло робота, который хочет, чтобы ему объяснили его предназначение

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

Очень хорошим примером, который вспоминается в первую очередь — это Redux Saga по сравнению Vuex Proxy. Обе являются примерами очень обобщённых библиотек. Но если сравнить использование saga со всеми её многословными определениями и многочисленными слоями и proxy, которая генерирует по запросу мутации при доступе к состоянию… то можно понять, что из них лучше для соло-разработчика или небольшой команды.

Упорядочивайте всё



Делайте всё модульным и стандартизированным, это относится и к самому коду, и к различным сервисам, из которых может состоять проект. Это позволяет сохранять ясность мышления и упрощает привыкание к коду. Вы будете удивлены, что многое сможете делать на автопилоте. Поэтому хороший стиль кода и использование контейнеризации (например, Docker) — ваши лучшие друзья.

Чего делать не нужно


Давайте подробнее разберём то, чего стоит избегать соло-разработчику или небольшой команде:

  1. Держитесь подальше от высокопроизводительных, но громоздких языков и/или фреймворков. Нужно поддерживать минимальный объём кода, потому что вы не можете позволить себе вводить/копировать десятки строк бойлерплейта для получения тривиальной функциональности. Также вам требуется простота отладки и пошагового выполнения любой строки кода. Если сервисом пользуется такое количество пользователей, что требуется подобное повышение производительности, то высока вероятность, что над проектом уже работает большая команда.
  2. Не используйте языки без строгой типизации. Вам нужно как можно чаще замечать ошибки в разработке, и IntelliSense — это огромный плюс, от которого нельзя отказываться. Исключение составляют случаи, когда вы работаете в очень специфической области, в которой даёт выигрыш использование конкретного языка (например, связка машинного обучения и Python). Но даже в этом случае вы всё равно можете пользоваться преимуществами статической проверки типов.
  3. Не переборщите с переусложнением. На мой взгляд, один из лучших способов сделать это — избавиться от всего переусложнения при подготовке проекта и создании самых простых требований к нему.
  4. Не доверяйте своей памяти. Когда вы используете строку на bash или небольшой скрипт для выполнения какой-то задачи, сохраните его и задокументируйте. Можно, например, использовать wiki GitHub или просто файл README. Также удобно хранить в проекте папку «scripts» и использовать скрипты npm/yarn в проектах node.
  5. Не слишком полагайтесь на силу воли.

Вот, например, мои проверенные временем скрипты для проектов node, которые могут послужить демонстрацией пунктов 4 и 5:

"git:commit": "git status && git add -N . && git add -p && sgc",
"git:stash": "git stash --all",
"git:nah": "git checkout . && git clean -df",
"git:amend": "git commit --amend --no-edit",

Конкретные рекомендации


Конвейеры данных/машинное обучение


Используйте для проектов Docker и не очень полагайтесь на то, что ваша личная машина настроена правильно. Даже если вам нужно использовать личную машину (например, локальный GPU), это можно реализовать при помощи локального кластера Kubernetes.

Бэкенд


Как я говорил выше, следует придерживаться языков со строгой типизацией и избегать многословия. Это означает, что Python или Go, вероятно, являются не лучшими вариантами. Лично мне нравится что-то типа C# с Entity Framework благодаря замечательной поддержке IDE (как Rider, так и VS), а также очень чёткой и читаемой архитектуре фреймворка. Если вы можете выполнять большинство задач интуитивно и с небольшой помощью IntelliSense, без необходимости гуглить или читать документацию, то это огромная победа для сочетания языка и фреймворка. Java тоже подходит, если вы мазохист (я сам не большой фанат Java).

Фронтенд (веб-приложения)


При работе в одиночку мне одинаково нравятся Vue и React, при условии, что проект создаётся на основе TypeScript. Однако если требуется серьёзный UI с большим объёмом динамической интеграции с API, и вы при этом работаете один, то определённо стоит выбирать Vue. Если вы используете компоненты классов и компоненты модулей Vuex (при помощи пакета vuex-class-component), то получение и сохранение данных при помощи API становится очень лёгким процессом. Для создания двусторонней привязки в любом компоненте достаточно задать свойство класса! Нет необходимости беспокоиться о мутациях, геттерах, сеттерах и boilerplate-коде. В сочетании с действиями hydrate/save/clear в модуле хранения (при необходимости с хэшем и временной меткой истечения срока действия для кэширования) — это всё, что нужно!

Архитектура


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

  • Вы будете единственным владельцем всех сервисов с полным контролем над тем, чем они являются и что они делают, и это уже позволяет избавиться от большой части проблем, связанных с микросервисами.
  • Можно использовать один инстанс обобщённых сервисов для нескольких приложений (например, для почтовых или push-уведомлений).
  • Если вы совершите где-то ошибку, и она проскользнёт через все меры контроля и войдёт в релиз (у вас ведь нет проектной команды или отдела QA), то не повлияет на целое приложение; прекратится работа или ухудшится производительность только одного сервиса.
  • Можно создавать новые модули приложения, выполняющие другие задачи, не ставя при этом под угрозу стабильность существующих сервисов (допустим, вам нужно, чтобы чат-приложение имело возможность голосовых/видеовызовов).

Кроме того, нужно обеспечить готовность всех сервисов к Docker. Это не только будет означать, что вы запросто сможете развернуть их где угодно и получить копию среды продакшена в промежуточной среде или даже в среде разработки, но вы также можете использовать Kubernetes или AWS ECS, при необходимости масштабируя приложение!

Заключение


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



На правах рекламы


Виртуальные серверы с процессорами AMD EPYC прекрасно подойдут для размещения и разработки крупных проектов, а также соло разработчикам. Частота ядра CPU до 3.4 GHz. Максимальная конфигурация позволит оторваться на полную — 128 ядер CPU, 512 ГБ RAM, 4000 ГБ NVMe.