Warning: Undefined array key 0 in /var/www/tgoop/function.php on line 65

Warning: Trying to access array offset on value of type null in /var/www/tgoop/function.php on line 65
61 - Telegram Web
Telegram Web
import __hello__
Хочу поділитись невеличким переліком проблем які я найчастіше бачу у тестах 1. Робити мок того що тобі не належить, наприклад http-клієнта Коли ви мокаєте зовнішній компонент, ви замінюєте його спрощеною версією, яка може не відображати його реальну поведінку.…
Ось ще вам дуже старий повчальний комікс про те що треба робити коли ви знаходите багу.

Перед тим як виправляти баг спитайте себе:
1. Чи допускав я цю помилку деінде?
2. Що станеться, коли я виправлю цей баг?
3. Що я можу зробити, щоб цей баг не виник знову?

Лінки:
- The day I started believing in Unit Tests
- Three Questions About Each Bug You Find
Тепер я цифровий археолог

Читав про історію пайтона, як він змінювався, як ставав популярним і зацікавився а які ж були його перші версії.

Погуглив сорці та збілдив усе у докері, ось тут можна подивитись. На диво, скомпілювати проєкт 30-річної давнини виявилось відносно легко.

У підсумку для тесту я зібрав 3 версії:
- 0.9.1 (1991), тому що цікаво якою була найперша публічна версія Python (звісно першою була 0.9.0, але різниця лише у один патч)
- 1.0.1 (1994), бо цікаво що змінилось і яким був перший мажорний реліз
- 1.6.1 (2000), щоб подивитись на останній реліз 1 версії

Отже що мені здалось цікавим:

Привітання різне у всіх версіях:

0.9.1

>>>

1.0.1

Python 1.0.1 (Jan 8 2024)
Copyright 1991-1994 Stichting Mathematisch Centrum, Amsterdam
>>>

1.6.1

Python 1.6.1 (#1, Jan 8 2024, 18:22:00) [GCC 4.7.4] on linux6
Copyright (c) 1995-2001 Corporation for National Research Initiatives.
All Rights Reserved.
Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
All Rights Reserved.
>>>


Юнікод у змінних не підтримується (принаймні у REPL):

>>> ї = 1
Parsing error: file <stdin>, line 1:
��ї = 1
^
Unhandled exception: run-time error: syntax error
>>>


help у REPL ще немає ніде, але exit у 1.6.1 у наявності

>>> exit
'Use Ctrl-D (i.e. EOF) to exit.'


getattr, setattr наявні вже у 1.0.1, але delattr відсутній (у 1.6.1 вже є)

Синтаксису import foo as bar ще не існує, проте вже є from foo import *

Немає bool, замість нього використовують 1 та 0

Особливості 0.9.1 (наявні лише у цій версії):
- не сприймає " лапки, видає syntax error
- при написанні класу треба обовʼзково вказувати () навіть якщо у нього немає суперкласу (class Foo():)
- __init__ ще не існує
- щось з наслідуванням, може його немає, бо методи суперкласу не доступні у його спадкоємцях
- ще немає and, or та is

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

Далі я вирішив зробити більш показовий тест - узяв код який написав на 3.11 коли вирішував AOC і спробував його портувати на старі версії поступово.

Про очевідні речі типу f-strings чи відсутніх модулів писати не буду, хто захоче - дивіться gist, там більш докладно.

З 3.11 на 1.6.1:
- Генератори та включення зʼявились лише у 2 😢
- Змінної __file__ ще не існує
- Синтаксис i += 1 ще не підтримується
- __eq__ та __slots__ також немає

Зрештою 1.6.1 відчувається дуже непогано, мені знадобилось зовсім мало часу щоб заставити код працювати, відчуття що це зовсім інша мова немає.

З 1.6.1 на 1.0.1:
- Мультилайн стрінги ще не завезли
- Стрінги здається що взагалі не обʼєкти, у них немає жодних методів чи атрибутів, усі операції над ними треба робити через модуль string
- int("42") не працює, замість цього string.atoi("42")
- Розпаковка (a, b = func()) працює лише з таплами, а функції tuple() немає 😁
- Немає assert
- У "%s" % (val,) val не може бути числом, параметри не приводяться автоматично до типу string
- Виключення це звичайні строки, тож user-defined виключення це raise "My exception", ValueError (навідміну від Exception) існує, але це звичайна змінна яка зберігає строку

Портувати код на 1.0.1 вже було більшим викликом, довелось написати свої примітивні асерти, та підгледіти функцію tuple

Написання коду на 1.0 мені здалось схожим на написання коду на Go 😁. У тому сенсі що стдліб малий, сахару мало, багато дуже простих речей доводиться писати самому. Але як для релізу якому 30 років, ну прям дуже непогано.

Цікаво що перший реліз мови не так вже й кардинально відрізняється від актуального сьогодні. Багато концепцій існувало від самого початку і її розвиток відчувається як поступова еволюція. І я тепер розумію звідки у стдлібі зʼявився модуль string (він доступний досі) і нащо він треба був 😁

Якщо хтось хоче сам потикати у раритет - можете скористатись імейджами що я створив

Про історію Python:
- A brief history of Python
- How Python Became the Popular Choice
Clean Architecture isn't understood by article authors

Один із улюблених постів на реддіті про помилки які найчастіше допускають автори статей про Clean Architecture. У коментарях зазначили що це мабуть через те що Роберт Мартін поганий письменник (і поганий комунікатор, і погана людина, і поганий гравець у гольф 😄)

Тож перелік того що найчастіше люди неправильно розуміють у CA:

- Контролери (або Презентери або ViewModels) зовсім не теж саме що і Use-Case Інтерактори. Контролери не мають містити логіки, а мають просто викликати методи Інтеракторів. Єдина логіка що вони можуть містити - мапити дата обʼєкти контролера у доменні ентіті.
- Юніт-тести майже виключно повинні писатися для Інтеракторів (а не для кожного маленького класу).
- Юніт-тести мають заміняти вам Acceptance та Функціональні тести. Ви не повинні писати E2E UI тести якщо використовуєте Clean Architecture. Юніт-тест повинен безпосередньо описувати користувацьку історію. Кожен крок у цій історії це "unit".
- Єдині моки що ви використовуєте у своїх юніт-тестах мають бути для output портів, що зазвичай означає DAO інтерфейси.
- Юніт-тести ніколи не повинні запускати код адаптерів. Дивись попередній пункт (здається що більшість це розуміють).
- Інтеграційні тести потрібні лише для перевірки ваших адаптерів, а не тестування бізнес-логіки.
- Автоматизовані тести GUI (наприклад, selenium) повинні писатись лише як smoke-тести. Вони просто перевіряють, що все працює разом, як супер-інтеграційний тест. Таких тестів повинно бути дуже мало.
- Дата об'єкти специфічні для Адаптерів не повинні перетинати межі портів (port boundaries). Наприклад, модель ORM обʼєкту не повинна бути доступна для об'єкта сервісу або Інтерактора. Інтерфейс DAO (тобто порт) повинен повертати доменні сутності замаплені з сутностей БД (здається що більшість це розуміють).
- Домен, сутності та інтерактори не повинні бути побудовані фреймворками. Вони повинні бути простими об'єктами.
- Звичайно, можуть бути прагматичні винятки з усього вищезазначеного, але мінімально.

Усе вищесказане також валідне й для Гексагональної Архітектури і архітектури Портів та Адаптерів, так як вони майже ідентичні CA.
Усі ж чули про ruff? Це такий лінтер all-in-one для пайтону написаний на Rust. Головна його конкурентна фішка - це швидкість, він дійсно значно швидший ніж будь який інший лінтер для пайтону, вміє автоматично фіксити код, а ще у нього можливо навіть інтегрують black та mypy.

Останній рік він був на хайпі - новини, твіттер, різні проєкти переводили на нього свої CI (один із таких проєктів FastAPI). А нещодавно автори цього лінтера заснували свою компанію Astral яка одразу ж підняла 4 мільйони доларів.

Мені уся ця метушня навкого ruff не подобається з таких причин:

1. Автори беруть вже існуючі лінтери та переписують їх на Rust (не хочу вчити раст щоб писати собі тулінг).
2. Плагіни для flake8 продовжують розвиватись і оновлюватись і ruff не завжди встигає за цим стежити. Та й взагалі імплементація у ruff може відрізнятись від оригіналу чи не містити частини функцій
3. Навідміну від flake8 ця штука моноліт і не має системи плагінів. Тобто якщо для flake8 я можу написати свій плагін, опублікувати його у pypi, використовувати й росповсюджувати, то для ruff мені треба робити МР у їх проєкт, чекати апрувів (якщо вони будуть) і чекати поки то потрапить у нову версію
4. Найбільша моя претензія - Python розробники не можуть вносити вклад у лінтер для пайтону, бо він написаний на зовсім іншій мові (дивись попередній пункт, навіть плагіни писати не можуть на расті). А дивлячись на зростаючу популярність ruff у мене це викликає побоювання що через нього flake8 та інші лінтери написані на пайтоні перестануть розвиватись, як наслідок - уся екосистема лінтерів буде залежати від проєкту на расті у котрий контрибьютить 2.5 розробника.

А ось сьогодні Anthony Sottile, мейнтейнер flake8, багатьох плагинів для flake8 і інших різних лінтерів висказав свою думку на рахунок ruff у відео. Якщо коротко:

1. Ruff це дуже вражаюче ПО яке робить багато крутих штук.
2. Автори Ruff скопіювали дуже багато результатів роботи пайтон комьюніті (специфічно частину яка про лінтери) за останні 15-20 років та переписали їх на Rust
3. Попередній пункт звісно не порушує жодних ліцензій (ліцензії коду який за основу взяв ruff це дозволяють)
4. Претензія Anthony у тому що ruff узяв результати роботи і нічого не віддав взамін
5. Більше того, була заснована компанія навколо ruff, яка зібрала 4 мільйони доларів і жодна частина цих коштів не була віддана на спонсорство flake8 чи інших проєктів без яких ruff просто би не існувало
6. Anthony засмучений через те що ruff "вбив" багато проєктів над якими він працював і він більше не бачить стимулів далі працювати над цими проєктами
7. Ruff це дуже вражаюче ПО, але їх підхід брати результати чиєїсь роботи і не віддавати нічого взамін "kinda sucks"

Звісно автори ruff мали повне право зробити те що вони зробили, але з етичної точки зору це не зовсім ок, і я розумію автора відео.

Я на ruff не спішив переходити з причин описаних у першій частині цього тексту і ще через те що у нього немає деяких плагінів котрими я користуюсь, а швидкість flake8 достатня, особливо якщо використовувати pre-commit котрий вміє запускати лінтери лише для змінених файлів. Тому я на ruff світчитись не планую і сподіваюсь що у flake8 та взагалі у лінтерів для пайтону написаних на пайтоні все буде добре.
Моноліт, мікросервіси, поліліт?

У сучасному світі розробки поширена думка, що моноліт застарів, а мікросервіси — єдиний правильний шлях побудови систем. Звісно, я трохи перебільшую, тим паче що час, коли кожна поважаюча себе компанія, мала у своєму блозі статтю про перехід від моноліту до 300 і більше мікросервісів, минув. Проте й досі часто розробники при старті нового проєкту одразу починають з мікросервісної архітектури. Але скоріш за все то не дуже гарна ідея і почати варто б було з побудови моноліту.

Бо починаючи новий проєкт, ви ще не знаєте, як правильно вибудувати bounded context і не розумієте меж доменних областей. Тому, у процесі розробки, вони будуть змінюватися: деякі сутності переходитимуть з одного контексту в інший, контексти дробитимуться та об'єднуватимуться, бізнес вимоги будуть постійно змінюватись. Таким чином, ваша система буде інтенсивно еволюціонувати, поки ви шляхом проб та помилок не визначите правильні межі. Такі великі зміни робити коли у тебе все побудовано на мікросервісах досить боляче. Більш доцільно почати з моноліту, а в процесі розробки та експлуатації, коли будете впевнені в правильності визначених bounded contexts, поступово "від'єднувати" частини системи в мікросервіси. Звичайно, не варто створювати мікросервіси лише тому, що так роблять усі. Це має бути обгрунтовано: можливо, частина вашої системи має вище навантаження і, виносячи її в окремий сервіс, ви зможете ефективніше масштабуватись; або в різних частинах системи можуть бути різні SLA та вимоги до безпеки; чи ви хочете передати частину системи в управління окремій команді, тощо. Гарний допис про те чому не варто стартувати з мікросервісів є у Мартіна Фаулера

Проте, ті, хто хоч раз спробував розділити вже існуючий, можливо застарілий, моноліт, скажуть, що це не просто. Сильна сторона моноліта "легкість змін" має зворотній бік — дуже легко побудувати систему із високою зв'язністю (high coupling), через що розбиття моноліту на окремі мікросервіси може бути настільки складним, що простіше переписати систему з нуля. Тому, щоб вирішити цю проблему, розумні люди придумали таку штуку як "модульний моноліт".

Модульний моноліт — це архітектурний прийом, що поєднує елементи монолітної архітектури з модульним підходом. Код розділений на модулі з чіткими межами в рамках одного додатку. Кожен модуль відповідає за певну функціональність і характеризується високою когезією та слабкою зв'язністю з іншими модулями. Слабка зв'язаність досягається завдяки комунікації між модулями через добре пропрацьований публічний API. Модулі можуть взаємодіяти як через прямі виклики методів, так і асинхронно через черги повідомлень, що ускладнює проектування, але спрощує перехід до мікросервісів (у разі необхідності). Кожен модуль представляє окремий bounded context, тож, якщо потрібно розділити моноліт на мікросервіси, це буде легко зробити. Ще один плюс такого підходу - ви можете ділити модулі між командами, тобто одна команда може ексклюзивно овнити один чи декілька модулів.

Більш детальний приклад модульного моноліту можно подивитись тут

Можливо, наступного разу розповім про наявні інструменти для Python, що сприяють побудові модульних монолітів.

Лінки:
- Дуже багато матеріалів по темі
- Monolith First
- Microservices Killer: Modular Monolithic Architecture
- microservices.io
Відосики про нормалізацію та денормалізацію SQL БД. Загальна інфа, але може бути корисною тим хто до співбесіди готується, освіжити знання, чи просто подобаються технічні відосики з гарним відеорядом.
Тут Dave Plummer твітнув дуже повчальну історію про те як він у 94 році накидав тимчасовий UI для діалогу форматування диску у WindowsNT. І ось вже минуло 30 років, а ви й досі у актуальній версії Windows можете відкрити цей "тимчасовий" діалог і подивитись на результат його роботи 😁

Мораль всім відома - немає нічого більш постійного аніж тимчасове, тому коли робите щось "тимчасове" у кодовій базі, потурбуйтесь про те щоб воно було достатньо оптимальне і вам не довелось надто червоніти за свої рішення, бо скоріш за все результати вашої роботи буде спостерігати ще не одне нове покоління програмістів 😁

Доречі у цього чувака є прикольний канал на ютубі про DIY, C++ та історію Windows.

Лінки:
- https://twitter.com/davepl1968/status/1772042158046146792
- https://www.youtube.com/@DavesGarage
Вийшов новий Technology Radar. Із цікавого (мені):
- Text to SQL in Trial (новий)
- CloudEvents in Adopt (піднявся із Trial)
- Pulumi in Trial (минулого разу також був у Trial)
- Rancher Desktop (новий, витиснув Colima)
- Kaniko in Adopt (минулий раз згадували у 2022 році)
- Mojo in Assess (новий)

Знов багато AI та не дуже багато чогось кардинально нового. Але може хтось для себе щось цікаве відкриє (мені не вдалось цього разу, хіба що Kaniko)

https://www.thoughtworks.com/radar
Forwarded from Алекс про усе
Дядько Боб на твічі – залітайте)

https://www.twitch.tv/ThePrimeagen

P.S. Це автор багатьох книг по програмуванні і хорошому коду. Якщо не читали дуже рекомендую
Додивився серіал по Fallout і ось що я можу сказати як фанат 1, 2 частини, New Vegas та хейтер частин від Bethesda.

Загалом непоганий серіал, на 3 з плюсом. Із бісячого:
- Антураж схоже що взяли за основу із 4 частини - замість похмурого і сірого цвітасте та веселе
- Постанову масових перестрілок та бійок взагалі з трейлерів 4 та 76: всі бʼються під веселу музичку у слоумо
- Головний герой знову шукає свого родича, знов батька - або сценаристи Bethesda мають якісь дитячи травми, або вони великі фанати останніх Форсажів (головне - сімʼя), інших пояснень у мене немає
- Немає супермутантів
- Взагалі дуже мало канонічних монстрів, мабуть бюджет не дозволив
- Кігтя смерті показали лише у якості черепа
- Персонажів гри, які могли дожити до часу у який відбуваються події серіалу немає, хоча тут я може неуважно дивився
- Якась дурня із штукою за котрою увесь сезон полюють усі кому не лінь

Із того що сподобалось:
- Братство Сталі - покидьки
- Показали молодого Містера Хауса
- Не було відсилок до Легіону
- Загалом є відсилки до New Vegas, а другий сезон можливо взагалі буде про Вегас

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

Так, це все ще канал про IT)
Добре, поки мене не було я не лише серіали дивився, я також встиг написати ще одну DI бібліотеку для Python 😎.

Навіщо то взагалі у Пайтоні? Ну сама концепція DI це дуже крута штука, яку можна використовувати будь де без усіляких фреймворків. Але у такому разі треба самому бутстрапити залежності при старті апки і думати як оверайдити залежності у тестах. До того ж скоріш за все це все скатиться у service locator та нескінченні if my_service is None: my_service = get_my_service().

Раніше я користувався dependency-injector. Це чудова ліба, але вона завжди здавалась мені дуже навороченою для моїх цілей. І якщо на робочих проєктах її використання ще якось було виправдано, то для маленьких pet-проєктів це точно оверкіл - я завжди починаю з перечитування документації перш ніж засетапити новий проєкт із цією лібою. До того ж вона вже 2 роки не розвивається, тому я почав шукати альтернативи.

Мені подобається концепція DI у FastAPI - залежності це звичайні функції, ніяких контейнерів чи цілої пачки різних типів провайдерів - якщо хочеш щоб твоя залежність була кешованою - просто оберни її у lru_cache.

Із того що я знайшов цікавого у pypi:
- FastDepends - типу як у FastAPI, але із якимись лівими функціями, інколи скаржиться на аргументи які не мають інжектитись через тайп анотації, не має ресурс менеджменту і не може ніяк засунути async залежність у sync функцію, навіть якщо ми вже у async контексті, а ще не дуже дружить із FastAPI 🤯
- picobox - дуже крута концепція, але функціонал в основному зусереджений на Scopes (щоб залежності кешувались як сінглтон, у треді, у асінк тасці, реквестах, тощо), не має ресурс менеджменту і не дуже дружить із тайп анотаціями
- injector - стара ліба, мабуть непогана, але мені ніколи не подобався її API
- di та rodi - це більше схоже на ресолвери залежностей, над якими ще треба побудувати свій зручний API, хоча я може і помиляюсь

Тобто нічого із того що я знайшов мені не підходить. А мені усього то потрібно:
1. Власне інжекція залежностей у аргументи функцій, було б гарно якби як у FastAPI
2. Менеджмент ресурсів - щоб можна було зробити залежність яка має teardown і кешує свій результат впродовж життя апки - зручно для конекшенів у БД
3. Можливість оверайдити залежності для тестів
4. Зручний API і без зайвих можливостей

Тож я написав picodi (спочатку це мало бути nanodi, але pypi сказав що імʼя дуже схоже на вже існуючу лібу і не дав створити із такою назвою)- по суті це декоратор котрий резолвить (просто викликає функцію) залежності і сує їх у декоровану функцію, усе. Із додаткових можливостей - ресурс менеджмент, оверайдинг залежностей, працює із FastAPI і бонус - можливість резолвити асинхронну залежність-ресурс у синхронну функцію і ніякого вайрінгу (і ніякого детекту циклічних залежностей також 😁). Можливо імплементація трохи наївна, але поки мені подобається - я вже замінив dependency-injector на декількох своїх pet-проєктах без якихось проблем.

Тож якщо у когось з вас є схожі вимоги до DI фреймворку - можете спробувати, та не соромтесь робити issues та PR's 😊.

https://github.com/yakimka/picodi
У Django зʼявляться background workers

Декілька днів тому прийняли DEP-14, наступним кроком буде власне імплементація. Як я зрозумів вони просто зроблять django-tasks частиною Django.
Не те щоб мене ця новина якось обходила, бо я вже давно з Джангою справ не маю (ну майже) але це гарна пропозиція, бо майже будь яка апка на Django трохи більша ніж hello world потребує можливості запускати таски у фоні, а не заставляти юзера чекати її виконання.
Усі для цього використовували Celery, але ця ліба досить велика та потужна і до того не завжи тривіальна у налаштуванні і коли тобі треба зробити лише одну-дві простих дії у бекграунді то тащити цю монструозну лібу не дуже хочеться.
Ну от тепер і не треба буде - у Джанзі і для цього тепер буде рішення "із коробки".
import __hello__
Добре, поки мене не було я не лише серіали дивився, я також встиг написати ще одну DI бібліотеку для Python 😎. Навіщо то взагалі у Пайтоні? Ну сама концепція DI це дуже крута штука, яку можна використовувати будь де без усіляких фреймворків. Але у такому…
Доречі, коли хочеться почати свій пет-проєкт який щось для мене покращить, чи просто just for fun, то треба якнайшвидше приступити до реализації, поки не перегоріло.
Бо поки засетапиш проєкт: додаси лінтери, сконфігуруєш їх, наставиш улюблених плагинів для пайтеста, напишеш Makefile, напишеш workflow для github actions (клятий github actions) - вже пройде декілька днів і бажання щось робити пропаде 😁.
А просто робити щось без цієї автоматизації і собі ж дорожче і не в кайф.

Тому одного разу я зробив собі шаблон для python-проєктів і одразу відчув користь:

- Не треба переносити сетап із минулого проєкту попутньо вирізаючи неактуальні частини конфігів і роблячи перейменування
- При створенні проєкту з шаблону можна робити різні налаштування і включати\виключати потрібні компоненти в новий проєкт. Наприклад якщо планується використовувати pydantic - одразу додати відповідний плагін до mypy
- Так як шаблон це тепер також мій окремий проєкт - він так само як будь який інший проєкт еволюціонує
- Dependabot допомагає слідкувати за актуальністю залежностей у шаблоні

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

Лінки:
- Cookiecutter - менеджер для таких от шаблонів. Не обовʼязково шаблон має бути для пайтона - це може бути шаблон будь чого, навіть не обовʼязково звʼязаний із програмуванням
Подивився на ютубі інтервʼю з чуваком, який переписав кафку.

⁃ написали все на golang. Сказав, що це мова, до якої немає питань. Типа вони з напарником ніколи її не обговорюють, а просто деліверять фічі;

⁃ в якості стореджа використовується S3. Це дає доволі суттєву економію, порівняно з EBS (що є по суті клаудним NAS на SSD). По суті це реальний cloud native storage, який може скейлитись до нескінченності і має майже 100% SLA. Недоліком є трохи вища latency;

⁃ хочуть повністю повторити протокол kafka, зараз вже все є, крім транзакцій. По суті це drop in replacement для кафки, і існуючі клієнти можуть перемкнутись на їхній сервіс без змін (якщо там немає транзакцій);

⁃ ноги у проекта ростуть з DataDog -- на початку є пара цікавих інсайдів про внутрянку останніх;

⁃ під час написання намагаються не дивитись на код kafka (який на java), натомість використовують код альтернативних клієнтів. Бо протокол дуже складний, мало документований, а в сторонніх клієнтах часто можна знайти коменти про реалізацію підтримки нововведень і різних corner cases

В цілому дуже сподобалось і саме інтервʼю, і проект який вони замутили. Ось посилання, якщо хочете подивитись самі: https://www.youtube.com/watch?v=xgzmxe6cj6A. Крім того, шо я тут написав, там багато цікавого про реалізацію, виклики, що стоять перед подібними системами, мотивацію і тд.

А це власне їхній стартап: https://www.warpstream.com/
Натрапив на просторах реддіта на репозиторій із переліком штук про котрі треба пам'ятати коли пишеш веб-сервіс на FastAPI.
Їх там зараз небагато, але всі дуже важливі. Мене найбільше зацікавив 9 пункт "Your dependencies may be running on threads" -
це може бути неочевидним, але якщо ваша async def view використовує синхронну залежність (навіть якщо вона нічого не робить а просто повертає примітивне значення)
то резолвінг цієї залежності буде відбуватись у тредпулі.

Тобто ось у цьому прикладі буде використовуватись тредпул незважаючи на те що root view використовує async def:


from fastapi import FastAPI, Depends

app = FastAPI()

def get_42():
return 42

@app.get("/")
async def root(value: int = Depends(get_42)):
return {"value": value}


Чим це погано? Тим що треди не резинові і за замовченням одночасно може жити лише 40 тредів, і якшо на ваш ендпоінт буде наплив трафіку, то перші 40 реквестів забʼють
тредпул, а решта буде чекати поки звільниться місце. Звісно що значення по-дефолту можна підняти, але воно всеодно не буде нескінченним.
Виправити у прикладі вище цю проблему просто - замінити def get_42(): на async def get_42(): і тоді всі реквести
будуть запускатись без тредпула, просто у поточному event loop.

Підсумовуючи:
- Завжди у першу чергу використовуйте async def для вьюх (це вже й так всі запамʼятали) і залежностей що інжектяться через Depends.
- Синхронні вьюхи використовуйте лише якщо вони роблять блокуючі операції, наприклад використовують бібліотеку requests для http запитів.
- Перевірте свої додатки - у тому ж пункті є код за допомогою якого можна це зробити

Лінки:
- https://github.com/Kludex/fastapi-tips
Мабуть не відкрию ні для кого Америку, але метадата про кожний пакет у pypi, кількість скачувань і інша інформація доступна у публічному BigQuery.
Тож можна отримати будь яку цікаву для вас інформацію. Ось мені було цікаво знайти нові плагіни для flake8.


SELECT
name,
CONCAT('https://pypi.org/project/', name) AS project_url,
MAX(upload_time) AS most_recent_upload_time
FROM
`bigquery-public-data.pypi.distribution_metadata`
WHERE
name LIKE 'flake8-%'
GROUP BY
name
ORDER BY
most_recent_upload_time DESC


Звісно ганьба що pypi сам не дає способу нормально шукати по назвам та не показує кількість скачувань пакетів, але маємо що маємо.

Лінки:
- https://packaging.python.org/en/latest/guides/analyzing-pypi-package-downloads/#public-dataset
- https://console.cloud.google.com/bigquery?p=bigquery-public-data&d=pypi&page=dataset
У соурскоді sqlite 😁

За замовчуванням префікс був "sqlite". Але потім Mcafee почала використовувати SQLite у своєму антивірусному продукті, і він почав створювати файли з назвою "sqlite" у папці c:/temp. Це дратувало багатьох користувачів Windows. Ці користувачі шукали в Google "sqlite", знаходили номери телефонів розробників і телефонували їм уночі, щоб поскаржитися. З цієї причини префікс назви за замовчуванням було змінено на "sqlite", написане навпаки. Таким чином, тимчасові файли все ще можна ідентифікувати, але будь-хто, достатньо розумний, щоб зрозуміти код, також, ймовірно, достатньо розумний, щоб знати, що дзвінок розробнику не допоможе позбутися файлу.
import __hello__
Опублікували відоси із PyCon US 2024 https://www.youtube.com/playlist?list=PL2Uw4_HvXqvYhjub9bw4uDAmNtprgAvlJ
Виявляється що у coverage.py є альтернатива - Slipcover. Це така сама тулза для виміру покриття проєкту тестами але усього із 5% оверхеда у швидкодії (Coveragepy робить виконання вашого коду у три рази повільнішим, для порівняння).
На великих проєктах втричі більш швидкі тести це дуже суттєво.

Ще цікава штука, у цьому докладі автор обмовився що із 5% оверхедом це можна ганяти і у продакшені. Тобто можна запустити прям свій веб сервер через цю тулзу і побачити чи є у проєкті "мертві" куски коду, котрі ніколи не викликаються, прям богата ідея.
2025/06/25 23:07:02
Back to Top
HTML Embed Code: