Pull to refresh
4
0
Владимир Ческидов @BotCoder

WEB разработчик

Send message

https://www.amcharts.com/ - тут есть такой функционал и не только такой.

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

OCP - вообще не про расширение классов, а про расширение функционала без изменения уже ранее написанного. Могу дать самые очевидные отсылки: декорация, проксирование, адаптирование, Chain of Responsibility, композиция и прочее, прочее...

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

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

И вообще, в конце‑концов любая объектная программа представляет собой дерево, которое сходится к буквально нескольким классам, которые и представляют собой программу и потому никакая «единственная ответственность» даже теоретически не достижима.

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

По моему логично ожидать при клонировании объекта, что его readonly свойства уже будут иметь значения и не будут подлежать изменению. Наоборот, странно ожидать обратного. Мне кажется, что если проблемы с клонированием появляются, то readonly использован не по назначению либо где-то произошла подмена понятий.

Я затрудняюсь как давно программистам уже известно понятие "Self-documenting code", но точно могу сказать, что с тех самых пор без любителей доказывать полезность комментариев не обходится ни одна тема касающаяся документирования и прозрачности проекта. Рад, что кто-то еще не устал развенчивать полезность комментариев, написанных в стиле: "Я не смог тебе объяснить свою логику, написанным кодом, поэтому сейчас запутаю еще и своим комментарием"

Есть и более серьезные статьи, но и этой
https://knowledge.autodesk.com/ru/support/inventor/learn-explore/caas/CloudHelp/cloudhelp/2019/RUS/Inventor-Help/files/GUID-63FA128E-63E2-4176-8653-327BD80D8A43-htm.html
хватит, чтобы показать, что

последовательно спускаться по абстракциям

, что является проектированием "сверху вниз" - это далеко не

в общем случае

.

Если интересно, то в проектах, где не пускают архитектуру на самотек, на текущий момент популярна модель проектирования "из середины к границам". Названия могут варьироваться, но смысл один:

Этап I (Серединный уровень абстракции): Проектирование модели предметной части таким образом, чтобы она отражала объекты предметной области, их инварианты и процедуры перехода объектов из одного состояния в другой не нарушая инварианты.

Этап II (Верхний уровень абстракции): Проектирование вариантов использования получившейся модели, формируя при этом пользовательский интерфейс. Пользователем при этом может быть код более высоких уровней абстракции, или API клиент, или человек пользующийся браузером

Этап III (Нижний уровень абстракции): Проектирование деталей реализации всего написанного в предыдущих этапах под конкретную платформу, то есть под ОС, под версию языка программирования, под технический стек, под framework и т.д.

Если мы действительно IT специалисты, то нужно уметь работать с абстракциями.

Если мы создали абстракцию "Дом" как некоторую композитную форму имеющую стены, пол и крышу, то дом из блоков, состоящих из воды в жидком агрегатном состоянии, не перестает быть домом даже если он просуществует таковым в реальном мире всего доли секунды пока его не расплескает земное притяжение. И этому примеру даже можно придумать полезное применение - красивые спецэффекты в каком-нибудь фильме. По моему я где-то такое даже уже видел.

Если мы вносим в абстракцию "Дом" понятие устойчивости и хрупкости в целом, то и в таком случае можем запустить симуляцию дома из воды. Он просто не пройдет проверку по критерию хрупкости. Но не перестанет быть домом. Просто будет домом с пометкой "непригоден". В разработке с такими понятиями приходится сталкиваться очень часто.

Если говорить про программирование, то процесс написания программы, особенно в случаях когда стоит цель автоматизировать бизнес или смоделировать что-то существующее в реальности, состоит в том, чтобы описать абстракциями все то, что лежит в предметной области. И поверьте моему опыту, я ни разу не встречал ничего такого, что нельзя было бы хоть в каком-то приближении описать, как вы сказали, аналогиями из IT.

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

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

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

В общем, не сдавайтесь в своих попытках работать с аналогиями. Это развивает

Может вы все же зайдете на github и посмотрите на объем среднестатистического приложения прежде чем бросаться такими заявлениями? Можете для саморазвития взять одно из таких среднестатистических приложений и избавить их от лишних уровней абстракций. В результате вы действительно с некоторой степенью вероятности получите меньший объем кода. Но труда на такое затратите больше чем разработчики потратили на написание исходного варианта. Но не это главное. Главное то, что вы не сможете поддерживать это приложение с той же непринужденной легкостью, с которой это делали разработчики оригинального приложения пользуясь выгодой от слоев абстракции.

Насчет "Все эти абстракции нужны лишь для одного — уменьшить себестоимость производства массового продукта":

Массовость и уникальность вообще никак не связаны с абстракциями в коде. Уровни абстракции действительно связаны с удешевлением конечного продукта, но совершенно другим образом. Все ухищрения программистов, принципы разработки, шаблоны проектирования, уровни абстракции и прочее служит всего одной цели: минимизировать необходимость вносить правки в уже хорошо продуманный и отлаженный программный код следуя процессу разработки. Другими словами: "Не допускать двойной работы". Другой причины нет и другого обоснования - тоже.

Обойтись без уровней абстракции можно только в небольших проектах, которые сводятся к одному нехитрому, или хитрому, но небольшому алгоритму. Если же объем приложения больше и/или если требования к нему со временем меняются (проект живой), то приходится уже обращаться ко всему богатству приемов, придуманных программистами, позволяющих удешевить процесс разработки.

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

Вот и думайте теперь где актуальны уровни абстракции, а где - нет.

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

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

Получается Gherkin — ярчайший пример декларативного программирования?

Scenario: Some determinable business situation
     Given some precondition
       And some other precondition
    When some action by the actor
      And some other action
      And yet another action
    Then some testable outcome is achieved
     And something else we can check happens too
Мы тут помогаем ребятам без опыта, так что давайте поделимся с ними ссылочкой на

А уж потом по готовой схеме генерировать классы Entity.
Консольная команда для этого имеется


How to Generate Entities from an Existing Database

Называется это Reverse Engineering — так же называется и аналогичная функция в MySQLWorkbench. MySQLWorkbench переводится как «MySQL скамейка» (Шутка. Называю ее так за исключительную глючность в Линукс среде)

Спасибо Fortop за дополнительную инфу для читателей. Хоть я и не разделяю таких подходов — они могут быть полезны для многих в определенных ситуациях.
Additionally, reduce the amount of bi-directional associations to the strict necessary.

After all, code that is not required should not be written in first place.


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

С другой стороны помню печальный опыт семилетней давности. Я очень часто натыкался на превышения допустимых объемов используемой памяти при работе с таблицами от 10к записей. Местами даже самим приходилось допиливать. Ограничивали буквально все. В одной критической сущности вообще от связей отказались, так как она была завязана на скрипт-краулер (он работал не менее минуты) и, как ни удаляй уже не нужные объекты из памяти, где-то внутри все равно происходило паразитное накопление приводящее к фатальным ошибкам.

С тех пор я вижу три фактора, которые на мой взгляд могли исключить эту проблему:
  • существенная эволюция PHP, а именно появление Слабых ссылок
  • сильно не вникал, но раз уж существует ReactPhp, то и со сборщиком мусора не хило поработали в новых версиях
  • семилетний этап развития самой библиотеки Doctrine


Вообще поднятая вами тема заинтриговала. С пол пинка я не нашел достаточно информации. Если кто-то найдет пруфы к текущему состоянию дел на этот счет или сможет воспроизвести проблему — будет круто, поразбираем.
Вы сущность на 2-3 десятка полей так же задаёте?

Разумеется нет! Но чаще большие сущности не появляются сразу с огромным количеством полей. Они такими становятся в процессе разработки. Так что создать через консоль сущностью с 3-мя полями на этапе прототипизирования проще чем вручную — сами создаются файл сущности и файл репозитория сущности + папка для репозиториев сущностей, если не создана до того. А потом уже эта заготовка подходит для заполнения произвольным набором полей.
Другое дело, что таким макаром можно вообще все игры списать к бесполезному с точки зрения мусору


Вот уж не скажите — многие игры заставляют напрячь головной мозг, обагащают багаж впечатлений и дают полет фантазии — это не мусор
Не хочется признавать, но в подавляющем большинстве случаев действительно ЧПУ окажется лишним. Об этом говорится и на странице недавнего ныне популярного у SEO-шников исследования

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


Однако никто не отменяет того, что заказчик сайта может решить, что важно внимание мелочам. И тут лучше знать как делать ЧПУ, чем не знать.

Ну что же, это грустно. Я помню, что 12 лет назад команда, в которой я работал, много сил и времени потратила, чтобы создать коробочный продукт под Joomla. Этот продукт позволял управлять ссылками на сайте, и тем какой вид будет у ЧПУ. Помню это было интересной работой для тех дремучих лет. Да и продукт раскупался как пирожки.

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

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

Если поменялся slug на ту страницу, для которой требовался ЧПУ, то это уже другая страница, которую нужно индексировать по новому в подавляющем большинстве случаев. Вы сами подумайте — вы поменяли название продукта/статьи/еще чего-то. Так что о редиректах тут речь идет только в том случае, когда ЧПУ применяется неуместно.

может быть длинным и сложным

Если полный адрес страницы укладывается в 128 символов, то кого это волнует? Да зачастую и более длинные ссылки мало кого раздражают. Длинный адрес — не является сложным. Плохо составленный адрес даже будучи коротким может вынести мозг почище 256-ти символьного.

по логам ничего не понятно

Логи нужно заполнять так, чтобы было понятно. А главное заполнять их исходя из понимания того как вы их будете потом читать и какая вам понадобится информация для понимания и в каком виде. И уж точно тут мало что зависит от длины адреса строки.
Если говорить про стандартные Apache логи, то чем вам облегчит чтение при урле типа
/products/123134

?
123134 — это такой же ID как и slug. В случае если в урле есть еще и slug категории, то у вас есть два ID для выборки интересующей статьи, которые, кстати, еще из логов уже могут указать на тематику страницы с данным урлом. В итоге, на сколько я понимаю, вы недовольны тем, что вам придется делать на одно действие больше при выборки из базы данных статьи, вызвавшей сбой в программе? На месте вашего работодателя (если таковой имеется) я бы подумал — повышать вам ЗП или нет.

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

Но, как я говорил в статье, Doctrine Sluggable behavior extension берет на себя ответственность по построению уникальных slug-ов.

Я сейчас создал три раза подряд продукт с одним и тем же именем: «Что-то осмысленное». Автоматически сгенерированные slug-и получились такими:
  • chto-to-osmyslennoe
  • chto-to-osmyslennoe-1
  • chto-to-osmyslennoe-2


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

@Gedmo\Slug(fields={"name", "publishDate"})

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

Возможность иметь продукты с одинаковым наименованием и slug-ом в двух разных категориях я не рассматривал.
Все зависит от ситуации. В большинстве случаев, даже на сайтах с хорошим ЧПУ и SEO оптимизацией, я вижу, что параметры фильтрации передаются на сервер банальными GET параметрами.

Если фильтрация и сортировка подразумевает сотню параметров, то в общем-то и нет смысла сувать это все в ЧПУ, так как такой URL уже приобретает характер служебного URL. То есть такого URL, который индексировать поисковик не должен, да и пользователю лишний раз его показывать не стоит.

Но если параметров фильтрации не больше 20-ти и одновременно из них не может быть выбрано больше 5-ти, то это можно оформить в виде ЧПУ ссылок.

Сами подумайте, ведь ЧПУ типа:
http(s)://Домен/slug-категории/slug-подкатегории/

уже является ЧПУ с фильтрацией. Здесь фильтрация по категории.

Значит здесь думать нужно так: если в результате фильтрации получаются URL-ы, которые вы в гипотетической смтуации могли бы вставить в гипотетическую менюшку и такая менюшка была бы удобна для пользователя, то подобная фильтрация заслуживает быть ЧПУ. А вот как это реализовать — это другой вопрос. Один экшин в симфони может сопоставляться с большим количеством маршрутов:
     /**
     * @Route("/search/category/{category_slug}/", name="search_by_category")
     * @Route("/search/date-from/{date-from}/date-to/{date-to}", name="search_by_date")
     * @Method({"GET"})
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
     */
    public function searchAction(Request $request, string $category_slug = null, $date-from = null, $date-to = null )
    {
        ...
    }


Либо еще как-то эксперементировать с маршрутами

Information

Rating
6,251-st
Location
Бишкек, Кыргызстан, Кыргызстан
Date of birth
Registered
Activity