Pull to refresh

Comments 119

UFO just landed and posted this here
Макконел систематизировал базовые принципы десятки лет и выпускал свою книгу «Совершенный код» два раза, его сложно превзойти… Разве что постараться донести основные принципы не на 900 страницах, а в одной статье
Я понял — инициатива наказуема :)
Да.
Особенно про фреймворки.
В нескольких компаниях наблюдал такую картину — для бэкенда сайта некто написал свой фреймворк для разбора URL (потому что у существующих есть, очевидно, фатальный недостаток). Но он уволился, после него ещё кто-то развивал систему, потом и он тоже уволился. Документации нет, комментариев нет, соглашений по стилю кода нет. Текущий программист и сам плохо разбирается, при этом у него нет времени тебе всё объяснять.
Как по мне, в таких вещах разбираться вообще невозможно.
А всё из-за нежелания «заточить топор». Видимо, психологически изучать чужое труднее — поэтому давайте напишем своё.
А с опытом становится понятно, что своё писать не надо — чужое уже работает, и баги там отлавливает куча людей, и развивается, и другие люди тоже не идиоты и соображают, что нужно для подобных вещей, и уже их там сделали…
В реальности у вас при разработке достаточно сложного приложения никогда не получится использовать только готовые фреймворки, т.к. у вас обязательно будут появляться специфичные задачи, из-за которых готовый фреймворк надо допиливать. В итоге, ваша кодовая база всегда превращается в «бизнес логика» + MyApplicationFramework. Но это и не проблема сама по себе, проблема в том, что зачастую они оказываются перемешаны и сложно понять, где у вас одно, а где другое.
Тут работает принцип модульности. Если Ваше приложение написано корректно и все классы и методы лежат на своих местах, то Вы никогда не запутаетесь в том, где у Вас framework, а где бизнес логика
Только теоретически, когда есть анлимитед времени на разработку.
На практике же граница периодически размывается, а иногда и нарушается насквозь каким-нибудь «грязным хаком».
У того же макконела это описывается как присутствующее зло, когда он говорит о необходимости периодических рефакторингов.
У меня есть стойкое ощущение, что можно написать универсальное средство, которое можно законфигурить под любой проект, чтобы быстро находить в нем ошибки, связанные с нарушениями такого рода.
Естественно, я говорю не по 100% случаев, но даже если 80% типичных ошибок нарушения уровней абстракции будет отлавливаться автоматически — это будет счастье. :-)
У меня есть стойкое ощущение, что можно написать универсальное средство, которое можно законфигурить под любой проект,

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

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


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

За дровишки в костёр споров — спасибо.
Спасибо, так и поступлю
По моему кодер — это быстрый программер. Конечно качество от этого страдает. Но часто чистых кодеров и чистых программеров не бывает.
Глядя на застой в существующем техническом прогрессе понимаешь, что тех и других либо очень мало, либо они заняты не тем чем должны.
Очень часто сейчас мы располагаем такими аппаратными возможностями, которые программно не используются никак.
Нужно радоваться наличию тех и других и двигать прогресс, а не только свой кошелёк. Вот в чём главная ошибка.
Думаю, у всего есть предназначение, даже если оно не очевидно… Скорость кодеров полезна на маленьких или одноразовых проектах, например, при создании прототипов. Программистов логично привлекать к созданию и поддержке крупных проектов.
а как насчёт способности кодеров связывать большие, готовые проекты в один?
Я думаю кодеры должны это делать быстрее, чем программисты. А это влияет на прогресс очень хорошо. Часто существует множество разных проектов, которые, если соединить, то получится очень интересная программа.
Если дать разрабатывать это программисту, то он посмотрит на вас, как на сумасшедшего и скажет, что надо ещё таких же как он человек 5 и времени пол года — год зарплату платить. Получается кодер эффективней программиста.

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

По-моему тут все понятно :-)
Нужно просто решать задачу. Любая деятельность должна быть направлена на решение какой-то задачи. Нет хороших программистов, плохих программистов и кодеров. Нет плохих заказчиков, хороших заказчиков или чего-то еще. Есть задача, которую нужно решить, в заданных граничных условиях.

Граничными условиями для бизнеса, с моей точки зрения, в 90% случаев являются:
1. бюджет
2. сроки
3. приемлемое качество

Если вы хороший специалист, то просто предупредите заказчика, что за его деньги и в его сроки сделать можно только плохо, и потом придется переделывать. Если заказчик — согласен это его право. Делайте быстро, дешево и плохо. Если вы его предупредили, а он хочет дорабатывать — скажите, что предупреждали и откажитесь от поддержки. Либо, откажитесь от проекта целиком, если боитесь попортить карму.

Если у вас нет возможности выбирать заказчиков у которых в граничных условиях на первом месте стоит качество и расширяемость, смените работу. Если не можете сделать и этого, то терпите. Вот такая она жизнь. В массовом производстве никому не нужны произведения искусства, а нужно быстро, недорого и нормально.

Быть специалистом значит уметь решить заданную задачу в заданных условиях, а не конючить, что вот мол то не так, а это подайте по-другому.

И да, я тут не рассматриваю случай, когда все вот эти class User образуют систему столь сложную и сильносвязанную, что лучше уж бы копипаст. Оверинжинириг это тема отдельного большого холивара.
По тексту статьи даже идти не хочу, но там половина — как минимум крайне сомнительна. Ну вот просто для примера:
class MailerWrap { public function send($params) { return Mailer::send($params); } }

Смотрите сами:
1. Что каждую подключаемую библиотеку во враппер оборачивать? У вас тогда проект превратится в кучу врапперов.
2. Наверное там кроме названия метода с send на post поменялось еще что-то, сигнатура например. Потому что смысл менять название метода, ломая обратную совместимость только ради названия? Так никто не делает, и значит ваш враппер будет беспозерен.
Это пример, а не призыв к действию. Цель — постараться объяснить аудитории смысл паттерна «метод доступа». Если в проекте есть внешний компонент с меняющимся интерфейсом, то для простоты и удобства изменения его можно «обернуть»
Пример неудачный. Вы рассуждаете из будущего, «что вот если бы он знал, что изменится интерфейс, то надо было сделать враппер». Откуда было понятно, что именно этот внешний компонент «с меняющимся интерфейсом»? У него в документации написано, что каждый релиз меняется интерфейс? Классическое «знал бы прикуп жил бы в Сочи». Альтернатива — только писать врапперы на все, но это уже тупак какой-то.
Да легко, если у вас мейлер изначально абстрагирован. А если не абстрагирован — то это беда, и лучше использовать другой.

А так получается абстракция ради абстракции.
Мы рассматриваем этот мейлер — каковой вызывается статическим методом. Это раз.
А два — ваш мейлер может оборачивать готовый с целью внести специфику приложения (например — добавляет стандартную для приложения подпись и т.д.)
подпись чего? письма? и для этого заворачивать мейлер? заворачивать мейлер вижу смысл когда его нужно приткнуть ко фреймворку, например, для использования вьюх для писем, а вот там уже инклудить стандартную подпись для приложения
Неважно. «Посылка почты в приложении X» может иметь свою специфику по сравнению с «посылкой почты вообще», каковую специфику полезно выделить в отдельный юнит.
… и этот юнит не является враппером вокруг мейлера, и не имеет никакого отношения к юнит-тестированию.
Не является но может быть нужным к юнит тестированию имеет отношение — позволит писать тесты более удобно
Нет, не позволит. Эта «специфика» — это тоже тестируемый код, поэтому вам нужно изолировать зависимость на шаг дальше.
Это уже будет другой код, а тот, исходный позволит.
А в «тот, исходный» нельзя вносить специфику вашего приложения.

Говорю же, два разных куска кода с разными целями.
Можно в нем как раз она и есть. (Тот исходный это не мейлер, если чо, а код использующий мейлер — сам-то мейлер мы не тестируем)
Если она в нем есть, то ее надо тестировать. Значит, надо разрывать зависимость с используемым мейлером. Далее смотри выше.
Дык я не говорю, что это снимет полностью проблему тестирования — я говорю что облегчит. (см ваше «не имеет никакого отношения к юнит-тестированию»)
Наличие дополнительной функицональности не облегчает тестирование.
Существует такая дополнительная функциональность в X которая облегчает тестирование Y, использующее X так как позволяет не тестировать его внутри Y
Вы эту функциональность тестировать не собираетесь?
А вы считаете, что декомпозиция функциональности на два компонента всегда облегчает тестирование?
Я обычно не так категоричен — может облегчить.
А может и нет. Что возвращает нас к вопросу об осмысленности добавления врапперов в произвольных местах.
а почему не использоать заведомо рабочий враппер сугубо для тестирования почтового враппера?
Единственный способ получить заведомо рабочий враппер — это протестировать его. Далее см. сначала.
я имею в виду, что враппер для тестирования обернутого мейлера, который используется в приложении, сделать как только можно проще чтобы его не тестировать ибо там нечему валиться или взять заведомо протестированную простую обертку
или нам все равно нужно тестировать и саму обертку?
Не надо тестировать мейлер (он сторонний). Надо тестировать код приложения, который с ним взаимодействует (например, что он посылает то, что нужно и тогда, когда нужно).

Соответственно, если сторонний мейлер криво написан, и плохо поддается изоляции, нужно писать враппер — максимально простой, только для того, чтобы добавить изолируемость для тестирования.

Как только речь заходит о «а давайте этот враппер будет еще и что-то делать (добавлять подпись, шифровать, блаблабла)» — нарушается принцип единой ответственности.
Надо тестировать код приложения, который с ним взаимодействует

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

мы либо говорим о разном и не понимаем друг друга, либо говорим об одном и том же, но разными словами )
Речь изначально шла о том, нужен ли враппер для мейлера.
В динамическом языке враппер, наверное, не нужен, надо только абстрагировать создание.
Это, как уже говорилось, не единственный вариант.
Вот либо раз, либо два. Потому что оборачивание статического метода — это специфика используемого языка (где, судя по всему, нельзя мокать статические вызовы) и используемого мейлера (который лучше заменить на вызываемый по интерфейсу).

А внесение специфики — это уже совершенно другой паттерн, который предполагает появление дополнительного отдельно тестируемого компонента.

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

Я, знаете, недавно побывал в роли заказчика в области в которой не очень хорошо разбираюсь — делал дома ремонт. И вот что я вам скажу — то, что заказчику нужен приемлемый результат за нормальные деньги и за вменяемое время — абсолютно нормально.

Вот вам пример — я делаю сан узел. У меня в нем кривой пол — перекос около сантиметра. Мастер естественно предлагает заливать стяжку. Но стентиметр стяжки залить нельзя — она треснет, минимум 5 (в самом высоком месте) в низком соответственно — 6. Тогда будет идеально ровный пол и все круто.

Минусы — растет цена, растет срок, «опускается потолок», появляется ступенька на входе в санузел.

Альтернатива — положить плитку как есть.
Минусы — я буду знать что мой пол кривой (на глаз это не видно), чуть сложнее с установкой стиралки и мебели, но регулируемые ножки решают все проблемы, чуть расширяющийся стык между полом и стеной.

Я выбираю как есть. Да, наверное мастеру неприятно класть «кривой пол» и хочется сделать идеальный санузел мечты, причем для моего же блага, но вот такой я кривой заказчик и хочу как мне нравится. Ремонтом остался более чем доволен.

Кстати побывать заказчиком — очень позитивный опыт, я многое для себя переосмыслил. Рекомендую.
Это опять же с мастером что-то не так. Вот он как раз просто решал поставленную задачу. А когда мне нужно было выровнять пол на 40мм, то я использовал вот это — www.ivsil.ru/catalogue/div4/item14.html. И ничего не трескается. Для больше надежности он еще сетку положил туда металлическую, но думаю можно было и без нее.
Тонкая стяжка потеряет несущую способность после отслоения (очень вероятная ситуация для цементной стяжки). Даже на сайте указано, что минимальная толщина стяжки 10 мм, хотя честно говоря сомнительно что 10мм стяжка будет надежной. Но речь не об этом, а о том, что меня устраивает кривой пол, но без ступеньки на входе больше чем ровный, но поднятый (даже на 10мм). И если я заказчик, хочу за свои деньги плохо, то в этом нет ничего страшного :-)
А потом приходит понимание, что нужно ипользовать декларативное программирование в виде внедрения ависимостей и контейнеров. И жить становится гораздо проще. Да, снала многие не понимают, зачем вся эта морока нужна, если все можно сделать гораздо проще и меньшим количеством кода (навеяло постом вы сломали javascript). Но, когда начинаешь писать, проходит время, добавляется функционала, рефакторится код и тогда уже приходит понимание. Но для многих уже становится поздо, что-то изменять.
Второй пример, когда в константу выносится еще и имя таблицы — это иллюстрация того как делать не нужно, и называется оверинжиниринг. Таблица в селекте уже имеет осмысленное имя. Также, этот кусок кода находится в классе User, а не в каком-нибудь ValidationRules.
Да, возможно, пример с именем таблицы неудачный, но представьте себе, что вы решили изменить название таблицы в БД, а запросов с явным её указанием много по коду проекта, тогда вариант с именованной константой более удобен для рефакторинга
А представьте себе, что вы решили запускать сервер приложения не на php, а в виде нативного приложения на айфоне. А клиент не в браузере, а в виде Windows Forms Application. Что тогда?

Закладываться на сомнительные «потребности» и есть оверинжиниринг. Почитайте про YAGNI. Не то, что бы ему надо следовать на 100%, но вот для таких примеров как ваш, отлично подходит.
Конечно, умение корректно определять граничные условия и уместно использовать приёмы/инструменты — важнейшие навыки профессионального инженера. Я убрал именованную константу для таблицы из статьи, чтобы не создавать прецедент оверинжиниринга, хотя это был просто пример, а не кусок кода реального проекта. Думаю, прочитав комментарии, аудитория сможет лучше понять баланс между гибкостью кода и «переразработкой».
На самом деле не хватает одного главного примера — ТЕСТов.
Если бы ТС их писал, то увидел бы, что у нет особой разницы между обоими его подходами, всё тот же лапшакод с захардкоджеными зависимостями, неперегружаемыми статическими методами и глобальными переменными.
Но благодаря ООП и специально подготовленному классу User можно написать значительно короче и понятнее:
$user->loadById($id);
echo $user->name;


Плохой пример, если честно.

Чем в данном случае является объект $user?
Если это объект, связанный с записью в БД в соответствии с концепцией ORM, то он может либо находиться в синхронном состоянии с конкретной записью, либо быть рассинхронизирован (например, при создании нового объекта, который еще не имеет записи в таблице/-ах). В первом случае метод ->loadById() не нужен (мы уже в синхроне), во втором — невозможен (записи-то нет уже или еще).

Правильнее или реализовать этот метод в виде статического метода класса
$user = User::findById($id);

или как в Doctrine — отдельной сущностью, EntityManager, управляющей персистентностью.

А ваш код — это не ORM, это говнокод какой-то. Сначала создаем объект, а потом его заставляем найти себя же в БД?
Благодарю за Ваши подсказки, поправил текст примера
Не за что.
Статья весьма жизненная.
Прочитав этот пост я понял, что:

Кодер — специалист, производящий продукт в рамках установленного бюджета и сроков.

Программист — это кодер, избалованный слишком большими сроками проектов. Возможно — не принимавший участия в больших коммерческих проектах со сжатыми сроками.

Вот и всё.

Сам я пишу говнокод и очень этим горжусь. Ибо 99.(9)% кода — пишется один раз. И повторно не используется. Если, разумеется, вы не архитектор. Но если вы архитектор — тогда такие посты вам совсем ни к чему.
Именно поэтому выбрал в качестве картинки к статье христоматийную сцену боя между ситхом и джедаем… Как и говаривал мастер Йода — «Тёмная стороне не сильнее, а быстрее». На закате жизни, Дарт Вейдер всё же вернулся на светлую сторону, с которой и начинал, потому что до него дошла простая истина, что светлая сторона — это путь к гармонии…
П.С.: прошу не воспринимать пост буквально, отсылки к «Star wars» носят иносказательный характер
Хороший, плохой… Главное, у кого ружьё!

И на хабре есть адепты тёмной стороны Силы, и нельзя сказать, что они так уж неправы. Во всём важен баланс.

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

Статья — оскорбление кодеров. ;) Кодер не является «плохим программистом», так же как хакер не является преступником.
Статья ни в коем случае не попытка кого-то задеть или уязвить, как и писалось до хабраката — цель уяснить разницу
Ну и не уяснили. Очередной слоовоонанизм, извините. Вёдра воды без конкретики. «Кодер», «программист», какая разница? Очередная попытка поклеить своих ярлыков. А точнее, рассказать о своих поклеенных ярлыках, используя для этого достаточно сомнительные примеры.
Да, для многих статья не откровение, но ещё одна возможность порефлексировать и переоценить все что делаешь и как делаешь — разминка для мозгов
кому как, а мне вступление понравилось больше примеров
Вот и думаю, может лучше научно-фантастический роман начать писать, а не CRM/ERP системы, как обычно :)
$user = User::model()->findByPk($id);
Это так код стал «проще»? Это, наоборот, хороший пример, как ООП в руках кодера порождает страшный говнокод.
Что это за model(), зачем оно здесь? (Я знаю про MVC, но к чему этот вызов здесь?)

Код без ООП выглядел бы гораздо проще и понятнее:
$user = user_load($id);

Знаете, чем программист отличается от кодера?
1. Программист пишет логи.
2. Программист пишет тесты.
3. Программист проверяет все коды возврата функций и исключения и корректно их обрабатывает.
4. Программист не забывает расставить ассерты.
5. Программист пишет грамотные комментарии к своему коду и своим коммитам.
данный кусок кода взят из YiiFramework
статический метод model — это некая статическая фабрика
результате мы получим не просто данные из таблицы user, а AR-объект с другими плюшками, которые могут пригодиться далее: поиск по связанным таблицам, если такие есть, мы можем изменить данные и вызвать метод save объекта $user и сохранить запись в таблице, можем провести вализацию
используя Ваш неООП подход, мы не сможем такого сделать, а будем городить костыли или писать велосипеды
Вообще-то это действительно так себе. И в Yii2 уже
$post = Post::find($id);

И кто мешает
$user = user_load($id);
$user->validate();

???
речь шла о конкретном примере и это в YiiFramework
да ничего не мешает. просто код читабельнее и я сомневаюсь, что в функцию user_load вы нормально воткнете все плюшка AR. ну разве что, использовав её как враппер, но мы же говорим о читабельности и поддерживаемости кода
можем изменить данные и вызвать метод save объекта $user и сохранить запись в таблице, можем провести вализацию

user_save($user);
user_validate($user);

В чем проблема? Где костыли?

Процедурный стиль, ООП стиль, функциональный стиль — это лишь инструменты. И не в выборе инструментов дело. А вот то, как эти инструменты используются и отличает программиста от кодера. Если вы не в курсе, то Линус пишет на С, а не на С++, и прекрасно обходится без статических фабрик.
>>В чем проблема? Где костыли?

Нет способа хорошо выделять общий код типа:

foreach($modifiedObjects as &$object)
{
      if ($object -> validate())
      {
          $object -> save()
      }
      else
      {
          $objectsWithErrors -> add($object)
      }
}



Процедурный стиль, ООП стиль, функциональный стиль — это лишь инструменты. И не в выборе инструментов дело.

Иногда в них. Я сомневаюсь, что PHP хороший язык для функционального программирования (ленивые вычисления, классы типов, функции как значения первого класса есть?), а ООП в нем уже общее место.
А вот это уже полиморфизм — и это сильная сторона ООП =)

Способ, конечно же, есть:
foreach($modifiedObjects as &$object)
{
      if ($object['validate']($object))
      {
          $object['save']($object);
      }
      else
      {
          $objectsWithErrors []= $object;
      }
}

В таком подходе есть один серьезный плюс — легко менять методы «на лету», создавая объекты, не привязанные к классам.
Но, смотрится это плохо, да и IDE не сможет подхватить эти функции. Это магия Си, её не нужно использовать в языках с развитым ООП.
вот это уже полиморфизм — и это сильная сторона ООП =)

функциональщики говорят, что у них это тоже есть (type classes)

Способ, конечно же, есть

Итого: мы согласились с тем, что хорошего способа нет.
Функциональщину я даже не рассматриваю — её преимущества не объяснить в комментариях, особенно ярым адептам ООП.
Хорошего способа — нет. Т.е. можно сделать ООП код без ООП конструкций языка (суть ООП не в ключевых словах, а в полиморфизме, наследовании), но с ними проще и понятнее. Там где действительно нужен полиморфизм — уходить в процедурщину я не советую.
костылей нет. я не говорю, что это какой-либо костыль
дело в том, что если дальше раширять приложение, то гораздо уробнее и приятнее расширять его если приложение было грамотно спроектировано
в моем опыте было два php-фреймвока (второй yii). даже два фремворка, реализующие MVC очень разнятся в удобстве работы сним. к примеру, в первом работа с БД реализована примерно так, как Вы описали выше:
load('user', $userId);
load('category', $categoryId);
load('foo', $fooId);

тоесть, там есть один класс Модель, который в конструктор принимает имя таблицы и потом от него танцуем. Да, получить данные с таблицы мы можем, но мы не забываем о принципе «Fat model, skinny controller», следуя которому, бизнес-логику следует вкладывать в модель для повторного использования, а не в контроллер. чтобы это сделать я допилил следующим образом: я расширил этот базовый класс Model и имею классы UserModel, PostModel и т.д… в них же реализую бизнес-логику. если же подходить к вопросу в процедурном стиле, то я не представляю как реализовать это.
если дальше раширять приложение, то гораздо уробнее и приятнее расширять его если приложение было грамотно спроектировано

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

если же подходить к вопросу в процедурном стиле, то я не представляю как реализовать это.

Не представляете? Наверное, мало работали в процедурном стиле?
да, плохие и хорошие проекты есть, но речь сейчас не об этом
Не представляете? Наверное, мало работали в процедурном стиле?

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

для чего тогда спорить? мы говорим об одном и том же
Это тяжелое наследие первого Yii, который ради обратной совместимости с PHP<5.3 не мог использовать метод __callStatic для статических методов класса-модели.
Не ругайте программистов, они извращались в то время как могли, и все-таки сделали неплохой продукт.
Ой, я не ругаю программистов, я лишь говорю, что это очень плохой пример преимуществ ООП. Можно было найти гораздо лучше.
Скажем, такой:

// Этот код выполнится, но когда где-нибудь потом всплывет ошибка, будет очень тяжело её локализовать
$user['age'] = -5;

// А вот этот код может отреагировать на неверное значение: ассертом, исключением, кодом возврата или же просто не изменив состояние объекта.
$user->setAge(-5);
Вы не поверите, но PHP позволяет и в первом случае модифицировать поведение объекта.
И иногда (редко, конечно) это пригождается.
Разумеется.
Причем высшая его степень — вся логика инкапсулирована в классе. А конечный «потребитель» видит наш объект, как просто массив. Не догадываясь в простых случаях о его внутренней структуре

$collection = new Collection;
$collection[] = $item1;
$collection[] = $item2;
$collection->doSomethingWithAllItems();
— где еще такое возможно?

Если наконец примут предложение насчет метода __cast(), PHP вообще станет самым полиморфным языком на свете.
В C++, например. В PHP, насколько я помню, еще нет перегрузки операторов, так что до С++ еще расти и расти =)
— где еще такое возможно?

А в питоне и руби разве нет?
А код без ООП (в данном конкретном случае) не решает основную проблему — каждый раз придется копипастить функции типа user_load(), product_load(), category_load(), foobar_load(), копируя один и тот же код (сводящийся к банальном запросу к БД). Вместо того, чтобы один раз написать метод load() в абстрактной модели.

И, разумеется, писать такое же количество банальных тестов. В ООП достаточно будет грамотно простестировать абстрактную модель. Один раз.
Если `_load` сплошь одинаковые, то никто не мешает написать одну функцию — `load`
load('user', $userId);
load('category', $categoryId);
load('foo', $fooId);


Если же функции все-таки разные (а обычно так и происходит), то при любом подходе придется писать дополнительный код и дополнительные тесты.
Как их сделать, чтоб при этом не получилось убогое подобие того, что и так есть в объектной системе PHP?
1. Иногда программист не пишет логов, ибо их некуда писать. Например, на микроконтроллере.
2. Иногда программист не пишет тестов, ибо для их написания нужно отрефакторить такую кучу legacy-кода, который написали до него, что он понимает нецелесообразность этого действа.
3. Иногда программист может не знать про какой-то код ошибки одной из внутренних библиотек, которую используют уже давно, и у нее нет автора, исходников и документации. Как-то работает — и все тут.
Да, и иногда программист может некорректно обрабатывать исключения и коды ошибок — например, падать вместо попытки исправиться. Все бывает.
4. Иногда программист не расставляет assert'ы. Например, их нет в том языке программирования, на котором он пишет.
5. Программист не всегда пишет комментарии. Код — лучшая документация, поэтому лучше написать код так, чтобы надобность в комментариях отпала.
Иногда это все допустимо. Только ситхи возводят все в абсолют!

иногда программист может некорректно обрабатывать исключения и коды ошибок — например, падать вместо попытки исправиться.

Падать вместо попытики исправиться — это иногда совершенно корректная обработка ошибок ;) Особенно во время разработки.
UFO just landed and posted this here
Я бы программиста переименовал в статье в разработчика.

В жизни есть люди, которые умеют писать код и называют себя программистами.

И это правильно — они программируют и они программисты.

Но опять-же только программировать недостаточно для того, чтобы быть разработчиком.

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

Чувствуете разницу?
Чо-то тут не то
if ($user->isGuest) $user->register($user->email, $user->name);


Зачем какому-то пользователю регистрировать чье-то другое имя и email — наверное $users -> register($user)?

В модели:
boolean registerUser(String email, String name);
User getUserByName(String name);
Если очень хочется, то можно и для почты сделать отдельный тип
Должно быть либо $userModel->register($user), либо $user->register()
Все, достаточно. А то, что в топике — классический такой говнокод =)
вроде так и написал, но ладно) Основная мысль в том, что автор по сути написал статью сам про себя сам того не понимая. Но статья от этого по мне стала еще лучше. На плохих примерах люди лучше учатся. Самое главное это не считать себя лучше других, а просто развиваться, как специалист. Если вы действительно лучше, то знающие люди это увидят, поверьте. Этим грешат джуны и это приходит со временм. Да и я сам от этого пока совсем не избавился, но в целом стараюсь. И кроме дикого самомнения, которое видно всем и никому не нравится (даже если оно и оправданное), это еще и забивает голову абсолютно ненужными мыслями. Даже на примере статьи, посчитайте, сколько времени автор потратил на нее. И исключительно для того, чтобы показать, что он лучше, чем другие.
Вопрос в том, понял ли автор, что он написал статью сам про себя? Возгордился и попал в сети темной стороны Силы =)
Да, конечно, если говорить о стороне силы, то я наверное Анакин Скайуокер/Дарт Вейдер — побывал и на тёмной и на светлой стороне, потому и сравниваю. За объяснения спасибо, поправил пример в статье
Вы считаете себя хорошим программистом?
Нет, я скорее просто многоопытный
Если следовать классификации автора то должен быть еще третий уровень — разработчик. Разработчик этот тот человек который решает проблему средствами позволяющими сделать это оптимально. Так имхо будет честнее.
Разработчик не ограничивается программой.
Он мыслит проблемами и бизнес-процессами с точки зрения пользователя.

Так точнее. :-)
Увы, тут действует бинарная логика. И оптимизировать уже качественно оптимизированное не имеет смысла. Вы либо говнокодите, либо пишите так, чтобы потом гордиться своей работой
По вашей классификации код либо идеален, либо это говнокод.
Если человек не знает какой-то библиотечной функции, которая элегантно решает задачу, и в единственном месте написал вместо одной строки две-три, то всё — он говнокодер?
Нет, он просто совершил переразработку (оверинжиниринг), но если код правильно оформлен, расположен в соответствующем модуле проекта и (само)документирован, то это не говно код, а альтернативная реализация. Этот код изолирован и его легко изменить в случае, когда программист поймёт, что его можно элегантно улучшить. Это главное в качественном коде.
Идеального кода нет, и это нужно понимать. Фокус в том, чтобы сделать код максимально простым, понятным и приспособленным к дальнейшим изменениям и модернизации любым программистом. Это и есть основные критерии качества кода для проектов с длительным сроком разработки/поддержки. Оптимизация подразумевает улучшение какой-либо качественной характеристики за счёт ухудшения других, значимость которых в текущих условиях не столь велика.
Sign up to leave a comment.

Articles