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

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


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

2021-06-21 14:05:06 Бинарный поиск и "О-большое"

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

Представьте, что ваш друг загадал число, от 1 до 100, а вам нужно его отгадать. При каждой попытке друг будет давать вам один из трёх ответов "Мало" , "Много", "В точку!". Если перебирать все варианты подряд (1, 2, 3, 4... то есть прямым поиском), то вы рискуете использовать 100 попыток, при самом плохом случае.

Но что если вы сразу ударите в середину и назовете число 50? "Мало", и вы сразу отсекли половину вариантов. Затем "75" — "Много", и еще половина вариантов ушла. Именно так и работает бинарный поиск.

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

Время выполнения и "О-большое"

Возможно вы забыли что такое логарифм, но точно помните, что такое возведение в степень. Так вот, запись log(2) 8 означает, в какую степень нужно возвести 2, чтобы получить 8, итак log(2) 8 = 3.

"О-большое" описывает, насколько быстро работает алгоритм. Простой поиск должен проверить каждый элемент. Для списка из 4 миллиардов (или любое другое n) чисел потребуется до 4 миллиар­дов попыток. Таким образом, максимальное количество попыток совпадает с размером списка. Такое время выполнения называется линейным и обозначается O(n).

С бинарным поиском дело обстоит иначе. Для списка из 4 миллиардов элементов, потребуется не более более 32 попыток. Впечатляет, да? Бинарный поиск выполняется за логарифмическое время и его сложность описывается как O(log n).

Если это время, то где же секунды?

А их здесь нет. "О-большое" не сообщает время в секундах, а позволяет сравнить количе­ство операций. Оно указывает, насколько быстро возрастает время выполнения алгоритма. А время в секундах уже будет зависеть от размера исходных данных, вычислительных мощностей и т.д.

"О-большое" определяет время выполнения в худшем случае.

То
есть если ваш друг, загадал число "1", то при прямом поиске вы угадаете его моментально, так как оно стоит на первом месте O(1). Но простой поиск всё равно выполняется за время O(n), фактически это утверждение о том, что в худшем случае придется перебрать все числа.

Надеюсь стало немного понятнее и теперь, когда в разных книгах или статьях вы встретите записи типа O(n), O(n!), O(n log n) вы не будете впадать в ступор, а будете осознанно понимать, что автор хочет до вас донести.

#junior #algorithm #source
1.3K viewsКирилл Сулимовский, 11:05
Открыть/Комментировать
2021-06-15 10:30:01 Validation (part 1). Валидация внутри доменного слоя приложения

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

Валидация сущности (Entity).

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

Не нужно создавать для Entity сервисы валидации. Вам придется делать бесконечные и ненужные геттеры внутри Entity, следить за тем что нужно обновить сервис в случае изменения самой сущности и не забывать его вызвать каждый раз при её создании.

Конструктор должен принимать все обязательные для существования сущности параметры и валидировать их перед тем, как присвоить значение свойству. Все необязательные параметры могут быть заданы значениями по-умолчанию и/или быть присвоенными отдельными методами, в которых также следует добавлять проверки перед присваиванием. В случае если нас что-то не устраивает — кидаем Exception. Пример

Но ведь мы же не будем показывать пользователям исключения?

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

Используйте Value Objects для проверки отдельных значений.

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

Из предыдущего примера мы можем отдельно вынести AccountNumber, переместив в него всю валидацию, отдельно выделить Value Object Money, который также может взять на себя операцию сложения для логики пополнения счета. Тогда наша Entity будет иметь примерно следующий вид. Так как в основной сущности мы уже работаем с валидными Value Objects, то нет необходимости проверять что-то дополнительно внутри сущности, мы и так всё затайпхинтили.

Тема очень обширная, так что ставь если интересна информация про валидацию пользовательских данных, взаимодействие с БД, а также про Incomplete, Invalid и Inconsistent объекты.

#php #oop #junior #source
1.2K viewsКирилл Сулимовский, 07:30
Открыть/Комментировать
2021-06-12 10:30:00 Data Transfer Object (DTO) и как его готовить?

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

Зачем он нужен?

Для упрощения рассмотрим всё тот-же кейс передачи данных между слоями внутри приложения.

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

Для примера рассмотрим контроллер и консольную команду внутри которых мы пытаемся вызывать уже существующий сервис (или command handler) для смены адреса доставки. И Request и Input являются частью инфраструктуры фреймворка, на которую мы не можем повлиять, при этом они имеют разный интерфейс. Плюс ко всему это делает нашу бизнес логику зависимой от той самой инфраструктуры.

Как раз здесь нам на помощь и приходит DTO, который позволит отделить слои друг от друга.

Должен ли DTO содержать валидацию?

Нет.


Внутри вообще ничего не должно быть, кроме примитивных данных. Оставьте первый этап валидации вашему фронтенду (или валидатору фреймворка), а второй уже самому доменному слою (Value Object, Entity и т.д.). То есть DTO не должен выбрасывать никаких исключений. Всё что вам нужно, это привести данные к правильным типам, присвоить полям их значения или null (если в вашем случае это допустимо). Это оставит знания о том, как работать с объектами домена внутри ядра приложения, а не в коде инфраструктуры.

Называйте ваши DTO по их намерениям (действиям)

Если данные будут использоваться для изменения адреса доставки заказа (как в примерах выше), назовите его ChangeDeliveryAddress (а не DeliveryAddressDTO). Во первых это уменьшит путаницу, т.к. разные действия, чаще всего будут иметь разный набор данных. Например DTO для создания адреса доставки может не содержать ID, а для изменения он уже обязателен.

#junior #php #dto #source
973 viewsКирилл Сулимовский, 07:30
Открыть/Комментировать
2021-06-07 09:40:09 The Everybody Poops Rule (Все какают)

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

Все какают. Но дома это делают не в каждой комнате. У вас есть специальная комната, в которой вы какаете, ставите дверь, и только там это делаете.

Да, звучит странно, но зато хорошо запоминается

Важно понимать, что этот процесс управляемый. Данное правило как раз помогает с этим жить при помощи сокрытия и инкапсуляции. Если код изолирован — не важно, что скрывается за интерфейсом. Главное, что мы гадим в определенных частях и "держим дверь закрытой".

Конечно, у подобных мест тоже следует определить стандарты. То есть нельзя совсем забить и втулить туда какой-то God Object с методами в 1000 строк, вызывающие запросы к БД в foreach. Здесь важно найти баланс. Это тоже непростая работа. Помните, положив код "за дверь" он не становится лучше, а значит учитывайте риски того, что вам придётся его переписывать.

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

• Как часто код будет использоваться?
• Как долго его можно не трогать?
• Является ли это основным доменом в вашей компании? (здесь лучше этого не делать)

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

#junior #oop #source
107 viewsКирилл Сулимовский, 06:40
Открыть/Комментировать
2021-06-05 13:00:03 Не PHP единым ;)

К сожалению наш любимый PHP подходит не для всех задач. Одной из таких является работа с Big Data. Мой коллега из Netpeak, Алексей Селезнёв, посвятил решению подобных проблем целый канал R4marketing.

Канал посвящён языку R. Специфический язык разработанный для визуализации данных, аналитики и статистикой обработки данных. На данный момент является главным конкурентом Python в области Data Science.

В канале публикуются:

- Статьи
- Видео уроки
- Вебинары и доклады с конференций
- Заметки по R
- Книги
- Бесплатные онлайн курсы
- Новости и релизы из мира R

В общем, если вам интересна область Data Science, то вы однозначно найдёте в канале много полезной информации.
768 viewsКирилл Сулимовский, 10:00
Открыть/Комментировать
2021-06-03 10:30:00 Regular Expression

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

Выберите удобный разделитель (delimiter)

Речь идет о символах, в которые мы оборачиваем наше выражение. Чаще всего в примерах используется slash "/"

/(foo|bar)/i

На самом деле для разделителя можно выбрать любой символ, например ~,!, @, #, $. Разделителями НЕ могут быть буквенно-цифровые символы (AZ, az и 0-9), многобайтовые символы (Такие как Emojis ) и обратная косая черта (\).

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

preg_match('/^https:\/\/example.com\/path/i', $uri);
// или
preg_match('~^https://example.com/path~i', $uri);

Именуйте скобочные группы (группы захвата)

Скобочными группами называется то, что находится внутри () скобок. Найденные результаты будут переданы в $matches.

$pattern = '~Price: (£|€)(\d+)~';
// или
$pattern = '~Price: (?£|€)(?\d+)~';

Именуя скобочные группы, мы сразу получаем два преимущества: это упростит чтение регулярного выражения, а также имена будут отображены в $matches;

Используйте символьные классы

Это также поможет сделать ваше выражение более читабельным. Самый распространенный класс \d - представляет собой одну цифру (эквивалентно [0-9]), при этом \D (в верхнем регистре) эквивалентно [^0-9] то есть не является цифрой. То есть использование верхнего регистра является обратным основному выражению.

\w соответствует слову (может состоять из букв, цифр и подчёркивания) A-Za-z0-9_
\s соответствует символу пробела (включая табуляцию и прерывание строки)
. соответствует любому символу

Так-же следует упомянуть, что при использовании выражений с поддержкой unicode (флаг /u), вы можете использовать еще огромное количество символьных классов \p{}. Например:

\p{Sc} — любой знак валюты
\p{P} — любой знак пунктуации
\p{L} — любая буква из любого языка

Весь перечень можно посмотреть здесь.

#junior #regexp #source
617 viewsКирилл Сулимовский, 07:30
Открыть/Комментировать
2021-05-31 11:00:50 Tell, Don't Ask (TDA)

Еще в 1997 году А. Шарп сформулировал такой принцип:

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

То, что мы принимаем решения за пределами объектов — нарушает их information hiding. В этом примере мы скрыли детали реализации. Это упростило понимание и поддержку нашего кода, а также сделало наш объект более осознанным.

Внимание, обычно в этом месте кто-то вспоминает про "анемичную модель", а кто-то про "god objects" и начинается дикий срач, так что будьте готовы, если хотите с кем-то обсудить эту тему ;)

Принципы — это не истина последней инстанции. Безусловно, мы должны держать TDA в голове, но не слепо ему следовать. Да он может привести к:

Раздутию классов и увеличения их сложности;
Увеличению coupling из-за того что у объекта много ответственности;
Нарушению SRP (single responsibility principle) в конце концов;

С другой стороны, если для регистрации User вам нужны только email и password, которые совсем не принимают участия в других процессах, то действительно ли всё должно быть в одном объекте? Или это совсем другой объект напр. Credentials?

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

#oop #middle #source
1.0K viewsКирилл Сулимовский, edited  08:00
Открыть/Комментировать
2021-05-28 11:06:13 Использование индексов в MySQL (part 2)

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

Повторяющиеся индексы могут не замедлить запросы SELECT, но вполне могут замедлить запросы на INSERT (а в некоторых случаях и UPDATE). В целом рекомендуется избегать дублирования ключей. Например если в одной таблице 2 индекса:

KEY `firstname` (`firstname`),
KEY `firstname_lastname_id` (`firstname`,`lastname`,`id`)

то firstname является дубликатом firstname_lastname_id, так как firstname является первым столбцом индекса firstname_lastname_id.

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

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

Начиная с версии 8+, MySQL поддерживает индексы по убыванию (нисходящие, DESC), что означает, что он может хранить индексы в порядке убывания. Это может пригодиться, когда у вас есть выборки где надо получать последние добавленные данные.

CREATE TABLE t (
c1 INT, c2 INT,
INDEX idx1 (c1 ASC, c2 ASC),
INDEX idx2 (c1 ASC, c2 DESC),
INDEX idx3 (c1 DESC, c2 ASC),
INDEX idx4 (c1 DESC, c2 DESC)
);

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

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

#MySQL #junior #source
592 viewsКирилл Сулимовский, 08:06
Открыть/Комментировать
2021-05-25 10:30:02 Правила по проектированию Entity (part 1)

В предыдущих статьях я уже несколько раз ссылался на понятие сущности Entity. Разные авторы (напр. Эванс, Нобак, Вернон) дают немного разные определения этого понятия, но суть сильно от этого не меняется.
Сущности — это объекты, которые хранят состояние вашего приложения. Но не "просто хранят".
И вот несколько правил, которые помогут вам проектировать такие объекты:

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

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

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

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

$order->getStatus(),
// isn't delivered
$order->setCancel()

Определите метод cancel(), который будет выполнять проверки внутри сущности и если всё согласовано — менять её состояние.

Не думайте всё время о базе данных.
Стоит оговориться, что речь идёт именно о проектировании структуры и самой сущности. Конечно, есть много случаев, когда нам нужно считаться с нашей базой (высокая конкуренция запросов, deadlocks и т.д.), но идея в том, чтобы перестроить мышление и думать об объектах, как о вещах в реальном мире, а не как о данных в таблице. Просто примите для себя, что маппинг данных в БД это отдельная задача.

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

#php #oop #junior #entity #source
677 viewsКирилл Сулимовский, 07:30
Открыть/Комментировать
2021-05-21 10:30:01 Whole value concept (Quantity pattern)

Я часто вижу, что этому концепту уделяют мало внимания при проектировании Value Objects, потому решил отдельно на нём остановиться.

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

Идея простая. Представим, что у нас есть геопозиция. Чтобы понять где именно находится точка нам нужна и широта и долгота. Поскольку сами по себе "широта" или "долгота" не имеют смысла друг без друга, значит они должны находиться в одном месте, внутри одного объекта. Другими словами не нужно создавать отдельные VO, если сами по себе они ничего не значат, а только являются составляющей другого объекта.

Другой пример. У нас есть сумма денег, которую нам нужно сложить с другой суммой. Чтобы принять решение можем ли мы сложить две amount, мы должны проверить currency. Поскольку currency напрямую влияет на логику вычислений, то оно должно находиться там-же, где и amount.

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

То есть если у нас есть данные которые влияют на логику - они должны быть частью состояния объекта где эта логика реализована. Да-да, вычисления(логика) также должны находиться внутри (например сложение/вычитание денег или вычисление расстояния в случае с гео).

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

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

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