Pull to refresh

Comments 61

А еще проектировать должен проектировщик, периодически консультируясь с постановщиком и кодером
Часто проектировщик и кодер (брр… не люблю это слово) это одно и то же лицо.

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

Такая модель практиковалась на моей прошлой работе — это действительно идеальный вариант.
Проектировщик — программист со стажем более 20 лет, который досконально знает все подводные камни, просто «рисует», как должно быть, а также может и ТЗ составить. Конечный программист реализует тело функции, у которого уже есть имя, входные-выходные параметры и что она должна делать.
Так вот, этот человек на моей старой работе, сам никакого когда не пишет — только дает указания, как сделать то или иное, а также и советуется с программистами.
Так что, в хороших компаниях всё построено именно так, как Вы говорите
Конечный программист реализует тело функции, у которого уже есть имя, входные-выходные параметры и что она должна делать

Называйте вещи своими именами, не «конечный программист», а «печатная машинка».
Печатная машинка отлаживать баги не умеет…
Печатная машинка с функцией отладки багов? Ну можно так.

Ещё стоит упомянуть принцип разделения контекстов, из которого следует, что не всё то DRY, что на DRY похоже.

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

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

Например, хорошо нормализованная база данных на старте проекта в перспективе выльется в большое количество запросов или в сложный запрос с множеством джоинов, чтобы вытянуть одно поле.
Совет содержит взаимоисключающие параграфы.
>>> оптимизируйте БД еще до ее создания… конечно же нормализируйте вашу модель данных
преждевременная оптимизация, имхо зло. А вот совершенно нормализованная структура, ну никак не сможет быть оптимальной, с точки зрения производительности.
К базе данных применимы свои методики рефакторинга, описанные кстати как в литературе и так и интернет статьях.

А, так, после труда Фаулера, и упомянутого в комментариях Макконнелла, сложно что-либо добавить к теме. Для себя нового не почерпнул, но считаю, подобные статьи всё же на правильную мельницу воду льют: глядишь, кто-то с сотой статьи всерьёз для себя вопросом задумается, и до первоисточников дойдёт.
Где-то в 90х-2000х ходил принцип: сделай, чтобы работало, потом профилируй и оптимизируй.
Я склонен и в 2010-ых его придерживаться.
Я бы ещё добавил про максимальное использование phpdoc блоков для прописывания типов переменных, получаемых, скажем, из того же DI, что в последствии значительно упростит статический анализ в «продвинутой IDE».
С php 7 это уже мало актуально.
Нет. Возможно, это актуально в том случае, когда ты внутри (условно) модели выносишь получение объекта из DI в метод. Ок, можно поставить возвращаемый тип как интерфейс этого объекта. Но что ты будешь делать в пободном кейсе (пример на Yii2):

$someResult = Yii::$app->myContainer->myMethod();


В таком случае уместно решить эту проблему 2-мя путями: использовать этот метод или же писать так:

/** @var MyContainerClass $myContainer */
$myContainer = Yii::$app->myContainer; 
$someResult = $myContainer->myMethod();
Да, по поводу DI Вы правы, «этот метод» мы используем с Yii до сих пор, и после перехода на 7.
В тоже время можно писать в переопределённом Application геттеры для всех компонентов и статически типизировать возвращаемые значения. Приняв такое соглашение, можно вовсе обойтись без док-блоков.
Да, по поводу DI Вы правы

это не DI, это сервис локатор, в этом то и проблема.

Это как вы определили паттерн по вызову метода у переменной приложения? Или я что то упустил?

ну вот смотрите. Это сервис локатор:


$myContainer = Yii::$app->myContainer; 

То есть все динамичненько, и мы понятия не имеем какой тип у объекта хранящегося в myContainer.


А вот dependency injection:


class SomeClass
{
    public function __construct(MyContainer $container)
    {
        // ...
    }
}

То есть все зависимости и их типы декларируются явно и при таком раскладе никаких "проблем с автокомлитом" быть не может. Проблемы с определением типов могут быть только при использовании service locator.


Ну и в целом использование контейнера напрямую — моветон. Это можно делать только на уровне фреймворка.

Все равно не понял, что там ErickSkrauch дергал у контейнера и как вы узнали, что этот контейнер именно локатор. Ну да ладно, видимо это я дурак.
Yii::$app->myContainer

вот это — сервис локатор. Что такое myContainer мне не известно. Как и статическому анализатору. Отсюда проблемы с автокомплитом. В случае инъекции зависимостей они декларируются как правило явно, и проблем быть не должно.

$app это локатор? Может myContainer это локатор?

в Yii вы к зависимостям обращаетесь как? Yii::app->someComponent или Yii::app->myContainer->get(SomeComponent::class)?

в Yii вы к зависимостям обращаетесь как?

Я хз, Yii не пользовался, потому и интересуюсь.

в любом случае. Если у вас есть что угодно, будь это Yii::app-> или же $container->get — это все сервис локатор. И возвращаемые типы можно узнать только в рантайме (или при помощи кастылей и плагинов к IDE).


В случае dependency injection получение зависимостей происходит сверху, а не по требованию. А стало быть зависимости и их типы прописаны явно. Мой комментарий относился преимущественно к этой фразе:


Возможно, это актуально в том случае, когда ты внутри (условно) модели выносишь получение объекта из DI в метод

и я пытаюсь объяснить что это никакого отношения к dependency injection не имеет. А сервис локатор и так признанный антипаттерн.

и я пытаюсь объяснить что это никакого отношения к dependency injection не имеет

Понятненько. Не увидел просто там ни SL, ни DI, вот и поинтересовался.
А сервис локатор и так признанный антипаттерн

А поделитесь ссылочкой.
Не увидел просто там ни SL

как жеж? когда мы просим какой-то объект (Yii::$app в нашем случае) дать нам зависимость — это service locator. Точно так же как ларавелевские Cache::get, симфоневый $controller->get('cache') и тд.


А поделитесь ссылочкой.

и тут более подробнее по проблемам которые привносит хреново реализованный (а это 99% реализаций) сервис локатор:



В частности там описан "правильный" сервис локатор который решает большую часть проблем.


Справедливости ради, есть кейсы где сервис локатор норм. например в контроллерах: http://davedevelopment.co.uk/2016/06/01/service-locators-have-their-place.html

когда мы просим какой-то объект (Yii::$app в нашем случае) дать нам зависимость

Если мы просим какой то объект дать нам нашу зависимость, то да.
и тут более подробнее по проблемам которые привносит хреново реализованный...

Так проблема скорее не в SL, а в том, что он используется субъектами напрямую (агрегируется в субъектах). Разве нет?
а в том, что он используется субъектами напрямую (агрегируется в субъектах). Разве нет?

ну не только. В плане тестируемости самый удобный вариант это все же Dependency Injection. У DI есть свои недостатки, например необходимость делать прокси для лэйзи инициализации (что бы по мелочи не тянуть весь граф зависимостей а только по требованию). Это существенно усложняет реализацию. Но зато если использовать готовый контейнер — все мегаудобно.


SL банально проще.

Тот же Zend советует использовать качественно сконфигурированный SL, вместо DI, ибо:
* Проще отлавливать ошибки
* Проще сконфигурировать
* Быстрее работает

Тем более не так давно они добавили в свой SL фабрику для создания proxy для lazy load сервисов на базе стороннего пакета.
Можно так же добавить, что unit-тесты являются лакмусовой бумажкой для кода проекта, а проект поддерживающий unit-тесты как правило куда более чистый, нежели проект, его не поддерживающий.

только если unit-тесты были написаны до кода. Тогда это мощный интерфейс проектирования и выявления ошибок проектирования (когда тесты тяжело писать становится или неудобно). Не говоря уже о том что мы перед тем как что-то написать должны будем подумать что оно будет делать.

только если unit-тесты были написаны до кода

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

Итого мы имеем следующие расходы времени:


  • Программист потратил время на продумывание того что он хочет сделать
  • Программист потратил время на реализацию
  • Программист потратил время на тестирование (ему ж как-то надо было проверить что все работает?)
  • Программист потратил время на тесты и выявил необходимость рефакторинга
  • Программист потратил время на рефакторинг.

Как-то много впустую потраченного времени, вам так не кажется?

При чем тут потраченное в пустую время и мой комментарий про «unit-тест = лакмусовая бумажка»?

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


Я не знаю кому нравится впустую тратить время.

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

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

Представьте себе что инженеры бы не проектировали айфон, а вот сразу приступили к разработке… Было бы что то ужасное, типо та фигня которая с Китая к нам лезет. Мы тоже инженеры, только софта.

Надеюсь ответ был полным.
Расход времени это цена за качественный продукт

Есть масса способов получить качественный продукт без этих оверхэдов.


проектирование, тестирование и рефакторинг просто необходимы для того что бы ваш код имел ценность.

Я это не отрицаю. Я лишь говорю о нюансах влияющих на общую эффективность. То что тесты после кода (если это не автоматизация UI тестов какая) — это вэйстадж (в терминологии lean).


Я когда то работал на компанию где денег не было на нормальное проектирование, тестирование и рефакторинг соответственно.

У меня "тестирование/рефакторинг" отдельным пунктом не билится. Это часть моей работы. Клиенту важен только результат а не как "его туда довезли".


Для меня эта работа сильно опустила мой проф. уровень и я лично не советую работать на компанию где пишут плохой код

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


потому что заказчик считает что проектирование, тестирование это фигня и кстати, он ещё говорит что сам все протестируют.

Знаете, годика 4 назад я так же рассуждал. Что мол "ох уж эти клиенты, опять не захотели тестирование", и мне очень просто сказали "А зачем ты предлагал? Они ж не понимают зачем это нужно, просто включи это в оценку по проекту и радуйся себе."


В целом "нежелание клиента платить за непонятное для него" не должно влиять на те практики, которые конкретно вы применяете в работе. Например вы же не говорите ему "ну вот мой рейт на пару центов выше чем мог быть потому что мне надо оплачивать лицензию на PhpStorm" например.


Представьте себе что инженеры бы не проектировали айфон, а вот сразу приступили к разработке…

проектирование айфона и его разработка в глазах инженера это один и тот же процесс если что.


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


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


p.s. вы когда-нибудь сидели на дэйли митинге? Ну тот который стандап но настолько долгий что люди садятся? Прикидывали примерно сколько денег это стоит вашим клиентам? Или плэнинги бесполезные по 4 часа… Или проекты которые начинаются с разработки второстепенного функционала вроде регистрации?

p.s. вы когда-нибудь сидели на дэйли митинге? Ну тот который стандап но настолько долгий что люди садятся? Прикидывали примерно сколько денег это стоит вашим клиентам? Или плэнинги бесполезные по 4 часа… Или проекты которые начинаются с разработки второстепенного функционала вроде регистрации?


Да, я знаю сколько обходиться это клиенту. И экономить деньги клиента это правильный подход, если можно исключить всякие бесполезности, то лучше это сделать.
Как раз за счёт проектирования, тестирования(того же tdd, bdd), рефакторинга, мы секономим время и деньги.

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

Я понял вашу позицию о бесполезности использования времени и ресурсов на то что можно в конкретной ситуации не делать, я с вами согласен. Делать что бы было, тоже не надо…
Как раз за счёт проектирования, тестирования(того же tdd, bdd)

интересный момент. TDD и BDD являются больше практиками проектирования а не тестирования. Тесты — это скорее побочный (и полезный) продукт этого вида деятельности.

Для меня эта работа сильно опустила мой проф. уровень и я лично не советую работать на компанию где пишут плохой код

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

Да и в целом, чтобы понять, что ИТ мир полностью построен на костылях, на сколько грязных и коварных, что можно лишь удивляться, как это все еще работает.
Да, tdd безусловно мощный инструмет, в любом случае до того как писать код(не имеет значение код теста или код самого класса), нужно проектировать структуру классов, связи между классами.

Насчёт tdd, эта штука действительно учит мозг мыслить правильно и писать код с учетом того что в результате должно быть.
Каждый раз, когда читаю такие статьи, думаю — неужели никто не читает Совершенный Код?
Там ведь буква в букву написано то же самое
А тут на хабре каждый раз всё это заново поднимается — как правильно называть функции, как проектировать…
Все эти вопросы хорошо разобраны до 7 главы
По сути, эта книга — настольная книга каждого разработчика
А в какой главе «Совершенного кода» обсуждается рефакторинг проекта? Видимо я что то недочитал (
Там говорится, что нужно изначально писать так, чтобы не было нужно делать рефакторинг, который описывает автор
В том числе там учитывается, что заказчик захочет поменять условия, задачи, и нужно делать архитектуру с неким запасом прочности, гибкости
В общем, первые 5-7 глав — для проектировщиков
остальные — для программистов
ЗЫ: я сам читаю главу 8
Там говорится, что нужно изначально писать так, чтобы не было нужно делать рефакторинг, который описывает автор

Ну теория часто далека от практики.

Также порекомендую "Чистый код".

У меня сложилось впечатление от этой книги что:


  • Для людей которые и так это знают эта книга бесполезна
  • Для людей которые этого НЕ знали, книга ничего так же не дает (из личного общения с разработчиками которые ее вроде и читали а по коду и не скажешь). Во всяком случае без перечитывания раз в пол года. И в этом ключе опять же непонятно зачем она нужна тогда.

p.s. Сам я от начала и до конца ее не читал, только отдельные главы. Потому мое мнение чисто субъективно и основано исключительно на общении людей, прочитавших эту книгу.

Периодически перечитываю эту книгу для повышения мотивации. Пока помогает.
Хорошее замечание по поводу перечитывания
Ведь недаром я написал — «настольная книга», то есть, его нужно перечитывать. Там слишком много деталей, слишком много тонкостей. Пока читаешь одну главу, успеваешь забыть все предыдущие
Поэтому очень эффективным является применение всех знаний сразу после прочтения
Я читал то ли «Чистый код», то ли «Совершенный код», не помню, да и есть ли особая разница. Вещи банальные, но такому любителю, как я, открыли глаза. Как-то до этого я больше задумывался о лихости оптимизаций и хитрости алгоритмов, но когда прочёл, то понял, почему, когда я пытаюсь наваять что-то серьёзное, это тонет в багах и превращается в разлапистое Ктулху.

Хорошо, что у профессионалов слово «рефакторинг» — обыденное и ходовое. Но блин… заглядывал в код к людям, которые зарабатывают этим на жизнь, и возникает ощущение, что слова с делами частееенько расходятся :(
что слова с делами частееенько расходятся :(

тут зависит от ситуации. Возможно чуваку на самом деле пофигу. А есть еще такая тема как traidable quality.

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

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

Так же не упомянул о важности разбираться с магическими циферками и буквочками в проекте, типа
if ($a * 5) {
Что значит 5 помнил программист который писал этот код, кстати помнил… но сам забыл…

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

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

продумайте как можно с минимальным количеством классов, достигнуть максимального результата


Не совсем хорошо написано. Можно ведь вообще сделать один огромный неуклюжий класс, который никуда не сопроводишь и повторно нигде не используешь :) Понятно, что вы имели в виду именно более простую архитектуру, но не в числе классов ведь дело (поменять слово «класс» на «сущность»?). Тем более, далее по тексту у вас высказана противоположная мысль, показывающая, что вы как раз со мной согласны:

Некоторые части функционала можно вынести в отдельные классы, что даст возможность использовать их повторно


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

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


Как-то конкретно в коде PHP от этого не уйдёшь :( В итоге приходится передавать целые структуры данных в виде ассоциативных массивов, а конкретно — от backend во frontend. Но поскольку у всех элементов backend есть frontend, таких передач данных очень и очень много. Весь frontend на этом зиждется :(

Классы, содержащие одинаковые переменные и методы. Проблему можно решить через создание дополнительного класса)


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

Articles