- PVSM.RU - https://www.pvsm.ru -
Осваивая рецепты эффективного развития программного проекта, постарался для себя найти причины, делающие полезным использование принципов развития архитектуры SOLID (статья Как не понимать принципы развития архитектуры SOLID [1]).
Анализ этих принципов позволил выделить несколько ключевых закономерностей и базовых элементов, существующих в разработке. Они позволили описать, понять и внедрить SOLID в реальной работе с программным проектом.
Стало интересно выполнить анализ применимости этих понятий для общепринятых парадигм программирования, например для ООП. Хорошо, если результат этой работы будет полезен и Вам.
На сегодняшний день существует множество подходов для проектирования и последующей реализации программных проектов. Наиболее востребованными в работе с большими программными проектами являются: структурное программирование [2], функциональное программирование [3], объектно-ориентированное программирование [4].
Для меня стал интересен анализ причин возникновения этих подходов проектирования. И в процессе анализа неожиданным открытием стал факт, что все они неявно основываются на следующей предпосылке:
Необходимость планомерного развития проекта
с минимизацией затрат на повторное написание кода,
тождественного или сходного с уже существующим.
Что такое проект без необходимости развития? Такие проекты изредка встречаются и в основном характеризуются быстрой сдельной оплатой без возникновения последующих обязательств со стороны программиста, например:
В подобных ситуациях усилия программиста, направленные на поддержание, например, объектно-ориентированного подхода, тратятся впустую. Часто бывает, что я обнаруживаю себя в таком бессмысленном занятии во время разработки одноразовой консольной утилиты, когда вдруг понимаю, что написание текста 4-ого класса в этом проекте задержало меня на 15 минут и к результату не приблизило. Самое печальное, что все классы, с трудом написанные в таких проектах, забываются и не используются повторно, то есть не облегчают нам работу в дальнейшем.
Во всех остальных ситуациях программист, минимизируя свой труд, должен развивать структурно-сложный проект, то есть:
Если поискать аналогии развитию программного проекта, то можно вспомнить эволюцию биологического вида.
Программный проект подобен сложному развивающемуся "организму".
Программист для этого организма - изменчивость и естественный отбор в одном лице.
Зарплата программиста совместно с его навыками - скорость эволюции.
Труд программиста не легок, но у программиста есть "помощник". Этот помощник спрятан где-то глубоко в устройстве нашего мира, в котором есть две особенности:
Этот полезный во многих областях алгоритм далее для краткости буду именовать универсальным алгоритмом. Его реализацию для конкретной области применения можно назвать специализацией, так как процесс уточнения алгоритма для использования в узкой области применения подобен эволюционной специализации клеток в живом организме.
Очевидно, что для создания алгоритма требуется выделить признаки, которые обеспечивают применимость алгоритма. Эти признаки необходимо искать во входных данных и в описании начальной ситуации (контекста). Для создания универсального алгоритма необходимо в каждой предметной области, имеющей свои наборы признаков данных и ситуаций, выделить тождественные для всех областей признаки применимости. Все остальные признаки, не обеспечивающие применимость, универсальным алгоритмом игнорируются. Формализуя универсальный алгоритм, мы пришли к необходимости использования абстрагирования — одного из самых важных принципов ООП. При этом для ООП характерен акцент лишь на абстракции данных.
Здесь попробую выписать примеры использования абстрагирования из разных областей.
Абстракция | Алгоритмы | Область применения |
---|---|---|
Натуральные числа | Алгоритмы количественных расчетов | Задачи учёта хозяйственных ценностей |
Масса-характеристика материального тела | Алгоритмы-операций сравнения количества вещества | Задачи сравнения ценности товара, не поддающегося счету |
Интерфейс с операциями для коллекции элементов: полный обход, сравнение и обмен позиций | Алгоритмы сортировки коллекции | Программирование |
Интерфейс одинаковых операций для "концевого узла" и "узла ветвления" в дереве | Алгоритмы на основе шаблона проектирования "Компоновщик" | Разработка сложного программного проекта |
Ключевое понятие "Работник" | Формулировки в разделе "Трудовой договор" | Трудовой кодекс |
Используя разные приемы абстракции, программист выполняет реализацию алгоритма в виде участка кода, который представляет собой обособленный и законченный элемент его труда. Этот элемент в зависимости от используемого языка программирования может представлять собой и функцию, и объект, и последовательность инструкций. Назовем для удобства дальнейшего изложения этот фрагмент кода словом "компонент".
Компонент — участок кода (процедура, класс, deployment component и т.д.):
С использованием термина компонент появляется возможность сформулировать совокупность простых закономерностей, существующих в разработке программного проекта. Эти закономерности представлю в виде следующих утверждений, разбитых на 3 категории.
Попробую, используя перечисленные утверждения, выполнить анализ основных понятий объектно-ориентированного программирования. Этот анализ обходит понятие абстрагирование, так как оно уже было описано ранее в формализации способа построения универсального алгоритма.
Данные понятия ООП закрепляют целесообразность использования специального вида компонента, описываемого совокупностью некоторых внутренних данных и методов работы с этими данными. Все утверждения группы [1] и [2] транслируются в ООП, для которого термин компонент заменяется понятием класс.
При этом, на первый взгляд, отношения класса и объекта исчерпываются группой утверждений [3], в которой база заменяется понятием класс, а реализация — понятием объект. Причем реализация получается динамическая, то есть изменяемая в процессе исполнения программы.
Понятие "инкапсуляция" можно рассмотреть с двух "сторон".
Первая сторона понятия "инкапсуляция" — это обособленность компонента от других участков кода. Это свойство позволяет программисту для внесения изменений в компонент выполнить операции в участках кода, которые расположены "близко". То есть минимизировать затраты времени программиста, исключая из работы поиск и анализ разрозненных взаимодействующих элементов программы. Эта сторона задается свойствами компонента, следующими из его определения.
Вторая сторона понятия "инкапсуляция" — это сокрытие внутренней реализации компонента. Это сокрытие возможно с использованием понятий база и реализация, описанных в группе утверждений [3]. Для этого публичные методы класса отождествляются с базой, а приватные и защищенные методы класса — с реализацией. В местах использования используются ограничения, формируемые базой, и потому появляется возможность производить изменения в реализации, не касающиеся базовых ограничений. И эти изменения реализации не нужно проверять в местах использования базы [3.5], что обеспечивает минимизацию трудозатрат программиста.
Примечательно, что понятие "инкапсуляция" имеет аналогию в биологии. Этот процесс первой своей стороной схож с биологическими функциями "Клеточной мембраны [5]".
Понятия "наследование" продолжает закреплять важность использования связки база + реализация. Для этого в группе утверждений [3] необходимо методы родительского класса отождествить с базой, а методы класса-наследника отождествить с реализацией.
В своей реализации понятие "наследование" позволяет использовать утверждение [2.3], то есть использовать дополнение кода вместо его изменения и дублирования. При этом необходимо исключить дублирование базового алгоритма. Однако, у подхода, использующего наследование для специализации универсального алгоритма, есть существенный минус. Этот недостаток — наличие двух сильно-связных компонентов, которые тяжело изменять независимо. Эти связи-зависимости порождаются отношением родитель-наследник.
Существует множество альтернативных способов использовать связку база + реализация. Приведу далее примеры таких способов.
База | Реализация | Область применения |
---|---|---|
Публичные методы класса | Приватные методы класса | Инкапсуляция |
Защищенные методы родительского класса | Методы класса-наследника | Наследование |
Интерфейс динамической библиотеки | Функционал динамической библиотеки | Компонент=динамическая библиотека |
Шаблонные (обобщенные) методы и классы (template, generic) | Инстанцирование шаблона с указываемыми аргументами | Обобщенное программирование |
Универсальные методы, принимающие делегаты | Специализация методов указанием конкретных процедур обработки | Процедуры сортировки или формирования дерева, с указанием метода оценки порядка элементов |
Классы, предусматривающие взаимодействие с шаблоном "Посетитель" | Формирование "Посетителя" с требуемым функционалом | Шаблон проектирования "Посетитель" |
Панель управления АЭС | Совокупность автоматики и оборудования АЭС | Сокрытие сложности системы от оператора АЭС |
Параллельно, подмечаю, что для понятия "наследование" из ООП, так же можно найти аналогию в процессах биологической эволюции. В биологии для этого используется термин "Наследственность [6]".
По моему мнению, понятие "полиморфизм" — это вторая сторона при взгляде на процедуру создания универсального алгоритма. Первая сторона ( абстрагирование) — это взгляд с точки зрения способов создания универсального алгоритма. В то же время при взгляде на универсальный алгоритм с точки зрения пользователя, получаем запись понятия полиморфизм. То есть полиморфизм это полезная способность функции (компонента) обрабатывать данные разных типов. Добавление этого понятия в ООП закрепляет полезность использования универсального алгоритма в разработке программного проекта.
Реализации полиморфизма в разных языках программирования сильно отличаются. В статье Википедии для полиморфизма [7], в зависимости от его реализации, выделяют 4 подтипа: параметрический, включения (или подтипов), перегрузки, приведения типов. Эти реализации имеют существенные отличия, но все они объединяются одной целью — это написание универсального алгоритма, который не нужно будет дублировать для конкретной его специализации.
И на этот раз почти без удивления, нашел аналогию для понятия "полиморфизм" в биологии. Название этого биологического термина полностью совпадает с понятием из ООП. "Полиморфизм [8]" — способность одного организма существовать в состояниях с различной внутренней структурой или в разных внешних формах.
Таким образом почти все основные понятия ООП можно представить в виде совокупности простых утверждений, сформированных на основе закономерностей развития программного проекта. При этом для ООП термин компонент отождествляется с понятием класс. Если же выделить для термина компонент другое значение, например функция, то возможно получится сформулировать основные понятия функционального программирования.
В процессе написания статьи были найдены биологические аналогии для понятий, используемых в программировании. Эти аналогии появляются из-за подобия способов развития программного продукта и некоторых процессов биологической эволюции.
IMHO, целесообразно рассмотреть эти две научные области совместно. При этом, возможно, получится провести перенос законов из одной отрасли в другую, и тем самым обеспечить развитие и информационных технологий, и формальных описаний биологических процессов.
Спасибо Вам за внимание.
Буду очень благодарен за отзывы, пожелания и предложения, так как они помогают мне скорректировать направление развития работы в этой области.
Под редакцией Борисовой М.В.
Автор: Алексей
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/314494
Ссылки в тексте:
[1] Как не понимать принципы развития архитектуры SOLID: https://habr.com/ru/post/444932/
[2] структурное программирование: https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%BD%D0%BE%D0%B5_%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%D0%B5
[3] функциональное программирование: https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%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%D0%B5
[4] объектно-ориентированное программирование: https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D0%B5_%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%D0%B5
[5] Клеточной мембраны: https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B5%D1%82%D0%BE%D1%87%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B5%D0%BC%D0%B1%D1%80%D0%B0%D0%BD%D0%B0
[6] Наследственность: https://ru.wikipedia.org/wiki/%D0%9D%D0%B0%D1%81%D0%BB%D0%B5%D0%B4%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D1%8C
[7] полиморфизма: https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%BB%D0%B8%D0%BC%D0%BE%D1%80%D1%84%D0%B8%D0%B7%D0%BC_(%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)
[8] Полиморфизм: https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%BB%D0%B8%D0%BC%D0%BE%D1%80%D1%84%D0%B8%D0%B7%D0%BC_(%D0%B1%D0%B8%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F)
[9] Общая теория алгоритмов wiki: https://bitbucket.org/aibor/ai_borisov_cit/wiki/Home
[10] Первая статья серии: https://habr.com/ru/post/446066/
[11] Источник: https://habr.com/ru/post/448026/?utm_source=habrahabr&utm_medium=rss&utm_campaign=448026
Нажмите здесь для печати.