Nine Steps to Start a Software Project

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Гибкость или её отсутствие не важны, проект по созданию программного обеспечения начинается с анализа и определения требований. Мы, в общем-то, определяем, что нужно сделать, каким-то образом, будь то на кусочке салфетки или в 100-страничном документе Word. Следующим шагом является превращение этого в работающее программное обеспечение как можно быстрее и с минимальными затратами. В идеале, этот прототипирование занимает неделю и выполняется архитектором, работающим в одиночку. Как только “скелет” готов, мы начинаем добавлять к нему “мясо” программного обеспечения. Для этого мы нанимаем команду программистов или передаем работу на аутсорсинг. Я вижу девять важных шагов в создании “скелета”; позвольте мне показать их по одному.

Давайте использовать некоторые примеры, чтобы это было более наглядно. Предположим, что я являюсь архитектором программного обеспечения, а проект - это “убийца Google”. Нас наняли, чтобы создать новый поисковый движок, и моя задача - превратить требования в прототип, также известный как “скелет” или доказательство концепции. Вот что у меня есть в качестве входных данных (предположим, это кусок салфетки… что еще может быть для “убийцы Google”, верно?):

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

Я не буду обсуждать, как создается программное обеспечение в конкретном техническом стеке. Это не важно для этой статьи. Сейчас важно то, как будет “укомплектована” моя программа. Другими словами, что я передам команде программистов после недели тяжелой работы - что является моим продуктом, или более формально, моими результатами.

Таким образом, давайте предположим, что мне удалось создать программное обеспечение, и оно работает.

Прежде всего, мне необходимо задокументировать свои ключевые технические решения и их альтернативы. Мы обычно работаем в GitHub, и лучшим средством документации является файл README.md в корневом каталоге репозитория. Я просто размещаю свой текст там в обычном формате Markdown. Этого достаточно для хорошего технического документа - он должен быть кратким; это важно.

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

Эти решения очень высокого уровня, но мне всё равно нужно их задокументировать. Как видите, я не объясняю подробно, почему альтернативы были отклонены, и это мой выбор. Если кто-то в будущем поставит под сомнение мои решения, они могут сказать, что альтернативы не были должным образом проанализированы. Будет ясно, чья это ошибка — моя. Поэтому я полностью несу ответственность за эти два выбранных мною варианта: Lucene и Java 8.

Ещё один пункт в списке:

Затем я прикрепляю простую диаграмму, чтобы проиллюстрировать свое решение:

[Lucene] -down- [UI] [Lucene] - [Scraper] [Analyzer] - [Lucene]

Как вы видите, в этом случае я полностью проигнорировал все альтернативы. Я даже не упомянул их. Опять же, я полностью несу ответственность за это; я сказал: “Я не вижу никаких альтернатив”. Если позже будет обнаружена лучшая альтернатива, будет очевидно, почему мы ее упустили и чья это была вина. Здесь не только речь идет о наказании, но и о дисциплине и прослеживаемости решений. Каждое решение должно быть прослеживаемо до человека, который его принял. Это помогает нам избегать плохих решений в будущем и делает весь проект более поддерживаемым и прозрачным.

Добавим еще одно решение в список:

В данном случае я задокументировал альтернативные варианты и объяснил, почему они нам не подходят. Как видите, причины очень субъективны; я в основном выразил свое личное мнение о трех этих фреймворках и определенно отдал предпочтение своему собственному открытому фреймворку Takes. Это хорошо? Нет, не очень. Но я - архитектор, и я делаю то, что считаю правильным для проекта.

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

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

Следующая глава в файле README.md должна объяснить, как я именно смог решить все высказанные в исходных требованиях проблемы. Я уже упомянул, что само собой разумеется, что наша система должна быть такой же быстрой и масштабируемой, как Google. Таким образом, допустим, есть две “проблемы” - производительность и масштабируемость.

Как архитектор программного обеспечения, я должен решить обе проблемы. Другими словами, мне нужно доказать, что мое решение быстрое и масштабируемое. Может быть, это не так, но если я считаю, что это так, я должен объяснить, почему я так думаю. Я не могу промолчать о проблемах. Вот что я бы сказал о производительности:

И вот этот пункт касается масштабируемости:

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

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

Как насчет этих двух предположений:

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

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

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

Теперь я перечисляю все потенциальные проблемы, которые я предвижу, и оцениваю их вероятность и влияние. Позвольте мне сначала показать вам пример:

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

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

Теперь мне нужно убедиться, что продукт “упакован” в непрерывную интеграцию, которая является важной составляющей любого программного пакета. Мне нужно настроить ее, предпочтительно в облаке, и убедиться, что сборка чистая.

Также важно убедиться, что непрерывная интеграционная платформа охватывает все критические области, включая:

  • Запуск интеграционных тестов и модульных тестов.

  • Анализ статический.

  • Сбор данных о покрытии тестами.

  • Генерация документации.

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

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

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

Он называется “статическим”, потому что не требует запуска программного обеспечения. Напротив, модульные тесты проверяют качество программного обеспечения во время выполнения приложения.

Существует множество инструментов для статического анализа, для практически каждого языка и формата. Я настоятельно рекомендую использовать их. Более того, я рекомендую настраивать их как можно строже, чтобы сделать сборку максимально хрупкой. Хрупкость сборки является ключевым фактором успеха в разработке программного обеспечения.

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

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

Независимо от того, насколько низким является порог, важно, находится ли он под контролем или нет.

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

“Трубопровод” означает, что есть ряд последовательно связанных элементов; например, для Java-приложения:

  • Package JAR file

  • Загрузите файл JAR в репозиторий.

  • Построить сайт JavaDoc

  • Загрузите сайт JavaDoc на Amazon S3.

Я использую Rultor для автоматизации всего процесса и упрощения его запуска, остановки и ведения журнала. Я просто отправляю сообщение “пожалуйста, выпустите сейчас” в тикет GitHub, и продукт упаковывается и развертывается за несколько минут.

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

Моя цель не удовлетворить их, а сделать все возможное в соответствии с требованиями и моим профессиональным пониманием проблемы и бизнес-сферы. Я уже писал об этом некоторое время назад: “Счастливый босс - ложная цель”. Снова, моя цель не сделать их счастливыми. Вместо этого, моя цель - создать идеальный прототип, так, как я понимаю слово идеальный. Если я провалюсь, значит, провалюсь. Проект найдет другого архитектора и попробует снова.

Вот и все. Скелет готов, и моя работа завершена.

Translated by ChatGPT gpt-3.5-turbo/42 on 2024-01-09 at 18:08

sixnines availability badge   GitHub stars