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

Эта статья является частью серии статей о том, «Как мы применяем методы и принципы серверной части на интерфейсе с помощью JavaScript в Teknasyon».

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

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

За время своей карьеры я заметил, что написание кода или использование библиотеки / фреймворка - это простая часть, но этого недостаточно. Написание чистого и понятного кода - сложная часть, но это веселее, особенно если мы понимаем основы программирования.

Эти проблемы не новы, и компания Teknasyon не единственная, кто их создает / создает. Написание масштабируемого кода - очень старая проблема, поэтому каждый должен знать или хотя бы прочитать о SOLID и шаблонах проектирования, которые являются проверенными решениями основных проблем в программном обеспечении, мы должны знать, какие проблемы решает каждый шаблон, а затем, когда мы видим проблему мы знаем, какие инструменты у нас есть.

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

Каков план?

Сначала мы поговорим о SOLID, SoC и шаблонах проектирования в целом и познакомимся с такими концепциями. Затем мы перечислим примеры кода для этих концепций во внешнем интерфейсе с помощью JavaScript / TypeScript. Конечно, мы не можем перечислить все доступные шаблоны проектирования, потому что их слишком много, мы упомянем только основные.

Разделение проблем и шаблонов проектирования будет опубликовано в отдельной статье.

Мы пропустим тесты здесь, потому что они не являются основной темой данной статьи.

Краткое введение в SOLID:

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

Краткое введение в разделение ответственности (SoC):

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

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

Разделение проблем - это разделение кода для каждой из этих проблем. Изменение интерфейса не должно требовать изменения кода бизнес-логики, и наоборот.

Краткое введение в шаблоны проектирования:

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

Принцип единой ответственности (SRP):

У класса должна быть только одна причина для изменения.

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

Этот принцип гласит, что у каждого класса должна быть одна цель, одна и ТОЛЬКО одна причина для изменения.

Давайте посмотрим на следующий класс:

Сейчас все выглядит нормально, но на самом деле нет! Смешивать логику вычислений с представлением - плохо, потому что это противоречит принципу единой ответственности (SRP).

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

Методы рисования и поворота относятся к другому объекту - рендерингу изображения квадрата. Так что здесь тоже высокий уровень сплоченности.

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

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

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

Не бойтесь создавать новые курсы.

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

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

Принцип открытого-закрытого (OCP):

Компоненты программного обеспечения должны быть закрыты для модификации, но открыты для расширения.

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

Взгляните на следующий пример:

Теперь, когда мы хотим добавить поддержку нового метода оплаты, мы должны открыть этот файл и добавить новый оператор «если»! Это не так хорошо, и это нарушает принцип открытого-закрытого.

Вместо этого мы можем переопределить метод «pay» в классе Payment, предоставив правильный вывод для всех способов оплаты, без изменения исходного кода:

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

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

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

Принцип замещения Лискова (LSP):

Введен Барбарой Лисков в 1980-е годы.

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

Так что это связано с наследованием, например, если у нас есть класс Bird, и Ostrich расширяет этот класс, но вы знаете, что страус не может летать! Таким образом, мы получим ненужный метод полета.

Взгляните на следующий код:

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

Реализовать это можно так:

Принцип замещения Лискова является третьим из принципов ТВЕРДЫХ принципов разработки Роберта К. Мартина. Он расширяет принцип открыто-закрыто и позволяет заменять объекты родительского класса объектами подкласса, не нарушая работу приложения.

Нереализованные методы всегда указывают на недостаток дизайна. Мы не можем использовать объект Ostrich / Duck везде, где мы используем объект Bird. Если он выглядит как утка и крякает как утка, но для этого нужны батарейки, вы, вероятно, ошиблись абстракцией!

Принцип разделения интерфейса (ISP):

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

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

Пример нарушения кода интернет-провайдера:

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

Использование нескольких интерфейсов вместо одного жирного интерфейса помогло нам предотвратить нарушение принципа SoC и принципа единой ответственности.

Принцип инверсии зависимостей (DIP):

A. Модули высокого уровня не должны зависеть от модулей низкого уровня, оба должны зависеть от абстракций.
B. Абстракции не должны зависеть от деталей, детали должны зависеть от абстракций.

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

Пример кода:

NiceHouse верхнего уровня зависит от класса «Alarm» нижнего уровня:

Чтобы следовать DIP, класс NiceHouse должен ссылаться на интерфейс (IAlarm), который реализуется объектом HouseAlarm:

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

Стоимость написания хорошего кода:

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

На это нужно время

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

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

Вы сделали это 🤗

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

Наша следующая тема - разделение проблем с помощью JavaScript / TypeScript, следите за обновлениями и берегитесь.