Expert JS React Developers for TUI wanted. Join Ciklum and get a $4000 sign-on bonus!
×Закрыть

Чистый код. Базовые принципы на примерах

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

Всем привет! Меня зовут Денис Оленин, я Senior PHP-разработчик в компании AmoMedia, которая входит в экосистему бизнесов Genesis.

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

Что такое чистый код и почему это важно

К условно «чистому» можно отнести код, обладающий такими свойствами:

  • легко читается и помогает быстро вникнуть новым разработчикам;
  • оформлен в соответствии со стандартами, принятыми в сообществе;
  • не создает проблем при расширении или изменении;
  • имеет предсказуемое поведение.

Для чего вообще писать код по каким-то правилам, ведь «работает и так»? Представьте команду разработчиков, которые начинают с нуля довольно простой проект. В первые месяцы все прекрасно, но бизнес-задачи периодически меняются, и команде все сложнее вносить изменения. В какой-то момент задача по созданию простой кнопки может затянуться на часы или даже дни. Причиной этого может быть низкое качество кода, который просто не готов к изменениям.

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

Основные требования к чистому коду

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

Содержательные имена

Выбирайте имена переменным, функциям, классам так, чтобы это имя достаточно точно объясняло, что делает этот код и для чего он создан.

// Bad
const DMYDATE = “d.m.Y”;

// Good
const PUBLIC_DATE_FORMAT = “d.m.Y”;

Функции/методы

Функции и методы должны выполнять только одну операцию и быть предельно короткими. Функции не должны содержать вложенных структур, так как это приводит к их увеличению.

// Bad
public function notify(array $usersId): void
{
    $users = DB::table(‘users’)->whereIn(‘id’, $usersId)->get();

    foreach ($users as $user) {
        notify($user);
    }
}

// Good
public function getUsers(array $usersId): Collection
{
    return DB::table(‘users’)->whereIn(‘id’, $usersId)->get();
}

public function notify(Collection $users): void
{
    foreach ($users as $user) {
        notify($user);
    }
}

Блоки и отступы

Блоки в командах if, else, while должны состоять из одной строки, в которой обычно содержится вызов функции. Максимальный уровень отступов в функции не должен превышать один-два. Это упрощает ее чтение и понимание.

По возможности избавьтесь от блока else, если используете if. Иногда полезно следовать от отрицания if (! $var) — таким образом может сократиться количество вложенных if блоков.

// Bad
$user = DB::table(‘users’)->find($id);

if ($user) {
    $post = $user->post()->first();
        if ($post) {
            return $post->created_at;
        } else {
            throw new ModelNotFoundException();
        }
} else {
    throw new ModelNotFoundException();
}

// Good
$user = DB::table(‘users’)->find($id);

if (! $user) {
    throw new ModelNotFoundException();
}

$post = $user->post()->first();

if (! $post) {
    throw new ModelNotFoundException();
}

return $post->created_at;

// Best
$user = DB::table(‘users’)->findOrFail($id);

$post = $user->post()->first();

if (! $post) {
    throw new ModelNotFoundException();
}

return $post->created_at;

Один уровень абстракции на функцию

Постарайтесь скрывать второстепенные подробности в ваших функциях/методах. Не стоит смешивать уровни абстракции в функциях — это всегда делает код запутанней.

// Bad
function saveFile(Request $request)
{
    file_put_content(‘someFileName’, $request->file(‘file’)->body);
    $file = new File;
    $file->body = $request->file(‘’)->body;
    $file->save();
}

// Good
class Storage {
    public function store(string $name, string $body) {
        file_put_content($name, $body);
    }
}

function saveFile(Request $request)
{
    (new Storage)->store(‘someFileName’, $request->file(‘file’)->body);
    $file = new File;
    $file->body = $request->file(‘file’)->body;
    $file->save();
}

Чтение кода сверху вниз

За каждой следующей функцией должны следовать функции, вызванные выше. Таким образом мы можем читать наш код последовательно, как рассказ. Дядюшка Боб (Роберт Мартин — инженер, автор книги «Чистый код») называет такой подход «правилом понижения».

// Bad
function isAvailablePost(int $id): bool
{
    return DB::table(‘posts’)
        ->where(‘id’, $id)
        ->where(‘status’, ‘active’)
        ->exists();
}

function getPost(int $id)
{
    return DB::table(‘posts’)->find($id);
}

function update(Request $request)
{
    if (isAvailablePost($request->get(‘post_id’))) {
        $post = getPost($request);
        $post->update([‘title’ => ‘Some new title’]);
    }
}

// Good
function update(Request $request)
{
    if (isAvailablePost($request->get(‘post_id’))) {
        $post = getPost($request);
        $post->update([‘title’ => ‘Some new title’]);
    }
}

function isAvailablePost(int $id): bool
{
    return DB::table(‘posts’)
        ->where(‘id’, $id)
        ->where(‘status’, ‘active’)
        ->exists();
}

function getPost(int $id)
{
    return DB::table(‘posts’)->find($id);
}

Команды switch

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

Аргументы функций

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

Объекты как аргументы

Если количество аргументов функции/метода превышает 2-3, то стоит задуматься об объединении некоторых аргументов в отдельную абстракцию или класс.

// Bad
function sendNotification(string $userName, string $email, string $message);

// Good
function sendNotification(User $user, string $message);

Использование аргументов-флагов

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

// Bad
public function context(Request $request): void
{
    $someFlag = $request->get(‘someParam’);
    $this->someProcess($request, $someFlag);
}

private function someProcess(string $someString, bool $flag)
{
    if (! $flag) {
        doSomeStuff();
    }

    doSomeAnotherStuff();
}

// Good
public function context(Request $request): void
{
    $someFlag = $request->get(‘someParam’);
    if (! $someFlag) {
        $this->someProcess($request);
    }

    $this->someAnotherProcess($request);
}

Избавьтесь от побочных эффектов

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

// Bad
function getPost(int $id)
{
    $post = DB::table(‘posts’)->find($id);
    $post->views += 1;
    $post->save();

    return $post;
}

// Good
function getPost(int $id)
{
    return DB::table(‘posts’)->find($id);
}

Изолируйте блоки try/catch

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

Плохие комментарии

Хорошо написанный код не нуждается ни в каких дополнительных комментариях. Если у вас есть комментарии, которые описывают, как работает ваш метод/функция, или оправдывают путаницу, то стоит задуматься о переработке кода.

Обязательные комментарии

Несмотря на существующие правила, не стоит писать для каждой функции или переменной комментарий PHPDoc. Иначе вы просто дублируете описание. В PHP 7+ есть все необходимые конструкции языка для того, чтоб избавиться от таких «обязательных» комментариев. Их точно стоит писать, только когда вы разрабатываете API.

Закон Деметры

Если модуль «А» знает о модуле «B», а модуль «B» знает о модуле «С», то модуль «А» не должен знать про модуль «С». Также объекты/модули никак не должны раскрывать свое внутреннее устройство.

// Bad
class Author {
    private Post $post;
...
    public function (Image $image)
    {
        $this->post->image->setUrl($image->getUrl());
    }
}

// Good
class Post {
    private Image $image;
...
    public function setImage(Image $image)
    {
        $this->image->setUrl($image->getUrl());
    }
}

class Author {
    private Post $post;
...
    public function (Image $image)
    {
        $this->post->setImage($image);
    }
}

Не связывайтесь с null

По возможности избегайте использование null в вашей бизнес-логике. Это создает лишнюю работу и проблемы на вызывающей стороне. Вместо кучи проверок на null лучше бросить исключение. В крайнем случае опускайте эту переменную на низкий уровень абстракции.

Если у вас возникает соблазн вернуть null из метода, рассмотрите возможность создания исключения или возврата объекта специального случая. Special case — подкласс, который обеспечивает особое поведение для конкретных случаев, известных как Null Object. Помните, возврат null из метода — это плохо, но передача null в метод еще хуже.

// Bad
function findUser(int $id): ?User
{
    return User::find($id);
}

// Good
/**
 * @param int $id
 * @throws ModelNotFoundException
 */
function findUser(int $id): User
{
    $user = User::find($id);
    if (! $user) {
        throw new ModelNotFoundException;
    }

    return $user;
}

// Best
class UnknownUser extends User {
    public function getName()
    {
        return ‘Some default name’;
    }
}

function findUser(int $id): User
{
    $user = User::find($id);
    if (! $user) {
        return new UnknownUser;
    }

    return $user;
}

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

Уверен, многие разработчики сочтут эти правила неким ограничением. Следовать им очень желательно, но это скорее рекомендации, чем ультиматум. Желаю всем чистого кода.

Полезная литература

  1. «Чистый код. Создание, анализ и рефакторинг». Роберт Мартин — основной источник по данной тематике.
  2. Handling Exceptional Conditions with Grace and Style. Nikola Poša (fwdays.com/...​s-with-grace-and-elegance) — отличный доклад на тему использования null в коде.
  3. SOLID Principles in PHP. Jeffrey Way (laracasts.com/...​s/solid-principles-in-php) — видеоуроки по SOLID с хорошими примерами.
👍НравитсяПонравилось8
В избранноеВ избранном5
Подписаться на тему «PHP»
LinkedIn

Похожие статьи

Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Давайте свой чистый код запилим. Со слоном и шлюхами. Нахиба Мартин книги пишет?

Есть про что похоливарить, но в общим и целом — лайк, понравилось.

1. Почему бы просто не понимать любой код?
2. Каким бы код ни был, тестирующие его тесты всегда очень просты и понятны.

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

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

А что такое «мок» и «стаб»? Не Олимпийский комитет? А то он гуглится.

Mock — фейковий об’єкт, який створюється на базі справжнього, але його методи нічого не роблять, або повертають дефолтне значення, або те яке ти назначив. Те ж з проперті. Створюється за допомогою бібліотеки.

Stub — а це вже справжній об’єкт зі справжніми даними і поведінкою. Створюється вручну через new.

Оба використовуються щоб затикати залежності того класу і методу, який ти тестуєш в Unit test.

Пришла в голову идея по этому поводу — например, проверять в геттерах возврат null
а потом составить статистику для всех проверок, когда они null обнаруживали.
И вот там, где null not found through long long time удалять потом проверку и тем самым оптимизировать код прямо на глазах. А сначала везде проверки и чрезмерные даже проверки вообще всего: границ и входящих параметров, аргументов, возвращаемых значений — всего.
А потом, согласно набранной статистики некоторые проверки поотменять и бум! рост производительности.

Це схоже на code assertions. А ідея видаляти провірки на ідею зі статті тут на доу запостили були в коменьах, що юніт тести які ніколи не ламалися, видаляти зовсім.

юніт тести які ніколи не ламалися, видаляти зовсім

Рефакторінг тестів не для тупого скорочення LOC проводиться

Простота не завжди означає, що код буде коротким

Якщо весь метод не стає в один рядок — такий код треба переписувати!

В вашому ЯП немає можливості розбити довгу строку на декілька?

Зараз у перловиків на очі сльози щастя навернулися...

Чтение кода сверху вниз

За каждой следующей функцией должны следовать функции, вызванные выше. Таким образом мы можем читать наш код последовательно, как рассказ. Дядюшка Боб (Роберт Мартин — инженер, автор книги «Чистый код») называет такой подход «правилом понижения».

отже, в ядрі лінуха код нечистий? ;)
github.com/...​s/bus/arm-integrator-lm.c (див. найпершу ж integrator_lm_populate() — вибрав навмання)

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

// Bad
public function context(Request $request): void
{
$someFlag = $request->get(‘someParam’);
$this->someProcess($request, $someFlag);
}

private function someProcess(string $someString, bool $flag)
{
if (! $flag) {
doSomeStuff();
}

doSomeAnotherStuff();
}

// Good
public function context(Request $request): void
{
$someFlag = $request->get(‘someParam’);
if (! $someFlag) {
$this->someProcess($request);
}

$this->someAnotherProcess($request);
}

huh?

Технічно тут бед коли флаг в методі сервісу, і гуд, коли він лише в методі контролеру, який вже сам викликає потрібний сервіс(чим контролер і має займатись)

За совет кидать эксепшен при каждом чихе автора разжаловать в июни и дать домашнее задание — изучить нагрузку в 2-х случаях: 1) метод возвращает null 2) метод возвращает эксепшен. Пока выглядит так, как будто автор с высоконагруженными проектами не работал

Пока выглядит так, как будто автор с высоконагруженными проектами не работал

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

Да и статья про чистый код, а не как задрачиваться с микробенчмарками.

Ну да ну да )) и инстанцирование обькта, да еще и содержащего стек вызовов по затратности сравнялось с return null ))) Жгите еще ). В высоконагруженном проекте я не думаю каждый раз стоит ли делать эксепшен/обрамлять строку двойными кавычками/работать с анонимными функциями в цикле и т.д и т.п. Я с этим давно разобрался и на автомате пишу так, чтоб минимизировать нагрузки. Поверьте, это не сложно. Нужно просто понимать почему надо писать так а не иначе и тогда все будет происходить на автомате.

Угу, знаю я таких оптимизаторов только из мира JS. Те не юзали forEach и строки конкатенировали через array.push потому, что в JSBench они показывали в 100 раз лучший перформанс. И все кажется логичным, for loop в 100 раз быстрее форича, но:

1. В масштабе целого аппа это будет капля в море, даже не брать i\o операции (которы практически всегда и стают ботлнеком, даже в языках которые нормально дружат с асиинхронностью, а про php я вообще молчу)
2. В один прекрасный момент вышла новая версия V8, где профит от этих гениальных оптимизаций в ущерб читаемости стал ничтожно мал.
3. В высокоуровневых языках практически все, что ты можешь заоптимизировть ручками, может\уже есть\будет оптимизироваться под капотом компилятора\виртуальной машины.

Можно еще разбивать обьект на переменные, потому что где-то когда-то прочитал, что в С медленные операторы доступа, но ща ж вроде не 90-е :)

Я с этим давно разобрался и на автомате пишу так, чтоб минимизировать нагрузки.

Ну а потому удивляются почему про пхп-шников легенды ходят))

строки конкатенировали через array.push

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

В масштабе целого аппа это будет капля в море

а миллион капель это 50 литров. Смотря что это за код, где этот код и насколько он горяч.

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

Да, на железо, которое появится через 10 лет, и на компиляторы, которые сделают конфетку, видно и рассчитывают разрабы «калькуляторов» на новомодных фреймворках, требующие железо последней свежести, чтобы не лагало :)

Может таки там был через литерал массива с джоином?

да, джойн имел ввиду

а миллион капель это 50 литров.

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

Смотря что это за код, где этот код и насколько он горяч.

ясно что есть исключения, на то они и исключения. Человек выше хвалился что он уже на автомате пишет «быстрый» код)

рассчитывают разрабы «калькуляторов» на новомодных фреймворках, требующие железо последней свежести, чтобы не лагало :)

хз хз где это такое, факт в том что железо с каждым годом становится быстрее, и фреймворки и языки тоже. вон ж даже в PHP уже JIT завезли вроде)))

угу, и тестят на холодном старте

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

Человек выше хвалился что он уже на автомате пишет «быстрый» код)

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

факт в том что железо с каждым годом становится быстрее, и фреймворки и языки тоже.

Но это конечному юзеру и не особо то заметно, т.к. код с опережающими темпами более пофигистским. Нынче утечка памяти на фронте- не беда, ведь клиент не будет держать вкладку открытой более часа, а у всех уже по 16 гб озу уже. Если посмотреть вопросы от индийских межгалактических сеньйоров на стеке, задающие одни и те же вопросы годами, регулярно каждый день, типа варнинга утечки в их Реактах, то похоже они ждут компилятор с нейросеткой, который сначала сможет погуглить вчерашние вопросы, что уже говорить об [микро]оптимизациях.

хз хз где это такое, факт в том что железо с каждым годом становится быстрее

Так, давайте залізячний прогрес використаємо не для збільшення функціоналу, а на тормозні джс фреймворки і низькокваліфікованих розробників.

я наверное тоже ни разу с высоконагруженными проектами не работал(чтобы под этим не подразумевалось :) ). Перфоманс траблы были по совершенно разным причинам, таким как сетевые проблемы, проблемы с хранилищами данных, проблемы с хапросами к хранилищам данных, проседание интеграции с внешними сервисами, кривые алгоритмы, и тд и тп.
Но ни разу, вообще ни разу не было проблем с перфомансом обработки исключений. А вот словить внезапный NullReferenceException, который к тому же логируется без стек трейса(секурити ж, гыгы), не репродьюсится на непрод енвах и послендующие медитации «а что же там налл и почему» — можно сказать классика жанра.

Хайлоад бывает очень разный. Где то сталкиваются с перфоманс траблами только при кривых запросах, а где-то вынуждены делать денормализацию, чтоб это хоть как-то шевелилось. Где-то в угоду производительности отказываются от внешних ключей (хотя проблем это порождает намного больше тот же NullReferenceException и вляпаться в них намного легче), а в других проектах (тоже считающих себя хайлоадом) техлид удивляется а как вообще можно без ФК. Просто нужно быть готовым что с рассуждениями " в любой непонятной ситуации кидаем исключение" на ряд проектов будет сложно попасть.

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

Теперь давайте прикинем, какой % рынка украинского ИТ занимает этот самый пресловутый "ряд проектов"(и любопытно, что это за проекты).

насного интересней прикинуть ПОЧЕМУ такой

% рынка украинского ИТ занимает этот самый пресловутый «ряд проектов»

Случайно не потому, что при попытке найма компании сталкиваются с рассказами украинских синьоров про то что программисту думать не надо за него все сделает оптимизатор? Компании 2-3 месяца помыкаются, видят что набрать достойную команду возможности нет и проект уходит на другой рынок...

Случайно не потому, что при попытке найма компании сталкиваются с рассказами украинских синьоров про то что программисту думать не надо за него все сделает оптимизатор?

Случайно не потому что что? Кто на ком стоял? Я попросил дать оценочную цифирь, вы мне начинаетет про случайные наймы рассказывать.

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

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

Хайлоад бывает очень разный.

Потому что компании и команды очень разные.
Некоторые backend разработчики уверены, что знание третьей нормальной формы им дарует правильное построение универсальной базы.
А все эти планы, хинты, ETL\ELT, OLAP и OLTP — эт же фигня.

За совет кидать эксепшен при каждом чихе автора разжаловать в июни и дать домашнее задание — изучить нагрузку в 2-х случаях: 1) метод возвращает null 2) метод возвращает эксепшен. Пока выглядит так, как будто автор с высоконагруженными проектами не работал

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

Собственно люди, которые веруют в 3ю нормальную форму и флоу-по-экспешнам — либо тролли, причем очень толстые, либо очень ограниченные (несмотря на регалии Лидов и Архитектов)

Хотів почитати статтю. Заглянув в коментарі, прочитав Пєніє, і впав в депресію. Все тлін...

Олексія просто адміни доу держать в заручниках в підвалі, де при створенні теми загоряється червона кнопка. Якщо він за 20 хв після створення теми не напише якусь нісенітницю, повз яку важко пройти, то йому відрубують один палець.
Пока слава богу всі пальці в Олексія цілі.

Але іноді він в ударі і йому за це пришивають ще декілька :)

Я подозреваю, что Алексей — вообще не человек :)

Какие_ваши_доказательства.жпг

Какие_ваши_доказательства.жпг

24к комментов...

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

Все приведенные примеры просто отпадут сами собой когда ты работаешь с умными и образоваными людьми

К сожалению, таковыми не рождаются, и в реальном коде этих примеров как риэлторов в Одессе

Похоже после того как Дядю Боба закидали ссаными тряпками и поперли из приличных комьюнити, он пошел проповедовать в PHP.

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

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

Если кратко, все эти принципы ложатся в общий набор БЮРОКРАТИЧЕСКОГО ДЕРЬМА. Ну или более цензурными словами, являются заменой оправданных действий и зависимостей — ритуалами и суевериями. И поскольку такая система не выдерживает никакой критики отсутствия причин так делать — ЗАПРЕЩАЕТСЯ сам поиск этих причин, вместо этого постулируется их священная незыблемая сущность.

Я понимаю ещё если вайтишники на это драконят. Но людям с настоящим высшим образованием должно быть как минимум стыдно. Вы образование—то получали ЗАЧЕМ? Оно нужно исключительно чтобы что-то МЕНЯТЬ. Чтобы пользоваться всем готовым и ничего не трогать — достаточно неполного среднего и каких-нить курсов.

Я бы даже сказал, не «бюрократического», а «религиозного».
Люди слепо верят, что бездумное следование каким-то правилам спасет и сохранит их от «страшного говонкода».

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

в случае бюрократии еще есть возможность какой-то дискусии
в случае религии — такой возможности нет

Да, есть такой миф. Притом и там, и там.

Ще скажіть що половина патернів ООП — то костилі які відпадають коли якийсь кодер в нову джаву додає функціональщіну

дві половини, я б навіть сказав напівдупи

Щось ти якісь не справжній джавіст

Бо я значно старший за жабу, та розумію звідки це все лайно з′явилося. Колись, на окремому коротесенькому етапі, це дійсно були найкращі милиці на світі. А потім з′явилися, чи краще сказати, набрали популярності, значно простіші та зрозуміліші механізми. А від старих хіба що синглтон лишився, та й той переписали всередині — замість ТУПО додати цей конструкт прямо в мову програмування (хоча в деякому сенсі він там є).

Коли якийсь з тих патернів знадобиться знову, його дешевше винайти знову, аніж визубрювати древні маразми, які ніколи вже не знадобляться. Особливо в тій формі, в якій писалися.

„Simplicity and elegance are unpopular because they require hard work and discipline to achieve and education to be appreciated.”

Ось і причина, чому ООП. ФПшники живуть в ілюзорному світі.

Reason 1 — It was thought to be easy to learn.
Reason 2 — It was thought to make code reuse easier.
Reason 3 — It was hyped.
Reason 4 — It created a new software industry.

на FP уже как-то странно наезжать — все языки эволюционируют в сторону FP

Пруфов конечно не будет, только домыслы. Вообще-то объектно-ориентированная модель прекрасна для понимания человеком. Вот только идеология, что ВООБЩЕ ВСЁ является объектом — должна была быть отстрелена, едва тренд пошёл в широкий продакшен.

Это как в Java — пока она была маленькой и на ней писалась всякая мелочь, была классной идея что на каждый объект можно повесить управление потоком, и таким образом заложить многопоточность прямо во всё. А результат — на каждую козявочку теперь висит грёбаный мониторинг, и вместо того чтобы получать её тупо по указателю, как делается в С++, к ней идёт обращение через тупейшую конструкцию, разумеется скрытую от глаз кодера, но от этого не менее тормозящую.

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

Вот в чём проблема к существующей объектной модели вместо потомка Object сделать ещё и примитивов уровня typedef, которыми можно манипулировать, не трогая вообще никакго кода, ни явно, ни неявно, а тупо передачей указателя? И соответственно безо всякого наследования, ибо нефиг.

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

Бюрократия — корень большинства проблем в программировании.

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

Чего-то на анемичную модель смахивает. Так все адекватные люди давно код пишут таким образом.
Что касается потоков, то в дотнете TPL сама по себе конфетка, а высокоуровневые обертки вокруг нее вроде TPL-Dataflow + Rx.NET + PLINQ, приправленное в правильных местах F#, ваще песня.

А як юніт тестувати, якщо використовувати всюди new, замість DI?

А какой смысл в тестах, которые ничего не тестируют? Юнит тесты это булшит еще поболее чем солид.

Юнит тесты это булшит еще поболее чем солид

Юнит тесты все булщит или только те что ничего не тестируют?

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

Твой троллинг слишком толстый, учись троллить тонко

“An even more professional approach is to leave the assertions in the code when you ship, and to automatically file a bug report on behalf of the end user and perhaps to try to re-start the application every time an assertion fails. At that same startup I mentioned above I had a boss who insisted that we not do this. I pointed out to him that an assertion failure meant that something in the program was very wrong and that it was likely that the program would produce the wrong result. Even the tiniest error in the kind of software we were building could cost a client $5 million in rework. He said it was more important that the company avoid the appearance of having done something wrong than that we stop before producing an incorrect result. I left the company. Maybe you are one of his clients today. ”

LOL

Схоже на те, що олдскульні програмісти не хочуть еволюціонувати.

Эволюция не имеет отношения к тому, что дядя Кент Бек решил срубить бабла на семинарах, книгах, консалтинге, попутно окучивая миллионы лохов.

btw, DI — это антипаттерн, т.к. он делает чистый код — «нечистым».
По итогу, невозможно понять, что происходит, без анализа всей кодобазы (что за х. сюда инжектится?...)

Pure function — це щось із ФП секти?

Термін звідти
Використовувати можна — будь-де

Что лишний раз доказывает: «чистый код» — всего лишь очередная религия, тормозящая прогресс.

А хто тобі завадив вдовольняти DI на етапі тестування?

Тобто? Якщо депенденсі не вказуються в конструкторі і методі, а всередині коду створюються, то як задовільнити їх? Я трохи гуляю в теорії, але спробую відповісти коли зрозумію про що мова.

За каждой следующей функцией должны следовать функции, вызванные выше. Таким образом мы можем читать наш код последовательно, как рассказ. Дядюшка Боб (Роберт Мартин — инженер, автор книги «Чистый код») называет такой подход «правилом понижения».

Если бы законы писались как ваш «чистыйкод», то все определения надо было бы размазать по тексту. Это называется «бюрократический маразм». По-вашему, всё что сказано Дядюшкой Бобом — верно? А Луна сделана из зелёного сыра?

Открою секрет Полишинеля — нейминг важнее всего этого маразма. Как только вы написали тип «Request» — попрощайтесь с читаемостью кода и узнаваемостью ошибок. Вы тупо завернули логику в картонную коробку с надписью ХЗ. И возможности тестирования этого ХЗ соответственные, протестировать можно всё что угодно, кроме собственно логики.

private function someProcess(string $someString, bool $flag)
{ if (! $flag) { doSomeStuff(); } doSomeAnotherStuff(); }

Ну да конечно. А то что при этом флаге может быть кучу всякого, делаться независимо от его наличия, у каких-то честей нет ветки else и так далее? Да чёрт возьми, вся логика на булевых выражениях пляшет, ПОЧЕМУ нельзя в функцию флаги-то передать?

Вот только за bool $flag следует отрывать яйца. Просто за сам факт намеренной обфускации кода. Что мешало назвать флаг $doSomeStuff ? Или тогда код не был бы слишком заумным, а этого нельзя допустить?

PS. По поводу функций, вызываемых сверху и описанных ниже. Вы просто не застали исторической эпохи, когда это вообще не допускалось. Равно как и сейчас в непосредственно интерпретируемых языках этого нельзя делать. Сначала объяви, потом пользуй.

В реальности же, если есть возможность вызываемой функции быть описанной ниже — её надо тупо перенести целиком в тело исходной, чтобы НЕ ДАВАТЬ ИМЕНИ. Ничто так не засоряет код, как лишние имена. А если и давать имя (например, ради использования в нескольких точках) — то чтобы его частью было имя вызывающей функции (или иной логической сущности, позволяющей группировать).

function update(Request $request){...
}function update_isAvailablePost(Request $request){...
}function update_getPost(int $id){...
} // end of update

Почему так: с точки зрения компилятора, это всё разные сущности. А с точки зрения человека (с его ограниченной памятью, ассоциативной по типу «все со всеми») — это единый блок с именем update, который НЕ НУЖНО читать, если вы не собираетесь заниматься конкретно этой частью функционала.

У людей просто адски короткая память. Зрительная больше — но она по сути ограничена экраном. Чтобы на экране код был понятен, он должен быть крупноблочным. А размазывание говна по тарелке есть ни что иное как обфускация. И к «чистому» коду имеет отношение как ДіяСіті к развитию экономики.

Давай вже, книжку пиши, чи що?)) Дивись як круто буде виглядати: О.Пєніє «Абсолютно чистий код»

Якщо Пєніє напише книжку про IT, IT прийдеться закривати.

Закрий будь ласка. З того боку.

PS. Якби я так вмів писати, писав би про ДіюСіті та МінЦифру :)

Нащо? Принцип KISS відомий, маніфест також. Що нового ви хочете почути?

Що стосується принципів написання коду, так само як і керування цим процесом — аз єсмь матьорий консерватор, та вважаю що за 5 років міняється все [лише для тих, хто тільки зайшов], а за 100 років — нічого. Так само як і за 200.

PS. Якби тру айтішники писали художні книжки, їх змогли б читати хіба що залізяки, та й те з помилками та крешами.

маніфест також

Ця російська методичка не відкривається.

Це вже краще. А то якесь російське болото, а не айті.

Не думал, что когда нибудь напишу это... но Олексій Пєніє правильные вещи говорит (в этом посте).

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

Все це добре, але

Ну чому б поряд з «так не треба писати» — зробити приклад як треба

Ну чому б поряд з „так не треба писати” — зробити приклад як треба

!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute®)&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0

Подписаться на комментарии