Квест → Как хакнуть форму
Прошли: 77
Основы объектно-ориентированного проектирования — О различии между простыми и сложными решениями.
перевод статьи "Foundations of OO Design"
Достаточно просто перепутать терминологию и называть системы "простыми" и "легкими" (re: в данной статье будет использоваться именно термин "легкий" в значении "простой с оттенком легкий", и "простой" как "простой" :) На самом деле труднопередаваемый нюанс языка, который в оригинале понятен и очевиден, но при попытке подобрать русскоязычный вариант, выясняется, что нет такой градации "простого". Ну нет у нас simple, easy, plain и т д А речь идет именно об этом. Читайте дальше, надеюсь, будет понятно). На самом деле это разные понятия, и от наших целей будет сильно зависеть то, как как мы проектируем систему. Разделяя "Простое" и "легкое", "комплексное" и "сложное" мы начинаем приходить к компромиссу в проектировании. Так мы и начнем делать наши проекты лучше.
Мы, в общем-то, живем в тяжелое время, чтобы отделить простое от легкого. Так давайте же изучим этот вопрос подробнее. Я собираюсь использовать кое-что из Rich Hickey's Examples:
Простое это противопоставление комплексному.
В принципе, это вполне объективная мера.
Простое означает:
Но не:
Простой в отсутствии чередования, а не количестве элементов. В этом контексте, два взаимосвязанных интерфейса сложнее, чем два отдельных друг от друга.
К примеру
interface A { public function doSomethingWithB(B $b); } interface B { public function doSomething(); } interface C { public function doThingOne(); public function doThingTwo(); } interface D { public function doSomethingElse(); public function doOtherThing(); public function doOtherThing2(); }
Из этого определения "простого" тут B+C проще, чем A+B, т к B+C не свяаны. Также C+D проще, чем A+B, хотя C+D делает "больше", но тут меньше взаимосвязи, а следовательно и чередования.
B проще, чем C, но нельзя говорить о C, как о самостоятельном , потому что этот интерфейс зависит от B. Таким образом, мы завершаем с этой иерархией "простоты" от самого простого до самого сложного:
B -> C -> B+C -> D -> B+D -> C+D -> A+B -> B+C+D -> A+B+C -> A+B+D -> A+B+C+D
Обратите внимание на то, что B+C проще, чем D, даже при том же числе методов. Это вызвано тем, что эти три метода из D связанные, они принадлежат тому же интерфейсу. У B+C есть то же число методов, но использование несвязанных интерфейсов далее разъединено, следовательно более простое.
Легкий - субъективная мера, то, что кажется легким мне, может не показаться таковым вам.
Легкий требует какого-то знания у автора, то есть я, не зная нидерландский язык,
буду считать книгу, написанную на нем трудной. Но при хорошем знании английского языка, книгу, написанную на нем, буду считать легкой, несмотря на её содержание.
То же самое для ООП, зная его достаточно глубоко, вам покажутся тривиальными какие-либо модификации.
Это два связанных, но не взаимозаменяемых понятия: трудность и сложность связана с вашими знаниями, тогда как простота (простота как антоним комплексности) связанна с понятием связности.
Со стороны более сложное решение кажется более трудным. Но на самом деле это не обязательно так. Если присмотреться, иногда дополнительная сложность может сделать вещи проще.
Таким образом, когда мы говорим о простоте, мы только говорим о связности и измеримой сложности. Мы не говорим о простоте в употреблении или простоте понимания.
Это - сложность, которая является основным принципом для решаемой задачи.
Если Вы пишете функцию, которая добавляет два числа, нет ничего проще, чем:
function add($a, $b) { return $a + $b; }
Основная сложность - достаточный минимум, чтобы решить проблему. По сути, это мера сложности проблемы.
Дополнительная сложность (иногда называемая случайной) является сложностью, это добавлено к решению, которое строго не требуется проблемой.
Если Вы пишете функцию, которая складывает два числа, то это будет так:
function add($a, $b) { if (!is_int($a) || !is_int($b)) { throw new \InvalidArgumentException( "Both A and B must be integers" ); } return $a + $b; }
Проверка ошибок тут - дополнительная сложность. Она необязательна для решения поставленной задачи (работало бы без неё), но добавляет уровень защиты.
"Дополнительная сложность" звучит с негативным оттенком, но она не всегда плоха. В данном случае - дополнительная проверка, делающая более устойчивым (надежным) приложение.
Эти принципы (аксиомы, если вам так больше нравится), являются базисом для всего вытекающего.
1.При прочих равных условиях простое решение всегда лучше, чем сложное решение. Обратите внимание на "при прочих равных условиях".
2.При прочих равных условиях решение должно попытаться минимизировать дополнительную сложность. Снова обратите внимание на "при прочих равных условиях".
3.При прочих равных условиях решение должно быть максимально просто для тех разработчиков, на кого вы ориентируеьтесь. Обратите внимание на то, что это не означает, что должно быть просто для всех, всё зависит от ваших целей. Если у вас профессиональная команда разработчиков, ориентируетесь на них. Если вы подумываете расширяться, ориентируетесь на кого-то с исходным набором навыков.
Например: если вы собираетесь нанимать разработчиков и используете у себя в проекте Symfony (например), то ориентируйтесь на максимальный фактор "легкости" для опытных Symfony разработчиков. (Примечание: имеется в виду преимущество в требовании опыта с Symphony, чем какие-либо еще навыки, которые будут менее значительными)
Это всё кажется очевидным. Но "при прочих равных условиях" на самом деле никогда не бывает, поэтому эти очевидности легко забываются.
В применении к реальному миру, все эти принципы всего лишь набор эвристик.
Ведь что такое ОО-подход и архитектура - это знание этих принципов и умение их взвешенно использовать в конкретной задаче.
Вот почему так трудно говорить об OO-подходе и архитектуре неабстрактным способом. Каждый, кто предложит вам какую-то определенную архитектуру, будет прав с точки зрения задачи, но при этом не зная всей специфики вашей системы не будет понимать, в чем проблема и\или впаривать вам своё видение.
Вместо этого мы должны понять и применить вышеупомянутые принципы к проектированию программного обеспечения.
Примечание. В начале статьи от меня есть примечание о терзаниях в переводе simple и easy в контексте этой статьи. Но сейчас, после полного её перевода, даже прихожу к мнению, что автор как раз-таки пытается донести мысль что "простой" не значит "легкий", так что русский язык даже лучше подходит для таких нюансов.