Инкапсуляция. Продолжение. Часть 3 из 3.
Второй совет, который я даю, состоит в том, чтобы представлять, что мы пишем не на интерпретируемом, а на компилируемом языке. Представьте, что ваш класс сразу после того, как вы закончите над ним работу, будет скомпилирован в некую библиотеку (DLL, например). Ваши коллеги и любой, кто будет работать с этим классом после вас, не смогут увидеть его код. То есть они не будут ничего знать о том, как работает ваш класс и что именно он делает. Все, что они будут видеть – это его интерфейс (за которым вы инкапсулировали все внутренности вашего класса). Когда вы начинаете мыслить подобным образом, вы начинаете более ответственно и внимательно относиться к интерфейсу вашего класса. Ведь интерфейс – это лицо, документация и «пульт с кнопками» вашего класса. Что увидят другие разработчики, глядя на ваш интерфейс? Поймут ли они, что делает ваш класс, для чего он предназначен? Смогут ли они с первой попытки воспользоваться вашим классом правильно, то есть так, как вы изначально задумали? Смогут ли они воспользоваться вашим классом неправильно, например, вызвав в самом начале какой-то метод, который должен вызываться только в середине? Задавая себе подобные вопросы, вы думаете об инкапсуляции (не только о ней, но и о ней тоже).
Итак, что же такое инкапсуляция с точки зрения повседневного написания кода? Это такое свойство класса, благодаря которому разработчик может решать, что именно пользователь класса (то есть, клиентский код) сможет и чего он не сможет сделать с помощью разрабатываемого класса. Как именно класс будет управляться из клиентского кода? Какие кнопки и рычажки мы дадим пользователю класса (то есть другим разработчикам и себе самому), а какие механизмы скроем? Именно на эти вопросы отвечает инкапсуляция.
В заключении хотел бы добавить еще пару мыслей из повседневной практики ревью и программирования. Первое: если вы создали класс и не задумываясь, автоматически сделали геттеры и сеттеры для всех его полей, лучше просто сделайте все поля публичными. С точки зрения инкапсуляции это одно и то же. Из этого вытекает второе: если у вас есть какое-то приватное поле, которое Шторм вам подсвечивает как неиспользуемое (пока не используемое) это не значит, что нужно автоматически открывать его наружу сеттером и геттером. Не нужно, если вы так считаете. Ведь это ваш класс, и вы знаете, зачем там это поле и должно ли оно торчать наружу. Третье: когда вы пользуетесь своим классом в клиентском коде, обращайте внимание на то, каким получается этот самый клиентский код, использующий ваш класс. Нет ли в этом коде какой-то технической логики (лишних циклов или подготовки данных, необходимых классу), которую вы хотели бы скрыть, инкапсулировать за интерфейсом класса, сделав клиентский код более легким и читаемым? Каждый класс, который вы пишите, нужно рассматривать именно из клиентского кода (если слова «клиентский код», вдруг, вызывают у вас затруднение, срочно погуглите). Именно во время работы с классом в клиентском коде вы имеете наилучшую возможность понять, не размотали ли вы случайно какие-то кишки класса наружу. Может лучше их спрятать (инкапсулировать) за интерфейсом?
Второй совет, который я даю, состоит в том, чтобы представлять, что мы пишем не на интерпретируемом, а на компилируемом языке. Представьте, что ваш класс сразу после того, как вы закончите над ним работу, будет скомпилирован в некую библиотеку (DLL, например). Ваши коллеги и любой, кто будет работать с этим классом после вас, не смогут увидеть его код. То есть они не будут ничего знать о том, как работает ваш класс и что именно он делает. Все, что они будут видеть – это его интерфейс (за которым вы инкапсулировали все внутренности вашего класса). Когда вы начинаете мыслить подобным образом, вы начинаете более ответственно и внимательно относиться к интерфейсу вашего класса. Ведь интерфейс – это лицо, документация и «пульт с кнопками» вашего класса. Что увидят другие разработчики, глядя на ваш интерфейс? Поймут ли они, что делает ваш класс, для чего он предназначен? Смогут ли они с первой попытки воспользоваться вашим классом правильно, то есть так, как вы изначально задумали? Смогут ли они воспользоваться вашим классом неправильно, например, вызвав в самом начале какой-то метод, который должен вызываться только в середине? Задавая себе подобные вопросы, вы думаете об инкапсуляции (не только о ней, но и о ней тоже).
Итак, что же такое инкапсуляция с точки зрения повседневного написания кода? Это такое свойство класса, благодаря которому разработчик может решать, что именно пользователь класса (то есть, клиентский код) сможет и чего он не сможет сделать с помощью разрабатываемого класса. Как именно класс будет управляться из клиентского кода? Какие кнопки и рычажки мы дадим пользователю класса (то есть другим разработчикам и себе самому), а какие механизмы скроем? Именно на эти вопросы отвечает инкапсуляция.
В заключении хотел бы добавить еще пару мыслей из повседневной практики ревью и программирования. Первое: если вы создали класс и не задумываясь, автоматически сделали геттеры и сеттеры для всех его полей, лучше просто сделайте все поля публичными. С точки зрения инкапсуляции это одно и то же. Из этого вытекает второе: если у вас есть какое-то приватное поле, которое Шторм вам подсвечивает как неиспользуемое (пока не используемое) это не значит, что нужно автоматически открывать его наружу сеттером и геттером. Не нужно, если вы так считаете. Ведь это ваш класс, и вы знаете, зачем там это поле и должно ли оно торчать наружу. Третье: когда вы пользуетесь своим классом в клиентском коде, обращайте внимание на то, каким получается этот самый клиентский код, использующий ваш класс. Нет ли в этом коде какой-то технической логики (лишних циклов или подготовки данных, необходимых классу), которую вы хотели бы скрыть, инкапсулировать за интерфейсом класса, сделав клиентский код более легким и читаемым? Каждый класс, который вы пишите, нужно рассматривать именно из клиентского кода (если слова «клиентский код», вдруг, вызывают у вас затруднение, срочно погуглите). Именно во время работы с классом в клиентском коде вы имеете наилучшую возможность понять, не размотали ли вы случайно какие-то кишки класса наружу. Может лучше их спрятать (инкапсулировать) за интерфейсом?
👏6❤1👍1🔥1
Собрав обратную связь после первого поста, решил взять паузу (удлиненную праздниками 🥂) на ее осмысление. Оказалось, что изначально задумывавшаяся направленность канала не слишком удачна. Точнее, тот материал, которым я планировал делиться, не слишком полезен, попадая как бы в середину. Более опытных ребят мне удивить, рассказав им что-то новое, практически нечем, а тех, кто мог бы еще много чему поучиться, не слишком занимают рассуждения о тонкостях красивого кода и хорошей архитектуры проекта, так как пристегнуть им эти рассуждения не к чему: волнуют более приземленные и насущные вопросы.
Поразмыслив над этим, я (не без внутреннего сопротивления) решил-таки, сместиться к более простым и повседневным аспектам разработки, интересным тем, кто находится вначале или в середине карьерного пути и хочет по этому самому пути сделать несколько новых шагов.
Попробую писать в таком ключе, надеюсь окажется полезным. Как всегда, ваша обратная связь в этом деле для меня главный ориентир, так что всегда буду вам благодарен за любые комментарии, как отправленные в личку, так и оставленные публично.
Поразмыслив над этим, я (не без внутреннего сопротивления) решил-таки, сместиться к более простым и повседневным аспектам разработки, интересным тем, кто находится вначале или в середине карьерного пути и хочет по этому самому пути сделать несколько новых шагов.
Попробую писать в таком ключе, надеюсь окажется полезным. Как всегда, ваша обратная связь в этом деле для меня главный ориентир, так что всегда буду вам благодарен за любые комментарии, как отправленные в личку, так и оставленные публично.
❤3👍1🔥1
Нужна ли рефлексия? И если нужна, то где? Случалось несколько раз спорить на эту тему с теми, кто считает, что использование рефлексии усложняет проект и делает его менее читаемым для джунов и даже миддлов. Но, пардон, что тут усложнять? Если речь идет о необходимости изменить/прочитать значение приватного свойства, то делов на три строчки кода. Где это нужно? Чаще всего – при ручной гидрации. Где нужна ручная гидрация? В проектах, следующих DDD, у вас ее будет не меньше половины (а если у вас ее меньше, то скорее всего зря вы притащили в свой проект DDD 😈).
Даже в проектах, подразумевающих типовое использование Doctrine, по мере их роста возникает потребность перелить результат запроса в объект вручную. И если вы в своем проекте хотя бы немного стремитесь к чистому коду и какому-то порядку в архитектуре, то вы не захотите изменять код своих сущностей ради потребностей репозитория.
Разумеется, возможности рефлексии шире, чем простое получение доступа к приватным полям. И, разумеется, использование рефлексии для обхода ограничений, задаваемых областями видимости членов класса, допустимо только в узких инфраструктурных целях.
#рефлексия #гидрация
Даже в проектах, подразумевающих типовое использование Doctrine, по мере их роста возникает потребность перелить результат запроса в объект вручную. И если вы в своем проекте хотя бы немного стремитесь к чистому коду и какому-то порядку в архитектуре, то вы не захотите изменять код своих сущностей ради потребностей репозитория.
Разумеется, возможности рефлексии шире, чем простое получение доступа к приватным полям. И, разумеется, использование рефлексии для обхода ограничений, задаваемых областями видимости членов класса, допустимо только в узких инфраструктурных целях.
#рефлексия #гидрация
Продолжая тему предыдущего 👆 поста: еще один пример менее частого, но все же встречающегося простого и полезного использования рефлексии – это работа с кастомными атрибутами. Из моей личной практики и отношения к коду кастомные атрибуты наиболее уместны в слое контроллеров (а в доменном слое ИМО неуместны вообще никакие атрибуты, ибо нечего засорять метаданными тонюсенький слой бизнес-логики).
В частности, мне приходилось активно пользоваться атрибутами собственного производства при реализации ABAC (альтернативы RBAC) и при написании API шлюзов. И там и там очень удобно было размечать каждый эндпоинт собственными атрибутами, передавая через них аргументы в более глубокие слои приложения, вызывавшиеся симфонийским
Вообще я очень люблю держать контроллеры максимально коротенькими, чистыми и супер-однотипными во всем, включая нейминг переменных. Это ускоряет и упрощает их копипасту, минимизируя трудозатраты на написание инфраструктурного кода. Также это облегчает беглое чтение контроллера глазами для ознакомления со списком существующих эндпоинтов и быстрого формирования понимания того, что вообще может приложение. Ведь дока API есть не всегда, как и уверенность в том, что эта самая дока актуальна.
Получилось в этом посте спонтанно затронуть огромную и интересную тему ABAC. Дам ка я, пожалуй, ссылочку на статью, с которой в эту тему можно начать погружаться.
Ну а если (не дай Бог, но мало ли 🤷♂️) у кого-то вызвало замешательство упоминание
#атрибуты #рефлексия #контроллер
В частности, мне приходилось активно пользоваться атрибутами собственного производства при реализации ABAC (альтернативы RBAC) и при написании API шлюзов. И там и там очень удобно было размечать каждый эндпоинт собственными атрибутами, передавая через них аргументы в более глубокие слои приложения, вызывавшиеся симфонийским
kernel.controller лисенером.Вообще я очень люблю держать контроллеры максимально коротенькими, чистыми и супер-однотипными во всем, включая нейминг переменных. Это ускоряет и упрощает их копипасту, минимизируя трудозатраты на написание инфраструктурного кода. Также это облегчает беглое чтение контроллера глазами для ознакомления со списком существующих эндпоинтов и быстрого формирования понимания того, что вообще может приложение. Ведь дока API есть не всегда, как и уверенность в том, что эта самая дока актуальна.
Получилось в этом посте спонтанно затронуть огромную и интересную тему ABAC. Дам ка я, пожалуй, ссылочку на статью, с которой в эту тему можно начать погружаться.
Ну а если (не дай Бог, но мало ли 🤷♂️) у кого-то вызвало замешательство упоминание
kernel.controller, то вот вам ссылочка на доку по встроенным симфонийским событиям.#атрибуты #рефлексия #контроллер
Быть или казаться?
Готовя следующий пост о том, нужно ли для успешного найма знать индексы БД, задумался. Тему успешного прохождения собеседований на вакансии до уровня Senior мне хотелось бы сделать одной из регулярно освещаемых в своем нарождающемся блоге. При этом я только сейчас осознал, как часто мне на самом деле приходилось встречаться с подходом «лишь бы пройти отбор» как в различных пабликах в сети, так и в живых коллегах.
То есть вместо того, чтобы понять требования вакансий определенного уровня и специальности, наработать требуемые компетенции и спокойно и с удовольствием найти достойную работу, люди затачиваются на некое подобие школьного списывания и зубрежки, ставя первоочередной целью именно прохождение отбора. А дальше хоть трава не расти.
С удивлением только сейчас осознал, как много мне на моем пути встретилось людей, с треском вылетавших с испытательного срока под недоуменные возгласы лидов о том, как этот человек вообще прошел техинтервью.
Что ж, вопросы совести и морали оставлю за рамками этого поста, скажу лишь, что мой подход кардинально отличается. Для того, чтобы получить Level UP по карьере, нужно не пытаться «сдать экзамен» любой ценой, а просто оптимизировать процесс подготовки к собеседованиям, поняв, какие компетенции дают наибольшее влияние на принятие решения по вашей кандидатуре, и сосредоточившись на их прокачке, игнорируя все остальные навыки, которые тоже востребованы, но не оказывают большого влияния на ваши шансы успешно трудоустроиться.
При таком подходе ваш найм будет честным, а полученная работа скорее всего будет требовать от вас немного больше, чем вы умеете, что поневоле заставит вас прокачать и те навыки, на которые вы забивали при подготовке к интервью.
#собеседования
Готовя следующий пост о том, нужно ли для успешного найма знать индексы БД, задумался. Тему успешного прохождения собеседований на вакансии до уровня Senior мне хотелось бы сделать одной из регулярно освещаемых в своем нарождающемся блоге. При этом я только сейчас осознал, как часто мне на самом деле приходилось встречаться с подходом «лишь бы пройти отбор» как в различных пабликах в сети, так и в живых коллегах.
То есть вместо того, чтобы понять требования вакансий определенного уровня и специальности, наработать требуемые компетенции и спокойно и с удовольствием найти достойную работу, люди затачиваются на некое подобие школьного списывания и зубрежки, ставя первоочередной целью именно прохождение отбора. А дальше хоть трава не расти.
С удивлением только сейчас осознал, как много мне на моем пути встретилось людей, с треском вылетавших с испытательного срока под недоуменные возгласы лидов о том, как этот человек вообще прошел техинтервью.
Что ж, вопросы совести и морали оставлю за рамками этого поста, скажу лишь, что мой подход кардинально отличается. Для того, чтобы получить Level UP по карьере, нужно не пытаться «сдать экзамен» любой ценой, а просто оптимизировать процесс подготовки к собеседованиям, поняв, какие компетенции дают наибольшее влияние на принятие решения по вашей кандидатуре, и сосредоточившись на их прокачке, игнорируя все остальные навыки, которые тоже востребованы, но не оказывают большого влияния на ваши шансы успешно трудоустроиться.
При таком подходе ваш найм будет честным, а полученная работа скорее всего будет требовать от вас немного больше, чем вы умеете, что поневоле заставит вас прокачать и те навыки, на которые вы забивали при подготовке к интервью.
#собеседования
👍2
Обязательно ли понимание индексов баз данных для карьерного роста разработчика?
Отвечу так: я дошел до позиций уровня senior без этого. Конечно, глядя из сегодняшнего дня на себя, первый раз получившего заветную лычку сеньора, я могу сказать, что я вообще ничего тогда не понимал ни то, что в БД, но и в написании кода. 😁
И все же: можно спокойно доходить до оффера не менее чем в трети собеседований на сеньорские вакансии, вообще ничего не зная об индексах кроме того, что они каким-то образом ускоряют выполнение запросов.
Однако цель этого поста не столько в том, чтобы обрадовать всех, кто, как и я, любит базы данных (да и вообще любые инфраструктурные компоненты) сильно меньше, чем написание кода, но и в том, чтобы порекомендовать вам источник, который содержит ответы на 90% вопросов, задаваемых по индексам во время техинтервью на позиции сеньора.
Вот такой видосик попался мне в свое время на глаза: https://www.youtube.com/watch?v=RUF3n_EIcy8
В нем автор очень доходчиво объясняет:
- общий принцип работы B-TREE индекса;
- как правильно строить составные индексы (об этом нередко спрашивают на собесах);
- что такое селективность и как она влияет на скорость работы индекса;
- как базово пользоваться EXPLAIN в MySQL.
Кроме того, к видосу прилагается тестовая база для самостоятельного выполнения учебных упражнений, что очень ценно, т. к. мне, например, часто приходилось самостоятельно выдумывать себе задания и тестовые наборы данных для закрепления материала какой-нибудь статьи.
#SQL_индексы #собеседования
Отвечу так: я дошел до позиций уровня senior без этого. Конечно, глядя из сегодняшнего дня на себя, первый раз получившего заветную лычку сеньора, я могу сказать, что я вообще ничего тогда не понимал ни то, что в БД, но и в написании кода. 😁
И все же: можно спокойно доходить до оффера не менее чем в трети собеседований на сеньорские вакансии, вообще ничего не зная об индексах кроме того, что они каким-то образом ускоряют выполнение запросов.
Однако цель этого поста не столько в том, чтобы обрадовать всех, кто, как и я, любит базы данных (да и вообще любые инфраструктурные компоненты) сильно меньше, чем написание кода, но и в том, чтобы порекомендовать вам источник, который содержит ответы на 90% вопросов, задаваемых по индексам во время техинтервью на позиции сеньора.
Вот такой видосик попался мне в свое время на глаза: https://www.youtube.com/watch?v=RUF3n_EIcy8
В нем автор очень доходчиво объясняет:
- общий принцип работы B-TREE индекса;
- как правильно строить составные индексы (об этом нередко спрашивают на собесах);
- что такое селективность и как она влияет на скорость работы индекса;
- как базово пользоваться EXPLAIN в MySQL.
Кроме того, к видосу прилагается тестовая база для самостоятельного выполнения учебных упражнений, что очень ценно, т. к. мне, например, часто приходилось самостоятельно выдумывать себе задания и тестовые наборы данных для закрепления материала какой-нибудь статьи.
#SQL_индексы #собеседования
YouTube
Базы данных. MySQL. Индексы
Презентация:
https://docs.google.com/presentation/d/153hP9EE2yo0-TEA4on6u5SOpUkM8siKDOxIegDNyhXI/edit?usp=sharing
Практика:
https://docs.google.com/spreadsheets/d/1cTs1lSIwtADVdZhEZOayukhvb67EgDBEwjQMTiqcMrA/edit?usp=sharing
Тестовая база:
https://driv…
https://docs.google.com/presentation/d/153hP9EE2yo0-TEA4on6u5SOpUkM8siKDOxIegDNyhXI/edit?usp=sharing
Практика:
https://docs.google.com/spreadsheets/d/1cTs1lSIwtADVdZhEZOayukhvb67EgDBEwjQMTiqcMrA/edit?usp=sharing
Тестовая база:
https://driv…
👍4
Instanceof и принцип подстановки Барбары Лисков.
Наткнулся сегодня в очередной раз на
Задумался над тем, почему так происходит, а заодно взял из любопытства один из своих типичных проектов и посмотрел, где я сам использую этот оператор. Случаи, которые я нашел в своем коде разберу в следующих постах.
Наткнулся сегодня в очередной раз на
instanceof в чужом коде и попытался вспомнить: был ли у меня хоть один случай на ревью, когда instanceof не нарушал принципа подстановки Барбары Лисков. Похоже, что не было.Задумался над тем, почему так происходит, а заодно взял из любопытства один из своих типичных проектов и посмотрел, где я сам использую этот оператор. Случаи, которые я нашел в своем коде разберу в следующих постах.
Instanceof и принцип подстановки Барбары Лисков.
Итак, первый случай из моего кода. Написание кастомного Symfony валидатора согласно симфонийской же доке (ссылка на пример кода от Symfony). Что мы здесь имеем? А имеем мы здесь самый частый случай грубого нарушения принципа Лисков, который мне встречается на ревью: сначала указываем в сигнатуре метода определенный тип аргумента и тут же в первой строчке метода заужаем этот тип с помощью
Бывает и более грубый случай, когда сигнатура метода не диктуется разработчику никаким родительским типом (классом или интерфейсом), а он зачем-то все равно указывает широкий тип аргумента метода, а затем в первой же строчке ограничивает его с помощью
Давайте попробуем разобраться с симфонийским валидатором, и понять, почему он так сделан, и как можно было бы уйти в нем от нарушения принципа Лисков. В рассматриваемом решении мы видим разделение ответственности между двумя классами. Класс
Проблема состоит в том, что по условиям задачи у нас есть четкая связка: один
Казалось бы, уже в самой этой формулировке прописано нарушение принципа Лисков, и нам нужно возвращаться к началу, чтобы по-другому спроектировать наше решение. Но давайте вспомним, как звучит принцип Лисков. Упрощенно он звучит так: если в сигнатуре метода объявлен аргумент определенного типа, то наш метод обязан корректно работать с любым подтипом того типа, который объявлен в сигнатуре. То есть, применительно к нашему примеру, любой Валидатор должен работать с любымне ставя приложение раком не приводя к аварийному завершению программы. Есть очень простой и проверенный способ добиться этого, причем в симфонийском валидаторе он реализован, но почему-то не применен.
Класс
Так вот, чтобы убрать в этом случае
#SOLID #Liskov #интерфейс_класса
Итак, первый случай из моего кода. Написание кастомного Symfony валидатора согласно симфонийской же доке (ссылка на пример кода от Symfony). Что мы здесь имеем? А имеем мы здесь самый частый случай грубого нарушения принципа Лисков, который мне встречается на ревью: сначала указываем в сигнатуре метода определенный тип аргумента и тут же в первой строчке метода заужаем этот тип с помощью
instanceof. Конкретно этот случай с Симфони еще чуть более простителен от того, что корень проблемы здесь в том, как спроектированы интерфейсы.Бывает и более грубый случай, когда сигнатура метода не диктуется разработчику никаким родительским типом (классом или интерфейсом), а он зачем-то все равно указывает широкий тип аргумента метода, а затем в первой же строчке ограничивает его с помощью
instanceof. Такую ошибку исправить легко: просто указать более точный тип аргумента в сигнатуре метода и убрать instaceof. А как быть с предыдущем случаем из Symfony, когда проблема навязана нам интерфейсом?Давайте попробуем разобраться с симфонийским валидатором, и понять, почему он так сделан, и как можно было бы уйти в нем от нарушения принципа Лисков. В рассматриваемом решении мы видим разделение ответственности между двумя классами. Класс
Constraint несет в себе метаданные, то есть, с помощью этого класса мы помечаем, какие поля каким образом мы хотим валидировать. Второй класс – ConstraintValidator (буду называть его просто Валидатор) выполняет собственно валидацию. Таким образом созданы две точки расширения: теперь можно произвольно развивать дерево метаданных и дерево валидаторов.Проблема состоит в том, что по условиям задачи у нас есть четкая связка: один
Constraint должен всегда соответствовать одному Валидатору. Лично мне не раз приходилось сталкиваться с такой проблемой при проектировании своих решений. Сначала мы описываем контракты в базовом типе, с одной стороны задавая рамки для будущих реализаций, а с другой – оставляя достаточно свободы «будущему себе» и своим коллегам. В то же время, нам как-то нужно добавить осведомленность о том, что каждый потомок одного супертипа (Валидатора) работает только с ограниченным набором (в данном случае только с одним из) потомков другого супертипа (Constraint).Казалось бы, уже в самой этой формулировке прописано нарушение принципа Лисков, и нам нужно возвращаться к началу, чтобы по-другому спроектировать наше решение. Но давайте вспомним, как звучит принцип Лисков. Упрощенно он звучит так: если в сигнатуре метода объявлен аргумент определенного типа, то наш метод обязан корректно работать с любым подтипом того типа, который объявлен в сигнатуре. То есть, применительно к нашему примеру, любой Валидатор должен работать с любым
Constraint, Класс
Constraint содержит метод validatedBy(), который должен возвращать имя класса Валидатора, который работает с этим Constraint. В Симфони этот метод используется в клиентском коде, в самом, так сказать, «головном» валидаторе, который благодаря этому методу сопоставляет списки Constraint и Валидаторов между собой. А instanceof здесь служит эдакой защитой от дурака.Так вот, чтобы убрать в этом случае
instanceof и начать соблюдать принцип Лисков, было бы правильно в самом ConstraintValidator вызывать метод Constraint::validatedBy() и, в случае если нам подсунули не тот Constraint, просто не выполнять валидацию. Таким образом наш валидатор становится способен работать с любым Constraint. Ведь принцип Лисков ничего не говорит о том, как именно наш метод должен обрабатывать любой подтип 🦊.#SOLID #Liskov #интерфейс_класса
👍1
Стоит ли расстраиваться, получив отказ после техинтервью? Я считаю, нужно радоваться. Давайте разберемся, какие могут быть причины отказа.
1. Специалист, проводивший техинтервью (сеньор, тимлид, техлид, начальник разработки, СТО) решил, что ваших навыков недостаточно.
2. Кто-то в менеджменте решил, что выне вышли рылом не подходите по софтам, фактам биографии, цвету глаз, возрасту, полу, манере шутить и т. п. и зарубил вашу кандидатуру несмотря на успешное прохождение техинтервью.
3. Вас в целом неплохо оценили, и были бы готовы сделать вам оффер, но на «ваше» место нашелся внутренний (да, так тоже бывает) или внешний более подходящий кандидат.
4. Вас оценили неплохо, но ваши зп ожидания оказались выше их (работодателя) оценки (или возможностей) и с вами решили не торговаться, чтобы «не снизить вашу мотивацию».
5. Вас оценили хорошо, но побоялись, что ваш часовой пояс сильно отличается от часового пояса команды. Живя в UTC +8, я получил за свою практику несколько единиц таких отказов.
6. Вас оценили хорошо, но вакансия предполагает небольшой объем фронтовых задач, а вы – чистый бэк.
Для меня последние четыре причины отказа – это однозначный повод для радости. Ведь в целом все условия для получения оффера выполнены, и не сошлись какие-то второстепенные моменты. То есть, такой итог техинтервью служит подтверждением вашей компетентности и говорит о хороших шансах при апплае на следующие вакансии (это если вы, вдруг, в себе сомневались).
Что касается причины №2, то могу вас заверить со всей уверенностью, что получение такого отказа – это ваша удача. Это все равно что в момент заключения сделки по покупке машины увидеть, что она не заводится, да и арки-то у нее ржавые, как сразу не заметил? Ведь хорошо же, что эти изъяны обнаружились до того, как машина стала вашей, правда? Так же и в случае с потенциальной новой работой: если неадекватный менеджмент проявил себя до того, как вы туда попали, то вам повезло.
Лично мне пару раз случалось попадать в ситуации, когда техинтервью проводит замечательнейший человек: и по части инженерных взглядов во всем мы с ним сходимся, и по софтам он просто душка, и то, как он описывает свое видение организации процессов, заставляет лишь удовлетворенно кивать. И вот ты принимаешь оффер, и интервьюер-душка куда-то исчезает. А ведь была договоренность, что я буду работать напрямую с ним 🤬! И вместо чудесного лида над тобой оказывается не пойми кто. Поэтому. Если неадекватный менеджмент выявился на стадии интервью, то это просто замечательно. Пусть даже он выявился тем, что отказал вам в вакансии по обидному для вас поводу. Хотя, на самом деле, вам в лицо это вряд ли скажут и узнать об отказе по причине №2 из списка выше можно только проявив настойчивость и имея возможность напрямую пообщаться с кем-то внутри компании.
#собеседования
1. Специалист, проводивший техинтервью (сеньор, тимлид, техлид, начальник разработки, СТО) решил, что ваших навыков недостаточно.
2. Кто-то в менеджменте решил, что вы
3. Вас в целом неплохо оценили, и были бы готовы сделать вам оффер, но на «ваше» место нашелся внутренний (да, так тоже бывает) или внешний более подходящий кандидат.
4. Вас оценили неплохо, но ваши зп ожидания оказались выше их (работодателя) оценки (или возможностей) и с вами решили не торговаться, чтобы «не снизить вашу мотивацию».
5. Вас оценили хорошо, но побоялись, что ваш часовой пояс сильно отличается от часового пояса команды. Живя в UTC +8, я получил за свою практику несколько единиц таких отказов.
6. Вас оценили хорошо, но вакансия предполагает небольшой объем фронтовых задач, а вы – чистый бэк.
Для меня последние четыре причины отказа – это однозначный повод для радости. Ведь в целом все условия для получения оффера выполнены, и не сошлись какие-то второстепенные моменты. То есть, такой итог техинтервью служит подтверждением вашей компетентности и говорит о хороших шансах при апплае на следующие вакансии (это если вы, вдруг, в себе сомневались).
Что касается причины №2, то могу вас заверить со всей уверенностью, что получение такого отказа – это ваша удача. Это все равно что в момент заключения сделки по покупке машины увидеть, что она не заводится, да и арки-то у нее ржавые, как сразу не заметил? Ведь хорошо же, что эти изъяны обнаружились до того, как машина стала вашей, правда? Так же и в случае с потенциальной новой работой: если неадекватный менеджмент проявил себя до того, как вы туда попали, то вам повезло.
Лично мне пару раз случалось попадать в ситуации, когда техинтервью проводит замечательнейший человек: и по части инженерных взглядов во всем мы с ним сходимся, и по софтам он просто душка, и то, как он описывает свое видение организации процессов, заставляет лишь удовлетворенно кивать. И вот ты принимаешь оффер, и интервьюер-душка куда-то исчезает. А ведь была договоренность, что я буду работать напрямую с ним 🤬! И вместо чудесного лида над тобой оказывается не пойми кто. Поэтому. Если неадекватный менеджмент выявился на стадии интервью, то это просто замечательно. Пусть даже он выявился тем, что отказал вам в вакансии по обидному для вас поводу. Хотя, на самом деле, вам в лицо это вряд ли скажут и узнать об отказе по причине №2 из списка выше можно только проявив настойчивость и имея возможность напрямую пообщаться с кем-то внутри компании.
#собеседования
❤🔥1👍1
Стоит ли расстраиваться, получив отказ после техинтервью? Продолжение предыдущего поста 👆
Ну и, наконец, причина №1. На самом деле этот пункт можно разделить на несколько подпунктов:
1. Вы согласны с оценкой интервьюера.
2. Интервьюер был в целом адекватный, но вы не согласны с его оценкой.
3. Интервьюер был неадекватный. Например, спрашивал вас, за что отвечает PSR-4, или на лайв-кодинге объявил вам, что ваш код не будет работать, потому что вы «не сделали фабрику», или получив три ответа на свой вопрос, объясняющих тему с разных сторон, объявил вам, что не один из ваших ответов не совпадает с «ответом из гугла».
Первый случай я всегда воспринимаю как возможность научиться новому. Ведь мне выпало знакомство с человеком, который в какой-то области или сразу в нескольких опытнее меня. У такого человека обязательно нужно просить совета, что почитать, где поучиться. Все самые полезные источники, по которым я учился, я получил именно на непройденных мной техинтервью. Иногда удается прямо в процессе интервью попросить интервьюера объяснить правильный ответ на его вопрос, что тоже может оказаться очень ценным. С грустью вынужден констатировать, что таких интервьюеров в моей практике было хорошо, если десятая часть, но они были! И именно им я во многом обязан своим ростом. Так что, получение такого отказа – это тоже повод для радости.
Что касается варианта №3 с неадекватным лидом, проводящим интервью, думаю, вы уже сами все поняли. См. в предыдущем посте про неадекватный менеджмент.
Остается случай, когда интервьюер вроде вел себя адекватно, но в целом вы не сошлись именно по техчасти. Чаще всего это лиды с большим стажем (намеренно пишу «стажем», а не «опытом»), чье мышление давно и прочно легло в определенное русло, покидать которое им крайне некомфортно. Нисколько не осуждая таких людей, я тем не менее, спрашиваю себя: насколько комфортно было бы мне работать с таким лидом?
Резюмируя, могу лишь повторить, что наше эмоциональное начало может понуждать нас расстраиваться в ответ на отказ после техинтервью. Но рациональное начало в нас (мы же все-таки инженеры😎 ) может лишь радоваться такому исходу.
#собеседования
Ну и, наконец, причина №1. На самом деле этот пункт можно разделить на несколько подпунктов:
1. Вы согласны с оценкой интервьюера.
2. Интервьюер был в целом адекватный, но вы не согласны с его оценкой.
3. Интервьюер был неадекватный. Например, спрашивал вас, за что отвечает PSR-4, или на лайв-кодинге объявил вам, что ваш код не будет работать, потому что вы «не сделали фабрику», или получив три ответа на свой вопрос, объясняющих тему с разных сторон, объявил вам, что не один из ваших ответов не совпадает с «ответом из гугла».
Первый случай я всегда воспринимаю как возможность научиться новому. Ведь мне выпало знакомство с человеком, который в какой-то области или сразу в нескольких опытнее меня. У такого человека обязательно нужно просить совета, что почитать, где поучиться. Все самые полезные источники, по которым я учился, я получил именно на непройденных мной техинтервью. Иногда удается прямо в процессе интервью попросить интервьюера объяснить правильный ответ на его вопрос, что тоже может оказаться очень ценным. С грустью вынужден констатировать, что таких интервьюеров в моей практике было хорошо, если десятая часть, но они были! И именно им я во многом обязан своим ростом. Так что, получение такого отказа – это тоже повод для радости.
Что касается варианта №3 с неадекватным лидом, проводящим интервью, думаю, вы уже сами все поняли. См. в предыдущем посте про неадекватный менеджмент.
Остается случай, когда интервьюер вроде вел себя адекватно, но в целом вы не сошлись именно по техчасти. Чаще всего это лиды с большим стажем (намеренно пишу «стажем», а не «опытом»), чье мышление давно и прочно легло в определенное русло, покидать которое им крайне некомфортно. Нисколько не осуждая таких людей, я тем не менее, спрашиваю себя: насколько комфортно было бы мне работать с таким лидом?
Резюмируя, могу лишь повторить, что наше эмоциональное начало может понуждать нас расстраиваться в ответ на отказ после техинтервью. Но рациональное начало в нас (мы же все-таки инженеры
#собеседования
Please open Telegram to view this post
VIEW IN TELEGRAM
❤🔥1
Классы коллекций как альтернатива plural types
Часто приходится объяснять эту несложную тему как в небольших докладиках, делаемых на команду, так и индивидуально.
Поскольку в PHP нет поддержки множественных типов, мы не можем написать такой код:
А это в свою очередь означает, что мы не можем явно контролировать тип каждого элемента массива, передаваемого в функцию, или возвращаемого из него. Конечно, мы можем написать что-то вроде:
Но при таком подходе мы засоряем код и не решаем проблему контроля типа элементов возвращаемого из функции массива.
И тут нам на помощь приходят классы коллекций:
☘️ За счет спред-оператора в конструкторе гарантируется, что все элементы коллекции будут одного типа.
☘️ Класс коллекции удобно расширять при необходимости методами типа
☘️ Любые манипуляции с элементами коллекции посредством циклов также лучше инкапсулировать в методах коллекции, что позволит их переиспользовать и сделает клиентский код чище.
☘️ Класс коллекции можно научить мерджиться, интерсектиться, выделять подмножества и т. д.
Лично я очень обширно использую коллекции в своем коде, самые толстые из которых включают сотни строк технической логики, разгружая тем самым клиентский код. И вам рекомендую!)
#чистый_код
Часто приходится объяснять эту несложную тему как в небольших докладиках, делаемых на команду, так и индивидуально.
Поскольку в PHP нет поддержки множественных типов, мы не можем написать такой код:
function foo(SomeClass[] $objects): ResultDTO[]
{
//...
}
А это в свою очередь означает, что мы не можем явно контролировать тип каждого элемента массива, передаваемого в функцию, или возвращаемого из него. Конечно, мы можем написать что-то вроде:
function foo(array $objects): array
{
if (!empty(array_filter($objects, fn ($o) => !$o instanceof SomeClass))) {
throw new \InvalidArgumentException();
}
//...
}
Но при таком подходе мы засоряем код и не решаем проблему контроля типа элементов возвращаемого из функции массива.
И тут нам на помощь приходят классы коллекций:
class UserCollection
{
/** @var User[] */
private array $elements;
public function __construct(User ...$elements)
{
$this->elements = $elements;
}
/**
* @return User[]
*/
public function getElements(): array
{
return $this->elements;
}
}
☘️ За счет спред-оператора в конструкторе гарантируется, что все элементы коллекции будут одного типа.
☘️ Класс коллекции удобно расширять при необходимости методами типа
addElement(), deleteElement() и т. п., добавляя синтаксического сахара и очищая клиентский код.☘️ Любые манипуляции с элементами коллекции посредством циклов также лучше инкапсулировать в методах коллекции, что позволит их переиспользовать и сделает клиентский код чище.
☘️ Класс коллекции можно научить мерджиться, интерсектиться, выделять подмножества и т. д.
Лично я очень обширно использую коллекции в своем коде, самые толстые из которых включают сотни строк технической логики, разгружая тем самым клиентский код. И вам рекомендую!)
#чистый_код
👍4🔥3❤2
Instanceof и принцип подстановки Барбары Лисков
Это второй пост, в котором я разбираю случаи применения
Первый пост
Нашел-таки у себя сразу два случая нарушения принципа Лисков оператором
Этот код - часть системы ABAC (альтернативы RBAC), о которой я уже писал в предыдущих постах. Коротко, зачем этот код нужен:
1️⃣ В обработчике
2️⃣ Микросервис ABAC помимо решения о доступе может прислать такую штуку, как обязательство (
3️⃣ За выполнение этого самого обязательства и отвечает метод
Проблема состоит в том, что при проектировании системы ABAC я, естественно, заложил абстрактный класс
Далее, при написании уже в контроллере кода, который отвечает за обработку обязательств, я, как это часто в таких случаях бывает, столкнулся с "безграничной свободой", которую сам же и заложил при проектировании абстракций, а теперь, во время написания реализации, вынужден как-то эту свободу ограничивать.
Ведь теоретически микросервис ABAC может прислать любые обязательства, хотя и не должен. Если это все-таки случилось, то это исключительная ситуация, которая однозначно должна вести к аварийному завершению приложения. Эдакий межсервисный
По сути, в такой ситуации вопрос состоит лишь в том, как именно должно падать наше приложение, ведь не упасть оно не может. Сейчас оно падает с нарушением принципа Лисков😂 . Чтобы это поправить, достаточно в сигнатуре метода
Далее, в клиентском коде, вызов
Вы можете спросить: а что, блин, изменилось и на хрен этот принцип Лисков нужен? Изменяется в такой ситуации то, что вы (и я в данном случае тоже, ведь у себя же нашел косяк 😱) набиваете руку и учитесь соблюдать SOLID без дополнительных энергозатрат, на автомате. А вот о пользе принципа Лисков я порассуждаю уже в другом посте.😄
#SOLID #Liskov #интерфейс_класса
Это второй пост, в котором я разбираю случаи применения
instanceof в своем коде на предмет нарушения принципа Лисков.Первый пост
Нашел-таки у себя сразу два случая нарушения принципа Лисков оператором
instanceof, и сегодня разберу первый из них. Имеем вот такой метод в контроллере:public function obligationCallback(ObligationResponse ...$obligations): void
{
$this->filterObligations = [];
foreach ($obligations as $obligation) {
if (!$obligation instanceof FilterObligationResponse) {
throw new UnhandledObligationException(self::class . ' . can not handle ' . $obligation::class);
}
$this->filterObligations[] = $obligation;
}
}
Этот код - часть системы ABAC (альтернативы RBAC), о которой я уже писал в предыдущих постах. Коротко, зачем этот код нужен:
kernel.controller_arguments (то есть, до вызова нашего контроллера) делается запрос в микросервис ABAC для принятия решения, имеет ли право юзер совершить запрашиваемое действие.Obligation). Если такое случилось, то наше приложение обязано выполнить это обязательство, либо отказать в доступе.obligationCallback() из примера выше.Проблема состоит в том, что при проектировании системы ABAC я, естественно, заложил абстрактный класс
ObligationResponse как точку расширения для создания в будущем любых обязательств.Далее, при написании уже в контроллере кода, который отвечает за обработку обязательств, я, как это часто в таких случаях бывает, столкнулся с "безграничной свободой", которую сам же и заложил при проектировании абстракций, а теперь, во время написания реализации, вынужден как-то эту свободу ограничивать.
Ведь теоретически микросервис ABAC может прислать любые обязательства, хотя и не должен. Если это все-таки случилось, то это исключительная ситуация, которая однозначно должна вести к аварийному завершению приложения. Эдакий межсервисный
\LogicException - нужно исправлять код, только не текущего приложения, а сервиса ABAC.По сути, в такой ситуации вопрос состоит лишь в том, как именно должно падать наше приложение, ведь не упасть оно не может. Сейчас оно падает с нарушением принципа Лисков
obligationCallback() из примера выше сузить тип аргумента до FilterObligationResponse (к счастью, сигнатуру нам здесь не диктует родительский класс или интерфейс).Далее, в клиентском коде, вызов
obligationCallback() следует обернуть в try-catch на отлов \TypeError и логировать ситуацию с явным указанием того, что микросервис ABAC прислал обязательство, которое контроллер не может обработать.Вы можете спросить: а что, блин, изменилось и на хрен этот принцип Лисков нужен? Изменяется в такой ситуации то, что вы (и я в данном случае тоже, ведь у себя же нашел косяк 😱) набиваете руку и учитесь соблюдать SOLID без дополнительных энергозатрат, на автомате. А вот о пользе принципа Лисков я порассуждаю уже в другом посте.
#SOLID #Liskov #интерфейс_класса
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Symfony vs Yii2. Устройство циклов обработки запросов.
В рамках написания своего первого лонгрида мне случилось нарисовать две упрощенные схемки того, как Symfony и Yii2 обрабатывают запрос. Разумеется, после этого возникло естественное желание сравнить два фреймворка в этом аспекте.
Концептуально то, как эти (да, скорее всего, и остальные тоже) фреймворки обрабатывают запрос, очень похоже. Есть класс приложения (в Symfony -
Но нам, конечно же, интереснее различия:
☘️ Symfony предоставляет гораздо больше встроенных событий. что позволяет более тонко вклиниваться в различные этапы прохождения цикла.
☘️ Симфонийский
☘️ В Yii2
☘️ Symfony оснащен гораздо более мощными и гибкими механизмами controller и argument резолвинга, что открывает обширные возможности, многие из которых в последних версиях стали доступны из коробки (см., например, здесь аннотации, начинающиеся с "Map").
☘️ Симфонийский роутинг состоит из большого количества классов и работает за счет тех же встроенных событий, которыми пользуемся мы сами, что позволяет проще и гибче его при нужде дорабатывать (согласен, нужда такая возникает редко, но у меня возникла😍 ).
В целом, погружаясь в то, как оба фреймворка устроены в своей основной части - цикла обработки HTTP запроса, я пришел к неожиданному для себя выводу.
Только во-первых, ваш код будет выглядеть гораздо более кандово из-за обращения к глобальным объектам и малого количества мест, куда вы этот код можете вставить. Вы, например, тупо будете вынуждены писать простыню в каком-нибудь
Ну а во-вторых, вы потратите гораздо больше усилий по сравнению с Symfony, т. к. в Symfony многие вещи тупо есть из коробки и этот фреймворк гораздо лучше задокументирован. Для доработки Yii2 вы не только напишите больше кода но и прочитаете очень много кода самого фреймворка, т. к. другого источника информации у вас просто не будет.
#Symfony #Yii2 #фреймворки
В рамках написания своего первого лонгрида мне случилось нарисовать две упрощенные схемки того, как Symfony и Yii2 обрабатывают запрос. Разумеется, после этого возникло естественное желание сравнить два фреймворка в этом аспекте.
Концептуально то, как эти (да, скорее всего, и остальные тоже) фреймворки обрабатывают запрос, очень похоже. Есть класс приложения (в Symfony -
Kernel, в Yii2 - Application), классы Response и Request, встроенные события, выбрасываемые по ходу прохождения цикла обработки запроса, и механизм резолвинга контроллеров.Но нам, конечно же, интереснее различия:
☘️ Symfony предоставляет гораздо больше встроенных событий. что позволяет более тонко вклиниваться в различные этапы прохождения цикла.
☘️ Симфонийский
Response отправляется на вывод php скрипта довольно поздно, что позволяет подменить или отредактировать его в самых разных ситуациях до, во время, и после обработки контроллера.☘️ В Yii2
Response (как и Request) является компонентом фреймворка, а значит, доступен глобально в любой точке приложения, что, в свою очередь также позволяет подменять эти объекты на разных стадиях обработки запроса.☘️ Symfony оснащен гораздо более мощными и гибкими механизмами controller и argument резолвинга, что открывает обширные возможности, многие из которых в последних версиях стали доступны из коробки (см., например, здесь аннотации, начинающиеся с "Map").
☘️ Симфонийский роутинг состоит из большого количества классов и работает за счет тех же встроенных событий, которыми пользуемся мы сами, что позволяет проще и гибче его при нужде дорабатывать (согласен, нужда такая возникает редко, но у меня возникла
В целом, погружаясь в то, как оба фреймворка устроены в своей основной части - цикла обработки HTTP запроса, я пришел к неожиданному для себя выводу.
В части тонкой настройки роутинга, резолвинга контроллера и аргументов, а также вмешательства в цикл обработки запроса на разных этапах, с помощью Yii2 можно делать практически все тоже самое, что и с помощью Symfony.
Только во-первых, ваш код будет выглядеть гораздо более кандово из-за обращения к глобальным объектам и малого количества мест, куда вы этот код можете вставить. Вы, например, тупо будете вынуждены писать простыню в каком-нибудь
afterAction() вашего BaseController, потому что другого места особо-то и нет (то есть, одно место на все случаи жизни = много кода с ифчиками для разных ситуаций).Ну а во-вторых, вы потратите гораздо больше усилий по сравнению с Symfony, т. к. в Symfony многие вещи тупо есть из коробки и этот фреймворк гораздо лучше задокументирован. Для доработки Yii2 вы не только напишите больше кода но и прочитаете очень много кода самого фреймворка, т. к. другого источника информации у вас просто не будет.
#Symfony #Yii2 #фреймворки
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Несколько дней назад заметил, что некоторые из моих постов набрали больше просмотров, чем у меня есть подписчиков. Подумал, коллеги-программисты делятся друг с другом моими материалами. Испытал гордость.
Сегодня узнал, что это дочка похвасталась в классе, что папа ведет телеграм-канал, и ее подруги нашли меня поиском и прочитали мои посты про инкапсуляцию и принцип подстановки Барбары Лисков. Испытал еще большую гордость.
Сегодня узнал, что это дочка похвасталась в классе, что папа ведет телеграм-канал, и ее подруги нашли меня поиском и прочитали мои посты про инкапсуляцию и принцип подстановки Барбары Лисков. Испытал еще большую гордость.
🔥13💅1
Вот такую настольную игру купил сегодня спонтанно по случаю холодной погоды 🥶 и желания остаться на выходных дома. Пусть рисунок печной трубы на обложке вас не смущает, игра вполне приличная .
Нужно бродить по дому и территории вокруг него, открывая клетки, каждая из которых таит полезный предмет или монстра. Цель игры - выжить, найти ключи от машины и канистру с бензином и дойти до этой самой машины. Игра интересна тем, что игроки, чей персонаж был убит, продолжают игру, управляя монстрами.
Мы играли всей семьей. К концу игры в живых остался только младший с кучей жизней. Увешанный гранатами и стволами 🔫, он почти добрался до машины, но мы втроем зажали его монстрами.
У жены, взявшей под управление босса монстров, так и не поднялась рука на ребенка. Старшая дочь, убитая в самом начале игры, увлеченно гонялась за братом по всему полю, обещая загрызть на смерть, но так и не догнала. И именно мне в решающий момент выпало достаточное количество ходов. С каменным сердцем недрогнувшей рукой я убил собственного сына💀 .
В общем, рекомендую. На один вечерок, когда на улице непогода, или выключили свет, очень даже ничего.
#отдых_от_работы
Нужно бродить по дому и территории вокруг него, открывая клетки, каждая из которых таит полезный предмет или монстра. Цель игры - выжить, найти ключи от машины и канистру с бензином и дойти до этой самой машины. Игра интересна тем, что игроки, чей персонаж был убит, продолжают игру, управляя монстрами.
Мы играли всей семьей. К концу игры в живых остался только младший с кучей жизней. Увешанный гранатами и стволами 🔫, он почти добрался до машины, но мы втроем зажали его монстрами.
У жены, взявшей под управление босса монстров, так и не поднялась рука на ребенка. Старшая дочь, убитая в самом начале игры, увлеченно гонялась за братом по всему полю, обещая загрызть на смерть, но так и не догнала. И именно мне в решающий момент выпало достаточное количество ходов. С каменным сердцем недрогнувшей рукой я убил собственного сына
В общем, рекомендую. На один вечерок, когда на улице непогода, или выключили свет, очень даже ничего.
#отдых_от_работы
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2😁1
Практическая польза CQRS
Публикую еще один кусок, который решил вырезать из своего готовящегося к публикации лонгрида.
Представьте, что нам нужно решить такую проблему: есть огромная масса legacy кода, написанного как попало, и база на 250+ таблиц, на которую смотрит куча классов
Разумеется, главный вопрос здесь состоит в том, как отвязаться от старого высокосвязанного кода. Для решения такой комплексной задачи применяется много инструментов, и в данном посте я остановлюсь только на одном из них.
Есть такой архитектурный подход CQRS. Если прям совсем утрировать, то он сводится к тому, что мы разделяем наши модели на модели чтения и модели записи, а связующим звеном между моделью чтения и записи выступает проекция.
Например, мы можем иметь таблицу в БД на 50 полей. Вместо того, чтобы писать один класс, отражающий все эти поля, мы можем сделать несколько моделей записи, первая из которых пишет только 15 полей, вторая пишет 30 полей, часть из которых может пересекаться с первой моделью, и так далее.
То же самое касается и моделей чтения. Вместо чтения всех 50 полей мы можем создавать более компактные представления (модели чтения) на 5, 20 и так далее полей в зависимости от решаемой задачи.
Применительно к нашей проблеме этот подход работает так. У нас есть 250+ таблиц и куча
Так что же нам остается? Мы можем при написании нового кода все-таки создавать новые модели, но воспринимать их как проекции из CQRS. Если у нас есть какой-нибудь старый
1️⃣ Поскольку новый класс будет наполняться данными из того же источника, что и старый, противоречий с данными не будет.
2️⃣ Поскольку мы воспринимаем новый класс лишь как проекцию большого объекта, созданную под конкретную задачу, это освобождает нас от обязанности переписывать всю модель. В то же время, ничто не мешает по мере выполнения новых задач наращивать эту проекцию вплоть до такого состояния, что она полностью воспроизведет старый объект.
Разумеется, при таком подходе мы делаем проекцию лишь данных, а вопрос, как быть с поведением, остается. К сожалению, формат телеграм-поста не поощряет длинные тексты, и я вынужден оставить за скобками (а точнее, на будущие посты) вопрос, как реализовывать поведение доменных сущностей в ситуации, когда мы не хотим больше дописывать legacy код, но обязаны к нему обращаться при написании нового функционала.
Публикую еще один кусок, который решил вырезать из своего готовящегося к публикации лонгрида.
Представьте, что нам нужно решить такую проблему: есть огромная масса legacy кода, написанного как попало, и база на 250+ таблиц, на которую смотрит куча классов
ActiveRecord. Далее произошла смена команды разработки с аутсорсной на продуктовую, и новая команда хочет писать новый код с применением слоистой архитектуры, ООП и SOLID.Разумеется, главный вопрос здесь состоит в том, как отвязаться от старого высокосвязанного кода. Для решения такой комплексной задачи применяется много инструментов, и в данном посте я остановлюсь только на одном из них.
Есть такой архитектурный подход CQRS. Если прям совсем утрировать, то он сводится к тому, что мы разделяем наши модели на модели чтения и модели записи, а связующим звеном между моделью чтения и записи выступает проекция.
Например, мы можем иметь таблицу в БД на 50 полей. Вместо того, чтобы писать один класс, отражающий все эти поля, мы можем сделать несколько моделей записи, первая из которых пишет только 15 полей, вторая пишет 30 полей, часть из которых может пересекаться с первой моделью, и так далее.
То же самое касается и моделей чтения. Вместо чтения всех 50 полей мы можем создавать более компактные представления (модели чтения) на 5, 20 и так далее полей в зависимости от решаемой задачи.
Применительно к нашей проблеме этот подход работает так. У нас есть 250+ таблиц и куча
ActiveRecord, которые кроме чтения данных из базы умеют и в бизнес-логику и черт-те знает что еще. Мы не можем опираться на эти модели при написании нового кода, поскольку в этом случае наш новый код по качеству очень быстро станет похож на старый. И мы не можем просто брать и переписывать старые модели даже по чуть-чуть из-за огромной связанности кода. Также мы не можем переписать все модели с нуля из-за огромного объема работы.Так что же нам остается? Мы можем при написании нового кода все-таки создавать новые модели, но воспринимать их как проекции из CQRS. Если у нас есть какой-нибудь старый
ActiveRecord под названием Schedule на 20 полей, а для решения текущей задачи нам требуется всего 5 полей, то мы можем создать новый класс Schedule на эти самые 5 полей. Что мы получим:Разумеется, при таком подходе мы делаем проекцию лишь данных, а вопрос, как быть с поведением, остается. К сожалению, формат телеграм-поста не поощряет длинные тексты, и я вынужден оставить за скобками (а точнее, на будущие посты) вопрос, как реализовывать поведение доменных сущностей в ситуации, когда мы не хотим больше дописывать legacy код, но обязаны к нему обращаться при написании нового функционала.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Вот и опубликовал, наконец, свой первый лонгрид о том, как решал задачу по объединению фреймворков Symfony и Yii2 в монолите с высокосвязанным кодом.
Код описываемого решения можно посмотреть здесь: https://github.com/slayervc/from-yii2-to-symfony
🪶 Публикация на vc.ru
🪶 Публикация на Хабре
#Лонгриды
Код описываемого решения можно посмотреть здесь: https://github.com/slayervc/from-yii2-to-symfony
🪶 Публикация на vc.ru
🪶 Публикация на Хабре
#Лонгриды
Alexander’s Substack
Переход на Symfony в заскорузлом Yii2 монолите: подробный разбор
Полгода назад мне посчастливилось решать интересную и нетипичную задачу по затаскиванию Symfony в Yii2 монолит.
👍3
