Статьи

Девять шагов для запуска программного проекта

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

Название изображения

Ин сюн (2002) Имоу Чжан

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

Each page is ranked by the number of mentions in
social networks like Twitter, LinkedIn, Facebook, etc.
The more mentions it has, the higher the rank and the
higher its position in the search results page.

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

Я не собираюсь обсуждать, как программное обеспечение создается в определенном техническом стеке. Это не важно для этой статьи. Теперь важно то, как моя работа по программированию будет «свернута». Другими словами, что я передам команде программистов после недели кропотливой работы — каков мой продукт, или, более формально, мои результаты .

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

Решения и альтернативы

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

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

Apache Lucene is a search engine. It is popular,
  mature enough, scalable, and written in Java. Alternatives
  are Solr, Sphinx, Gigablast, and many others.
Java 8 is a programming language, and JVM is a
  runtime platform. I know how they work, and the team
  has enough experience with them. Alternatives are
  Ruby, Python, Go, Scala, and tons of others.

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

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

Three modules make up the app: UI, scraper,
  and analyzer. They are fully decoupled and
  communicate strictly through Lucene. I don't
  see any alternatives.

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

UML

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

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

Takes Framework is used for UI. It helps keep our
  code truly object-oriented, testable, fast, and
  decoupled from the data model. Alternatives:
  - Spring: It is big, complex, and ugly
  - Play: Similar to Spring, big and ugly
  - Spark: Not as clear as Takes

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

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

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

Обеспокоенность

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

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

The system is as fast as the Lucene search engine, while
Lucene is rather fast even with large amounts of data.

И это о масштабируемости:

The bottleneck is in Lucene, and it is scalable
vertically. Not sure about horizontal scalability.

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

Предположения

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

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

1. I assume that social platforms won't block our
   calls and will provide counters for all pages.
2. I assume that Lucene will be enough for both
   indexing and data storage, so we won't need a
   database engine.

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

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

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

риски

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

1. Lucene may not be able to handle billions of documents [6x9]
2. Social platforms will ban our requests [8x9]

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

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

Непрерывная интеграция

Теперь я должен убедиться, что продукт «обернут» в непрерывную интеграцию, которая является критическим компонентом любого программного пакета. Я должен настроить его, желательно в облаке , и убедиться, что сборка чистая.

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

  • Сборка на нескольких платформах, таких как Linux, Windows и Mac.
  • Запуск интеграционных и юнит-тестов.
  • Анализировать статически.
  • Сбор тестового покрытия.
  • Генерация документации.

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

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

Статический анализ

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

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

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

Тестовое покрытие

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

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

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

Непрерывная доставка

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

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

  • Запустить автоматическую сборку (так же, как при непрерывной интеграции)
  • JAR-файл пакета
  • Загрузить файл JAR в хранилище
  • Создать сайт JavaDoc
  • Загрузить сайт JavaDoc на Amazon S3

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

принятие

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

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

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