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

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

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

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

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

Создание команды

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

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

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

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

Приоритет требований

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

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

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

Дизайн для публикации

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

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

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

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

Тестирование и доставка

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

Во-первых, как и в любом проекте, необходимы автоматизированные тесты. Для общих компонентов им необходимо протестировать все API. Обязательно нужно проверить общее использование компонентов. В некоторых случаях может иметь смысл имитировать использование конкретного проекта, если существуют уникальные способы интеграции клиента или клиентов. Модульные тесты запускаются как часть сборки, и сбой в ней не позволит опубликовать сборку в области выпуска, чтобы клиенты могли ее забрать. Однако могут быть интеграционные тесты, в которых используется несколько компонентов. Для этого необходимо где-то разместить сборку, чтобы интеграционные тесты могли собрать связанные сборки и протестировать их вместе. Если сборки не должны быть доступны клиентам до тех пор, пока не пройдут тесты интеграции, то рекомендуется публиковать сборки изначально в что-то вроде «последней» директории. Интеграционные тесты будут извлекать из «последней» директории, и, если они пройдут, эта сборка будет переведена в «последнюю_принятую» директорию. Затем клиенты обычно выбирают только из каталога «latest_accepted», чтобы быть уверенным, что они получают только сборки, прошедшие все тесты.

Заключение

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

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

Если вы являетесь или знаете талантливого инженера-программиста, который вам подойдет, узнайте, как присоединиться к команде Tenable Sensors Shared Infrastructure!