В Google у каждой библиотеки (например, libc, OpenSSL, а также библиотеки, разработанные самой компанией, например для поддержания многопоточности в Java) есть свой хранитель, ответственный за то, чтобы она не только компилировалась, но и успешно проходила тесты для всех зависящих от нее проектов, совсем как настоящий библиотекарь. Хранитель также отвечает за перевод каждого проекта со старой версии на новую.
Представьте реальную организацию, пользующуюся 81 версией библиотеки Java Struts. Всех версии, кроме одной, серьезно уязвимы. Поддержка всех этих вариантов — у каждого свои особенности — создает огромную операционную нагрузку. Кроме того, такое большое количество делает обновление версий рискованным и опасным, из-за чего разработчики не горят желанием эти обновления проводить. Порочный круг.
Единое хранилище исходного кода решает большинство этих проблем, и к тому же можно создать автоматизированные тесты, позволяющие командам переходить на новые версии уверенно и безопасно.
Если мы не можем собирать все приложения с единого дерева исходного кода, нужно найти другой способ поддержки хороших версий библиотек и их зависимостей. Например, можно завести единое хранилище, такое как Nexus, Artifactory или репозиторий Debian или RPM. Это хранилище затем необходимо регулярно обновлять, если в репозиториях или в производственных системах будут выявлены уязвимые места.
Распространяйте знания, используя автоматизированные тесты как документацию и механизм обмена опытом
После того как мы создали общие для всей организации библиотеки, стоит заняться быстрым распространением профессиональных компетенций и улучшений. Включение в библиотеки большого количества автоматизированных тестов сделает их самодокументирующимися, и другим инженерам будет легко понять, как они работают.
Если мы внедрили методологию разработки через тестирование (TDD), где тесты пишутся до кода, то такое преимущество мы получим практически без лишних действий. Такой подход превращает наши наборы тестов в актуальную спецификацию системы. Любой сотрудник, желающий понять, как работать с какой-либо системой, может просто взглянуть на набор тестов и увидеть работающие примеры того, как пользоваться API-системой.
В идеале у каждой библиотеки должен быть свой хранитель или своя команда. Они становятся источником знаний о данной библиотеке. Кроме того, в эксплуатации должна использоваться только одна, наилучшая версия библиотеки (в идеальном случае), отражающая накопленные знания и опыт организации.
В этой модели инженер, ответственный за библиотеку, также отвечает и за перевод всех групп, пользующихся его репозиторием, с устаревшей версии на новую. Это, в свою очередь, требует быстрого обнаружения ошибок перехода между версиями библиотеки. Помочь могут исчерпывающее автоматизированное тестирование и непрерывная интеграция для всех систем, использующих ту или иную библиотеку.
Чтобы быстрее распространять знания, можно также создать группы обсуждений или чаты для каждой библиотеки и сервиса. Благодаря этому любой сотрудник, имеющий вопросы, может получить ответ от других пользователей, часто отвечающих быстрее, чем разработчики.
С помощью такого инструмента коммуникации мы облегчаем обмен знаниями и опытом, а сотрудники получают возможность помогать друг другу с проблемами и новыми подходами к разработке.
Определите четкие нефункциональные требования, чтобы при проектировании учитывались пожелания эксплуатации
Когда разработчики следят за судьбой своего продукта после того, как закончили его создание, и участвуют в ликвидации сбоев в производственной среде, сопровождать приложение становится гораздо проще и безопаснее. Кроме того, когда приложения и код сознательно пишутся с расчетом на высокую скорость потока и быстрые развертывания, то появляется возможность сформулировать набор нефункциональных требований, заслуживающих интеграции во все сервисы компании.
Благодаря таким нефункциональным требованиям наши сервисы будет легко развертывать и поддерживать, замечать и решать проблемы будет проще, а при отказе неисправных компонентов система не будет полностью выходить из строя. Примерами нефункциональных требований могут быть:
• достаточный объем производственной телеметрии в приложениях и средах;
• способность четко отслеживать зависимости;
• адаптивные сервисы, способные поддерживать минимум функциональности даже при масштабных сбоях;
Читать дальше