Aendor обратиться по имени
Вторник, 07 Декабря 2010 г. 13:15 (ссылка)
Функциональное программирование больно той же самой болезнью: нужно проектировать задом наперёд. Сначала проектируется общий вид основной функции, а потом всё ниже и ниже проектируются вспомогательные. То же самое в ООП: сначала проектируем интерфейс, а потом пытаемся реализовать. И если интерфейс оказался неподходящим, то переделывать придётся весь код. Если высокоуровневая функция в функциональном подоходе оказалась неподходящей, то переделывать весь код придётся в гораздо большей степени, чем в императивном ООП.
Оба подхода заставляют по форме (что должно быть) определить содержание (как должно быть). Вобщем-то вполне себе математичный подход. Теоретически красивый. Да, мы вот сейчас всё пишем и пишем, и на словах, действительно ООП гораздо красивее обычного структурного подхода. Кроме того, можно кучу книжек писать, ООП - богатая среда для мудрствований, например, вот те же замечательные философствования о шаблонах и рефакторинге. Так же как и функциональное программирование, а когда оно ещё и с монадами, то вообще, ууУУух как поумничать можно и статьи пописать.
C же освобождает от необходимости проектировать строго определённый интерфейс, конечно, от ответа на вопрос: что код должен делать? уйти вряд ли удасться, но ответ этот может быть достаточно нестрогим. Язык ориентирован на работу с данными, а не объектами. Если я совершу ошибку на этапе придумывания интерфейса, то мне никто не мешает напрямую залезть в структуру данных, и написать новый код для работы с ней, в том месте, где он нужен. Да, это грязно, это не математично, это нарушение кучи принципов, об этом не напишешь умную книжку, потому что это глупо, но это работет. И работает не только корректно, но и эффективно. Если подобный код мне нужен будет во многих местах - родилась абстракция - я его вынесу в соответсвующий модуль, и доступ к нему сделаю частью интерфейса.
Мог бы я подобное обнаружить на бумажке? Запросто, если бы писал на бумажке настоящую программу, до уровня операторов и вызов функций, а не просто рисовал бы стрелочки, то наверняка обнаружил бы то же самое. Но на бумажке невозможно написать нечто более или менее сложное.
Я могу предполагать, что в этом случае списки эффективны, но на реальных данных может оказаться, что они убивают производительность, или, вдруг оказывается, что для реализации некоторой возможности в новой версии нужно обращение к произвольному элементу. Если я это всё буду учитывать только после того, как напишу программу на бумажке, потом закодирую на ООП, потом откомпилирую, потом пойму, что все мои расчёты, мягко говоря, некорректные, потом опять сяду за бумажку... Я рискую ни одной эффективной программы за всю жизнь не написать.
В итоге, конечно, у меня тоже появляются объекты в программе, но границы у них не жёсткие, а размытые, и объекты именно появляются, а не спускаются сверху. Не тотальная закапсулированность позволяет упростить взаимодействие, особенно, при использовании в новом коде. А то, что объект возник естественным путём освобождает меня от необходимости прописывать какую-то невостребованную функциональность.
Да, всё то же самое можно делать и на C++, например. Но тогда надо будет делать все данные и методы изначально открытыми, и возникает вопрос, а зачем тогда этот весь этот лишний классовый синтаксис?
Ещё можно сказать, что в Smalltalk именно так формировались интерфейсы. Они формировались снизу вверх. Они возникали, а не навязывались сверху. Наследования же вообще не было. Все эти, на мой взгляд, сложности, связанные с проектирование сверху вниз, появились в компилируемых языках, в которых для повышения эффективности стали путать типы и объекты.
И последнее замечание: в книжках по функциональному программированию, обычно, всё истолковывается в терминах и примерах из императивных языков программирования, поэтому, в них со сравнением с другими технологиями всё лучше.