Skip to content

Commit

Permalink
Added Actions in Library
Browse files Browse the repository at this point in the history
tabuna committed Oct 11, 2024
1 parent d0904d5 commit e538693
Showing 7 changed files with 136 additions and 80 deletions.
12 changes: 5 additions & 7 deletions resources/views/library/actions.blade.php
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
@extends('layout')
@section('title', 'Один класс — одна задача')
@section('description', 'Каждый класс в приложении должен отвечать только за одну конкретную задачу или функциональность.')
@section('description', 'Каждый класс в приложении должен отвечать только за одну конкретную задачу.')
@section('content')

<x-header align="align-items-end">
<x-slot name="sup">Чистота и порядок</x-slot>
<x-header align="align-items-center" image="/img/ui/finger.svg">
<x-slot name="sup">Ясность с первого взгляда</x-slot>
<x-slot name="title">Один класс — одна задача</x-slot>
<x-slot name="description">
Каждый класс в приложении должен отвечать только за одну конкретную задачу или функциональность.
</x-slot>
<x-slot name="content">
<img src="/img/gusli.svg" class="img-fluid d-block mx-auto">
Каждый класс в приложении должен сосредоточиться на выполнении одной конкретной задачи или функции
</x-slot>
</x-header>

@php
$sections = collect([
'basics',
'focus',
'package',
'conventions',
'tests',
])
23 changes: 21 additions & 2 deletions resources/views/library/index.blade.php
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
<x-container>

<div class="row g-4">
<div class="col-md-6 col-lg-8 mb-4">
<div class="col-md-6 col-lg-8">

<div class="bg-primary bg-opacity-10 rounded p-4 p-xl-5 position-relative overflow-hidden mb-4">
<img src="/img/bird.svg" class="position-absolute w-50 bottom-0 end-0">
@@ -74,7 +74,7 @@ class="link-body-emphasis text-decoration-none icon-link icon-link-hover stretch
</div>
</div>

<div class="col-md-6 col-lg-4 mb-4">
<div class="col-md-6 col-lg-4">
<div class="bg-secondary bg-opacity-10 rounded p-5 h-100 position-relative overflow-hidden">
<img src="/img/sign.svg" class="position-absolute w-100 bottom-0 end-0 d-none d-lg-block">
<ul class="d-grid gap-5 list-unstyled text-balance">
@@ -95,6 +95,25 @@ class="link-body-emphasis text-decoration-none icon-link icon-link-hover stretch

</div>
</div>


<div class="col-md-6 col-lg-4">
<div class="bg-secondary bg-opacity-10 rounded p-5 h-100 position-relative overflow-hidden">
<div class="d-flex flex-column position-relative h-100">
<h3 class="mb-3 fw-bold">Действия</h3>
<p class="mb-auto fw-light">
Класс должен сосредоточиться на выполнении одной конкретной задачи
</p>

<a href="{{ route('library.actions') }}"
class="link-body-emphasis text-decoration-none icon-link icon-link-hover stretched-link mt-4">
Начать читать
<x-icon path="i.arrow-right" class="bi" />
</a>
</div>
</div>
</div>

</div>

</x-container>
33 changes: 16 additions & 17 deletions storage/library/actions/basics.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
---
title: "Основы"
description: "Что такое принцип 'Один класс — одна задача'?"
description: "Что такое принцип <code>One Class, One Task</code>?"
---

Принцип «Один класс — одна задача» (One Class, One Task) предполагает, что каждый класс в приложении должен отвечать
только за одну конкретную задачу или функциональность. Это упрощает структуру кода, делает его более понятным и легким
для поддержки. В контексте Laravel этот подход помогает организовать бизнес-логику в виде отдельных классов, которые
выполняют конкретные действия, что позволяет избежать перегруженности классов и улучшает читаемость кода.

Преимущества использования принципа «Один класс — одна задача»:

- **Читаемость кода**: каждый класс отвечает только за одну задачу, что упрощает понимание его назначения и логики.
- **Поддерживаемость**: изменение и тестирование классов становится проще, так как каждый класс содержит только одну
задачу.
- **Изоляция логики**: каждый класс действия изолирован от других частей приложения, что упрощает его тестирование и
поддержку.
- **Повторное использование**: классы действий могут быть повторно использованы в разных частях приложения, что
упрощает разработку и поддержку кода.
- **Улучшение архитектуры**: применение принципа «Один класс — одна задача» помогает улучшить архитектуру вашего
приложения, сделав его более гибким и масштабируемым.
Принцип «Один класс — одна задача» (`One Class, One Task`) устанавливает требование, согласно которому каждый класс в приложении должен выполнять лишь одну конкретную задачу или функциональность. Этот подход способствует созданию более структурированного и предсказуемого кода, а также облегчает его поддержку.

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

##### Что это даст?

- **Читаемость кода**: Наличие класса, отвечающего за единую задачу, значительно упрощает понимание его назначения и поведения. Это особенно важно в рамках командной разработки или при возвращении к проекту спустя значительное время, так как открыв класс, разработчик может быстро оценить его функциональность.

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

- **Снижение сложности**: Логика приложения становится более управляемой, когда она разбивается на мелкие, специализированные части. Такой подход способствует снижению уровня сложности кода и облегчает его восприятие.

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

Тем не менее, важно сохранять баланс между дроблением логики на мелкие классы и чрезмерной детализацией. Не все аспекты логики следует выносить в отдельные классы, необходимо учитывать контекст.
24 changes: 14 additions & 10 deletions storage/library/actions/conventions.md
Original file line number Diff line number Diff line change
@@ -3,16 +3,20 @@ title: "Рекомендуемые соглашения"
description: "Помогут вам оставаться последовательными при организации вашего приложения"
---

**Начните с глагола**

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

**Используйте папку `Actions`**
##### Начните с глагола

Создайте папку `app/Actions` и сгруппируйте свои действия внутри неё по темам. Это помогает поддерживать структуру
вашего кода организованной и логичной. Например:
Названия классов действий должны представлять собой глаголы, отражающие выполняемую задачу.

Например, если класс предназначен для отправки письма для сброса пароля, его следует назвать `SendResetPasswordEmail`.


##### Используйте директорию `Actions`

Создайте папку `app/Actions` и сгруппируйте свои действия внутри неё по модулям.
Это поможет поддерживать структуру вашего кода организованной и логичной. Например:

```php
app/
@@ -41,8 +45,8 @@ app/
└── ...
```

В качестве альтернативы, если ваше приложение уже разделено на темы — или модули — вы можете создать папку `Actions` под
каждым из этих модулей. Например:
Если ваше приложение уже разделено на модули - создайте директорию `Actions` в
каждом из них:

```php
app/
@@ -59,4 +63,4 @@ app/
└── ...
```

Такая организация помогает вам поддерживать порядок в коде и упрощает его навигацию.
Такая организация поможет вам поддерживать порядок в коде и упростит навигацию.
48 changes: 4 additions & 44 deletions storage/library/actions/focus.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
title: "Фокус на работе приложения"
description: "Что такое принцип 'Один класс — одна задача'?"
description: "Использование <code>Actions</code> позволяет сосредоточиться на бизнес-логике приложения, а не на технических деталях."
---

Использование `Actions` позволяет сосредоточиться на бизнес-логике приложения, а не на технических деталях.
Классы `Action` выполняют конкретные задачи и изолируют их от других частей приложения, что упрощает понимание кода и
его поддержку. Логика, связанная с выполнением одной задачи, собирается в одном месте, что облегчает её изменение и тестирование.

Пример класса действия:

```php
class GenerateReservationCode
@@ -29,49 +29,9 @@ class GenerateReservationCode
}
```

Это позволит вам вызывать объект класса, как если бы он был функцией. Например:
Данный класс можно вызвать как функцию:

```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. Важно помнить, что главная цель — разделить логику
вашего приложения на небольшие, легко понимаемые и поддерживаемые части.
49 changes: 49 additions & 0 deletions storage/library/actions/package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: "Пакет Laravel Actions"
description: "Действие можно удобно запустить как объект, контроллер, фоновую задачу и консольную команду."
---

В экосистеме Laravel есть прекрасный пакет `Laravel Actions` который способствует организации кода вокруг действий.
Данный пакет позволяет создавать классы действий, которые могут быть вызваны в различных контекстах, таких как контроллеры, события и консольные команды.
Это обеспечивает более универсальный и гибкий код.


Пример использования:

```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()
```

Если вам нужно выполнить действие в очереди, то вы так же можете это сделать, например:

```php
GenerateReservationCode::dispatch();
```

> **Примечание** Вы можете узнать больше об удобстве использование действий с пакетом `Laravel Actions` на его [официальном сайте](https://laravelactions.com/).
27 changes: 27 additions & 0 deletions storage/library/actions/tests.md
Original file line number Diff line number Diff line change
@@ -5,3 +5,30 @@ description: "Что такое принцип 'Один класс — одна

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

```php
class GenerateReservationCodeTest extends TestCase
{
public function testGeneratedCodeContainsOnlyAllowedCharacters(): void
{
$code = GenerateReservationCode::run(8);

$this->assertMatchesRegularExpression(
'/^[BCDFGHJLMNPRSTVWXYZ2456789]+$/',
$code
);
}

public function testGeneratedCodeIsUrlSafe(): void
{
$code = GenerateReservationCode::run();

$this->assertTrue(
filter_var($code, FILTER_VALIDATE_URL) === false
);
}
}
```

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

0 comments on commit e538693

Please sign in to comment.