Это код, который легко читать, понимать, поддерживать и расширять. Он эффективно решает поставленные задачи и соответствует требованиям качества, которые важны для конкретного проекта и команды.
Код должен быть понятным для других разработчиков, даже если они не знакомы с проектом. Использование осмысленных имён для переменных, функций и классов, а также наличие чётких комментариев помогают быстрее понять логику программы. Читаемый код снижает риск ошибок при поддержке и улучшении, упрощает ревью и обучение новых участников команды.
Код должен легко поддаваться изменениям, чтобы можно было адаптировать его под новые требования или исправлять ошибки. Это достигается за счёт модульности, изолирования логики и избегания «жёсткого» связывания частей кода. Хорошая структура и стандартизация, такие как следование принципам SOLID или архитектурным шаблонам (например, MVC), делают код более устойчивым.
Хороший код решает задачи самым простым и прямым способом. Простой код легче читать, тестировать и отлаживать. Он избегает ненужных усложнений и излишних абстракций, но при этом остаётся гибким. Следование принципу KISS (Keep It Simple, Stupid) и принципу YAGNI (You Aren't Gonna Need It) помогает держать код простым.
Код должен быть оптимизирован для выполнения задачи без избыточного потребления ресурсов, таких как время выполнения и память. Хотя преждевременная оптимизация нежелательна, хороший код учитывает производительность и избегает явных узких мест. Понимание алгоритмов и структур данных помогает писать эффективный и быстрый код.
Хороший код легко тестировать. Это означает, что его можно покрыть модульными, интеграционными и системными тестами. Тестируемость обеспечивается за счёт слабого сцепления и высокой связанности, а также соблюдения принципов инверсии зависимостей. Код, который легко тестировать, позволяет быстрее находить и исправлять ошибки, что повышает общую надёжность.
Хороший код легко адаптируется к изменяющимся требованиям. Новые функции можно добавлять без значительных изменений существующей логики. Это достигается благодаря слабому сцеплению и высокой связанности, применению шаблонов проектирования и принципов SOLID.
Хотя код должен быть самодокументируемым, иногда необходимы комментарии и документация, чтобы объяснить сложную логику, архитектурные решения или нюансы реализации. Хорошая документация помогает быстрее разобраться в коде и понять его использование.
Код должен соответствовать общим стандартам стиля, принятым в проекте или языке. Это делает его единообразным и легко читаемым для других участников команды. Использование линтеров, форматтеров и следование общеотраслевым стандартам (например, PEP8 для Python) помогает поддерживать единый стиль.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
INNER JOIN возвращает только строки, которые имеют совпадения в обеих таблицах.
Таким образом, LEFT JOIN сохраняет все данные левой таблицы, а INNER JOIN работает только с пересечением данных.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Это процесс создания системы, которая продолжает корректно работать даже при частичных сбоях. Отказоустойчивость позволяет приложению оставаться доступным, минимизировать потери данных и поддерживать положительный пользовательский опыт в случае непредвиденных ситуаций.
Балансировщики нагрузки распределяют входящий трафик между несколькими серверами, чтобы снизить нагрузку на отдельные серверы и избежать перегрузок. В случае сбоя одного сервера запросы автоматически перенаправляются на работающие экземпляры. Использование балансировщика повышает масштабируемость системы, поскольку позволяет легко добавлять или убирать серверы по мере необходимости.
Развертывание приложения на нескольких серверах (в кластере) позволяет избежать единой точки отказа (SPOF — Single Point of Failure). Горизонтальное масштабирование даёт возможность добавлять дополнительные серверы при увеличении нагрузки, что повышает отказоустойчивость и общую производительность системы. Сервисы, такие как Kubernetes и Docker Swarm, упрощают управление и оркестрацию контейнеров в кластере, автоматизируя процесс развертывания, обновлений и балансировки нагрузки.
Важные данные должны регулярно сохраняться в резервных копиях и реплицироваться на несколько узлов или в несколько дата-центров. Репликация базы данных (например, master-slave или master-master репликация) обеспечивает доступность данных, даже если один из узлов выходит из строя. Для обеспечения целостности данных реплики могут быть синхронными (обеспечивают актуальность данных на всех узлах, но добавляют задержку) или асинхронными (с меньшей задержкой, но возможностью устаревания данных).
Использование кешей (Redis, Memcached) снижает нагрузку на базу данных и позволяет быстрее обрабатывать запросы, снижая риски сбоев из-за высокой нагрузки. Content Delivery Network (CDN) распределяет контент по серверам, находящимся близко к пользователю. Это снижает нагрузку на основной сервер и обеспечивает доступность контента в случае перегрузки или отказа в одном из центров обработки данных.
Настройка систем мониторинга (например, Prometheus, Grafana, New Relic) позволяет оперативно выявлять сбои и реагировать на проблемы. Системы автоматического восстановления могут перезапускать упавшие серверы или контейнеры. Например, инструменты оркестрации, такие как Kubernetes, могут автоматически восстанавливать неработающие контейнеры. Настройка системы оповещений для обнаружения потенциальных проблем (например, медленного ответа сервера) позволяет вовремя реагировать на них и предотвращать крупные сбои.
Для работы с критически важными задачами, которые могут быть временно отложены, целесообразно использовать системы очередей сообщений (например, RabbitMQ, Kafka). Очереди позволяют обрабатывать запросы асинхронно, обеспечивая бесперебойную работу системы при перегрузках. Если один компонент выходит из строя, другой может продолжить обработку сообщений из очереди после восстановления.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2. Зависимость от ручных процессов: отсутствие автоматизированных процедур восстановления может замедлить работу.
3. Недостаточная документация или неполные инструкции по восстановлению системы.
Эти факторы могут усложнить устранение неполадок и требуют проактивного подхода к подготовке.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🤔1
Позволяет компонентам обмениваться данными и выполнять задачи независимо друг от друга, не дожидаясь завершения операций. Асинхронное общение широко применяется в микросервисных архитектурах и других распределённых системах, так как повышает масштабируемость, гибкость и отказоустойчивость системы.
Очереди сообщений (например, RabbitMQ, Apache Kafka, Amazon SQS) помогают отправлять и получать сообщения асинхронно, обеспечивая буфер между отправителем и получателем. Брокеры сообщений сохраняют сообщения до тех пор, пока получатель не будет готов их обработать, что помогает управлять потоками данных и уравновешивать нагрузку. Такой подход позволяет отправителю отправить сообщение и сразу продолжить свою работу, не дожидаясь ответа, что повышает производительность системы.
В модели «издатель-подписчик» компоненты могут публиковать события, на которые подписаны другие компоненты, а брокер сообщений доставляет события всем подписчикам. Этот паттерн позволяет системе оставаться слабосвязанной, так как издатель не знает, сколько и какие конкретно сервисы получат событие. Такие системы часто применяются для уведомлений, регистрации событий, обработки данных и отправки уведомлений нескольким сервисам одновременно.
В очереди задач сообщения представляют собой задачи для выполнения, которые обрабатываются одним или несколькими исполнителями. Этот паттерн полезен для распределения нагрузки на сервисы, позволяя выполнять задачи асинхронно, когда они становятся доступны, и автоматически управлять потоками. Например, задача по отправке электронной почты может быть помещена в очередь и обработана отдельным рабочим процессом, что освобождает основной сервис от ожидания завершения отправки.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это два ключевых свойства модульной архитектуры программного обеспечения, которые помогают оценить качество кода и архитектурных решений.
Описывает степень зависимости одного модуля от других. Высокое сцепление означает, что модули сильно зависят друг от друга, что затрудняет их изменение, тестирование и повторное использование, так как изменения в одном модуле требуют изменений в зависимых модулях. Идеально стремиться к слабому сцеплению, чтобы модули были максимально независимыми. Это позволяет изменять или заменять один модуль без необходимости изменения других.
Описывает, насколько тесно связанные и объединённые общей задачей элементы внутри одного модуля. Высокая связанность означает, что все функции и данные модуля логически связаны и выполняют одну задачу. Это упрощает понимание кода и делает модуль более автономным.Высокая связанность считается хорошей практикой, так как модуль с высокой связанностью проще в обслуживании, его легче изменить или заменить.
Представьте модуль, который управляет пользователями: если в модуле только функции для работы с пользователями (например, добавление и удаление), он обладает высокой связанностью, так как его функции направлены на одну задачу. Если модуль при этом минимально зависит от других частей системы, это говорит о слабом сцеплении.
Это желательные качества. Они помогают создать более гибкую и поддерживаемую систему.
Лучше, когда оно слабое, так как снижает зависимость между модулями.
Лучше, когда она высокая, так как все функции модуля работают на достижение одной цели.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Логика предметной области в хранимых процедурах — это подход, при котором бизнес-логика (правила и операции, связанные с управлением данными) реализуется непосредственно на уровне базы данных с использованием хранимых процедур. Этот подход имеет свои плюсы и минусы, которые важно учитывать при проектировании архитектуры приложения.
Хранимые процедуры выполняются на уровне базы данных, что позволяет избежать сетевых задержек при передаче данных между приложением и базой. Процедуры могут работать с данными напрямую, избегая лишних перегрузок и ускоряя обработку сложных запросов.
Современные СУБД могут кэшировать планы выполнения хранимых процедур, что снижает накладные расходы на компиляцию и оптимизацию запросов. Благодаря кэшированию повышается производительность повторных вызовов процедур, особенно в случаях обработки больших объёмов данных.
Хранимые процедуры могут содержать бизнес-логику, обеспечивая консистентность её выполнения независимо от источника вызова. Это удобно при использовании единой базы данных для нескольких приложений. Такой подход уменьшает дублирование кода, так как логика определена в одном месте — в базе данных.
Хранимые процедуры могут содержать сложные транзакции, обеспечивая целостность данных и управление транзакциями на уровне базы. Это может быть удобнее, чем реализация транзакций на уровне приложения, особенно для сложных многошаговых операций.
Логика, встроенная в хранимые процедуры, позволяет лучше контролировать доступ к данным. Разработчики могут ограничить прямой доступ к таблицам, предоставляя доступ к данным только через процедуры. Это повышает безопасность, так как доступ к данным осуществляется через контролируемые процедуры, где можно задать права доступа.
Реализация бизнес-логики в хранимых процедурах может усложнить кодовую базу, так как SQL и процедурные языки базы данных, такие как PL/pgSQL или T-SQL, могут быть менее выразительными и сложными в поддержке. Такой код часто труднее тестировать, отлаживать и версионировать, чем код на языке высокого уровня, таком как Java или Python.
Бизнес-логика, встроенная в хранимые процедуры, делает приложение сильно зависимым от конкретной СУБД, что затрудняет переносимость. Если требуется смена СУБД, перенос логики может оказаться сложным и трудозатратным. Различия в реализации хранимых процедур для разных СУБД также могут затруднять кросс-платформенное развитие.
Базы данных, хотя и мощные, могут столкнуться с ограничениями производительности при высокой нагрузке. В случае высокой нагрузки сервер приложений может масштабироваться горизонтально (добавлением серверов), а сервер базы данных — нет. Вложение большого объёма бизнес-логики в базу данных может привести к её перегрузке, ограничивая гибкость и масштабируемость приложения.
Изменение хранимых процедур часто требует обновлений на уровне базы данных, что может быть сложным и требовать простоя. В отличие от кода приложения, обновление хранимых процедур затрагивает работу всей базы. Этот фактор особенно неудобен в условиях Agile-разработки, где быстрое внесение изменений является важной частью процесса.
Тестирование и автоматизация развертывания хранимых процедур сложнее, чем тестирование и развертывание бизнес-логики на стороне приложения. CI/CD процессы для хранимых процедур менее развиты и часто требуют дополнительных инструментов и сложной настройки, что добавляет накладные расходы на разработку.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Оператор
goto считается "злом" в программировании, потому что его использование может значительно усложнить структуру и логику программы, делая код трудным для понимания, сопровождения и отладки. goto нарушает последовательный поток выполнения программы, произвольно перемещая управление в другое место кода. Это может привести к хаотичной структуре, где трудно проследить, как данные перемещаются и как выполняется логика. Переходы с помощью goto делают код нечитаемым, поскольку программисту приходится "прыгать" по коду, чтобы понять, что происходит. В больших программах это приводит к запутанной логике и фрагментированности.В коде с частым использованием
goto может появиться так называемый "спагетти-код", где переплетённые переходы между различными частями кода делают его сложным для понимания. В "спагетти-коде" контроль над выполнением разбросан по многим местам, что приводит к ошибкам, особенно при модификации программы.Логика с использованием
goto труднее отлаживать, поскольку управление переходит в произвольные места. Это осложняет трассировку и отслеживание исполнения программы, делая выявление ошибок более трудоёмким. Внесение изменений также становится рискованным: даже малейшее изменение может привести к неожиданным ошибкам из-за непредсказуемого изменения порядка выполнения.Структурное программирование основывается на трёх базовых конструкциях: последовательности, ветвления и цикла.
goto же позволяет "вырваться" за пределы этих конструкций, что разрушает структурированность программы. Программы с goto теряют понятную иерархию и становятся неуправляемыми, так как переходы могут происходить в любой момент, минуя условные конструкции, циклы и функции.Код с
goto часто сложно разделить на отдельные модули или функции, поскольку переходы могут приводить к произвольным точкам в коде, включая те, которые выходят за пределы функций. Это также усложняет повторное использование кода, так как фрагменты, использующие goto, могут зависеть от конкретного места выполнения.В системном программировании или драйверах, где требуется максимальная производительность и минимальные накладные расходы.
В некоторых языках, таких как C,
goto может использоваться для выхода из нескольких уровней вложенных циклов, что иногда более эффективно и проще, чем добавление флагов или вспомогательных функций.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2🎉1
Термин «Ошибка на миллиард долларов» в отношении
NULL был введён известным учёным и программистом Тони Хоаром, который в 1965 году изобрёл NULL-ссылки. Спустя годы он назвал это решение "ошибкой на миллиард долларов", поскольку использование NULL привело ко множеству ошибок и уязвимостей, стоивших компаниям и разработчикам огромных затрат на устранение последствий.NULL часто приводит к ошибкам из-за его некорректной обработки. Если программа ожидает, что переменная содержит значение, а вместо этого встречается NULL, это приводит к сбоям, падениям и исключениям. Популярная ошибка — это NullPointerException, которая происходит, когда программа пытается использовать NULL как объект или ссылку. Такие ошибки трудно обнаружить, так как их проявление зависит от условий выполнения программы и использования данных, что делает их сложными для отладки и тестирования.Использование
NULL обязывает программистов проверять каждую переменную на предмет NULL, чтобы избежать сбоев. Это усложняет код, делает его менее читаемым и подверженным ошибкам, особенно когда проверки на NULL игнорируются или забываются. Чем больше кода, связанного с обработкой NULL, тем выше вероятность появления багов, особенно если пропущены проверки.NULL разрушает понятие инкапсуляции, так как от программиста требуется знать, может ли переменная быть NULL или нет. Часто интерфейсы неявно предполагают, что некоторые данные могут быть NULL, что может вводить разработчика в заблуждение. В дополнение, использование NULL неявно снижает выразительность кода, так как вместо определённого значения "ничего" (например, "не определено" или "неизвестно") часто используется просто NULL, что ухудшает понимание кода.Ошибки, связанные с
NULL, могут привести не только к сбоям, но и к уязвимостям, открывающим путь для атак. Например, злоумышленники могут использовать уязвимости, вызванные неправильной обработкой NULL, чтобы вызвать некорректное поведение системы или обойти ограничения доступа.В языках, таких как Java, Kotlin, C# и других, существуют типы
Optional (или Option в функциональных языках), которые обязывают явно указывать, что переменная может не содержать значения. Optional заставляет программиста явно обрабатывать случаи отсутствия значения, что уменьшает вероятность случайного использования NULL и упрощает работу с отсутствием данных.Некоторые языки, например Kotlin и Swift, поддерживают строгую систему типов, которая позволяет объявлять
nullable и non-nullable переменные. Если переменная объявлена как non-nullable, компилятор не позволит присвоить ей NULL или использовать её как NULL. Этот подход повышает безопасность кода на этапе компиляции, предотвращая распространённые ошибки с NULL-ссылками.Современные инструменты статического анализа (такие как SonarQube, ReSharper, FindBugs) могут автоматически обнаруживать места потенциального использования
NULL и предупреждать разработчиков. Эти инструменты помогают выявить случаи, когда переменная может оказаться NULL, и помогают предотвратить ошибки до выполнения программы.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Плохая организация кода проявляется в признаках, которые затрудняют его понимание, сопровождение и расширение. Такие проблемы могут быть следствием недостатков в архитектуре, неверного структурирования модулей, низкой читаемости и слабой гибкости.
Повторение одних и тех же блоков кода в нескольких местах. Дублированный код усложняет сопровождение, поскольку изменения нужно вносить в нескольких местах, что повышает вероятность ошибок. Выявлять общие фрагменты кода и выделять их в отдельные функции или методы. Следовать принципу DRY (Don't Repeat Yourself).
Модуль содержит функции, которые не связаны общей задачей, или класс имеет свойства и методы, не объединённые одной логикой. Пониженная связанность затрудняет понимание того, за что отвечает модуль или класс, увеличивает вероятность ошибок. Стремиться к высокой связанности, чтобы модули выполняли одну чёткую задачу. Следовать принципу Single Responsibility (единственная ответственность).
Модули или классы сильно зависят друг от друга и для работы требуют конкретной реализации других частей системы. Высокое сцепление снижает гибкость и увеличивает время на изменения. Модификация одной части кода требует модификации множества зависимых компонентов. Стремиться к слабому сцеплению, разрабатывая независимые модули с понятными интерфейсами. Использовать инверсию зависимостей и интерфейсы.
Сложные алгоритмы или структуры, которые можно упростить без потери функциональности. Усложнённый код труднее понимать, тестировать и отлаживать. Большая вероятность ошибок из-за запутанной логики. Применять KISS (Keep It Simple, Stupid) и YAGNI (You Aren't Gonna Need It) для минимизации сложности и реализации только необходимых функций.
Функции, занимающие несколько экранов кода, и методы, которые выполняют несколько задач одновременно. Длинный код труден для понимания, тестирования и повторного использования. Длинные функции часто имеют слишком много ответственности. Разделять функции на более короткие, каждая из которых выполняет только одну задачу. Стремиться к следованию принципу SRP (Single Responsibility Principle).
Непонятные или непоследовательные имена, которые не отражают назначение переменной, функции или класса. Повышает сложность чтения и понимания кода для других разработчиков, увеличивает вероятность ошибок. Использовать осмысленные, выразительные имена, которые чётко отражают их цель. Следовать принятым стандартам именования и писать самодокументируемый код.
Подключение библиотек или модулей, которые не используются или используются минимально. Увеличивает сложность кода, усложняет деплой и повышает риск конфликта версий. Регулярно проверять зависимости и удалять неиспользуемые, использовать только необходимые библиотеки и модули.
Модули и классы не соответствуют базовым принципам SOLID (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion). Проблемы с расширяемостью и поддержкой. Изменения могут привести к ошибкам в коде и сильному сцеплению. Проверять архитектуру на соответствие принципам SOLID и вносить улучшения, если структура нарушена.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Полезен анализ планов выполнения (
EXPLAIN), системные логи запросов и внешние инструменты мониторинга вроде Percona или Datadog. В PostgreSQL используйте pg_stat_statements для анализа запросов по времени выполненияSELECT query, total_time FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;
В MySQL включите
slow_query_log для записи медленных запросовSET GLOBAL slow_query_log = 1; SET GLOBAL long_query_time = 1;
В SQL Server используйте
sys.dm_exec_query_statsSELECT TOP 10 total_elapsed_time / execution_count AS AvgTime, text FROM sys.dm_exec_query_stats CROSS APPLY sys.dm_exec_sql_text(sql_handle) ORDER BY AvgTime DESC;
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🤯2
Разработчики могут не любить Java по нескольким причинам, связанным с особенностями языка, его экосистемы и исторической репутацией.
Java часто критикуют за необходимость писать много шаблонного (boilerplate) кода. Например, для выполнения простых операций, таких как создание POJO-классов (Plain Old Java Object), разработчики вынуждены прописывать геттеры, сеттеры, конструкторы, методы
equals и hashCode. Несмотря на наличие библиотек, таких как Lombok, для уменьшения шаблонности, это остается одной из претензий к языку.Исторически Java обновлялась медленно, что вызывало недовольство. До перехода на модель выпуска версий каждые шесть месяцев (с Java 9), промежутки между релизами были слишком большими. Это приводило к отставанию языка от более динамично развивающихся конкурентов, таких как Kotlin, Scala или Python.
Некоторые считают Java "устаревшим" языком из-за особенностей, таких как ручное управление многопоточностью (до появления улучшенных инструментов в Java 8 и последующих версиях) или отсутствие "современного" синтаксиса (например, до появления
var).Раньше Java часто ассоциировалась с медленной работой из-за интерпретируемой природы байт-кода и большого объема памяти, необходимого для запуска JVM. Хотя современные реализации JVM (HotSpot, GraalVM) сделали Java очень быстрой, этот стереотип все еще живет.
В крупных проектах на Java все еще можно столкнуться с использованием старых библиотек и инструментов, таких как XML-конфигурации для Spring. Такие проекты требуют больше усилий для модернизации и поддержки.
Java — строго типизированный язык. Это обеспечивает надежность и удобство поддержки, но снижает гибкость при разработке прототипов или экспериментировании. Это особенно заметно в сравнении с языками, такими как Python или JavaScript.
Kotlin, развиваемый JetBrains, стал официальным языком разработки для Android в 2017 году. Он предлагает более лаконичный синтаксис, мощные функции работы с null-значениями, и в целом воспринимается как более "современный" язык.
Java обладает огромной экосистемой, которая может быть одновременно преимуществом и недостатком. Иногда требуется глубокое понимание JVM, инструментов сборки (Maven, Gradle), и других особенностей.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1