Просить совета у программиста — плохая идея. Но если вы всё-таки решитесь, в ответ услышите что-то типа «сушите код, соблюдайте принцип единственной ответственности, никогда не переписывайте код с нуля».
Если последуете совету сушить код, то есть будете соблюдать принцип DRY, у вас появятся функции с четырьмя булевыми параметрами, а также таблицы, позволяющие отслеживать изменение состояния. Выделение модулей может усложнить отслеживание изменений. А отказ переписывать код уменьшает вероятность сделать удачный продукт.
Справка: выражение «сушите код» произошло от акронима DRY — Don’t repeat yourself, не повторяйся.
Советы выше нельзя назвать изначально неправильными. Но слепое следование этим рекомендациям порождает больше проблем, чем выгод.
В некоторых ситуация лучше делать прямо противоположные вещи: постоянно переписывать код, избегать выделения модулей, повторять код, чтобы не писать всю программу в одной большой функции. Это сложнее, чем слепо соблюдать принцип DRY, но можно попробовать.
Содержание
Игнорируйте принцип DRY, чтобы находить нужные абстракции
Рекомендация соблюдать принцип DRY — трюизм, общая фраза, которая не имеет смысла вне контекста.
Никто не любит писать шаблоны. Программисту скучно работать с банальными задачами. Когда нужно написать один и тот же шаблонный код, скажем, восемь раз подряд, разработчик устаёт до того, как открывает редактор. Поэтому не надо советовать программистам соблюдать принцип DRY. Вместо этого лучше показать, как и когда стоит использовать этот принцип.
Некоторые специалисты интерпретируют принцип DRY как рекомендацию не использовать копипаст, то есть не использовать повторяющийся код. Но лучший способ избежать повторений — не изобретать велосипед заново, то есть не создавать повторно то, что уже существует. К счастью, большинство разработчиков поступает именно так.
Практически каждое веб-приложение нуждается в операционной системе, базе данных и других инструментах. Современные сайты повторно используют миллионы строк кода. К сожалению, программисты хорошо усвоили принцип DRY, который в руках неопытных специалистов превращается в принцип «всегда используй абстракцию».
Под абстракцией в данном случае подразумеваются две связанные вещи. Это идея, которую мы хотим реализовать, и реализация этой идеи с помощью выбранного языка программирования. Абстракции — способ повторения, так что вы можете менять части программы в одном месте. Абстракции помогают управлять изменениями в системе и поведением её компонентов.
При постоянном использовании абстракции вам приходится гадать, какие части кода нужно менять одновременно. Принцип DRY при слепом использовании приводит к появлению беспорядочного и жёстко связанного кода. Напротив, повторение позволяет понять, какие абстракции на самом деле нужны для реализации идеи.
Как точно заметила Сэнди Мэтц, повторение намного дешевле неправильных абстракций.
У вас не получится заранее писать абстракции, которые можно использовать повторно. Самые успешные библиотеки и фреймворки обычно не создаются с нуля, а выделяются из больших систем. Если вы не сделали с помощью своей новой библиотеки что-то работающее, вряд ли она кому-то пригодится. Повторное использование кода — не лучшее оправдание, чтобы избегать дублирования кода. Поэтому создание переиспользуемого кода можно считать одной из форм преждевременной оптимизации.
Когда вопрос касается повторений в собственном проекте, задача не в том, чтобы повторно использовать код, а скорее в том, чтобы иметь возможность вносить согласованные изменения. Используйте абстракции, когда вы уверены в согласованности компонентов. Не стремитесь переиспользовать код, иногда повторение — лучшее решение.
Повторяйтесь, но не повторяйте ошибки других людей. Повторяйтесь, чтобы найти нужные абстракции, потом повторяйтесь ещё раз, чтобы реализовать их.
Некоторые люди считают, что суть принципа DRY не в отсутствии повторения кода, а в отказе от повторения функциональности и ответственности. Это принцип единственной ответственности, с которым тоже связано много заблуждений.
Объединяйте ответственности, чтобы управлять взаимодействиями между ними
Большие сервисы рекомендуется разделять на небольшие модули. Каждый модуль решает одну задачу и делает это хорошо. Это позволяет разработчикам надеяться на упрощение изменений и поддержки кода.
Это хорошо работает в небольших проектах. Например, повторное использование переменных — важный источник ошибок в коде. Но иногда этот подход не работает. Да, использование одного класса для решения двух задач может выглядеть некрасиво. Но попытка создать два класса для решения двух задач может привести к появлению двух некрасивых классов. Программисту придётся учитывать ещё и взаимодействие этих классов.
Единственная разница между объединением и разделением чего-то заключается в том, что одни изменения становятся проще, чем другие. Один из примеров — выбор между монолитом и микросервисами. Разработчику приходится решать, что проще: создавать и разворачивать один сервис или использовать композицию созданных независимо друг от друга сервисов.
Важная разница между этими подходами в том, что глобальные изменения проще выполнять в первом случае, а локальные — во втором. Выбор подхода для конкретной команды зависит скорее от факторов окружения, чем от конкретных изменений.
Использование монолитного решения может стать проблемой, когда понадобится добавить новые функции. А микросервисы могут стать проблемой, когда нужна точная координация. Монолит может лучше работать с флагами функций, а микросервисы хорошо работают, когда используется автоматизированное развёртывание.
Даже монолит можно разделить на микросервисы внутри одного репозитория. В этом случае он будет разворачиваться как одно целое. Практически всё можно разделить на составные части. Проблема в том, чтобы понять, когда это действительно выгодно.
Модульность — это не просто механическое разделение программы на минимально возможные части
Некоторые программисты своеобразно понимают принцип единственной ответственности. Они жестоко расчленяют программы и получают огромное количество небольших взаимосвязанных модулей. Похожую ситуацию можно увидеть в Bash. Если абстрагироваться от кода, так же устроены очень дорогие механические часы.
Командная строка в UNIX — хороший пример коллекции небольших компонентов, каждый из которых выполняет ровно одну функцию. Из-за этого специалисту иногда бывает сложно понять, какой именно компонент использовать для решения конкретной задачи, и как заставить этот компонент работать правильно. Отличный пример — команда awk, для корректного использования которой приходится устраивать танцы с бубном.
Ещё один наглядный пример принципа единственной ответственности — Git. С помощью git checkout вы можете выполнить шесть разных операций, но все они используют похожие операции под капотом. То есть компоненты можно использовать разными способами, даже если они выполняют одну функцию.
Слой небольших компонентов без общих функций создаёт потребность в дополнительном слое, где функции пересекаются. Если такого слоя нет, пользователь создаст его с помощью алиасов Bash, скриптов или даже с помощью таблицы, из которой можно копипастить данные.
Но даже дополнительный слой не решает проблему. В Git уже есть дружественные к пользователю команды, созданные для автоматизации работы. Но с пользовательским интерфейсом Git всё ещё сложно работать. Всегда легче добавить флаг к существующей команде, чем использовать его параллельно.
Точно так же функции получают новые булевы флаги, а классы получают новые методы, когда необходимо изменить код. Попытки избежать дублирования в таких случаях создают путаницу.
Компоненты можно создавать в соответствии с принципом единственной ответственности. Но со временем ответственность этих компонентов всё равно меняется, а сами компоненты начинают взаимодействовать друг с другом непредсказуемыми способами. Ответственность модуля в системе в текущий момент времени не всегда коррелирует с тем, во что превратится модуль в будущем.
Суть модульности заключается в ограничении вариантов роста
Программист часто изменяет модуль не потому, что именно его нужно изменить, а потому что этот модуль проще всего изменить. Получается, модуль определяет, за какие части системы он никогда не будет отвечать, а не за какие части он отвечает в текущий момент.
Когда у единицы нет правил, определяющих, какой код можно в неё добавить, эта единица принимает в себя больше и больше частей системы. Это всегда верно для модулей с названием util. Также это объясняет, почему в модели MVC большая часть кода попадает в Controller.
В теории модель MVC предполагает объединение кода приложения в три взаимосвязанных блока. Первый блок для баз данных, второй для пользовательского интерфейса, а третий связывает два первых блока. На практике MVC часто представляет собой монолит с двумя подсистемами: первая для базы данных, вторая для пользовательского интерфейса. И обе подсистемы находятся внутри третьей: контроллера.
Цель использования MVC не ограничивается помещением кода базы данных в один блок. MVC также предполагает отделение кода базы данных от кода фронтенда. Наши данные и то, как мы хотим их просматривать, меняются со временем независимо от кода фронтенда.
Повторное использование и разделение кода на маленькие компоненты — хорошая практика. Но она должна быть результатом других желаемых изменений. Эта практика — компромисс, связанный с необходимостью упрощать код.
Разделение кода на компоненты или объединение в монолит нельзя считать хорошими или плохими практиками без учёта контекста. Итоговая оценка зависит от изменений, которые производятся во время дальнейшей работы над приложением. В конце концов, речь идёт об оптимизации кода для возможности изменять его в дальнейшем. Это редко достигается с помощью переиспользуемого кода, так как работа с изменениями часто подразумевает переписывание приложения с нуля.
Переписывайте всё
Обычно команда или разработчик решают переписывать приложение с нуля, когда другого выхода не ос��аётся. Например, когда технический долг приводит к тому, что попытки рефакторинга становятся опасными. Или когда система находится в критическом состоянии.
Но иногда причины для переписывания кода менее драматичные. Например, какое-то API перестаёт работать, стартап прекращает работать, или в моду вошли новые подходы, а владелец продукта хочет следовать моде.
Полное переписывание — рискованная затея, так как замена одной работающей системы на другую происходит не за 5 минут. Специалисты редко понимают старую систему полностью, так как некоторые её свойства носят случайный характер. Добавьте сюда скудную документацию, написанные для галочки тесты, неудачные интерфейсы, которые ограничивают поведение пользователей.
Если замена системы связана с переписыванием всего кода, заранее подготовьтесь к тому, что ваш продукт не будет работать во время этой замены.
Чтобы успешно переписать приложение, нужно планировать миграцию со старой системы на новую, уменьшение нагрузки и другие шаги. Обе системы необходимо поддерживать, пока вы не отключите старую. Медленная и осторожная миграция — единственный правильный вариант, когда вы работаете с большими системами.
Чтобы добиться успеха, нужно в первую очередь решать самые важные и тяжёлые задачи. Часто они связаны с производительностью системы, с проблемным пользователем или с самым крупным клиентом.
Если замена не принесла успеха спустя три месяца, она уже никогда не будет успешной.
Чем дольше вы запускаете новую систему, тем больше времени тратите на поиск багов. К сожалению, миграция откладывается из-за необходимости работы над новыми функциями. В новом проекте появляются возможности для раздувания функциональности. Это известно как эффект второй системы, суть которого заключается в замене небольших работающих систем на большие системы с избыточной функциональностью и оверинжинирингом.
Эффект второй системы срабатывает, когда команда неправильно подходит к переписыванию, например, планирует слишком много функций, реализует слишком мало, к тому же, реализованные функции работают ненадёжно. Это похоже на создание игрового движка без игр или каркаса без продукта внутри. Итоговый код получается беспорядочным набором модулей, он не решает свои задачи.
Правило не переписывать код появилось из-за того, что переписывание обычно откладывается до последнего, ожидания разработчиков от новой системы завышенные, команда ждёт, что все изменения немедленно начнут работать. Гораздо эффективнее использовать правило «никогда не переписывайте код в спешке», чем просто «никогда не переписывайте код».
null === true, запретов не существует
Проблема с буквальным следованием советам в том, что этот подход редко работает на практике. А следование советам любой ценой приводит к плохим последствиям.
Принцип DRY не нужно понимать буквально. Надо помнить, что иногда повторения вредны, а иногда полезны. И что можно использовать абстракции, когда необходимо объединить сущности.
Принцип единственной ответственности в этом ключе можно перефразировать так: разделение кода на модули полезно, если интерфейсы модулей простые.
Вместо принципа «не переписывай» лучше использовать принцип «не бросай то, что работает». Лучше составить план миграции, поддерживать какое-то время обе системы, и только потом отключить старую.
Когда вы слышите совет, нужно попробовать понять среду и окружение, в которой собираетесь его применять. Среда и окружение могут перевернуть всё с ног на голову и сделать совет вредным. Принципы вроде DRY являются компромиссом, который может быть выгодным для небольших систем, но разрушительным для больших проектов.
При работе с большими системами сложно сразу понять последствия того или иного решения. Иногда они проявляются спустя какое-то время после имплементации изменений. И вам придётся тратить дополнительные ресурсы, чтобы завершить процесс.
В конце концов мы называем хорошие решения чистым кодом, а плохие решения техническим долгом. И забываем, что к хорошим и плохим решениям иногда приводят одни и те же правила.
Адаптированный перевод статьи Repeat yourself, do more than one thing, and rewrite everything by tef. Мнение автора оригинальной публикации может не совпадать с мнением администрации «Хекслета».
<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="ru" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<link href="https://mc.yandex.ru" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26 17:28:13 UTC","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false};gon.token="7h9Z2JFIaVjnw4ZwS9h2AxSm2SXrDHelPMHk5X8KgmsBzpLvYzbEOFGAouhH14Z01K_0j-M7iQeBIX6xLQ1lBQ";gon.locale="ru";gon.language="ru";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLSeibfGq-KvWQ2Fyru-zkFFRVTLBuzXAHAoEyN1p49FtDmNoNA";
//]]>
</script>
<meta charset="utf-8">
<title>Не сушите код, нарушайте принцип единственной ответственности, переписывайте всё: (без)вредные советы программистам</title>
<meta name="description" content="Если последуете совету сушить код, то есть будете соблюдать принцип DRY, у вас появятся функции с четырьмя булевыми параметрами, а также таблицы для отслеживания изменения состояния. Выделение модулей может усложнить отслеживание изменений. А отказ переписывать код уменьшает вероятность сделать">
<link rel="canonical" href="https://ru.hexlet.io/blog/posts/ne-sushite-kod-narushayte-printsip-edinstvennoy-otvetstvennosti-perepisyvayte-vsyo-bez-vrednye-sovety-programmistam">
<meta property="og:title" content="Не сушите код, нарушайте принцип единственной ответственности, переписывайте всё: (без)вредные советы программистам">
<meta property="og:description" content="Если последуете совету сушить код, то есть будете соблюдать принцип DRY, у вас появятся функции с четырьмя булевыми параметрами, а также таблицы для отслеживания изменения состояния. Выделение модулей может усложнить отслеживание изменений. А отказ переписывать код уменьшает вероятность сделать удачный продукт.">
<meta property="og:image" content="https://ru.hexlet.io/vite/assets/blog_post-7eTyeLLt.webp">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="ikqd6RVNp9MFtL6hijDRt7CZ2T_Y4dY-iwAE9DNfkG9lm1be5zMKs7P3mjmGPyHAcJD0ldDWKJw24J6gYVh3AQ" />
<script src="/vite/assets/inertia-INZxX8jp.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-6pOtQ3OW.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<link rel="preload" as="image" href="/vite/assets/blog_post-7eTyeLLt.webp"/><link rel="preload" as="image" href="/vite/assets/development-BVihs_d5.png"/><div id="app" data-page="{"component":"web/blog/posts/show","props":{"errors":{},"locale":"ru","language":"ru","httpsHost":"https://ru.hexlet.io","host":"ru.hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26T17:28:13.741Z","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false}},"cloudflareTurnstileSiteKey":"0x4AAAAAAA15KmeFXzd2H0Xo","vkIdClientId":"51586979","yandexIdClientId":"88d071f1d3384eb4bd1deb37910235c7","formAuthToken":"k8hyOG33iyTx5qxp8nGQ04c8Aff7jbF5P40jwBg7GWh8GbkPn4kmREeliPH-fmCkRzUsXfO6T9uCbbmUSjz-Bg","post":{"model_name":"BlogPost","category":{"id":4,"name":"Код","slug":"code","state":"published","created_at":"2016-08-23T13:33:44.258Z"},"creator":{"public_name":"Дмитрий Дементий","id":174372,"is_tutor":false},"tags":[{"id":1119,"slug":"bez-steka","name":"Без стека"}],"id":466,"title":"Не сушите код, нарушайте принцип единственной ответственности, переписывайте всё: (без)вредные советы программистам","slug":"ne-sushite-kod-narushayte-printsip-edinstvennoy-otvetstvennosti-perepisyvayte-vsyo-bez-vrednye-sovety-programmistam","state":"published","summary":"Если последуете совету сушить код, то есть будете соблюдать принцип DRY, у вас появятся функции с четырьмя булевыми параметрами, а также таблицы для отслеживания изменения состояния. Выделение модулей может усложнить отслеживание изменений. А отказ переписывать код уменьшает вероятность сделать удачный продукт. ","votes_count":5,"created_at":"2019-09-13T15:11:17.649Z","published_at":"2019-09-14T05:29:50.020Z","body":"Просить совета у программиста — плохая идея. Но если вы всё-таки решитесь, в ответ услышите что-то типа «сушите код, соблюдайте принцип единственной ответственности, никогда не переписывайте код с нуля».\n\nЕсли последуете совету сушить код, то есть будете соблюдать принцип DRY, у вас появятся функции с четырьмя булевыми параметрами, а также таблицы, позволяющие отслеживать изменение состояния. Выделение модулей может усложнить отслеживание изменений. А отказ переписывать код уменьшает вероятность сделать удачный продукт. \n___\n_Справка: выражение «сушите код» произошло от акронима DRY — Don’t repeat yourself, не повторяйся._\n___\n\nСоветы выше нельзя назвать изначально неправильными. Но слепое следование этим рекомендациям порождает больше проблем, чем выгод.\n\nВ некоторых ситуация лучше делать прямо противоположные вещи: постоянно переписывать код, избегать выделения модулей, повторять код, чтобы не писать всю программу в одной большой функции. Это сложнее, чем слепо соблюдать принцип DRY, но можно попробовать. \n\n::posts\n\n## Содержание\n\n## Игнорируйте принцип DRY, чтобы находить нужные абстракции\n\nРекомендация соблюдать принцип DRY — трюизм, общая фраза, которая не имеет смысла вне контекста. \n\nНикто не любит писать шаблоны. Программисту скучно работать с банальными задачами. Когда нужно написать один и тот же шаблонный код, скажем, восемь раз подряд, разработчик устаёт до того, как открывает редактор. Поэтому не надо советовать программистам соблюдать принцип DRY. Вместо этого лучше показать, как и когда стоит использовать этот принцип. \n\nНекоторые специалисты интерпретируют принцип DRY как рекомендацию не использовать копипаст, то есть не использовать повторяющийся код. Но лучший способ избежать повторений — не изобретать велосипед заново, то есть не создавать повторно то, что уже существует. К счастью, большинство разработчиков поступает именно так. \n\nПрактически каждое веб-приложение нуждается в операционной системе, базе данных и других инструментах. Современные сайты повторно используют миллионы строк кода. К сожалению, программисты хорошо усвоили принцип DRY, который в руках неопытных специалистов превращается в принцип «всегда используй абстракцию».\n\nПод абстракцией в данном случае подразумеваются две связанные вещи. Это идея, которую мы хотим реализовать, и реализация этой идеи с помощью выбранного языка программирования. Абстракции — способ повторения, так что вы можете менять части программы в одном месте. Абстракции помогают управлять изменениями в системе и поведением её компонентов. \n\nПри постоянном использовании абстракции вам приходится гадать, какие части кода нужно менять одновременно. Принцип DRY при слепом использовании приводит к появлению беспорядочного и жёстко связанного кода. Напротив, повторение позволяет понять, какие абстракции на самом деле нужны для реализации идеи. \n___\n_Как точно заметила Сэнди Мэтц, повторение намного дешевле неправильных абстракций._\n___\n\nУ вас не получится заранее писать абстракции, которые можно использовать повторно. Самые успешные библиотеки и фреймворки обычно не создаются с нуля, а выделяются из больших систем. Если вы не сделали с помощью своей новой библиотеки что-то работающее, вряд ли она кому-то пригодится. Повторное использование кода — не лучшее оправдание, чтобы избегать дублирования кода. Поэтому создание переиспользуемого кода можно считать одной из форм преждевременной оптимизации.\n\nКогда вопрос касается повторений в собственном проекте, задача не в том, чтобы повторно использовать код, а скорее в том, чтобы иметь возможность вносить согласованные изменения. Используйте абстракции, когда вы уверены в согласованности компонентов. Не стремитесь переиспользовать код, иногда повторение — лучшее решение. \n\nПовторяйтесь, но не повторяйте ошибки других людей. Повторяйтесь, чтобы найти нужные абстракции, потом повторяйтесь ещё раз, чтобы реализовать их. \n\nНекоторые люди считают, что суть принципа DRY не в отсутствии повторения кода, а в отказе от повторения функциональности и ответственности. Это принцип единственной ответственности, с которым тоже связано много заблуждений. \n\n\n## Объединяйте ответственности, чтобы управлять взаимодействиями между ними\n\nБольшие сервисы рекомендуется разделять на небольшие модули. Каждый модуль решает одну задачу и делает это хорошо. Это позволяет разработчикам надеяться на упрощение изменений и поддержки кода. \n\nЭто хорошо работает в небольших проектах. Например, повторное использование переменных — важный источник ошибок в коде. Но иногда этот подход не работает. Да, использование одного класса для решения двух задач может выглядеть некрасиво. Но попытка создать два класса для решения двух задач может привести к появлению двух некрасивых классов. Программисту придётся учитывать ещё и взаимодействие этих классов.\n\nЕдинственная разница между объединением и разделением чего-то заключается в том, что одни изменения становятся проще, чем другие. Один из примеров — выбор между монолитом и микросервисами. Разработчику приходится решать, что проще: создавать и разворачивать один сервис или использовать композицию созданных независимо друг от друга сервисов. \n\nВажная разница между этими подходами в том, что глобальные изменения проще выполнять в первом случае, а локальные — во втором. Выбор подхода для конкретной команды зависит скорее от факторов окружения, чем от конкретных изменений.\n\nИспользование монолитного решения может стать проблемой, когда понадобится добавить новые функции. А микросервисы могут стать проблемой, когда нужна точная координация. Монолит может лучше работать с флагами функций, а микросервисы хорошо работают, когда используется автоматизированное развёртывание.\n\nДаже монолит можно разделить на микросервисы внутри одного репозитория. В этом случае он будет разворачиваться как одно целое. Практически всё можно разделить на составные части. Проблема в том, чтобы понять, когда это действительно выгодно.\n\n\n## Модульность — это не просто механическое разделение программы на минимально возможные части\n\nНекоторые программисты своеобразно понимают принцип единственной ответственности. Они жестоко расчленяют программы и получают огромное количество небольших взаимосвязанных модулей. Похожую ситуацию можно увидеть в Bash. Если абстрагироваться от кода, так же устроены очень дорогие механические часы. \n\nКомандная строка в UNIX — хороший пример коллекции небольших компонентов, каждый из которых выполняет ровно одну функцию. Из-за этого специалисту иногда бывает сложно понять, какой именно компонент использовать для решения конкретной задачи, и как заставить этот компонент работать правильно. Отличный пример — команда `awk`, для корректного использования которой приходится устраивать танцы с бубном. \n\nЕщё один наглядный пример принципа единственной ответственности — Git. С помощью `git checkout` вы можете выполнить шесть разных операций, но все они используют похожие операции под капотом. То есть компоненты можно использовать разными способами, даже если они выполняют одну функцию.\n\nСлой небольших компонентов без общих функций создаёт потребность в дополнительном слое, где функции пересекаются. Если такого слоя нет, пользователь создаст его с помощью алиасов Bash, скриптов или даже с помощью таблицы, из которой можно копипастить данные. \n\nНо даже дополнительный слой не решает проблему. В Git уже есть дружественные к пользователю команды, созданные для автоматизации работы. Но с пользовательским интерфейсом Git всё ещё сложно работать. Всегда легче добавить флаг к существующей команде, чем использовать его параллельно. \n\nТочно так же функции получают новые булевы флаги, а классы получают новые методы, когда необходимо изменить код. Попытки избежать дублирования в таких случаях создают путаницу. \n\nКомпоненты можно создавать в соответствии с принципом единственной ответственности. Но со временем ответственность этих компонентов всё равно меняется, а сами компоненты начинают взаимодействовать друг с другом непредсказуемыми способами. Ответственность модуля в системе в текущий момент времени не всегда коррелирует с тем, во что превратится модуль в будущем. \n\n## Суть модульности заключается в ограничении вариантов роста\n\nПрограммист часто изменяет модуль не потому, что именно его нужно изменить, а потому что этот модуль проще всего изменить. Получается, модуль определяет, за какие части системы он никогда не будет отвечать, а не за какие части он отвечает в текущий момент. \n\nКогда у единицы нет правил, определяющих, какой код можно в неё добавить, эта единица принимает в себя больше и больше частей системы. Это всегда верно для модулей с названием `util`. Также это объясняет, почему [в модели MVC](https://ru.hexlet.io/blog/posts/chto-takoe-mvc-rasskazyvaem-prostymi-slovami) большая часть кода попадает в Controller. \n\nВ теории модель MVC предполагает объединение кода приложения в три взаимосвязанных блока. Первый блок для баз данных, второй для пользовательского интерфейса, а третий связывает два первых блока. На практике MVC часто представляет собой монолит с двумя подсистемами: первая для базы данных, вторая для пользовательского интерфейса. И обе подсистемы находятся внутри третьей: контроллера. \n\nЦель использования MVC не ограничивается помещением кода базы данных в один блок. MVC также предполагает отделение кода базы данных от кода фронтенда. Наши данные и то, как мы хотим их просматривать, меняются со временем независимо от кода фронтенда. \n\nПовторное использование и разделение кода на маленькие компоненты — хорошая практика. Но она должна быть результатом других желаемых изменений. Эта практика — компромисс, связанный с необходимостью упрощать код. \n\nРазделение кода на компоненты или объединение в монолит нельзя считать хорошими или плохими практиками без учёта контекста. Итоговая оценка зависит от изменений, которые производятся во время дальнейшей работы над приложением. В конце концов, речь идёт об оптимизации кода для возможности изменять его в дальнейшем. Это редко достигается с помощью переиспользуемого кода, так как работа с изменениями часто подразумевает переписывание приложения с нуля. \n\n\n## Переписывайте всё\n\nОбычно команда или разработчик решают переписывать приложение с нуля, когда другого выхода не остаётся. Например, когда технический долг приводит к тому, что попытки рефакторинга становятся опасными. Или когда система находится в критическом состоянии.\n\nНо иногда причины для переписывания кода менее драматичные. Например, какое-то API перестаёт работать, стартап прекращает работать, или в моду вошли новые подходы, а владелец продукта хочет следовать моде. \n\nПолное переписывание — рискованная затея, так как замена одной работающей системы на другую происходит не за 5 минут. Специалисты редко понимают старую систему полностью, так как некоторые её свойства носят случайный характер. Добавьте сюда скудную документацию, написанные для галочки тесты, неудачные интерфейсы, которые ограничивают поведение пользователей. \n\nЕсли замена системы связана с переписыванием всего кода, заранее подготовьтесь к тому, что ваш продукт не будет работать во время этой замены.\n\nЧтобы успешно переписать приложение, нужно планировать миграцию со старой системы на новую, уменьшение нагрузки и другие шаги. Обе системы необходимо поддерживать, пока вы не отключите старую. Медленная и осторожная миграция — единственный правильный вариант, когда вы работаете с большими системами. \n\nЧтобы добиться успеха, нужно в первую очередь решать самые важные и тяжёлые задачи. Часто они связаны с производительностью системы, с проблемным пользователем или с самым крупным клиентом. \n\nЕсли замена не принесла успеха спустя три месяца, она уже никогда не будет успешной. \n\nЧем дольше вы запускаете новую систему, тем больше времени тратите на поиск багов. К сожалению, миграция откладывается из-за необходимости работы над новыми функциями. В новом проекте появляются возможности для раздувания функциональности. Это известно как эффект второй системы, суть которого заключается в замене небольших работающих систем на большие системы с избыточной функциональностью и оверинжинирингом.\n\nЭффект второй системы срабатывает, когда команда неправильно подходит к переписыванию, например, планирует слишком много функций, реализует слишком мало, к тому же, реализованные функции работают ненадёжно. Это похоже на создание игрового движка без игр или каркаса без продукта внутри. Итоговый код получается беспорядочным набором модулей, он не решает свои задачи. \n\nПравило не переписывать код появилось из-за того, что переписывание обычно откладывается до последнего, ожидания разработчиков от новой системы завышенные, команда ждёт, что все изменения немедленно начнут работать. Гораздо эффективнее использовать правило «никогда не переписывайте код в спешке», чем просто «никогда не переписывайте код».\n\n::posts\n\n## null === true, запретов не существует\n\nПроблема с буквальным следованием советам в том, что этот подход редко работает на практике. А следование советам любой ценой приводит к плохим последствиям. \n\nПринцип DRY не нужно понимать буквально. Надо помнить, что иногда повторения вредны, а иногда полезны. И что можно использовать абстракции, когда необходимо объединить сущности. \n\nПринцип единственной ответственности в этом ключе можно перефразировать так: разделение кода на модули полезно, если интерфейсы модулей простые. \n\nВместо принципа «не переписывай» лучше использовать принцип «не бросай то, что работает». Лучше составить план миграции, поддерживать какое-то время обе системы, и только потом отключить старую. \n\nКогда вы слышите совет, нужно попробовать понять среду и окружение, в которой собираетесь его применять. Среда и окружение могут перевернуть всё с ног на голову и сделать совет вредным. Принципы вроде DRY являются компромиссом, который может быть выгодным для небольших систем, но разрушительным для больших проектов. \n\nПри работе с большими системами сложно сразу понять последствия того или иного решения. Иногда они проявляются спустя какое-то время после имплементации изменений. И вам придётся тратить дополнительные ресурсы, чтобы завершить процесс.\n\nВ конце концов мы называем хорошие решения чистым кодом, а плохие решения техническим долгом. И забываем, что к хорошим и плохим решениям иногда приводят одни и те же правила. \n\n_Адаптированный перевод статьи [Repeat yourself, do more than one thing, and rewrite everything](https://programmingisterrible.com/post/176657481103/repeat-yourself-do-more-than-one-thing-and?fbclid=IwAR0cMBDIofSCLP1amW7RCY7WjQhhYQ8tnytj63rRbSyJcBepK1Bl03M9npY) by tef. Мнение автора оригинальной публикации может не совпадать с мнением администрации «Хекслета»._","reading_time":7,"url":"https://ru.hexlet.io/blog/posts/ne-sushite-kod-narushayte-printsip-edinstvennoy-otvetstvennosti-perepisyvayte-vsyo-bez-vrednye-sovety-programmistam","cover_thumb_variant":null,"cover_list_variant":"/vite/assets/blog_post-7eTyeLLt.webp","cover_main_variant":"/vite/assets/blog_post-7eTyeLLt.webp","related_stacks_count":5},"relatedPosts":[{"model_name":"BlogPost","id":416,"title":"Язык программирования JavaScript: где его используют и почему он популярен","slug":"stoit-li-uchit-javascript-perspektivy-situatsiya-na-rynke-truda-mneniya-ekspertov","summary":"Рассказываем, что это за язык программирования — JavaScript, где его используют, насколько он популярен и с чего начать изучение JavaScript.","created_at":"2019-07-26T08:17:06.287Z","published_at":"2023-10-04T08:41:58.734Z","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTcwMywicHVyIjoiYmxvYl9pZCJ9fQ==--aa69869c906a992728ba7c26886fa1b715024424/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX2FuZF9wYWQiOls3MDgsMzU0XSwic2F2ZXIiOnsicXVhbGl0eSI6ODV9fSwicHVyIjoidmFyaWF0aW9uIn19--324dc52aa55ebe818c2a887ebcb832b9ad1c0381/%D1%8F%D0%B7%D1%8B%D0%BA%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8Fjavascript-01.png"},{"model_name":"BlogPost","id":362,"title":"Язык программирования PHP: рейтинг, сферы применения, прогнозы экспертов","slug":"zachem-izuchat-php-reyting-perspektivy-sfery-primeneniya","summary":"Рассказываем, зачем и где учить PHP, где его применяют, сколько зарабатывают PHP-разработчики, а также приводим мнения экспертов о перспективах и популярности языка. ","created_at":"2019-06-21T09:57:49.863Z","published_at":"2023-03-24T11:43:13.709Z","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTcxNSwicHVyIjoiYmxvYl9pZCJ9fQ==--483469e30822f45e5959af1ca8e34c28c3fe28db/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX2FuZF9wYWQiOls3MDgsMzU0XSwic2F2ZXIiOnsicXVhbGl0eSI6ODV9fSwicHVyIjoidmFyaWF0aW9uIn19--324dc52aa55ebe818c2a887ebcb832b9ad1c0381/%D1%81%D1%87%D0%B5%D0%B3%D0%BE%D0%BD%D0%B0%D1%87%D0%B0%D1%82%D1%8C%D0%B8%D0%B7%D1%83%D1%87%D0%B0%D1%82%D1%8Cphp-2-01.png"},{"model_name":"BlogPost","id":12,"title":"Среды разработки: какие они бывают и чем отличаются друг от друга","slug":"environment","summary":"Сооснователь Хекслета Кирилл Мокевнин рассказывает, какие бывают среды разработки, как проводится контроль и испытание фичи и что такое интеграция.","created_at":"2016-08-23T14:10:57.533Z","published_at":"2023-03-21T13:40:16.878Z","cover_list_variant":"/vite/assets/blog_post-7eTyeLLt.webp"}],"category":{"id":4,"name":"Код","slug":"code","state":"published","created_at":"2016-08-23T13:33:44.258Z"},"mainStackCategory":{"id":11,"name":"Курсы по Java","slug":"java","short_name":"Java","order":80,"state":"published","category_slug":"courses_java"},"categories":[{"id":6,"name":"Мотивация","slug":"motivation","state":"published","created_at":"2016-10-06T18:31:38.903Z"},{"id":3,"name":"Истории успеха","slug":"success","state":"published","created_at":"2016-07-30T12:57:18.308Z"},{"id":14,"name":"Дневник студента","slug":"student-diary","state":"published","created_at":"2019-02-25T13:27:09.471Z"},{"id":4,"name":"Код","slug":"code","state":"published","created_at":"2016-08-23T13:33:44.258Z"},{"id":12,"name":"Карьера","slug":"career","state":"published","created_at":"2017-07-21T15:42:21.481Z"}],"relatedLandings":[{"stack":{"id":36,"slug":"java-sicp","title":"СИКП на Java","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4100,"duration_in_months":1},"id":60,"slug":"java-sicp","title":"СИКП на Java","subtitle":"Навык понимать программы на фундаментальном уровне, уверенно проходить собеседования и решать сложные задачи","subtitle_for_lists":"Изучите фундаментальные принципы программирования на Java","locale":"ru","current":true,"duration_in_months_text":"1 месяц","stack_slug":"java-sicp","price_text":"от 3 900 ₽","duration_text":"1 месяц","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDAxNiwicHVyIjoiYmxvYl9pZCJ9fQ==--eb66b9b5e26fafa32844ce0f4522c3ed84544040/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Hand%20coding-rafiki.png"},{"stack":{"id":20,"slug":"js-sicp","title":"СИКП на JS","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4050,"duration_in_months":1},"id":28,"slug":"js-sicp","title":"СИКП на JS","subtitle":"Навык понимать программы на фундаментальном уровне, уверенно проходить собеседования и решать сложные задачи","subtitle_for_lists":"Навык фундаментального программирования","locale":"ru","current":true,"duration_in_months_text":"1 месяц","stack_slug":"js-sicp","price_text":"от 3 900 ₽","duration_text":"1 месяц","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MCwicHVyIjoiYmxvYl9pZCJ9fQ==--9348098e4053d798b6f34bee4ef66947540261e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png"},{"stack":{"id":37,"slug":"python-sicp","title":"СИКП на Python","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4150,"duration_in_months":1},"id":62,"slug":"python-sicp","title":"СИКП на Python","subtitle":"Навык понимать код на фундаментальном уровне, уверенно проходить собеседования и решать сложные задачи","subtitle_for_lists":"Изучите Python на глубоком уровне для решения сложных задач","locale":"ru","current":true,"duration_in_months_text":"1 месяц","stack_slug":"python-sicp","price_text":"от 3 900 ₽","duration_text":"1 месяц","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc1OCwicHVyIjoiYmxvYl9pZCJ9fQ==--023ea18f500b1c4c91617fa96bbc52df8395da39/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Software%20engineer-bro.png"},{"stack":{"id":28,"slug":"php-sicp","title":"СИКП на PHP","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4010,"duration_in_months":1},"id":44,"slug":"php-sicp","title":"СИКП на PHP","subtitle":"Навык понимать программы на глубоком уровне, уверенно проходить собеседования и решать сложные задачи","subtitle_for_lists":"Навык фундаментального понимания программ на PHP","locale":"ru","current":true,"duration_in_months_text":"1 месяц","stack_slug":"php-sicp","price_text":"от 3 900 ₽","duration_text":"1 месяц","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MywicHVyIjoiYmxvYl9pZCJ9fQ==--61c43d4881ca8feecc6f37dfafdc4e304f34b52f/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Software%20engineer-bro.png"},{"stack":{"id":29,"slug":"js-oop","title":"ООП на Javascript","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4250,"duration_in_months":2},"id":46,"slug":"js-oop","title":"ООП на Javascript","subtitle":"Навык глубокого понимания архитектуры и написания чистого кода, позволяющий решать сложные задачи","subtitle_for_lists":"Изучите архитектуру и принципы чистого кода на JS","locale":"ru","current":true,"duration_in_months_text":"2 месяца","stack_slug":"js-oop","price_text":"от 3 900 ₽","duration_text":"2 месяца","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDAxOSwicHVyIjoiYmxvYl9pZCJ9fQ==--84efd2b6854b7000046e9ce06e6be85d38af5ab8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/JavaScript%20frameworks-cuate.png"}]},"url":"/blog/posts/ne-sushite-kod-narushayte-printsip-edinstvennoy-otvetstvennosti-perepisyvayte-vsyo-bez-vrednye-sovety-programmistam","version":"0b0c6d4ebbd40fd58630a0dd89cc25544ccdf24e","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><script type="application/ld+json">{"@context":"https://schema.org","@type":"Article","author":"Дмитрий Дементий","name":"Не сушите код, нарушайте принцип единственной ответственности, переписывайте всё: (без)вредные советы программистам","datePublished":"2019-09-14T05:29:50.020Z","headline":"Если последуете совету сушить код, то есть будете соблюдать принцип DRY, у вас появятся функции с четырьмя булевыми параметрами, а также таблицы для отслеживания изменения состояния. Выделение модулей может усложнить отслеживание изменений. А отказ переписывать код уменьшает вероятность сделать удачный продукт. ","image":"/vite/assets/blog_post-7eTyeLLt.webp","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":5}]}</script><div style="--container-size:var(--container-size-lg);margin-top:var(--mantine-spacing-xl);height:100%" class="m_7485cace mantine-Container-root" data-size="lg" data-strategy="block"><script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"position":1,"@type":"ListItem","item":{"@id":"/blog","name":"Блог Хекслета"}},{"position":2,"@type":"ListItem","item":{"@id":"/blog/categories/code","name":"Код"}},{"position":3,"@type":"ListItem","item":{"@id":"/blog/posts/ne-sushite-kod-narushayte-printsip-edinstvennoy-otvetstvennosti-perepisyvayte-vsyo-bez-vrednye-sovety-programmistam","name":"Не сушите код, нарушайте принцип единственной ответственности, переписывайте всё: (без)вредные советы программистам"}}]}</script><div style="margin-bottom:var(--mantine-spacing-xs)" class="m_8b3717df mantine-Breadcrumbs-root"><a style="--text-fz:var(--mantine-font-size-sm);--text-lh:var(--mantine-line-height-sm);white-space:normal;color:inherit" class="mantine-focus-auto m_849cf0da m_f678d540 mantine-Breadcrumbs-breadcrumb m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-size="sm" data-underline="hover" href="/"><div style="color:inherit" class="m_4451eb3a mantine-Center-root"><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-home-link "><path d="M20.085 11.085l-8.085 -8.085l-9 9h2v7a2 2 0 0 0 2 2h4.5"></path><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 1.807 1.143"></path><path d="M20 21a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path><path d="M20 16a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path><path d="M15 19a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path><path d="M21 16l-5 3l5 2"></path></svg></div></a><div class="m_3b8f2208 mantine-Breadcrumbs-separator">/</div><a style="--text-fz:var(--mantine-font-size-sm);--text-lh:var(--mantine-line-height-sm);white-space:normal;color:inherit" class="mantine-focus-auto m_849cf0da m_f678d540 mantine-Breadcrumbs-breadcrumb m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-size="sm" data-underline="hover" href="/blog">Блог Хекслета</a><div class="m_3b8f2208 mantine-Breadcrumbs-separator">/</div><a style="--text-fz:var(--mantine-font-size-sm);--text-lh:var(--mantine-line-height-sm);white-space:normal;color:inherit" class="mantine-focus-auto m_849cf0da m_f678d540 mantine-Breadcrumbs-breadcrumb m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-size="sm" data-underline="hover" href="/blog/categories/code">Код</a><div class="m_3b8f2208 mantine-Breadcrumbs-separator">/</div><p style="--text-fz:var(--mantine-font-size-sm);--text-lh:var(--mantine-line-height-sm);white-space:normal;color:var(--mantine-color-dimmed)" class="mantine-focus-auto m_f678d540 mantine-Breadcrumbs-breadcrumb m_b6d8b162 mantine-Text-root" data-size="sm">Не сушите код, нарушайте принцип единственной ответственности, переписывайте всё: (без)вредные советы программистам</p></div><style data-mantine-styles="inline">.__m__-_R_eub_{margin-bottom:var(--mantine-spacing-xs);}@media(min-width: 36em){.__m__-_R_eub_{margin-bottom:var(--mantine-spacing-xs);}}</style><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root __m__-_R_eub_"><style data-mantine-styles="inline">.__m__-_R_deub_{width:100%;}@media(min-width: 36em){.__m__-_R_deub_{width:70%;}}@media(min-width: 75em){.__m__-_R_deub_{width:75%;}}</style><div class="__m__-_R_deub_"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size)" class="m_8a5d1357 mantine-Title-root" data-order="1">Не сушите код, нарушайте принцип единственной ответственности, переписывайте всё: (без)вредные советы программистам</h1></div></div></div><div style="position:absolute;top:calc(18.75rem * var(--mantine-scale))" class=""></div><style data-mantine-styles="inline">.__m__-_R_2iub_{--grid-gutter:var(--mantine-spacing-xl);}</style><div class="m_410352e9 mantine-Grid-root __m__-_R_2iub_"><div class="m_dee7bd2f mantine-Grid-inner"><style data-mantine-styles="inline">.__m__-_R_dmiub_{--col-flex-grow:auto;--col-flex-basis:100%;--col-max-width:100%;}@media(min-width: 48em){.__m__-_R_dmiub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}@media(min-width: 62em){.__m__-_R_dmiub_{--col-flex-grow:auto;--col-flex-basis:66.66666666666667%;--col-max-width:66.66666666666667%;}}</style><div class="m_96bdd299 mantine-Grid-col __m__-_R_dmiub_"><div style="--stack-gap:var(--mantine-spacing-md);--stack-align:stretch;--stack-justify:flex-start;margin-bottom:var(--mantine-spacing-xl)" class="m_6d731127 mantine-Stack-root"><div class=""><div style="--group-gap:var(--mantine-spacing-xs);--group-align:center;--group-justify:flex-start;--group-wrap:wrap;margin-bottom:var(--mantine-spacing-xl)" class="m_4081bf90 mantine-Group-root"><button style="--badge-height:var(--badge-height-sm);--badge-padding-x:var(--badge-padding-x-sm);--badge-fz:var(--badge-fz-sm);--badge-bg:var(--mantine-color-default);--badge-color:var(--mantine-color-default-color);--badge-bd:calc(0.0625rem * var(--mantine-scale)) solid var(--mantine-color-default-border);cursor:pointer;color:inherit" class="m_347db0ec mantine-Badge-root" data-variant="default" data-size="sm" type="button" aria-label="Без стека"><span class="m_5add502a mantine-Badge-label">Без стека</span></button></div><div style="--group-gap:calc(0.625rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:wrap;margin-bottom:var(--mantine-spacing-sm);color:var(--mantine-color-gray-text)" class="m_4081bf90 mantine-Group-root"><div style="--group-gap:calc(0.1875rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:wrap;margin-inline-end:var(--mantine-spacing-lg)" class="m_4081bf90 mantine-Group-root">14 сентября 2019 г.</div><div style="--group-gap:calc(0.1875rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-clock "><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path><path d="M12 7v5l3 3"></path></svg></div>7 минут</div><div style="--group-gap:calc(0.1875rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-thumb-up "><path d="M7 11v8a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-7a1 1 0 0 1 1 -1h3a4 4 0 0 0 4 -4v-1a2 2 0 0 1 4 0v5h3a2 2 0 0 1 2 2l-1 5a2 3 0 0 1 -2 2h-7a3 3 0 0 1 -3 -3"></path></svg></div>5</div></div><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img style="--image-radius:var(--mantine-radius-md);--image-object-fit:cover;width:100%;height:100%" class="m_9e117634 mantine-Image-root" src="/vite/assets/blog_post-7eTyeLLt.webp" alt="Не сушите код, нарушайте принцип единственной ответственности, переписывайте всё: (без)вредные советы программистам"/></div></div><div role="link" tabindex="0" style="cursor:pointer"><button style="display:block;width:100%" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Присоединяйтесь к нашему Telegram-сообществу"><div style="background-color:light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-6))" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:flex-start;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><div style="--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:auto;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-brand-telegram "><path d="M15 10l-4 4l6 6l4 -16l-18 7l4 2l2 6l3 -4"></path></svg></div>Присоединяйтесь к нашему Telegram-сообществу</div></div></button></div><div style="margin-bottom:var(--mantine-spacing-xl)" class="m_d08caa0 mantine-Typography-root"><p>Просить совета у программиста — плохая идея. Но если вы всё-таки решитесь, в ответ услышите что-то типа «сушите код, соблюдайте принцип единственной ответственности, никогда не переписывайте код с нуля».</p>
<p>Если последуете совету сушить код, то есть будете соблюдать принцип DRY, у вас появятся функции с четырьмя булевыми параметрами, а также таблицы, позволяющие отслеживать изменение состояния. Выделение модулей может усложнить отслеживание изменений. А отказ переписывать код уменьшает вероятность сделать удачный продукт.</p>
<hr/>
<p><em>Справка: выражение «сушите код» произошло от акронима DRY — Don’t repeat yourself, не повторяйся.</em></p>
<hr/>
<p>Советы выше нельзя назвать изначально неправильными. Но слепое следование этим рекомендациям порождает больше проблем, чем выгод.</p>
<p>В некоторых ситуация лучше делать прямо противоположные вещи: постоянно переписывать код, избегать выделения модулей, повторять код, чтобы не писать всю программу в одной большой функции. Это сложнее, чем слепо соблюдать принцип DRY, но можно попробовать.</p>
<style data-mantine-styles="inline">.__m__-_R_fderddmiub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:80%;}@media(min-width: 36em){.__m__-_R_fderddmiub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_fderddmiub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/stoit-li-uchit-javascript-perspektivy-situatsiya-na-rynke-truda-mneniya-ekspertov"><div style="padding-top:0rem;height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="margin-bottom:var(--mantine-spacing-sm)" class="m_599a2148 mantine-Card-section" data-first-section="true"><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img class="m_9e117634 mantine-Image-root" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTcwMywicHVyIjoiYmxvYl9pZCJ9fQ==--aa69869c906a992728ba7c26886fa1b715024424/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX2FuZF9wYWQiOls3MDgsMzU0XSwic2F2ZXIiOnsicXVhbGl0eSI6ODV9fSwicHVyIjoidmFyaWF0aW9uIn19--324dc52aa55ebe818c2a887ebcb832b9ad1c0381/%D1%8F%D0%B7%D1%8B%D0%BA%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8Fjavascript-01.png" loading="lazy" alt="Язык программирования JavaScript: где его используют и почему он популярен"/></div></div><p style="margin-bottom:var(--mantine-spacing-xs);font-size:var(--mantine-font-size-lg);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Язык программирования JavaScript: где его используют и почему он популярен</p><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Рассказываем, что это за язык программирования — JavaScript, где его используют, насколько он поп...</p><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-sm)" class="m_4081bf90 mantine-Group-root">4 октября 2023 г.<p style="font-size:inherit" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/zachem-izuchat-php-reyting-perspektivy-sfery-primeneniya"><div style="padding-top:0rem;height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="margin-bottom:var(--mantine-spacing-sm)" class="m_599a2148 mantine-Card-section" data-first-section="true"><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img class="m_9e117634 mantine-Image-root" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTcxNSwicHVyIjoiYmxvYl9pZCJ9fQ==--483469e30822f45e5959af1ca8e34c28c3fe28db/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX2FuZF9wYWQiOls3MDgsMzU0XSwic2F2ZXIiOnsicXVhbGl0eSI6ODV9fSwicHVyIjoidmFyaWF0aW9uIn19--324dc52aa55ebe818c2a887ebcb832b9ad1c0381/%D1%81%D1%87%D0%B5%D0%B3%D0%BE%D0%BD%D0%B0%D1%87%D0%B0%D1%82%D1%8C%D0%B8%D0%B7%D1%83%D1%87%D0%B0%D1%82%D1%8Cphp-2-01.png" loading="lazy" alt="Язык программирования PHP: рейтинг, сферы применения, прогнозы экспертов"/></div></div><p style="margin-bottom:var(--mantine-spacing-xs);font-size:var(--mantine-font-size-lg);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Язык программирования PHP: рейтинг, сферы применения, прогнозы экспертов</p><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Рассказываем, зачем и где учить PHP, где его применяют, сколько зарабатывают PHP-разработчики, а ...</p><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-sm)" class="m_4081bf90 mantine-Group-root">24 марта 2023 г.<p style="font-size:inherit" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/environment"><div style="padding-top:0rem;height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="margin-bottom:var(--mantine-spacing-sm)" class="m_599a2148 mantine-Card-section" data-first-section="true"><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img class="m_9e117634 mantine-Image-root" src="/vite/assets/blog_post-7eTyeLLt.webp" loading="lazy" alt="Среды разработки: какие они бывают и чем отличаются друг от друга"/></div></div><p style="margin-bottom:var(--mantine-spacing-xs);font-size:var(--mantine-font-size-lg);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Среды разработки: какие они бывают и чем отличаются друг от друга</p><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Сооснователь Хекслета Кирилл Мокевнин рассказывает, какие бывают среды разработки, как проводится...</p><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-sm)" class="m_4081bf90 mantine-Group-root">21 марта 2023 г.<p style="font-size:inherit" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></a></div></div></div></div></div>
<h2 id="heading-2-1">Содержание</h2>
<ul>
<li><a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="#heading-2-2">Игнорируйте принцип DRY, чтобы находить нужные абстракции</a></li>
<li><a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="#heading-2-3">Объединяйте ответственности, чтобы управлять взаимодействиями между ними</a></li>
<li><a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="#heading-2-4">Модульность — это не просто механическое разделение программы на минимально возможные части</a></li>
<li><a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="#heading-2-5">Суть модульности заключается в ограничении вариантов роста</a></li>
<li><a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="#heading-2-6">Переписывайте всё</a></li>
<li><a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="#heading-2-7">null === true, запретов не существует</a></li>
</ul>
<h2 id="heading-2-2">Игнорируйте принцип DRY, чтобы находить нужные абстракции</h2>
<p>Рекомендация соблюдать принцип DRY — трюизм, общая фраза, которая не имеет смысла вне контекста.</p>
<p>Никто не любит писать шаблоны. Программисту скучно работать с банальными задачами. Когда нужно написать один и тот же шаблонный код, скажем, восемь раз подряд, разработчик устаёт до того, как открывает редактор. Поэтому не надо советовать программистам соблюдать принцип DRY. Вместо этого лучше показать, как и когда стоит использовать этот принцип.</p>
<p>Некоторые специалисты интерпретируют принцип DRY как рекомендацию не использовать копипаст, то есть не использовать повторяющийся код. Но лучший способ избежать повторений — не изобретать велосипед заново, то есть не создавать повторно то, что уже существует. К счастью, большинство разработчиков поступает именно так.</p>
<p>Практически каждое веб-приложение нуждается в операционной системе, базе данных и других инструментах. Современные сайты повторно используют миллионы строк кода. К сожалению, программисты хорошо усвоили принцип DRY, который в руках неопытных специалистов превращается в принцип «всегда используй абстракцию».</p>
<p>Под абстракцией в данном случае подразумеваются две связанные вещи. Это идея, которую мы хотим реализовать, и реализация этой идеи с помощью выбранного языка программирования. Абстракции — способ повторения, так что вы можете менять части программы в одном месте. Абстракции помогают управлять изменениями в системе и поведением её компонентов.</p>
<p>При постоянном использовании абстракции вам приходится гадать, какие части кода нужно менять одновременно. Принцип DRY при слепом использовании приводит к появлению беспорядочного и жёстко связанного кода. Напротив, повторение позволяет понять, какие абстракции на самом деле нужны для реализации идеи.</p>
<hr/>
<p><em>Как точно заметила Сэнди Мэтц, повторение намного дешевле неправильных абстракций.</em></p>
<hr/>
<p>У вас не получится заранее писать абстракции, которые можно использовать повторно. Самые успешные библиотеки и фреймворки обычно не создаются с нуля, а выделяются из больших систем. Если вы не сделали с помощью своей новой библиотеки что-то работающее, вряд ли она кому-то пригодится. Повторное использование кода — не лучшее оправдание, чтобы избегать дублирования кода. Поэтому создание переиспользуемого кода можно считать одной из форм преждевременной оптимизации.</p>
<p>Когда вопрос касается повторений в собственном проекте, задача не в том, чтобы повторно использовать код, а скорее в том, чтобы иметь возможность вносить согласованные изменения. Используйте абстракции, когда вы уверены в согласованности компонентов. Не стремитесь переиспользовать код, иногда повторение — лучшее решение.</p>
<p>Повторяйтесь, но не повторяйте ошибки других людей. Повторяйтесь, чтобы найти нужные абстракции, потом повторяйтесь ещё раз, чтобы реализовать их.</p>
<p>Некоторые люди считают, что суть принципа DRY не в отсутствии повторения кода, а в отказе от повторения функциональности и ответственности. Это принцип единственной ответственности, с которым тоже связано много заблуждений.</p>
<h2 id="heading-2-3">Объединяйте ответственности, чтобы управлять взаимодействиями между ними</h2>
<p>Большие сервисы рекомендуется разделять на небольшие модули. Каждый модуль решает одну задачу и делает это хорошо. Это позволяет разработчикам надеяться на упрощение изменений и поддержки кода.</p>
<p>Это хорошо работает в небольших проектах. Например, повторное использование переменных — важный источник ошибок в коде. Но иногда этот подход не работает. Да, использование одного класса для решения двух задач может выглядеть некрасиво. Но попытка создать два класса для решения двух задач может привести к появлению двух некрасивых классов. Программисту придётся учитывать ещё и взаимодействие этих классов.</p>
<p>Единственная разница между объединением и разделением чего-то заключается в том, что одни изменения становятся проще, чем другие. Один из примеров — выбор между монолитом и микросервисами. Разработчику приходится решать, что проще: создавать и разворачивать один сервис или использовать композицию созданных независимо друг от друга сервисов.</p>
<p>Важная разница между этими подходами в том, что глобальные изменения проще выполнять в первом случае, а локальные — во втором. Выбор подхода для конкретной команды зависит скорее от факторов окружения, чем от конкретных изменений.</p>
<p>Использование монолитного решения может стать проблемой, когда понадобится добавить новые функции. А микросервисы могут стать проблемой, когда нужна точная координация. Монолит может лучше работать с флагами функций, а микросервисы хорошо работают, когда используется автоматизированное развёртывание.</p>
<p>Даже монолит можно разделить на микросервисы внутри одного репозитория. В этом случае он будет разворачиваться как одно целое. Практически всё можно разделить на составные части. Проблема в том, чтобы понять, когда это действительно выгодно.</p>
<h2 id="heading-2-4">Модульность — это не просто механическое разделение программы на минимально возможные части</h2>
<p>Некоторые программисты своеобразно понимают принцип единственной ответственности. Они жестоко расчленяют программы и получают огромное количество небольших взаимосвязанных модулей. Похожую ситуацию можно увидеть в Bash. Если абстрагироваться от кода, так же устроены очень дорогие механические часы.</p>
<p>Командная строка в UNIX — хороший пример коллекции небольших компонентов, каждый из которых выполняет ровно одну функцию. Из-за этого специалисту иногда бывает сложно понять, какой именно компонент использовать для решения конкретной задачи, и как заставить этот компонент работать правильно. Отличный пример — команда <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">awk</code>, для корректного использования которой приходится устраивать танцы с бубном.</p>
<p>Ещё один наглядный пример принципа единственной ответственности — Git. С помощью <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">git checkout</code> вы можете выполнить шесть разных операций, но все они используют похожие операции под капотом. То есть компоненты можно использовать разными способами, даже если они выполняют одну функцию.</p>
<p>Слой небольших компонентов без общих функций создаёт потребность в дополнительном слое, где функции пересекаются. Если такого слоя нет, пользователь создаст его с помощью алиасов Bash, скриптов или даже с помощью таблицы, из которой можно копипастить данные.</p>
<p>Но даже дополнительный слой не решает проблему. В Git уже есть дружественные к пользователю команды, созданные для автоматизации работы. Но с пользовательским интерфейсом Git всё ещё сложно работать. Всегда легче добавить флаг к существующей команде, чем использовать его параллельно.</p>
<p>Точно так же функции получают новые булевы флаги, а классы получают новые методы, когда необходимо изменить код. Попытки избежать дублирования в таких случаях создают путаницу.</p>
<p>Компоненты можно создавать в соответствии с принципом единственной ответственности. Но со временем ответственность этих компонентов всё равно меняется, а сами компоненты начинают взаимодействовать друг с другом непредсказуемыми способами. Ответственность модуля в системе в текущий момент времени не всегда коррелирует с тем, во что превратится модуль в будущем.</p>
<h2 id="heading-2-5">Суть модульности заключается в ограничении вариантов роста</h2>
<p>Программист часто изменяет модуль не потому, что именно его нужно изменить, а потому что этот модуль проще всего изменить. Получается, модуль определяет, за какие части системы он никогда не будет отвечать, а не за какие части он отвечает в текущий момент.</p>
<p>Когда у единицы нет правил, определяющих, какой код можно в неё добавить, эта единица принимает в себя больше и больше частей системы. Это всегда верно для модулей с названием <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">util</code>. Также это объясняет, почему <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://ru.hexlet.io/blog/posts/chto-takoe-mvc-rasskazyvaem-prostymi-slovami" rel="noopener noreferrer" target="_blank">в модели MVC</a> большая часть кода попадает в Controller.</p>
<p>В теории модель MVC предполагает объединение кода приложения в три взаимосвязанных блока. Первый блок для баз данных, второй для пользовательского интерфейса, а третий связывает два первых блока. На практике MVC часто представляет собой монолит с двумя подсистемами: первая для базы данных, вторая для пользовательского интерфейса. И обе подсистемы находятся внутри третьей: контроллера.</p>
<p>Цель использования MVC не ограничивается помещением кода базы данных в один блок. MVC также предполагает отделение кода базы данных от кода фронтенда. Наши данные и то, как мы хотим их просматривать, меняются со временем независимо от кода фронтенда.</p>
<p>Повторное использование и разделение кода на маленькие компоненты — хорошая практика. Но она должна быть результатом других желаемых изменений. Эта практика — компромисс, связанный с необходимостью упрощать код.</p>
<p>Разделение кода на компоненты или объединение в монолит нельзя считать хорошими или плохими практиками без учёта контекста. Итоговая оценка зависит от изменений, которые производятся во время дальнейшей работы над приложением. В конце концов, речь идёт об оптимизации кода для возможности изменять его в дальнейшем. Это редко достигается с помощью переиспользуемого кода, так как работа с изменениями часто подразумевает переписывание приложения с нуля.</p>
<h2 id="heading-2-6">Переписывайте всё</h2>
<p>Обычно команда или разработчик решают переписывать приложение с нуля, когда другого выхода не остаётся. Например, когда технический долг приводит к тому, что попытки рефакторинга становятся опасными. Или когда система находится в критическом состоянии.</p>
<p>Но иногда причины для переписывания кода менее драматичные. Например, какое-то API перестаёт работать, стартап прекращает работать, или в моду вошли новые подходы, а владелец продукта хочет следовать моде.</p>
<p>Полное переписывание — рискованная затея, так как замена одной работающей системы на другую происходит не за 5 минут. Специалисты редко понимают старую систему полностью, так как некоторые её свойства носят случайный характер. Добавьте сюда скудную документацию, написанные для галочки тесты, неудачные интерфейсы, которые ограничивают поведение пользователей.</p>
<p>Если замена системы связана с переписыванием всего кода, заранее подготовьтесь к тому, что ваш продукт не будет работать во время этой замены.</p>
<p>Чтобы успешно переписать приложение, нужно планировать миграцию со старой системы на новую, уменьшение нагрузки и другие шаги. Обе системы необходимо поддерживать, пока вы не отключите старую. Медленная и осторожная миграция — единственный правильный вариант, когда вы работаете с большими системами.</p>
<p>Чтобы добиться успеха, нужно в первую очередь решать самые важные и тяжёлые задачи. Часто они связаны с производительностью системы, с проблемным пользователем или с самым крупным клиентом.</p>
<p>Если замена не принесла успеха спустя три месяца, она уже никогда не будет успешной.</p>
<p>Чем дольше вы запускаете новую систему, тем больше времени тратите на поиск багов. К сожалению, миграция откладывается из-за необходимости работы над новыми функциями. В новом проекте появляются возможности для раздувания функциональности. Это известно как эффект второй системы, суть которого заключается в замене небольших работающих систем на большие системы с избыточной функциональностью и оверинжинирингом.</p>
<p>Эффект второй системы срабатывает, когда команда неправильно подходит к переписыванию, например, планирует слишком много функций, реализует слишком мало, к тому же, реализованные функции работают ненадёжно. Это похоже на создание игрового движка без игр или каркаса без продукта внутри. Итоговый код получается беспорядочным набором модулей, он не решает свои задачи.</p>
<p>Правило не переписывать код появилось из-за того, что переписывание обычно откладывается до последнего, ожидания разработчиков от новой системы завышенные, команда ждёт, что все изменения немедленно начнут работать. Гораздо эффективнее использовать правило «никогда не переписывайте код в спешке», чем просто «никогда не переписывайте код».</p>
<style data-mantine-styles="inline">.__m__-_R_3jderddmiub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:80%;}@media(min-width: 36em){.__m__-_R_3jderddmiub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_3jderddmiub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/stoit-li-uchit-javascript-perspektivy-situatsiya-na-rynke-truda-mneniya-ekspertov"><div style="padding-top:0rem;height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="margin-bottom:var(--mantine-spacing-sm)" class="m_599a2148 mantine-Card-section" data-first-section="true"><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img class="m_9e117634 mantine-Image-root" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTcwMywicHVyIjoiYmxvYl9pZCJ9fQ==--aa69869c906a992728ba7c26886fa1b715024424/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX2FuZF9wYWQiOls3MDgsMzU0XSwic2F2ZXIiOnsicXVhbGl0eSI6ODV9fSwicHVyIjoidmFyaWF0aW9uIn19--324dc52aa55ebe818c2a887ebcb832b9ad1c0381/%D1%8F%D0%B7%D1%8B%D0%BA%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8Fjavascript-01.png" loading="lazy" alt="Язык программирования JavaScript: где его используют и почему он популярен"/></div></div><p style="margin-bottom:var(--mantine-spacing-xs);font-size:var(--mantine-font-size-lg);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Язык программирования JavaScript: где его используют и почему он популярен</p><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Рассказываем, что это за язык программирования — JavaScript, где его используют, насколько он поп...</p><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-sm)" class="m_4081bf90 mantine-Group-root">4 октября 2023 г.<p style="font-size:inherit" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/zachem-izuchat-php-reyting-perspektivy-sfery-primeneniya"><div style="padding-top:0rem;height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="margin-bottom:var(--mantine-spacing-sm)" class="m_599a2148 mantine-Card-section" data-first-section="true"><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img class="m_9e117634 mantine-Image-root" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTcxNSwicHVyIjoiYmxvYl9pZCJ9fQ==--483469e30822f45e5959af1ca8e34c28c3fe28db/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX2FuZF9wYWQiOls3MDgsMzU0XSwic2F2ZXIiOnsicXVhbGl0eSI6ODV9fSwicHVyIjoidmFyaWF0aW9uIn19--324dc52aa55ebe818c2a887ebcb832b9ad1c0381/%D1%81%D1%87%D0%B5%D0%B3%D0%BE%D0%BD%D0%B0%D1%87%D0%B0%D1%82%D1%8C%D0%B8%D0%B7%D1%83%D1%87%D0%B0%D1%82%D1%8Cphp-2-01.png" loading="lazy" alt="Язык программирования PHP: рейтинг, сферы применения, прогнозы экспертов"/></div></div><p style="margin-bottom:var(--mantine-spacing-xs);font-size:var(--mantine-font-size-lg);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Язык программирования PHP: рейтинг, сферы применения, прогнозы экспертов</p><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Рассказываем, зачем и где учить PHP, где его применяют, сколько зарабатывают PHP-разработчики, а ...</p><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-sm)" class="m_4081bf90 mantine-Group-root">24 марта 2023 г.<p style="font-size:inherit" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/environment"><div style="padding-top:0rem;height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="margin-bottom:var(--mantine-spacing-sm)" class="m_599a2148 mantine-Card-section" data-first-section="true"><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img class="m_9e117634 mantine-Image-root" src="/vite/assets/blog_post-7eTyeLLt.webp" loading="lazy" alt="Среды разработки: какие они бывают и чем отличаются друг от друга"/></div></div><p style="margin-bottom:var(--mantine-spacing-xs);font-size:var(--mantine-font-size-lg);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Среды разработки: какие они бывают и чем отличаются друг от друга</p><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Сооснователь Хекслета Кирилл Мокевнин рассказывает, какие бывают среды разработки, как проводится...</p><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-sm)" class="m_4081bf90 mantine-Group-root">21 марта 2023 г.<p style="font-size:inherit" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></a></div></div></div></div></div>
<h2 id="heading-2-7">null === true, запретов не существует</h2>
<p>Проблема с буквальным следованием советам в том, что этот подход редко работает на практике. А следование советам любой ценой приводит к плохим последствиям.</p>
<p>Принцип DRY не нужно понимать буквально. Надо помнить, что иногда повторения вредны, а иногда полезны. И что можно использовать абстракции, когда необходимо объединить сущности.</p>
<p>Принцип единственной ответственности в этом ключе можно перефразировать так: разделение кода на модули полезно, если интерфейсы модулей простые.</p>
<p>Вместо принципа «не переписывай» лучше использовать принцип «не бросай то, что работает». Лучше составить план миграции, поддерживать какое-то время обе системы, и только потом отключить старую.</p>
<p>Когда вы слышите совет, нужно попробовать понять среду и окружение, в которой собираетесь его применять. Среда и окружение могут перевернуть всё с ног на голову и сделать совет вредным. Принципы вроде DRY являются компромиссом, который может быть выгодным для небольших систем, но разрушительным для больших проектов.</p>
<p>При работе с большими системами сложно сразу понять последствия того или иного решения. Иногда они проявляются спустя какое-то время после имплементации изменений. И вам придётся тратить дополнительные ресурсы, чтобы завершить процесс.</p>
<p>В конце концов мы называем хорошие решения чистым кодом, а плохие решения техническим долгом. И забываем, что к хорошим и плохим решениям иногда приводят одни и те же правила.</p>
<p><em>Адаптированный перевод статьи <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://programmingisterrible.com/post/176657481103/repeat-yourself-do-more-than-one-thing-and?fbclid=IwAR0cMBDIofSCLP1amW7RCY7WjQhhYQ8tnytj63rRbSyJcBepK1Bl03M9npY" rel="noopener noreferrer" target="_blank">Repeat yourself, do more than one thing, and rewrite everything</a> by tef. Мнение автора оригинальной публикации может не совпадать с мнением администрации «Хекслета».</em></p></div><div class=""><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-bottom:var(--mantine-spacing-lg)" class="m_4081bf90 mantine-Group-root"><div class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:var(--mantine-spacing-xs);color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-user "><path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0"></path><path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2"></path></svg></div><p style="margin-inline-end:var(--mantine-spacing-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Дмитрий Дементий</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">6 лет назад</p></div><div style="align-items:center" class="m_8bffd616 mantine-Flex-root __m__-_R_5dirddmiub_"><a style="display:inline-flex" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/ne-sushite-kod-narushayte-printsip-edinstvennoy-otvetstvennosti-perepisyvayte-vsyo-bez-vrednye-sovety-programmistam/votes"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:var(--mantine-spacing-xs);color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-thumb-up "><path d="M7 11v8a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-7a1 1 0 0 1 1 -1h3a4 4 0 0 0 4 -4v-1a2 2 0 0 1 4 0v5h3a2 2 0 0 1 2 2l-1 5a2 3 0 0 1 -2 2h-7a3 3 0 0 1 -3 -3"></path></svg></div></a><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">5</p></div></div></div><div style="background-color:var(--mantine-color-indigo-light);border:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding:var(--mantine-spacing-xl)" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root"><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Читайте также:</p><ul style="margin-inline-start:var(--mantine-spacing-lg)" class="m_abbac491 mantine-List-root"><li style="margin-bottom:var(--mantine-spacing-sm)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><a style="color:inherit" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/stoit-li-uchit-javascript-perspektivy-situatsiya-na-rynke-truda-mneniya-ekspertov">Язык программирования JavaScript: где его используют и почему он популярен</a></span></div></li><li style="margin-bottom:var(--mantine-spacing-sm)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><a style="color:inherit" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/zachem-izuchat-php-reyting-perspektivy-sfery-primeneniya">Язык программирования PHP: рейтинг, сферы применения, прогнозы экспертов</a></span></div></li><li style="margin-bottom:var(--mantine-spacing-sm)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><a style="color:inherit" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/environment">Среды разработки: какие они бывают и чем отличаются друг от друга</a></span></div></li></ul></div><div style="margin-block:var(--mantine-spacing-xl)" class="m_3eebeb36 mantine-Divider-root" data-orientation="horizontal" role="separator"></div></div><div></div></div><style data-mantine-styles="inline">.__m__-_R_lmiub_{--col-flex-grow:auto;--col-flex-basis:100%;--col-max-width:100%;}@media(min-width: 48em){.__m__-_R_lmiub_{--col-flex-grow:auto;--col-flex-basis:16.666666666666668%;--col-max-width:16.666666666666668%;}}@media(min-width: 62em){.__m__-_R_lmiub_{--col-flex-grow:auto;--col-flex-basis:33.333333333333336%;--col-max-width:33.333333333333336%;}}</style><div class="m_96bdd299 mantine-Grid-col __m__-_R_lmiub_ mantine-visible-from-md"><div style="background-color:var(--mantine-color-indigo-light);border:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-bottom:var(--mantine-spacing-xl);padding:var(--mantine-spacing-xl);width:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root"><div style="margin-bottom:var(--mantine-spacing-md)" class="m_4451eb3a mantine-Center-root" data-inline="true"><p style="font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Категории</p></div><ul class="m_abbac491 mantine-List-root"><li style="margin-bottom:var(--mantine-spacing-xs)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><button style="color:inherit;text-decoration:underline" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Мотивация">Мотивация</button></span></div></li><li style="margin-bottom:var(--mantine-spacing-xs)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><button style="color:inherit;text-decoration:underline" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Истории успеха">Истории успеха</button></span></div></li><li style="margin-bottom:var(--mantine-spacing-xs)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><button style="color:inherit;text-decoration:underline" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Дневник студента">Дневник студента</button></span></div></li><li style="margin-bottom:var(--mantine-spacing-xs)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><button style="color:inherit;text-decoration:underline" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Код">Код</button></span></div></li><li style="margin-bottom:var(--mantine-spacing-xs)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><button style="color:inherit;text-decoration:underline" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Карьера">Карьера</button></span></div></li></ul></div><div style="justify-content:end;margin-top:0rem;position:sticky;top:calc(5rem * var(--mantine-scale))" class="m_8bffd616 mantine-Flex-root __m__-_R_5dlmiub_"><div tabindex="0" style="cursor:pointer"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses_java?promo_name=program_category&promo_position=blog_post&promo_creative=card&promo_type=card"><div style="background-color:var(--mantine-color-default);border:calc(0.0625rem * var(--mantine-scale)) solid var(--mantine-color-default-border);padding-inline:var(--mantine-spacing-xl);padding-top:var(--mantine-spacing-xl);padding-bottom:var(--mantine-spacing-xs);width:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root"><div class="m_4451eb3a mantine-Center-root" data-inline="true"><p style="font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Курсы по Java</p></div><img class="m_9e117634 mantine-Image-root" src="/vite/assets/development-BVihs_d5.png"/><p style="margin-bottom:var(--mantine-spacing-xs);text-align:right" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></a></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-CdBlNCiQ.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>