20.01.2020
Последние несколько лет в сообществе специалистов 1С тема разработки программного обеспечения по промышленным стандартам пользуется огромной популярностью. На тематическом портале Infostart можно найти много публикаций по настройке серверов сборок и статических анализаторов кода, работе с тестовыми фреймворками и прочим инструментарием продвинутого разработчика, призванным улучшить качество кода.
Удивительно то, что при всем внимании к вопросу «как выявлять ошибки?» – а он один из основных, которые успешно решают DevOps-практики, – недостаточно внимания уделяется вопросам архитектуры прикладных решений. Иными словами, мало кто на деле пытается найти и устранить одну из главных потенциальных причин возникновения проблем. Можно было бы предположить, что принципы написания устойчивого кода настолько очевидны, что ими владеет любой специалист 1С и обсуждать тут нечего. Но, к сожалению, практика показывает, что это не так.
Являясь инициатором внедрения DevOps-практик в своей команде, я прекрасно понимаю их важность и нужность, но считаю основной составляющей качественного продукта именно грамотное проектирование. В этой статье хотелось бы поделиться практическим опытом создания решений с модульной архитектурой и описать общие подходы, инструментарий и принципы организации процесса разработки.
Критерии качества архитектуры
Для начала давайте попробуем ответить на вопрос, чем отличается хорошая архитектура от плохой. Так, если в вашей системе:
· добавление новой функциональности приводит к проблемам в работе существующих функций;
· появление новых требований к системе чаще всего приводит к длительным и дорогостоящим доработкам;
· тяжело распараллелить работу разработчиков;
· проблематично использовать уже написанный ранее код;
то это говорит о наличии архитектурных ошибок.
Например, в нашей практике был забавный случай, когда параллельно на проекте работали два разработчика, и один из них вносил изменения, ломающие функциональность у другого. Тот, в свою очередь, исправлял появляющиеся баги, но это приводило к тому, что отваливалась функциональность у первого разработчика. Оказалось, что на момент, когда эта коллизия была выявлена, прошло уже несколько итераций процесса отладки.
На сегодняшний день не существует «чудо-инструментов», с помощью которых можно было бы автоматически выявлять архитектурные ошибки, хотя некоторые метрики статического анализа могут косвенно указывать на наличие соответствующих проблем. Поэтому можно сказать, что признаками хорошей архитектуры являются, во-первых, гибкость, т. е. возможность внесения изменений в существующую функциональность с небольшими трудозатратами и невысокими рисками возникновения ошибок; во-вторых, возможность повторного использования уже написанного кода; и в-третьих, масштабируемость процесса разработки, которая позволяет сократить время разработки за счет привлечения в проект дополнительных разработчиков.
В идеале программа с правильно реализованной архитектурой превращается в своего рода конструктор, который состоит из набора взаимодействующих между собой блоков. А это, в свою очередь, означает достаточно высокую степень ее модульности.
Декомпозиция
Краеугольным камнем грамотного проектирования является декомпозиция, т. е. разделение сложного объекта или процесса на несколько простых частей. И в большинстве случаев под термином «архитектура» подразумевается именно результат декомпозиции.
Разделение единого программного решения на несколько относительно независимых подсистем позволяет разработчикам получить ряд преимуществ. И не важно, разрабатываете вы конфигурацию с нуля или, что чаще бывает, занимаетесь доработкой типовой конфигурации, – декомпозиция поможет вам избежать лишних часов непродуктивной работы, боли и страданий.
Так, при корректном осуществлении декомпозиции системы снижается сложность каждой из выделенных подсистем, а соответственно, улучшается понимание написанного кода и упрощается его поддержка. Кроме того, появляется возможность распараллелить работу групп разработчиков, и тогда каждая из них работает над своей независимой подсистемой с минимальным риском затронуть код, написанный другой группой. Наконец, становится возможным повторно использовать уже разработанные подсистемы за счет того, что они получаются относительно независимыми друг от друга. Например, можно взять и перенести в другой проект требуемую функциональность, не боясь, что это потребует переноса большого количества ненужных зависимых объектов метаданных.
Далеко не всегда существует единственно верное решение вопроса грамотной декомпозиции, что зачастую является весьма творческой задачей. По этой причине нельзя автоматизированно проверить правильность архитектурного решения. Часто понимание приходит на практике, когда в процессе разработки выясняются новые подробности и внезапно появляются новые требования.
Тем не менее общие принципы «правильной» декомпозиции сформулировать можно, и выглядят они так:
· выделяемые подсистемы должны быть минимально связаны друг с другом;
· каждая подсистема должна быть сфокусирована на решении одной узкой проблемы, а не заниматься выполнением разнородных функций или не связанных между собой обязанностей;
· подсистемы должны как можно меньше «знать» друг о друге.
Программный интерфейс
Как же реализовать данные принципы на практике? Для этого нужно понимать еще несколько важных вещей.
Как уже говорилось выше, подсистемы конфигурации должны разрабатываться исходя из принципа их минимального «знания» друг о друге. В то же время этим подсистемам необходимо взаимодействовать между собой, для чего используются экспортные процедуры и функции, специально предназначенные для сторонних потребителей. В идеале любое получение данных из другой подсистемы должно производиться через программный интерфейс, который скрывает от пользователя подробности внутренней реализации. И если эта реализация будет изменена, то не возникнет необходимости переписывать код, в котором используются данные этой подсистемы.
Нам приходилось сталкиваться с ситуациями, когда доработки типовых конфигураций выполнялись без использования существующего программного интерфейса. Это приводило к неработоспособности решения после очередного обновления, когда разработчики типовой конфигурации изменяли внутреннюю структуру хранения данных в своих подсистемах.
Переопределение
Для того, чтобы совместить возможность повторного использования уже реализованных подсистем с возможностью изменять и дополнять их функциональность, стандартами 1С заданы так называемые «переопределяемые» объекты, т. е. объекты метаданных, которые разработчики подсистемы предоставляют для изменения. Типичным примером таких объектов являются переопределяемые общие модули.
Рассмотрим для примера организацию процесса разработки по модульному принципу, имевшую место в одном из наших проектов. Для того, чтобы ее осуществить, нам потребовалось провести некоторые организационно-технические изменения. И к тому моменту, когда мы озадачились вопросами модульности, у нас уже был создан инструмент для обработки всего многообразия рутинных операций, неизбежно возникающих при таком подходе. Подробно этот инструмент описан в статье infostart.ru/public/1113324.
Кроме того, было очевидно, что для написания кода, который будет использоваться многократно, нужно серьезно отнестись к контролю качества этого кода. Естественным решением стало определение зон ответственности для архитекторов отдельных подсистем. Как правило, эту роль выполняют специалисты, непосредственно проектирующие и разрабатывающие данные подсистемы. Они, во-первых, анализируют бизнес-требования на доработку и чаще всего занимаются проектированием технических решений, а во-вторых, всегда имеют возможность проконтролировать вносимые изменения и при необходимости не допустить их попадания в основную ветку разработки.
Именно потребность контроля изменений была для нас основной причиной перехода на систему контроля версий Git. При использовании этого инструмента становится гораздо проще проводить рецензирование кода (code review). Кроме того, появляется возможность не допустить нежелательных изменений, защитив основную ветку разработки от непосредственного применения сторонних изменений: все изменения сторонних разработчиков вносятся через соответствующие запросы архитектору на слияние (т. н. мердж-реквесты).
На портале Infostart описаны различные способы подружить Git и 1С. Самый распространенный, наверное, – это автоматический перенос изменений из хранилища в Git с использованием библиотеки Oscript. Но такая схема работы предполагает, что Git в основном используется как архив, в котором можно быстро посмотреть сделанные изменения, а не как полноценная среда Git-flow с несколькими ветками разработки и мердж-реквестами. По этой причине мы принципиально отказались от использования хранилища, при этом ведя разработку в конфигураторе. В целом мы внимательно следим за развитием интегрированной среды разработки 1C: EDT, но пока не готовы полноценно переходить на эту IDE.
Далее, нужно понимать, что code review - это потенциальный источник конфликтов в команде, и даже сама идея того, что реализованные доработки могут быть отвергнуты, может вызвать негативную реакцию – один наш коллега, например, назвал полицейским подходом схему, при которой изменения в основной ветке чисто технически нельзя произвести без акцепта архитектора. Возможно, придется приложить некоторые усилия для того, чтобы донести до коллег мысль о том, что профессиональный разработчик ПО – это не свободный художник, а специалист, который должен соблюдать регламенты и уметь работать в команде. Необходимое и достаточное условие для этого – наличие политической воли.
Тем не менее именно возможность контроля позволяет быстро изменить мотивацию разработчика с «побыстрее закрыть задачу» до «выполнить задачу качественно». Так, в нашем опыте организации модульной разработки, представленном выше, оказалось достаточно нескольких отклоненных мердж-реквестов с обсуждением допущенных ошибок, чтобы подход участников проекта к написанию кода чудесным образом поменялся. Для нас одним из признаков того, что это произошло, стало значительное увеличение количества обсуждений задач с архитектором именно до, а не после начала разработки. Как оказалось, это позволяет минимизировать количество кода, не прошедшего процедуру рецензирования.
Кроме того, при всем понимании важности качественного проектирования не стоит забывать, что такие работы требуют выделения соответствующих ресурсов. Если результатом работы разработчика обычно является вполне конкретная функциональность решения, которую можно «пощупать», то результатами работы архитектора являются постановки задач разработчику, в которых он лишь описывает техническую реализацию поступивших бизнес-требований. В процессе формирования этих постановок архитектору приходится проводить аналитическую работу, пытаясь сформулировать оптимальное решение поставленной задачи. Но в целом эта работа приводит к увеличению общих трудозатрат на решение бизнес-задачи, что, в свою очередь, может потребовать обоснования роли архитектора в процессе. Действительно, зачем сидеть и рисовать какие-то квадратики со стрелочками, когда можно просто писать код? Зачем вводить дополнительное звено между разработчиком и аналитиком, увеличивая время решения задачи?
Отвечая на эти вопросы, я часто вспоминаю ситуации, с которыми регулярно сталкиваюсь во время езды за рулем по городу, когда по соседней полосе меня обгоняет другой автомобиль и уносится вдаль… а потом мы с ним вместе стоим на светофоре. В таких ситуациях хорошо понятно, что по большому счету неважно, насколько большую скорость можно развить на отдельных участках пути, если это не поможет быстрее добраться до конечной цели.
Если провести аналогию, то проект внедрения 1С – это поездка из точки А в точку В, в которой важно, во-первых, прибыть в назначенное место, и во-вторых, прибыть вовремя. А для этого важнее и безопаснее правильно спланировать маршрут, чем обладать навыками гонщика. Тот факт, что вы можете быстро решить отдельные задачи, совсем не означает, что вы сможете уложиться в сроки и не превысите бюджеты. Поэтому нужно мыслить с точки зрения успешности проекта в целом, а не конкретных его этапов. При таком подходе обосновать затраты на проектирование значительно проще.
Модульная разработка: что еще почитать
1. Официальная документация 1С («Система стандартов и методик разработки», раздел «Разработка и использование библиотек»);
2. Хорошая статья о принципах проектирования архитектуры систем: https://habr.com/ru/post/276593/. Кстати, там содержится и большое количество полезных ссылок на другие ресурсы по теме;
3. Если еще не используете в своей разработке инструментарий Git, но хотите его изучить, то советую начать с прочтения вот этой книги: https://git-scm.com/book/ru/v2;
4. Для того, чтобы внедрение code review принесло пользу и не стало источником раздора в команде, рекомендую изучить методики и лучшие практики его проведения. В Сети много статей по этой теме, например https://habr.com/ru/post/473308/.