Получи случайную криптовалюту за регистрацию!

Beer::PHP 🍺

Логотип телеграм канала @beerphp — Beer::PHP 🍺 B
Логотип телеграм канала @beerphp — Beer::PHP 🍺
Адрес канала: @beerphp
Категории: Технологии , Образование
Язык: Русский
Количество подписчиков: 3.05K
Описание канала:

Здесь публикуются короткие заметки о PHP, Linux, Unit Testing, DB, OOP, etc., выдержки из статей, книг, видео, курсов и других материалов.
Теперь тебе больше не нужно перерывать тонны информации ;)
@genkovich — написать автору канала.

Рейтинги и Отзывы

3.33

3 отзыва

Оценить канал beerphp и оставить отзыв — могут только зарегестрированные пользователи. Все отзывы проходят модерацию.

5 звезд

1

4 звезд

0

3 звезд

1

2 звезд

1

1 звезд

0


Последние сообщения 5

2021-07-21 11:05:33
WordPress Digest

Ребзя, среди нас не малая часть ребят, которые работают с WordPress, в котором я, честно признаться, совсем не разбираюсь. Потому спешу порекомендовать вам канал WordPress Digest, где публикуется куча свежих материалов из мира WordPress:

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

Короче, очень рекомендую, канал точно поможет быть всегда в тренде ;)

#wordpress #php #wpdigest
1.6K viewsKirill Sulimovsky, 08:05
Открыть/Комментировать
2021-07-19 11:38:53 Идемпотентные операции

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

Например умножение на 0 и на 1 — идемпотентная операция:

x * 1 == x * 1 * 1
x * 0 == x * 0 * 0

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

x := 4

Но при чем тут Веб-приложения?

Migrations

Представьте ситуацию: Ваше приложение растёт и перед вами поставили задачу разделить сущность/таблицу Users на данные для доступа Access (напр. login, password, token) и профиля Profile (name, surname, address и т.д.).

Вам нужно написать миграцию, которая создаст 2 новые таблицы в них скопирует необходимые данные пользователей, после чего исходную таблицу переименует в deprecated. Но что если посреди копирования миграция крашнется? Что произойдёт если запустить миграцию еще раз?

Чтобы не беспокоиться об этом — позаботьтесь об идемпотентности ваших миграций. Если ваша БД поддерживает транзакции этих операций — не забудьте их использовать. Если у ваc MySQL, где для операций DDL (CREATE, ALTER, DROP) нет возможности сделать транзакцию, позаботьтесь о том, чтобы использовать CREATE TABLE IF NOT EXISTS, а данные для копирования не просто выбирались полностью (SELECT * FROM USERS), а брались только те, у которых еще нет ряда в Profiles.

Message Queues

Другой пример: Вам надо отправить письма определенной группе пользователей, но посреди отправки вы понимаете, что что-то пошло не так, у вас проблемы с SMTP и ваши письма перестали отправляться. После того как работа SMTP была восстановлена — вам нужно продолжить отправку. Но что будет, если вы запустите команду второй раз?

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

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

Позже рассмотрим идемпотентность HTTP-методов

#junior #php #architecture #source
1.4K viewsКирилл Сулимовский, edited  08:38
Открыть/Комментировать
2021-07-13 09:35:00 PSR-4 и Composer autoload

А пока полным ходом идёт заполнение опросника, спешу продолжить тему автозагрузчика. Кстати, реально спасибо всем, кто заполнил опросник. Я не ожидал, что будет столько отклика и полезных ответов. Позже обязательно сведу все результаты и поделюсь с вами, а пока перейдем к материалу =)

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

Начало было положено в 2010 с PSR-0 (Autoloading Standard), который ни много ни мало стал первым шагом к объединению фреймворков, а также безболезненной возможности установки пакетов в ваше приложение (напр. composer в 2012). Однако уже в 2014 ему на смену пришел PSR-4, а PSR-0 был объявлен deprecated.

Согласно PSR-4 мы должны называть файл, взяв название класса и добавив к нему расширение .php, при этом регистр названия класса и файла должны полностью совпадать.

Наш файл должен лежать в каталоге, путь которого совпадает с частями нашего namespace. Например MyModule\Sub\SomeClass будет лежать по пути MyModule/Sub/SomeClass.php.

Обычно в качестве неймспейса верхнего уровня выбирают название приложения / пакета, иногда вместе с названием компании или ником разработчика (например в фреймворке Symfony все классы лежат внутри неймспейса Symfony). По мере роста пакета добавляются дополнительные уровни вложенности и получится что-то вроде \Symfony\Component\HttpFoundation\Request.

Composer autoload

Но, чтобы не писать свой автозагрузчик руками - можно использовать composer.json. Для этого в нём следует создать директиву autoload, во внутри которого прописать "psr-4" и правила, по которым следует сопоставить корневой неймспейс с корневой папкой проекта. Это будет выглядеть так.

Нужно обратить внимание, что:

1. Важно писать psr-4 именно в нижнем регистре.
2. В качестве разделителя использовать двойной бекслеш \\ — это особенность json, первый он воспринимает как экранирование.
3. В конце неймспейса также следует указывать \\

Есть возможность поиска определенного неймспейса сразу в нескольких директориях, для этого их нужно указать как массив.
Также есть возможность указать fallback каталог, в котором будет искаться любое пространство имён, для этого оставляем неймспейс пустым.

Все ссылки будут объеденены во время install / update / dump-autoload в один массив, который композер положит в сгенерированный файл vendor/composer/autoload_psr4.php и пробросит путь к нему в основной файл автозагрузки vendor/autoload.php (там могут быть подключены и другие файлы типа psr-0, classmap и т.д.)

Вам остается только подключить файл в свой проект с помощью require_once __DIR__ . '/vendor/autoload.php'; и можно избавить себя от необходимости писать собственный автозагрузчик.

Также напоминаю, что обсудить любую тему и прокомментировать пост можно в нашем чатике, так что присоединяйся

#php #psr #autoload #composer #junior #source
1.7K viewsКирилл Сулимовский, 06:35
Открыть/Комментировать
2021-07-10 09:20:00
Опросник

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

Внутри всего 5 вопросов, которые могут помочь мне лучше понять, что за подписчики тут тусуются, а следовательно лучше адаптировать материал под вас :)

Четыре вопроса обязательных, но там достаточно быстро тыкнуть мышкой. Последний — для творческого полёта мыслей и на него необязательно отвечать, но я буду очень благодарен тем людям, которые там напишут хотя-бы 1-2 предложения.

Короче, залетай, заполняй, помоги автору делать топовый контент!
1.4K viewsКирилл Сулимовский, 06:20
Открыть/Комментировать
2021-07-08 09:35:00 Autoload (автозагрузчик)

На всякий случай начнём с основ, т.к. не все знают, как это работает.

Все мы ежедневно создаём классы, которые помещаем в отдельные файлы. Внутри класса мы можем использовать другие классы. И для того, чтобы наш интерпретатор знал о используемом классе, мы должны подключить (require) файл, в котором описан используемый класс. Пока вроде просто. Когда число классов увеличивается, писать все эти require_once становится неудобно. Но выход есть!

PHP позволяет тебе зарегистрировать автозагрузчик

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

Если ни один автозагрузчик не подключит файл с вызываемым классом, то будет выведена ошибка об обращении к несуществующему классу. Вот примеры, когда автозагрузчик будет вызван, а когда нет.

Несколько правил, если нужно написать автозагрузчик самостоятельно:

Aвтозагрузчик не должен выдавать ошибку, если он не может найти файл с классом — может быть, этот класс подгрузит следующий автозагрузчик.
Нужно писать автозагрузчик только для своих файлов и не использовать файлы сторонних библиотек.
Не нужно изобретать свои правила сопоставления имен классов и файлов, лучше всего использовать общепринятый стандарт PSR-4 (о нем поговорим позже).

#php #autoload #junior #source
1.3K viewsКирилл Сулимовский, 06:35
Открыть/Комментировать
2021-07-05 09:35:00 Validation (part 3). Валидация пользовательских данных

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

Это круто работает если нам надо прервать какую-то операцию, но не слишком удобно, если мы хотим показать пользователю ошибки, особенно если их несколько (например при заполнении формы).

Первое, что приходит в голову, это добавить валидацию в контроллер. При этом у нас уже есть готовые Value Object's, которые используются и доменном слое! Что нам мешает провалидировать Email? Мы точно будем знать, что изменив правила валидации в одном месте, они изменятся везде.

С одной стороны мы убрали дублирование, с другой нет. Мы начинаем переносить всю бизнес логику в контроллер и подсознание говорит, что мы делаем что-то не так. И не надо так делать!

Нам надо просто убедиться, что пользователь не ошибся при вводе данных

Мы должны сделать всё от нас зависящее, чтобы помочь пользователю это сделать. Пока пользователь вводит свои данные — вы уже можете выдать предупреждение, что email выглядит некорректно.

Такую валидацию вы можете доверить фронтовой части вашего приложения (да-да, вообще убрать из контроллера ), если работаете c Vue, React, etc..., или доверить встроенным валидаторам фреймворка, если используете twig, blade, etc... Главное помните, что ваша задача помочь пользователю, а не ввести его в ступор своими правилами.

Но есть более сложные бизнес требования

Например во время заказа, вам нужно проверить, что на складе всё еще есть хотя-бы одна единица товара, которую заказывает пользователь (ведь пока он чехлился, кто-то другой мог забрать последнюю единицу первее чем он нажал кнопку). Такие проверки должны выполняться в application слое приложения и отлавливаться через Exception'ы.

Исключения обязательно нужно контролировать

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

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

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

Чтобы не дублировать подобный код в каждом контроллере — настройте перехватчик в production среде на уровне вашего фреймворка (для development окружения их "глушить" не нужно).

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

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

#php #oop #validation #middle #source
1.1K viewsКирилл Сулимовский, 06:35
Открыть/Комментировать
2021-07-03 09:39:36 Чатик Beer::PHP

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

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

К сожалению в связи с дефицитом времени практически нет возможности его модерировать. Однако, я нашел выход :)

Вступить в чат можно за символическую (часто просто неподъемную для программиста) подписку 1$ в месяц. Оплата внедрена с целью нажиться на подписч... кхм.. максимально отфильтровать людей и оставить только действительно заинтересованных.

Если что-то не получается — вот подробная инструкция.

Также выкатил короткий свод правил чатика.

Вступай в чатик, общайся с коллегами и делись своим опытом, мы тебя ждём!
1.2K viewsКирилл Сулимовский, 06:39
Открыть/Комментировать
2021-07-01 09:35:00 Repositories (Репозитории)

Каждая сущность (Entity) должна иметь репозиторий. Именно он выступает неким "адаптером" между внешним хранилищем (например БД) и нашим доменным слоем. Но вот проблема.

Если мы будем вызывать реализацию репозитория внутри нашего Application слоя, то нарушим правило разделения приложения, которое гласит, что внешние слои могут зависеть от внутренних, а не наоборот (Infrastructure -> Application -> Domain).

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

Почему интерфейс репозитория принадлежит доменному слою, а сам репозиторий нет?

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

Держите код Repository в чистоте

Очень частое упрощение — весь код, который работает с базой выносим в репозиторий. В итоге получаем, что в репозитории у нас 2 метода, которые мы используем постоянно (например getById() и save()) и 5 методов, которые у нас узконаправлены (например используются для каких-то частных выборок типа отчетов). Здесь вообще стоит немного углубиться в тему Read Model, но пока обойдемся более простой идеей.

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

Ваши view не всегда нужны все данные ваших Entity / Агрегатов.
Вам не придётся делать ненужные getters в вашей основной Entity.
Ваши Entity не должны содержать весь список данных "на всякий случай", со всеми ссылками на другие сущности (например Customer со всеми заказами, со всеми данными этих заказов).
В конце концов вы можете разделить источники данных, в то время как Entity могут работать с реляционной, то View могут быть получены из того же Redis, для ускорения получения данных (вопрос консистентности тоже рассмотрим отдельно).

#php #oop #repository #middle #source
1.4K viewsКирилл Сулимовский, 06:35
Открыть/Комментировать
2021-06-29 09:20:00
Сегодня в IT-среде никого не удивишь историей, в которой какой-то разработчик стал джуном в рекордно короткие сроки. А дальше — всё сложнее. Количество предложений уменьшается, риски и нагрузка возрастают, а когда-то бурное русло карьерного и профессионального роста забивается повседневной рутиной.

Чтобы разработчики могли развиваться, совершенствовать навыки и повышать ликвидность на рынке труда, образовательная платформа GeekBrains открыла новое направление для middle-специалистов — профессию архитектора информационных систем.

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

Посмотреть программу курса и получить бесплатную карьерную консультацию можно здесь:
https://gb.ru/link/S-6_Wz
1.4K viewsКирилл Сулимовский, 06:20
Открыть/Комментировать
2021-06-24 09:35:00 Validation (part 2). Всё еще внутри доменного слоя приложения

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

Объект должен гарантировать что его данные должны быть полными, действительными и консистентными.

Данные неполные (Incomplete) , если для выполнения простых задач отсутствует их логический кусок. Например для Money, если бы у нас была сумма, но отсутствовала валюта. В таком случае мы бы не смогли корректно производить сложение. Более подробно про эту проблему я писал в этом посте.

Недействительные данные (Invalid) — которые имеют правильный тип, но обладают не всеми нужными качествами. Будет проще на примере. Возьмем тот же Money, на данный момент в конструктор мы можем передать любую строку, которая будет обозначать валюту, а это значит, что пользователь может создать объект с несуществующей валютой или той, которая никак не относится к нашему бизнесу (например вы не работает с криптой, а вам передали биткоин). Для выхода из сложившейся ситуации можно (надеемся в php 8.1 уже будет из коробки) использовать Enum (пример для более ранних версий), чтобы убедиться, в корректности переданного значения.

Неконсистентные (Inconsistent) — когда два и более куска данных противоречат друг другу. Например заказ нельзя перевести в статус "доставляется", если нет адреса доставки. То есть помимо текущего состояния объект также несет ответственность за переход между состояниями. Например если заказ оплачен и доставлен — его нельзя просто так "отменить" (подробнее в этом посте).

Связь с другой сущностью по ID

Если в качестве связи с другой сущностью в метод или в конструктор мы передаём ID, то мы наверняка не можем быть уверенны, что Entity с таким ID существует в рамках нашей системы, ведь на входе мы можем убедиться лишь в том, что ID соответствует определенному шаблону (например UUID).

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

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

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

Вроде по доменной всё. На очереди пользовательская валидация.

#middle #php #oop #source
1.4K viewsКирилл Сулимовский, 06:35
Открыть/Комментировать