ООП — это здорово, но оно незаметно усложняет ваши простые программы.

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

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

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

Как ООП усложняет простые проекты

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



В настоящее время мы можем использовать удобные для человека языки программирования с различными парадигмами — благодаря англоподобному синтаксису и современным языковым функциям. Парадигма ООП побуждает разработчиков разбивать операторы исходного кода на классы и создавать объекты с состоянием и действиями. ООП — хороший выбор для решения бизнес-ориентированных задач, поскольку мы можем легко изолировать бизнес-сущности как классы. Например, посмотрите, как основанная на Python платформа с открытым исходным кодом ERPNext использует наследование с бизнес-сущностью Customer с родительским классом TransactionBase:

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

Кроме того, отсутствие иерархии типов делает объекты в Go гораздо более легкими, чем в таких языках, как C++ или Java. — Перейти в раздел Часто задаваемые вопросы

Иногда вам нужно даже создавать классы и объекты для сущностей, которым не нужно несколько экземпляров (например, приложение, сервер, конфигурация и т. д.), чтобы придерживаться стиля OO. Такая ситуация часто случается с не бизнес-ориентированными проектами.

Парадигма процедурного программирования для программных проектов

Если ООП часто усложняет проекты, какая альтернативная парадигма подходит для разработки программных систем? Функциональное программирование? — мы можем использовать некоторые концепции функционального программирования, но не все — поскольку чистое функциональное программирование предлагает решения для неуниверсальных вариантов использования, таких как сложная обработка данных и математические вычисления.

Когда и как вы впервые изучили компьютерные алгоритмы? — вы, вероятно, начали изучать алгоритмы с блок-схем, изучая общие структуры управления. Позже вы, вероятно, изучали структурное программирование, используя эти управляющие операторы. Разработка программного обеспечения с помощью структурного программирования несложна, поскольку оно не имеет абстракции от теоретических алгоритмов информатики и меньше абстракции от родного языка ЦП (сборка ISA). Мы можем комбинировать концепции из парадигм структурированного, модульного, процедурного и функционального программирования, чтобы создать простую альтернативу ООП.

Вот простая альтернатива ООП:

Мы можем использовать модули вместо классов, процедуры (функции) вместо методов класса (или классов), записи вместо объектов с состоянием, пользовательские стили кода вместо модификаторов доступа и переменные уровня модуля вместо постоянных состояний класса. Например, посмотрите, как я разложил программный код CLI на несколько модулей CommonJS в соответствии с принципами модульного программирования:

В ООП мы часто распределяем логику по методам класса, тогда нам приходится проверять несколько классов, чтобы понять конкретный логический поток. В крупных ООП-проектах понимание конкретного логического потока, несомненно, требует много времени. Следовательно, мы можем писать функции вместо методов класса. Но какова альтернатива приватным методам? Мы можем использовать собственный стиль кода для представления частных функций. Посмотрите на следующий пример:

Управление состоянием программы легко и естественно с помощью ООП, но концепции, подобные наследованию, могут усложнить процесс обработки состояния. Существует два подхода к управлению состоянием программы в процедурном программировании: с глобальными переменными или с передачей состояния в качестве аргумента — выберите один из них в соответствии с вашими предпочтениями и требованиями. Обработка состояния на основе аргументов дает хорошо тестируемый и чистый код. Тем не менее, обработка состояния на основе глобальных переменных неплоха — она также дает хороший код, если мы не меняем состояние программы во многих местах.

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

Эта альтернатива процедурному программированию выглядит великолепно, но как мы можем управлять пулами объектов с отслеживанием состояния? Например, как мы можем реализовать список процессов без класса Process на основе ООП? В мире процедурного программирования объект становится записью. Посмотрите на следующий пример:

Приведенный выше фрагмент кода C++ является частью модуля управления расширениями. Он имеет переменную loadedExtensions уровня модуля и несколько связанных с ней процедур. Если мы перепишем это с парадигмой ООП, нам, вероятно, потребуется создать два класса: Extension и ExtensionManager, но сейчас все просто с одним минимальным модулем. Здесь мы использовали вектор строки для хранения информации о расширении, но мы можем использовать вектор структуры, если в записи расширения много полей (не объект).

Использование парадигмы процедурного программирования

Мы действительно можем использовать подход процедурного программирования с C, поскольку C является процедурным языком. Например, проверьте функции обработки файлов из Стандартной библиотеки C, вы заметите, что вам нужно передать указатель FILE в каждую функцию обработки файлов. Кроме того, мы можем увидеть шаблон процедурного программирования, изучив исходный код ядра Linux, как показано ниже:

Использование чисто процедурной парадигмы, несомненно, невозможно в популярных языках программирования, таких как C++, JavaScript и Python. Причина в том, что стандартные API-интерфейсы библиотек этих языков предлагают ООП-классы для программистов. Например, посмотрите, как стандартная библиотека JavaScript предлагает объектно-ориентированный интерфейс для создания наборов:

let numbers = new Set(); // constructor
numbers.add(10); // class method
console.log(numbers.size); // class property

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

Заключение

ООП — это естественная парадигма программирования для решения почти всех реальных проблем, но она искусственна с точки зрения процессора. ЦП не рассматривает набор инструкций конкретной программы как объекты и ссылки, а рассматривает всю программу как набор процедур и параметров. Таким образом, с технической точки зрения парадигма естественного программирования является процедурной парадигмой разработки программных систем.

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

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

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



Спасибо за прочтение.