Making reliable distributed systems in the presence of software errors (2003) [pdf]
%PDF-1.3
5 0 obj
<< /Length 737 /Filter /FlateDecode >>
stream
xڵUKO0WHc;>@b% eiEд;~4PV\\V=رy|̸0q"e\\%\*H-YD 9Ze2& Őg¨Ҡ3D=>mErX\\/ )=9>8IrA3H³J>\['\[R{89CRԿ8EXDMkUĿKRcRIX|m8vcM"mc-jjb|4ӍYJ+{A=4e16}{gρ\`sa(w 1}@+\\\\pȜc5AKt!}'n\\\[M8pe$ZQdP\`N\]͚Lۛ쨣Hg6GsBxfܱ ?jQ<ߵT{P̯?c)n\[y%̲OprN5~qxvHrz:T:vT7Q Iɩw4fQ+8V\[ %ͅt-x^\]z\]>ä́^ukK!zvXh#O&gCT fqkk5
endstream
endobj
4 0 obj
<< /Type /Page /Contents 5 0 R /Resources 3 0 R /MediaBox \[0 0 595.276 841.89\] /Parent 12 0 R >>
endobj
1 0 obj
<< /Type /XObject /Subtype /Form /FormType 1 /Matrix \[1 0 0 1 0 0\] /BBox \[0 0 143 73\] /Resources << /ProcSet \[ /PDF \] /ExtGState << /R8 13 0 R /R4 14 0 R >> >> /Length 15 0 R /Filter /FlateDecode >>
stream
xYn-;mVzn2#m@sǀ\\R#E?ſ߿GJm>k?kZ\_cߏҾv>K~Rr~>8J?3x>jK\_cxy+e\*o뫔/|篲g=|jv~PUOWW9K<+;><c϶\_kQZag<xk쉳q?(w ֝ Ip\_\`; }T?q\_ugnkQy߹uei<qw;a=pL\]'j\*#@=k5BLv~&4<yyZ:1y!&F|@yQU,8} 7q=6Aݶ\*g95\]\\T7Ky1PO9yb~nw.ڸQ~QzP· DZs«rUC\] 0C!K83{0\\ЮѪ\]C!S s+B/qҺsCrvks6}MYX=HPпC<Ӈs3?3Ϸa!9OM·ΎXŞ8|h'湻.3>-C @:k1>@y˹C\*X>p"ۂ @owԩv!X8a5-z-:Ʋyӛ2=;d\*繲9oAkY\_;,,=ᰐ3>R;"8l=ׄ>@>xݞ\\FyV!vY\]1w1ޘML9JJv9&#qzGmr>9E/ϓdྟ\_ov9, \]:$玚"#jyH灈Dsd@f"T~Gf\[tV">ƟWћňq\[qJ\[$V,KD)Q!xg\\ܚtpv7ҘBudm.$0#HKg8G V5lC/u9 l{ihs9C ;ajB٪> t|^P4vfAu$F0P ʥ.hDA9GyhȑtR 7 ښ^՟66:lĕb<Ү.$Jɻ(Ʋ~hAόBs~Q^|j9Xꂥ.~u:,%MT(zϰL:"(:t4݇/vk|eQq}t%I9jBY9L9\]N& #QK;bggwcYjUh\\PM8-Z%d3x~خ"+,Π£n zo~?^'-BZ}C0^bUq\[$"Jދ鳣&mu(0AP/dm{ę3>rP1-$$2đ7;TƃAg\\R$1#) mh 3~.b8fK'C/x9#\*N,}v89\`sb3\`8 \[S\*7g,v?3?ܷ ʾJ \[A?tSKBs\`y$Xu4ٟ|HdoܥfaDX%39.L=a\*0 #RnI0葡L&u;Ce+JMI\_Z^8tT0wJ#g|q2!3mԹ3"O~e;,D)Rı΅P# \[@y/.ϹG6s:t? eMf,\_B;PAXHG뇫b/+D<cflI.:eLט/l'B-HR \]$agra;{9rrs;UPymX4)iEf㕇qjS(;bedȑLtˆ &>߫HŖ)8퇀ˡeGA 9ݹ.\_U(61,%#t$gC&ʄ+SA)SHݍ\_NE%d̨RZpf ?dAH,͜c\*g(|@'13sdg\]\[Lw"{"hx<.#ob@E4$ i=ǃ4#{,<Y f^a&mVFS$dG2 hAB:Z{Q\_F т1>P$9PA<X{TdMBt=\\{9=CvOtO&E^JwM6'\]!9V|rɟTEyQX/> -|0&u$)i5,yץ}ceCGw\_ړm$)5 |>s"dؒdthjziYF%\\~ˤyKΈ+bK0g\\qtOT%,\*\_\\~9pϊBpCkB+@$\_s}Op^5efJDM\]-n. p)Rd7>Od0 \`J7Dmbs}t|)\`n3h\[V!ueX Cװd\`~>G:EͰ6q@cvKl |6\`ldwBÉo T=Iiw#Ar#tV:ܒA\`;\_J\`樼:4{OSH!H8!c3vavg{rmS<3,r8!UD0^0 1\`\`Nz\`{ſb$R\`wZ5~9kf\*OpZ |=,w$M x%;L%6R\_ :BYqOHRŬ.sw5g+(%h1y6\*kyVES\]@E,;DFxKY1oEnSeKz&Ƙ':rxwEb1\\!^pX\]=}2x7\_^v+\*~EU;A9-IIKTP,c(0v4@,8f qIwy-<@!Yg Վ.S4 2E\]AgG<dXY3<9\_5U>2|kӏ4^\[Gbڗa@h<)Y&\*bpG'td:\*o}탌Otda 2hyL\\Xdif\\ۀ-ZS#2 &h\\Yo~!7z8 LuÅCP\]k?}C0 F>Jз;,) Qb\[:ӬT\_n@@!=\`5^/Ed/pveU&lB>TVD-r3: \]pLE@lvIMd5Q{yœܰ'T~a >x @u\\8qhjqc 7 E \*\]Jʭ\`(2/ W%Wi:=PRB,+$ >;9HR\[,fßfRDʽdmܺ/<yE%<{8@Hшxvi}ό\_HEE-"-XJt6m}Fn{~gӼgŌ0~s|kW|b4wH5ﱥמo ڵ7JH@~(abe3Ы-nWNjNR1,dg|LBq+&\*BWiƥԕBJiʲcؽkl➱7&x\\B 5q.9:\]mRף>aFybU{r@aR=B~Q2p\\kRgƻ}2aax\`5Vq4\[0?&G'K$\[TѸQv&xZ Y/ឨ {^zVE\\̵Pp\] O;5k-5C+ 1.p{|do@սV,L>{X&ևɓB|CR/\*3>.sMX!G!P(8Z/ o}X< K)!?'Jx-->c TAi\_""GAyK~yw낇35>yR#?Grig\\3 ·0\\,sE 'Ss,GP83nbby@zqy\[@gL>+?O(hX={UL;m dI! FMV70\[w\_fW+E1sxbP,#\[BWpo\*I\[b"kD,?zoqr{BC-礌\*Y!Ԫ\*96͑k.?Ŕ(%z,MJйL0A:/{<+b<,@W>PmEkxX<bLqSDZMY=êbOÚֈsAe8CTuvYq\]Ѷ7pp 4' =LLo@xĸ?AӝEVXEaԲ5
Комментарии (16)
- Участники вспоминают Джо Армстронга и его ссылки на работу Джима Грея о Tandem.
- Отмечают, что Erlang/Elixir были технологически опережающими, но не стали массовыми.
- Идеи Erlang постепенно проникают в .NET и Java через Akka и Orleans.
- Удивляются, почему Erlang не используется даже в новых коммутаторах Ericsson, хотя был создан для них.
- Считают, что полное внедрение Erlang угрожает существующим бизнесам и рабочим местам, а рынок предпочитает «хуже, но дешевле».
Build durable workflows with Postgres
-
Выбор хранилища метаданных рабочих процессов оказался ключевым. Нужно было простое: чекпойнт состояния и восстановление после сбоя. Postgres выбрали за технические возможности, а не только за популярность и 40-летнюю проверку временем.
-
Масштабируемые очереди
Классическая таблица-очередь страдает от конкуренции: все воркеры пытаются взять одни и те же задачи. Postgres решает это черезFOR UPDATE SKIP LOCKED
: строки блокируются и пропускаются, если уже захвачены. Воркеры без конфликтов берут следующие N записей, позволяя обрабатывать десятки тысяч задач в секунду. -
Наблюдаемость
Каждый шаг сохраняется, поэтому можно строить дашборды и фильтры. SQL позволяет писать сложные запросы напрямую; индексы поcreated_at
,executor_id
,status
ускоряют выборки из миллионов записей без лишних затрат. -
Exactly-once для шагов с БД
Обычно гарантируется «по крайней мере один раз», но если шаг меняет данные в той же транзакции, что и чекпойнт, Postgres обеспечит, что изменения зафиксируются ровно один раз даже после перезапуска.
Комментарии (49)
- Пользователи хвалят DBOS за простоту миграции с graphile-worker и отсутствие необходимости менять инфраструктуру.
- Сравнения с Temporal, Azure Durable Functions, Inngest, Restate и Cloudflare: DBOS выглядит проще и легче, но Temporal/Cloudflare критикуют за сложность самостоятельного хостинга и высокую цену.
- Некоторые жалуются, что «сервер» DBOS (Conductor) не open-source, что ограничивает самостоятельное развёртывание.
- Планы по добавлению Java, C#, Go и поддержке сообщества уже анонсированы; Python и TypeScript уже поддерживаются.
- Отмечена возможность комбинировать DBOS с Dagster/Oban/pgflow для более сложной оркестрации.
Byte Buddy is a code generation and manipulation library for Java
Byte Buddy — библиотека для генерации Java-классов во время выполнения без компилятора. В отличие от встроенных средств, она позволяет создавать произвольные классы, а не только прокси по интерфейсам.
Поддержка
- Коммерческая: обучение, консультации, разработка — пишите rafael.wth@gmail.com.
- Общие вопросы: задавайте на Stack Overflow с тегом
byte-buddy
; для неформатных тем — рассылка. - Баги и фичи: issue tracker; пришлите пример кода и версию Java.
- Разработка: делайте pull-request; крупные фичи обсудите заранее в рассылке.
Проект ведёт Rafael Winterhalter с 2014 г.
Комментарии (27)
- В обсуждении сравнивают новый стандартный API для генерации байт-кода в JDK 24 (JEP 484) и старое решение ByteBuddy.
- Упоминают JavaPoet (теперь форк от Palantir) как удобный инструмент для генерации кода на уровне исходников.
- Micronaut показан примером фреймворка, избегающего runtime-генерации, делая всё во время компиляции.
- Поднимаются вечные споры «Java vs Kotlin»: кто-то считает Java «C для JVM», кто-то предпочитает Kotlin, а LLM якобы лучше понимают Java.
PHP compile time generics: yay or nay?
Кратко:
PHP-фонд предлагает реализовать только компиляторные обобщения (generics) для интерфейсов и абстрактных классов.
Синтаксис:
interface Repository<Item> {
public function find(int $id): Item;
}
class UserRepo implements Repository<User> { … }
- Все проверки типов происходят на этапе компиляции.
- Ошибки ловятся до запуска кода.
new Repository<User>()
по-прежнему невозможно, но и не усложняется.
Почему не полные обобщения?
Полноценные runtime-generics требуют сложного вывода типов и резко замедляют работу, особенно при объединённых типах и массивах.
Откуда идея?
- 2023-2024: эксперименты Arnaud Le Blanc показали, что 80 % пользы можно получить без 80 % сложностей.
- 2025: Gina Banyard разрабатывала «ассоциированные типы» и поняла, что их легко переформулировать как ограниченные обобщения.
Вопрос сообществу:
Поддержите ли вы такой вариант и проголосуете ли «за»?
Комментарии (50)
- В обсуждении разбираются плюсы и минусы добавления дженериков в PHP.
- Участники спорят, не приведёт ли это к «размагничиванию» типов, и объясняют разницу между reified (типы сохраняются в рантайме, как в C#) и erased (типы стираются, как в Java) дженериками.
- Поднимается вопрос: почему
class Repo<T> {}
труднее реализовать, чемclass BlogPostRepo extends BaseRepo<BlogPost> {}
. - Многие разработчики просят хотя бы строго типизированные массивы, считая их более полезными, чем полноценные дженерики.
- Часть команды уже использует PHPStan и strict_types, считая этого достаточным без изменений ядра языка.
We shouldn't have needed lockfiles 💬 Длинная дискуссия
Представьте, вы пишете проект и вам нужна библиотека — назовем ее libpupa.
Вы находите текущую версию 1.2.3 и добавляете в зависимости: "libpupa": "1.2.3" Автор libpupa 1.2.3 в свою очередь зависел от liblupa версии 0.7.8 и записал это: "liblupa": "0.7.8" То есть libpupa 1.2.3 навсегда зависит от liblupa 0.7.8. Алгоритм разрешения зависимостей простой и детерминированный: берем версии верхнего уровня, затем версии их зависимостей, и так далее. Достаточно указать только верхние уровни — транзитивные получатся одинаковыми всегда. Зачем отдельный lockfile?
Но люди изобрели lockfile из‑за диапазонов версий. Диапазоны делают сборку зависимой от времени: сегодня вы получите liblupa 0.7.8, через 10 минут — 0.7.9. Это определяется не при публикации, а при сборке: вы можете подтянуть версию, которой не существовало на момент выпуска libpupa 1.2.3. Откуда автор libpupa знает, что будущая 0.7.9 не сломает его код? Семантическое версионирование — это лишь намек, не гарантия.
И смешно то, что эти диапазоны все равно «замораживают» в lockfile, и вы не получаете предполагаемой пользы. «Перегенерируй lockfile и обновись» — это ничем не отличается от обновления верхнеуровневых зависимостей. «Lockfile решает конфликты версий?» — нет: библиотека либо работает с новой версией, либо нет; запись «0.7.*» не помогает — все равно нужно выбрать рабочую версию.
«Но раз lockfile существует, значит, нужен!» — не обязательно. Пример: Maven. Экосистема Java 20 лет обходится без lockfile, при этом тянет сотни библиотек — и все детерминировано.
Вывод: lockfile усложняет без достаточных причин. Менеджеры зависимостей могут работать без него.
UPD: В Maven при конфликте транзитивных зависимостей выбирается версия, ближайшая к корню. Это детерминированно и позволяет переопределять версии. Если вышла d 2.1 с патчами безопасности, добавьте ее в корень — она и будет выбрана, не дожидаясь обновлений у всех. Если автоматически брать самую большую версию, вы потеряете возможность переопределения.
Комментарии (267)
- Обсуждение крутится вокруг необходимости lock-файлов и версионирования: одни считают, что фиксированные версии и детерминированные алгоритмы достаточно, другие настаивают, что lock-файлы критичны для воспроизводимости и безопасности.
- Приводят примеры из экосистем Maven/Java, Go (MVS), Cargo/Rust, .NET, Scala: у каждого свои компромиссы; даже при детерминированном резолве сеть/репозитории делают сборки недетерминированными без lock-файлов и хэшей.
- Аргументы за версии-диапазоны: автоматическое получение патчей безопасности без вмешательства авторов верхнеуровневых библиотек; но это ломается при конфликтующих транзитивных зависимостях и несовместимых API/ABI.
- Много комментариев о том, что lock-файлы особенно нужны приложениям (прод, стейджинг, аудит), а для библиотек — меньше, но всё равно полезны из-за пересборок и целостности (хэши артефактов).
- Подчёркивают проблемы разных языков: в компилируемых — типы из разных версий несовместимы; в JS Node могут сосуществовать несколько версий, но это не решает безопасность/детерминизм.
- Некоторые отмечают, что главная путаница — не в lock-файлах, а в культуре семвера, централизованных репозиториях и UX инструментов; предлагают BOM/snapshot-подходы и периодические обновления с тестами/реновейтом.
- Отдельная ветка критикует дизайн сайта с анимированными иконками, мешающими чтению.