Pull to refresh
63
0.5
Михаил @michael_v89

Программист

Send message

пусть вероятность попасть в конкретную точку окружности (над ℝ²), выбирая точки случайно, равна нулю

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

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

Нет. Если количество точек обозначить N и назначить вероятность 1/N, то суммарная вероятность будет 1.

Похоже, что для написания прошлой статьи я выбрал не совсем верный тон

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

Нелогичные утверждения присутствуют уже во введении:
"В основе Рекурсивной гипотезы реальности (RHR) лежит простая, но фундаментальная аксиома: реальность существует и самодостаточна."

Если она существует и самодостатчна, то ваша гипотеза тут вообще не нужна. Она не дает ничего нового, всё уже задано в аксиоме.

реальность — это самодостаточный процесс, где два простых состояния, 0 и 1, через рекурсию порождают бесконечность
В физике простые частицы объединяются в атомы, а те — в молекулы с миллионами способов взаимодействия.

Как именно из 0 и 1 получить конкретный атом водорода?

Случайность вносит новизну

Вы же сказали, что есть только 0 и 1, откуда вдруг взялась третья сущность "случайность"? Как из 0 и 1 получить случайность?

Два разряда — это не просто абстракция. Они отражают реальные процессы: в физике частицы и античастицы, в биологии «вкл/выкл» генов, в космологии чередование пустоты и вещества. Но как именно? Представьте, что эти два разряда начинают диалог: 0 говорит «нет», 1 отвечает «да», и в этом споре рождаются узоры, повторяющиеся на разных масштабах, как ветви дерева или спирали галактик.

Так где ответ на вопрос "как именно"? Я вот представил, у меня получилось 2 параллельные бесконечные цепочки

000000000000000000000000000000000000...
111111111111111111111111111111111111...

Что дальше?

Вы тут фактически утверждаете "Оно как-то само появляется, я не знаю как".

в физике частицы и античастицы

Так вы же хотели дать ответ на вопрос, откуда появились частицы и античастицы. А теперь постулируете "Ну они просто есть". Зачем тогда нужна ваша гипотеза?

будь то формализация математических основ

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

потому что мы все привыкли к одноядерным процессорам
продолжают моделировать полностью асинхронный мир — синхронными шаблонами

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

Мне не надо ждать, пока вон та тетка оплатит свою колбасу, я уже отпихнул её, схватил свою, и несусь к кассе.

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

Разница между примером с Inventory и этим только в том, что здесь этих Inventory несколько в виде рядов товара на прилавке, которые подготовлены заранее. Это можно сделать и в "обычном" подходе. Вместо одной записи Inventory в базе будет 10, и время ожидания будет N×t/10.

Покупатели сначала выстраиваются в очередь к нашему супер-раздавателю колбас, а потом — к кассиру.

В "обычном" подходе всё то же самое, про резервирвание уже написали. То, что вы называете N×t, это ожидание резервирования. В вашей очереди к раздавателю последний будет точно так же ждать всех предыдущих то же самое время N×t.
В "обычном" подходе мьютексы на весь процесс покупки обычно не делают, один платит через PayPal, другой банковской картой, зачем им друг друга ждать?

и просто забить на потерявшиеся колбасы (этот вариант неприменим, если магазин ...)

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

API магазина блокирует не чужие деньги, а свой товар на своем складе.

эти высокие древовидные иерархии ООП работают так себе

А при чем тут древовидные иерархии? Разговор про инкапсуляцию в одном классе.

Нет, так делаете вы. Я написал "можно", а вы заменили это на слово "должны" и сделали утверждение, что я так сказал.

То, что вы плохо владеете русским языком

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

можно
"Есть возможность. Разрешается, позволительно."
должен
"Обязан сделать что-н."

Выражение "можно поставить дизлайк" ни в каком смысле не является декларацией "люди должны так делать".

именно что нет

Ну тогда какие претензии? Объектная модель не обещала вам математической консистентности. Если она вам нужна, используйте совместно с объектной моделью тот инструмент, который эту консистентность обеспечивает. А у вас получается "Молоток мешает делать хорошую работу, потому что не умеет откручивать шурупы".

математическое доказательство консистентности
мешает писать хороший код

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

Мне никогда не было нужно доказательство математической консистентности. В физическом мире ее вообще нельзя гарантировать. Для меня хороший код это в первую очередь понятный код.
Есть книга под названием "Совершенный код", много разработчиков считают ее хорошей. Там тоже нет ничего про доказательство математической консистентности. Зато есть про понятность и выразительность.

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

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

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

А при чем тут ООП? Так можно сделать в любом языке.

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

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

Вы никогда не выражали никакого неодобрения

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

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

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

Лично я исхожу из того
Короче говоря, я сам минусую те статьи

И почему вы решили, что ваше понимание самое верное, и все должны так делать?

просто объясняю свою точку зрения

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

часто минус ставят вместо комментария

Если мою точку зрения уже написал кто-то другой, и я с ней согласен, зачем я должен писать то же самое еще раз? И читать 20 похожих комментариев вместо 20 минусов мне тоже не хочется.

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

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

Есть только два варианта разрешения конфликта: 1 блокировать монетоприёмник и считыватель карт пока турникет открыт,
1 нарушает инкапсуляцию (потроха нашего FSM экспортируются в прошивку железяк самого турникета)

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

или 2 накапливать «проходы» и не закрывать турникет
2 невозможен в ООП без плясок с бубном

Очередь и FSM это 2 разных компонента. Если вы хотите накапливать события, очередь вам нужна будет хоть с ООП, хоть не с ООП. Если не хотите, не нужна. ООП тут ни при чем, как вам надо по задаче, так и делаете. Непонятно, почему вы ждете, что FSM в стиле ООП будет вам магически сам очередь обрабатывать.

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

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

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

Что-то предпринять, определенно, надо
Но что именно — мы не знаем, потому что (та-дам!) инкапсуляция.

В вызывающем коде знаем. Что именно надо предпринять, зависит от вызывающего кода, а не от вызываемого.
Это как если бы начальник вас спросил "Слетай на Луну, принеси мне лунного грунта - Это не входит в мои рабочие обязанности - Что мне делать с этим ответом?". Вы бы сказали "Что хотите, то и делайте, я же не знаю нафига вам лунный грунт". А если бы не сказали, то подумали.

код не отработал, как было задумано

Если в коде явно написано return errorCode, значит это было задумано. То есть была предусмотрена эта ситуация и написана обработка для нее.
Там может быть и return Enum.ValueA; ... return Enum.ValueB; ... на 10 значений. Какое из них не было задумано?

практически невозможно имплементировать на объектной модели, не потеряв математическое доказательство консистентности

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

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

Ну вы же спорите со значением термина, который придуман каким-то дурачком.
Какой источник вы привели в статье, про тот я и говорю. Если вы считаете, что в Википедии написано неправильно, непонятно, зачем вы тогда его приводили. Вы можете привести тот источник, определение в котором соответствует вашему пониманию?

Конечно, конечно.

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

Нельзя же минусовать за аргументированно высказанную позицию, просто потому, что ты с ней не согласен

А за что тогда можно минусовать? Минус это и есть выражение несогласия. На английском это называется еще более явно - "дизлайк", что означает "не нравится". Если я не согласен, значит по этому критерию статья мне не нравится. Не нравится, значит можно поставить дизлайк.

encapsulation prevents external code from being concerned with the internal workings of an object
Инкапсуляция должна бы запретить любое изменение внутреннего состояния сущности (объекта) извне любым способом, кроме специально разрешенных автором.

Почему у вас "prevents external code from being concerned" вдруг превратилось в "forbids external code to be able to change"? "Сoncerned" и "change" это же не синонимы. Если вызывающий код не имеет доступа к private-полям, то он уже "prevented", потому что вы можете переименовать поля эти поля и поменять их типы, не меняя вызывающий код.

на балансе есть сумма снятия
не дает выходить балансу в минус

Это одно и то же, только одно проверяется до уменьшения баланса, второе после. Если нет нужной суммы, то после снятия будет минус. То есть это условие в WHERE будет false тогда и только тогда, когда констрейнт тоже будет false.

Как? Не писать на PHP.

При чем тут именно PHP? Вы не верите, что я могу на Java написать то же самое? Там отличие только в синтаксисе.

Я к тому, что ditry, ugly наработки не стоит описывать

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

Зачем до этого ставить select, какой в нём смысл?

Вот еще один пример.

class AccountController {
  public function withdraw(int $accountId, Money $amount) {
    $account = $this->accountRepository->findOne($accountId, needLock: true);
    if ($account === null) {
      return $this->notFoundResponse();
    }
    
    $result = $this->accountService->withdraw($account, $amount);
    $this->accountRepository->unlock($account);

    if ($result instanceof ErrorList) {
      return $this->validationErrorResponse($result);
    }
    
    $newAccountState = $result;
    return $this->successResponse([
      'id' => $newAccountState->id,
      'balance' => $newAccountState->balance,
      'currency' => $newAccountState->currency,
    ]);
  }
}

class AccountService {
  public function withdraw(Account $account, Money $amount): Account|ErrorList {
    $validationErrors = $this->accountService->isWithdrawAllowed($account, $amount);
    if ($validationErrors->isEmpty()) {
      return $validationErrors;
    }
    
    $account->balance -= $amount->value;
    $this->entityManager->save($account);
    
    $this->sendMessageToKafka(['type' => MessageType::Withdraw, 'account' => $account]);

    return $account;
  }
  
  private function isWithdrawAllowed(Account $account, Money $amount): ErrorList {
    $errors = [];
    
    if ($account->state === AccountState::FROZEN) {
      $errors[] = 'Account is frozen';
    }
    
    if ($account->currency !== $amount->currency) {
      $errors[] = 'Currency does not match';
    }
    
    if ($account->balance <= $amount->value) {
      $errors[] = 'Insufficient balance';
    }
    
    return new ErrorList($errors);
  }
}

class Account {
  public int $id;
  public Decimal $balance;
  public Currency $currency;
  public AccountState $state;
}

Покажите, как вы напишете эту логику без SELECT.

А, так у вас "1" в "balance >= 1" это diff, а не ожидаемое значение баланса! Из вашего описания в статье это непонятно.
Тогда непонятно, зачем вообще нужно это условие в WHERE, оно делает то же самое, что и констрейнт "balance >= 0", который проверяется после UPDATE.

Зачем до этого ставить select, какой в нём смысл?

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

Приведите тесткейс бага.

Был Postgres под рукой, решил проверить.

SQL
create or replace function decreaseBalance(accountId int, diff decimal, sleep int) returns decimal language plpgsql as
$$
declare initialBalance decimal; finalBalance decimal;
begin
    select balance from account where id = accountId into initialBalance;
    perform pg_sleep(sleep);
    update account set balance = balance - diff where balance >= initialBalance and id = accountId
    returning balance into finalBalance;

    return finalBalance;
end;
$$;

create or replace function increaseBalance(accountId int, diff decimal, sleep int) returns decimal language plpgsql as
$$
declare initialBalance decimal; finalBalance decimal;
begin
    select balance from account where id = accountId into initialBalance;
    perform pg_sleep(sleep);
    update account set balance = balance + diff where balance <= initialBalance and id = accountId
    returning balance into finalBalance;

    return finalBalance;
end;
$$;

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

select increaseBalance(1, 10,  8) as res1;
select decreaseBalance(1, 10,  4) as res2;
select decreaseBalance(1, 10, 12) as res3;
-- 100 90 90

Так все запросы выполнятся, финальный баланс 100 - 10 + 10 - 10 = 90.

select increaseBalance(1, 10, 16) as res1;
select decreaseBalance(1, 10,  4) as res2;
select decreaseBalance(1, 10, 12) as res3;
-- 100 90 null

А так второе списание не выполнится, хотя отличается только порядок коммита транзакций, финальный баланс 100 - 10 - 0 + 10 = 100.
То есть если пользователь покупает товар в интернет-магазине и одновременно приходит списание за подписку на Netflix, то одна транзакция будет сбойная, и ее придется повторять.

select increaseBalance(1, 10, 16) as res1;
select decreaseBalance(1, 10,  2) as res2;
select decreaseBalance(1, 10,  2) as res3;
select increaseBalance(1, 20,  4) as res4;
-- null 90 null 110

А так не выполнится одно пополнение и одно списание, финальный баланс 100 - 10 - 0 + 20 + 0 = 110. То есть половина операций будут сбойные, при том что баланса достаточно для всех операций. Для высоконагруженного ресурса, который часто меняется, такие сбои транзакций будут происходить постоянно.
С блокировками все операции выполнятся без сбоев в порядке поступления.

Information

Rating
2,039-th
Location
Россия
Registered
Activity