Вступление:
И так здравствуйте меня зовут Крючков Владимир Вячеславович. Сегодня я хочу поднять актуальный и фундаментальный вопрос в процессе разработки – Слабое связывание и Высокое сопряжение/зацепление. Узнаем что из себя представляет спагетти-код и как от него избавиться. И в конце приведу 7-8 принципов для создания хорошего и качественного кода в разработке.
Подготовьтесь! Выпейте кофе, чай с сахаром или шоколадом, чтобы взбодриться и приготовьтесь поглощать информацию.
Я снабдил каждый важный слайд картинкой, подходящий под описание и хочу, чтобы у вас закрепилась данная ассоциация) А еще лучше если вы станете применять некоторые принципы в своей повседневной работе.
О чем речь?
Речь пойдет о фундаментальных принципах проектирования и разработки программного обеспечения. Многие вещи программисты делают по наитию, через опыт, а мы сегодня попробуем структурировать и приложить к методологии эти знании.
На самом деле это принцип взят и теории ООП. Эти два принципа входят в аббревиатуру GRASP. В 1С нет как таковы классов, но описанные принципы можно применить и к языку 1С Enterprise.
Шаблоны GRASP.
Это два шаблона из GRASP (англ. general responsibility assignment software patterns — общие шаблоны распределения ответственностей).
Их всего девять. Некоторые выделяют 5 основных и 4 дополнительных.
- Информационный эксперт (Information expert)
- Создатель (Creator)
- Контроллер (Controller)
- Слабое связывание (Low Coupling)
- Высокое сопряжение (High Cohesion)
- Полиморфизм (Polymorphism)
- Чистая выдумка (Pure Fabrication)
- Посредник (Indirection)
- Устойчивость к изменениям (Protected Variation)
Мы сегодня поговорим про два из них – слабое связывание и высокое сопряжение.
Что за сущность класс в 1С?
Прежде чем продолжим давайте попробуем провести некоторую аналогию с классом и будем называть ее сущность. К сущности я отношу набор понятий и каждый раз может меняться в зависимости от ситуации.
- Обработка (реквизиты, ТЧ, модуль объекта)
- Комбинацию из общих модулей и объектов метаданных (справочники, документы, регистры)
- Отдельный общий модуль, отдельный объект метаданных
- Расширения – вот это на текущий момент самая близкая аналогия
И так начнем!
Слабое связывание.
Картинка у вас надеюсь вызывает ассоциацию перехода от клубка запутанных и ветвистых нитей к их упорядочиваю и переходу. Попробуйте себя ассоциировать с тем человечком «программистом», достигшим просветления :-)
Проблема
И так у нас есть проблема, задача. Она может быть сформулирована следующим образом:
Как обеспечить независимость, незначительное влияние изменений и повысить возможность повторного использования?
Мы хотим получить код/архитектуру решений более независимую от влияния изменений и повысить возможность повторного использования.
Что значит независимую от влияния изменений – это значит если мы хотим поправить в некоторой маленькой функции маленький кусочек кода, то это должно быть без довеска необходимости менять все файлы конфигурации.
Пример: все знают БСП? Вот я вспоминаю один случай, когда они изменили местоположение функции «Текущий пользователь» из общего модуля «Общего Назначения» в «Пользователи», то пришлось перелопатить всю конфигурацию, когда мы накатывали обновление БСП, т.е. они нарушили принцип «открытый/закрытый» об этом речь пойдет ниже.
Что значит повторное использование кода – это значит, что я пишу функцию или процедуру не для одного случая и называю ее «Получить Реквизит Сумма Заказа Клиента», а «Получить Реквизиты Объекта». В результате я смогу вызывать ее многократно и не писать каждый раз новый код, замусоривая конфигурацию (вспоминаем про рефакторинг).
Решение.
Требуется распределять обязанности, чтобы степень связанности осталась низкой.
I) Слабая связанность.
Что такое слабая связанность?
Это мера на сколько жестко связан один элемент с другими, либо каким количеством данных/информации обладает о других элементах.
Ниже приведу примеры по типу плохо и хорошо.
Найди нужную нить!
Если элементы сильно связаны, то любое их изменение приводит к изменению во всех связанных объектах. Слабо проследить нить решения?
Возможен взрыв мозга.
Особенно в некоторых ситуациях. И я думаю вы встречались с ситуацией, а фиг его знает, что там происходит, давайте напишем в стороне? И тем самым мы добавляем еще одну нитку в этот клубок.
Если все распутать
Чем меньше элемент знает о соседях, тем лучше.
Но вот котику видимо не понять. Уверен, что первая ситуация с клубком нитей - его работа!
Проблемы высокой связанности.
Идем дальше и поговорим о высокой связанности. И к основным проблемам высокой связанности можно отнести следующие утверждения:
- Изменения в других модулях/объектах приводят к изменению в локальном текущем и наоборот.
- Затрудняет понимание каждого модуля в отдельности
- Усложняет повторное использование, так как требует анализа взаимосвязей
Сильное связывание. Пример.
Посмотрите на пример и увидите одну из самых плохих ситуаций, которые вызывает следование принципу создание высоких связей в коде. Оба модуля переплетены максимально и взывают функции и процедуры из друг друга. А теперь представьте, что этих модулей 1000 как в ERP!
Лучше слабое связывание. Пример.
Смотрим на картинку ниже и видим, что перекрестные ссылки исчезли. Появилась прозрачность и исчезла запутанность для понимания кода и последовательности операций.
Хочу отметить, что четкого требования делать все слабо связанно нет, но стремиться к такой ситуации необходимо всегда.
Сущности, которые являются достаточно общими по своей природе и с высокой степенью вероятности будут повторно использоваться в дальнейшем, должны иметь минимальную степень связанности с другими сущностями.
II) Высокая сопряженность.
И так вторая сущность — это высокая сопряженность или зацепление – перевод с английского. Текущая заставка должна направить ваше мышление на то, о чем пойдет далее речь.
Проблема
Рассмотрим проблему/задачу, сформулированную следующим образом:
Как обеспечить возможность управления сложностью?
Хотим обеспечить возможность управления сложностью? Звучит фантастически, но хорошо)
Что понимаем под сложностью? Это то на сколько тяжело выглядит ваш код и вообще вся структура – сколько из него торчит костылей и потрачено скотча, сколько мегабайт весит все это чудо, сколько функций и объектов в нем утонуло.
Решение.
Распределять обязанности, поддерживающие высокую сопряженность/зацепление (сгруппированность).
Сильное сопряжение. Определение.
Сопряженность/зацепление (в основном функциональное зацепление) – это мера связанности и сфокусированности обязанностей.
Т.е. у нас есть группировка по функциональному (самый оптимальный), логической, структурной и др. принципу.
Пример Бардак.
Представьте себе магазин, в который вы пришли за покупками (пончики, лимоны и кофе). А у них пронесся ураган, и вместо сгруппированных по полочкам и отделам/рядам стеллажам валяется как попало и вперемешку. И вот в этом бардаке вам надо найти лимон, кофе и пончики. А магазин размером с АШАН?
Ваш код тоже похож на вот это?
Порядок.
Но лучше все же так. Вон видите указатель на кофе, а вон бакалея и пончики!
Слабое сопряжение проблемы.
Слабое сопряжение привносит нам следующий перечень проблем:
- Трудность понимания
- Сложность при повторном использовании
- Сложность поддержки
- Ненадежность, постоянная подверженность изменениям
Пример код слабая сопряженность.
Смотрим и видим, что не понятно какую функциональную обязанность выполняет данный модуль, всего понемножку. На мой взгляд этот общий модуль должен называться как «Общий модуль. Помойка», согласны?
Выдохнули. Немного котиков, чашку чая, отвлекитесь.
Сейчас было тяжело. Не так конечно, как мне вчера в 23 часа вечера, но тоже не просто) Вопросы? Передохнули? Продолжаем?
Как вы думаете к чему приведет использование антирекомендаций – сильное связывание и слабое сопряжение? Смотрите ниже, чтобы знать ответ.
III) Спагетти код и распутывание
Спагетти код и макаронная архитектура.
Ага это спагетти код и макаронная архитектура - «bone appétit».
Рецепт
И так вот вам рецепт хороших макарон, но плохого кода.
Распутываем. Иерархическая декомпозиция.
Всегда есть решение по распутыванию, но лучше делать сразу хорошо. Самый простой и эффективный способ - это иерархическая декомпозиция. Что это значит?
Сначала код разделяется на несколько больших частей – к примеру, подсистем. Далее эти подсистемы дробятся на более мелкие сущности. В процессе дробления происходит перегруппировка связей, иногда можно ввести некоторого посредника на которого замкнуть все эти связи.
Распутываем. Модульность.
Известный факт, что одни из самых лучших систем – это системы, обладающие модульностью. Это свойство системы, разбитой на множество модулей с высокой сопряженностью и низкой связанностью.
Распутываем. Дао хорошей разработки.
И так переходим к заключительной части. Это некоторые правила хорошего тона, которые вы должны помнить и всегда вспомнить при разработке кода. Я специально нашел картинки и придумал/нашел ассоциации чтобы они вам запомнились.
Поехали…
1) Будь скромным
Не вставляйте на показ процедуры, функции, переменные, объекты и данные.
К примеру, мы сделали экспортную в модуле формы или глобальную переменную. Теперь ее начали использовать в коде и что получаем? Если мы захотим ее переименовать, то придется менять ее вызовы и использование во всех точках кода!
Правильно сделать экспортную функцию, которую вызвать. В ООП – это запрет использовать public везде, у нас это экспорт и непосредственное обращение к регистрам и т.д.
Будь скромным. Пример плохой
Вот так делать нельзя. Пример с усилением акцента, но так тоже пишут.
Будь скромным. Пример правильно
Вот так делать правильнее! Используем шаблон наблюдатель.
2) Принцип минимальности.
Идеальная функция, процедура обладает следующими свойствами:
- Один вход и один выход;
- Одна решаемая задача
Принцип модульности, чем из более простых кирпичиков кода будет сложен модуль, тем более понятным и прочным будет здание.
3) Закон Деметры.
Если «А» знает «Б», а «Б» знает «С», то «А» не должна знать про «С».
Это один из принципов противодействия запутыванию кода.
Закон Деметры. Пример
Если модуль «Заказ клиента» вызывает модуль «Продажи», а «Продажи» вызывает модуль «Лимиты», то «Заказ клиента» не должен вызывать функции модуля «Лимиты».
4) Не смотри на медузу Горгону
Смотри на объекты через «зеркало» интерфейсов.
Суть в том, что если ваш код не опирается на подготовленные блоки, а изобилует велосипедами, то он можно сказать «окаменевает», становится тяжелым на изменения.
Не смотри на медузу Горгону. Пример плохой код
Плохо непосредственно обращаться к данным. Т.е. этим образом вы сразу нарушаете принцип слабого связывания.
Не смотри на медузу Горгону. Пример хороший код
Правильно работать через интерфейсы.
5) Разделяй и властвуй.
Используй декомпозицию - разделяй сложные/огромные функции монстры на части.
Не стоит писать мега функции, разделяем на части и получаем профит.
6) Гусь свинье не товарищ.
Процедуры и функции должны группироваться или объединяться по некоторой общности.
Тут думаю понятно свалка и бардак всегда плохо. Высокое сопряжение нам тут поможет.
7) Принцип открытости и закрытости.
Будьте открыты для всего нового в будущем, но не переписывайте прошлое.
Это мой любимый принцип. Суть в том, чтобы при модификации приложений мы не переписывали старые функции, а только добавляли новые. Иными словами, мы должны всегда писать новый код.
8) Мысли паттернами.
Подходите к решению задачи используя готовые алгоритмы и принципы проектирования. Выбирайте подходящий по критериям и начинайте разработку, а не придумывайте что-то свое.
Это также один из основных принципов, мы должны начинать при написании кода автоматически вспоминать, перебирать и подставлять подходящий паттерн под задачу. О них более подробно расскажу позже. Мы покажем действие паттернов на примерах, и убедимся, то что некоторые из них используем неосознанно.
Заключение. Инь и Янь.
Связывание и зацепление — это «Инь» и «Янь» проектирования ПО.
И так как вы поняли, то эти два подхода идут вместе, и они как Инь и Янь. Только с опытом приходит понятие тонкой грани баланса. Для достижения качественного и сбалансированного кода применяйте к разработке принципы, которые мы рассмотрели выше и прибудет с нами сила!
Про качество кода я рассказывал в этих статьях: