Принципы программирования: расшифровываем аббревиатуры

Перевод статьи «10 Coding principles and acronyms demystified!».

Принципы программирования

Если говорить об аббревиатурах, в индустрии разработки программ вы их встретите в больших количествах. Тут KISS (англ. «поцелуй»), там SLAP (англ. «шлепок») — названия интригующие, но какие-то бессмысленные. Если вы только начинаете изучать программирование, подобные словечки, проскальзывающие в пояснениях, могут здорово раздражать. Особенно, если вы не знаете, что они означают! Если это как раз ваш случай, этот пост — для вас!

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

KISS

Начнем с самых популярных. Keep It Stupid Simple («Придерживайся простоты», аббревиатура KISSв качестве отдельного слова означает «поцелуй») это один из самых известных принципов программирования. Значение его довольно понятное, хотя и очень широкое.

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

В качестве примеров нарушения этого принципа можно назвать написание отдельной функции только лишь для осуществления операции сложения или использование побитового оператора (right shift >> 1) для деления целых чисел на 2. Последнее, безусловно, более эффективно, чем обычное (/2), но при этом очень сильно снижается понятность кода. Применяя такой подход, вы осуществляете clever coding («заумный» кодинг») и over-optimization (чрезмерную оптимизацию). И то, и другое в долгосрочной перспективе не слишком хорошо сказывается на здоровье вашего кода.

DRY

Принцип Don’t Repeat Yourself («Не повторяйся», аббревиатура DRYв качестве отдельного слова означает «сухой») по своей природе очень похож на принцип KISS. Он тоже имеет довольно простое, но широкое значение.

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

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

Принцип "сухости"

YAGNI

YAGNI это определенно самая длинная аббревиатура в нашем списке. Принцип You Aren’t Gonna Need It («Тебе это не понадобится», YAGNI) может противоречить точке зрения некоторых программистов.

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

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

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

SLAP

Только представьте: код можно не только поцеловать (KISS) и высушить (DRY), но также и шлепнуть (SLAP)!

Single Level of Abstraction Principle («Принцип единого уровня абстракций», SLAP) диктует нам, как мы должны организовывать свой код (в частности, функции), чтобы он оставался поддерживаемым.

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

«Функции должны выполнять только одно действие, но выполнять его хорошо» (Роберт Мартин).

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

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

SRP

Single Responsibility Principle («Принцип единой ответственности», SRP) в чем-то похож на SLAP, но направлен на объектно-ориентированное программирование. Этот принцип гласит, что объекты и классы (а также функции и методы) нужно организовывать так, чтобы каждый из них имел только одну зону ответственности.

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

Как справиться с этой проблемой? Скажем, наш контроллер отвечает за компьютер. Он должен контролировать температуру CPU, скорость вентилятора, дисковое пространство, внешние устройства и т. п. вещи. Имейте в виду, что это означает не только свойства, но и методы, с которыми мы взаимодействуем. Как насчет того, чтобы создать несколько классов вместо того чтобы хранить все напрямую в одном классе? Так у нас появляются DevicesController, DiskSpaceController и т. д. А после мы можем использовать все эти классы, чтобы составить высокоуровневый класс Controller, который теперь будет куда проще поддерживать. Конечно, в реальности подобный код потребует куда большей организации, но, я надеюсь, идею вы уловили.

OCP

Мы уже говорили о расширяемости кода, когда обсуждали YAGNI. Open-Closed Principle («Принцип открытости-закрытости», OCP) некоторым образом связан с предыдущим правилом, но представляет собой другой взгляд на вещи.

Принцип открытости-закрытости

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

Получается, OCP конфликтует с YAGNI? Ведь это две противоположные точки зрения на будущее нашего кода! Нет, это не так.

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

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

LSP

Liskov Substitution Principle («Принцип подстановки Барбары Лисков», LSP) назван в честь его автора, Барбары Лисков. Это принцип объектно-ориентированного программирования, касающийся классов, интерфейсов, типов и подтипов.

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

ISP

Interface Segregation Principle («Принцип разделения интерфейса», ISP) это еще один принцип, затрагивающий тему организации кода. Он главным образом касается интерфейсов и статически типизированных языков программирования. Т.е., люди, пишущие код на JavaScript, не часто будут сталкиваться с применением этого принципа на практике. Тем не менее, знание этого принципа в любом случае способствует улучшению кода.

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

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

Обособление кода и интерфейсов

DIP

Как и OCP, Dependency Inversion Principle («Принцип инверсии зависимостей», DIP) в большей степени касается общей архитектуры вашего кода. Фактически, это один из самых важных принципов проектирования архитектуры кода.

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

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

SOLID

Пять принципов, которые мы уже обсудили — SRP, OCP, LSP, ISP, DIP — вместе составляют набор принципов SOLID, описанный Робертом Мартином. Эти принципы способствуют созданию хорошего объектно-ориентированного (и не только) кода.

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

[customscript]techrocks_custom_after_post_html[/customscript]

[customscript]techrocks_custom_script[/customscript]

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх