Заметки о codestyle

от автора

Довольно часто сталкиваюсь с вопросом касательно качества кода: «Почему написано именно так, а не так?». И я объясняю каждый раз. Именно поэтому решил составить эдакую заметку с некоторыми примерами и объяснениями.

Второй возникающий вопрос: «Где научился так красиво писать?». Ответ на который будет к концу статьи.

Приведу три примера, с которыми сталкиваюсь чаще всего.

Пример 1

use App\Models\Payment; use Illuminate\Database\Eloquent\Model;  class Foo extends Model {   public function user(){     return $this->hasOne('App\Models\User');   }    public function payments(){     return $this->hasMany(Payment::class);   } }

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

Начнём с того, что открывающиеся фигурные скобки лучше переносить на новую строку. Это позволит сделать код более приятным в чтении (Привет, PSR-12).

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

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

class Foo {     public function user()     {         //     } }

То у другого он может быть таким:

class Foo {         public function user()         {                 //         } }

Или таким:

class Foo {   public function user()   {     //   } }

Согласитесь, разница ощутима. А символ «пробела» он и в Африке символ «пробела», отображающийся на всех устройствах одинаково.

Размер в два символа лучше не использовать по той причине, что код становится нечитабельным и выглядит как «по линейке» — в одну слегка кривую вертикальную линию. И отследить в таком массиве вложенные операторы становится проблемной задачей.

Итак, после ревью код будет выглядеть так:

use App\Models\Payment; use App\Models\User; use Illuminate\Database\Eloquent\Model;  class Foo extends Model {     public function user()     {         return $this->hasOne(User::class);     }      public function payments()     {         return $this->hasMany(Payment::class);     } }

Пример 2

Недавно встретил такой участок кода (вставлю картинкой, чтобы не нарушить его вид):

Даже не буду говорить о существовании паттернов — скажу лишь о том, что ООП было придумано для сокращения дубляжа кода, но…

Данный участок очень плохо читается. Приходится вычитывать каждое слово с целью понять что в нём происходит и не пропустил ли чего при чтении.

Проведём код-ревью:

class NewsService {     public function sendNews(EmployerNews $employerNews)     {         $this->dispatch($employerNews, WorkPositionIdsJob::class);         $this->dispatch($employerNews, WorkPositionTypesJob::class);         $this->dispatch($employerNews, EmployerIdsJob::class);     }      protected function dispatch(EmployerNews $news, string $class): void     {         $job   = $this->job($news, $class);         $delay = $this->delay();          dispatch($job)->delay($delay);     }      protected function job(EmployerNews $news, string $job): AbstractJob     {         return new $job($news->getAttributes());     }      protected function delay(): Carbon     {         return Carbon::now()->addSecond();     } }

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

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

То же самое касается и примерно таких проблемных участков, как:

switch($value){     case 'foo':         //         break;     case 'bar':         //         break; }
if ($employerPriceCategory->default) {     return false; } $defaultCategory = EmployerPriceCategory::where('default', true)     ->first(['id']); Employer::query()     ->where('employer_price_category_id', $employerPriceCategory->id)     ->update([         'employer_price_category_id' => $defaultCategory->id,     ]);
$districts = $this->getDistricts(); $this->output->writeln('districts: ' . sizeof($districts)); $period = $this->getPeriod(); foreach ($period as $start) {     $end = $start->copy()->endOfDay();     $this->output->writeln('date = ' . $start->format('Y-m-d'));     // }

Это же просто ужас! Как такое вообще можно читать? А писать?!

Давайте отрефакторим их!

switch($value) {     case 'foo':         //         break;      case 'bar':         //         break; }
if ($employerPriceCategory->default) {     return false; }  $defaultCategory = EmployerPriceCategory::query()     ->select(['id'])     ->where('default', true)     ->first();  Employer::query()     ->where('employer_price_category_id', $employerPriceCategory->id)     ->update(['employer_price_category_id' => $defaultCategory->id]);

Мы давно пережили времена недостатка места на дисках и не стоит дорожить лишним символом «пробела», который компилятор всё равно удалит для себя. Это обычная экономия на спичках. Зачем усложнять жизнь не только себе, но и тем, кто после Вас будет поддерживать этот код? Заканчивайте какать там, где едите.

Пример 3

Помимо вставки дополнительных символов «пробела» и переносов строк, старайтесь разделять код на логические блоки.

Логический блок — это участок кода состоящий из нескольких строк, объединённых между собой какой-либо общей чертой.

Для примера возьмём следующий участок:

$salaryFirstBaseEmployer = $employer->salaryBases->first()->salary_base; $salaryLastBaseEmployer = $employer->salaryBases->last()->salary_base; $begin = Carbon::parse('2020-05-01')->startOfMonth()->startOfDay(); $end = $begin->clone()->endOfMonth()->endOfDay(); $endMonth = $begin->clone()->endOfMonth(); $startPeriod = new CarbonPeriod($begin, $end); $endPeriod = new CarbonPeriod($begin, $end);

В нём мы видим непонятный массив текста. Отформатируем его, разбив на логические блоки:

$salaryFirstBaseEmployer = $employer->salaryBases->first()->salary_base; $salaryLastBaseEmployer  = $employer->salaryBases->last()->salary_base;  $begin = Carbon::parse('2020-05-01')->startOfMonth()->startOfDay();  $end      = $begin->clone()->endOfMonth()->endOfDay(); $endMonth = $begin->clone()->endOfMonth();  $startPeriod = new CarbonPeriod($begin, $end); $endPeriod   = new CarbonPeriod($begin, $end);

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

Заключение

Очень давно мне дали дельный совет:

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

И это единственное правило, помогающее писать чистый и красивый код на любом языке программирования.

P.S.: Уже несколько людей, включая сообщения вне Хабра, написали о том, что есть такие штуки как PSR, автокомплит кода, форматирование кода в IDE, cs-fixer и так далее. Вы правда думаете, что я не знаю о их существовании? Проблема, раскрытая в статье, не в том, что их не используют, а в том, что мешает изначально красиво писать код, не поджигая пуканы других разработчиков?..

ссылка на оригинал статьи https://habr.com/ru/post/541792/


Комментарии

Добавить комментарий

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