From 56e3c6d1151f587c52e1cdf6f0e67195d6e69577 Mon Sep 17 00:00:00 2001 From: Alexandr Chernyaev Date: Tue, 10 Sep 2024 01:16:13 +0300 Subject: [PATCH] Init `Action` page for library --- resources/views/library/actions.blade.php | 29 +++++++++ routes/web.php | 1 + storage/library/actions/basics.md | 21 +++++++ storage/library/actions/conventions.md | 62 ++++++++++++++++++ storage/library/actions/focus.md | 77 +++++++++++++++++++++++ storage/library/actions/tests.md | 7 +++ 6 files changed, 197 insertions(+) create mode 100644 resources/views/library/actions.blade.php create mode 100755 storage/library/actions/basics.md create mode 100644 storage/library/actions/conventions.md create mode 100755 storage/library/actions/focus.md create mode 100644 storage/library/actions/tests.md diff --git a/resources/views/library/actions.blade.php b/resources/views/library/actions.blade.php new file mode 100644 index 00000000..96488b41 --- /dev/null +++ b/resources/views/library/actions.blade.php @@ -0,0 +1,29 @@ +@extends('layout') +@section('title', 'Один класс — одна задача') +@section('description', 'Каждый класс в приложении должен отвечать только за одну конкретную задачу или функциональность.') +@section('content') + + + Чистота и порядок + Один класс — одна задача + + Каждый класс в приложении должен отвечать только за одну конкретную задачу или функциональность. + + + + + + + @php + $sections = collect([ + 'basics', + 'focus', + 'conventions', + 'tests', + ]) + ->map(fn ($file) => \Illuminate\Support\Str::of($file)->start('actions/')) + ->map(fn ($file) => new \App\Library($file)); + @endphp + + @include('particles.library-section', ['sections' => $sections]) +@endsection diff --git a/routes/web.php b/routes/web.php index 8454a903..c45274cc 100644 --- a/routes/web.php +++ b/routes/web.php @@ -63,6 +63,7 @@ Route::view('/library/how-to-ask', 'library.how-to-ask')->name('library.how-to-ask'); Route::view('/library/collection', 'library.collection')->name('library.collection'); Route::view('/library/solid', 'library.solid')->name('library.solid'); +Route::view('/library/actions', 'library.actions')->name('library.actions'); /* |-------------------------------------------------------------------------- | Open Quiz diff --git a/storage/library/actions/basics.md b/storage/library/actions/basics.md new file mode 100755 index 00000000..3cf44344 --- /dev/null +++ b/storage/library/actions/basics.md @@ -0,0 +1,21 @@ +--- +title: "Основы" +description: "Что такое принцип 'Один класс — одна задача'?" +--- + +Принцип «Один класс — одна задача» (One Class, One Task) предполагает, что каждый класс в приложении должен отвечать +только за одну конкретную задачу или функциональность. Это упрощает структуру кода, делает его более понятным и легким +для поддержки. В контексте Laravel этот подход помогает организовать бизнес-логику в виде отдельных классов, которые +выполняют конкретные действия, что позволяет избежать перегруженности классов и улучшает читаемость кода. + +Преимущества использования принципа «Один класс — одна задача»: + +- **Читаемость кода**: каждый класс отвечает только за одну задачу, что упрощает понимание его назначения и логики. +- **Поддерживаемость**: изменение и тестирование классов становится проще, так как каждый класс содержит только одну + задачу. +- **Изоляция логики**: каждый класс действия изолирован от других частей приложения, что упрощает его тестирование и + поддержку. +- **Повторное использование**: классы действий могут быть повторно использованы в разных частях приложения, что + упрощает разработку и поддержку кода. +- **Улучшение архитектуры**: применение принципа «Один класс — одна задача» помогает улучшить архитектуру вашего + приложения, сделав его более гибким и масштабируемым. diff --git a/storage/library/actions/conventions.md b/storage/library/actions/conventions.md new file mode 100644 index 00000000..3f3a4f0c --- /dev/null +++ b/storage/library/actions/conventions.md @@ -0,0 +1,62 @@ +--- +title: "Рекомендуемые соглашения" +description: "Помогут вам оставаться последовательными при организации вашего приложения" +--- + +**Начните с глагола** + +Назовите свои классы действий как небольшие явные предложения, начинающиеся с глагола. Например, действие, которое +«отправляет электронное письмо пользователю для сброса пароля», можно назвать `SendResetPasswordEmail`. Такой подход +делает названия классов самодокументированными и легко понятными, что улучшает читабельность кода. + +**Используйте папку `Actions`** + +Создайте папку `app/Actions` и сгруппируйте свои действия внутри неё по темам. Это помогает поддерживать структуру +вашего кода организованной и логичной. Например: + +```php +app/ +├── Actions/ +│ ├── Authentication/ +│ │ ├── LoginUser.php +│ │ ├── RegisterUser.php +│ │ ├── ResetUserPassword.php +│ │ └── SendResetPasswordEmail.php +│ ├── Leads/ +│ │ ├── BulkRemoveLead.php +│ │ ├── CreateNewLead.php +│ │ ├── GetLeadDetails.php +│ │ ├── MarkLeadAsCustomer.php +│ │ ├── MarkLeadAsLost.php +│ │ ├── RemoveLead.php +│ │ ├── SearchLeadsForUser.php +│ │ └── UpdateLeadDetails.php +│ └── Settings/ +│ ├── GetUserSettings.php +│ ├── UpdateUserAvatar.php +│ ├── UpdateUserDetails.php +│ ├── UpdateUserPassword.php +│ └── DeleteUserAccount.php +├── Models/ +└── ... +``` + +В качестве альтернативы, если ваше приложение уже разделено на темы — или модули — вы можете создать папку `Actions` под +каждым из этих модулей. Например: + +```php +app/ +├── Authentication/ +│ ├── Actions/ +│ ├── Models/ +│ └── ... +├── Leads/ +│ ├── Actions/ +│ ├── Models/ +│ └── ... +└── Settings/ + ├── Actions/ + └── ... +``` + +Такая организация помогает вам поддерживать порядок в коде и упрощает его навигацию. diff --git a/storage/library/actions/focus.md b/storage/library/actions/focus.md new file mode 100755 index 00000000..5b760b15 --- /dev/null +++ b/storage/library/actions/focus.md @@ -0,0 +1,77 @@ +--- +title: "Фокус на работе приложения" +description: "Что такое принцип 'Один класс — одна задача'?" +--- + +Использование `Actions` позволяет сосредоточиться на бизнес-логике приложения, а не на технических деталях. +Классы `Action` выполняют конкретные задачи и изолируют их от других частей приложения, что упрощает понимание кода и +его поддержку. Логика, связанная с выполнением одной задачи, собирается в одном месте, что облегчает её изменение и тестирование. + + +```php +class GenerateReservationCode +{ + const UNAMBIGUOUS_ALPHABET = 'BCDFGHJLMNPRSTVWXYZ2456789'; + + public function __invoke(int $characters = 7): string + { + do { + $code = $this->generateCode($characters); + } while (Reservation::where('code', $code)->exists()); + + return $code; + } + + protected function generateCode(int $characters): string + { + return substr(str_shuffle(str_repeat(static::UNAMBIGUOUS_ALPHABET, $characters)), 0, $characters); + } +} +``` + +Это позволит вам вызывать объект класса, как если бы он был функцией. Например: +```php +$generator = new GenerateReservationCode(); +$reservationCode = $generator(8); // Генерация кода длиной 8 символов +``` + + +В это системе Laravel есть прекрасный пакет `Laravel Actions` — это пакет, который предлагает новый способ организации +логики вашего Laravel-приложения, сосредоточив внимание на действиях, которые выполняет ваше приложение. Вместо создания +контроллеров, джобов, слушателей и других элементов, этот пакет позволяет создавать PHP-классы, каждый из которых +выполняет одну конкретную задачу. Эти классы можно запускать как угодно: из контроллеров, консольных команд, событий и +так далее. + +```php +class GenerateReservationCode +{ + use AsAction; + + const UNAMBIGUOUS_ALPHABET = 'BCDFGHJLMNPRSTVWXYZ2456789'; + + public function handle(int $characters = 7): string + { + do { + $code = $this->generateCode($characters); + } while(Reservation::where('code', $code)->exists()); + + return $code; + } + + protected function generateCode(int $characters): string + { + return substr(str_shuffle(str_repeat(static::UNAMBIGUOUS_ALPHABET, $characters)), 0, $characters); + } +} +``` + +и вызывать его так: +```php +GenerateReservationCode::run() // Генерация кода длиной 7 символов +``` + +> **Примечание** Вы можете узнать больше об удобстве использование действий с пакетом `Laravel Actions` на его [официальном сайте](https://laravelactions.com/). + +Но вам не обязательно использовать пакет, чтобы следовать принципу «Один класс — одна задача». Вы можете создавать свои +собственные классы действий, используя стандартные средства Laravel/PHP. Важно помнить, что главная цель — разделить логику +вашего приложения на небольшие, легко понимаемые и поддерживаемые части. diff --git a/storage/library/actions/tests.md b/storage/library/actions/tests.md new file mode 100644 index 00000000..bca4089a --- /dev/null +++ b/storage/library/actions/tests.md @@ -0,0 +1,7 @@ +--- +title: "Тестирование" +description: "Что такое принцип 'Один класс — одна задача'?" +--- + +Поскольку каждый `Action` отвечает за одну задачу, его тестирование становится более простым и эффективным. +Вы можете изолировать и протестировать каждое действие отдельно, что упрощает написание и выполнение тестов.