Částečně, co píše Jan Judas níže. Ono to v zásadě docela funguje, ale třeba:
- dependency injection je docela šílený, naprosto neflexibilní a v samotném principu porušuje IoC.
- asi trochu zvyk s Java, ale přijde mi přirozené používat class variables místo globals a opět poměrně limituje dependency injection.
- sqlalchemy: pydantic docela funguje na serializaci, ale pro ORM se musí všechno konvertovat. V Hibernate, když jsem třeba řešil i poměrně komplexní geo typy, tak jsem si vytvořil buď UserType nebo plugin a měl jsem automaticky podporu všude. sqlalchemy či geoalchemy vyžadovaly explicitní konverze.
Ne, že by to nešlo, ale ta vyspělost je někde jinde...
My jsme FastAPI použili na mock služby a na dvě prod. služby s fakt jednoduchým REST API s jen několika endpointy. A teď budu kontraverzní, ale pro tak "malé" věci ta struktura projektů s FastAPI byla ok (ostatně v malých měřítkách přestávají naše developerská pravidla platit obecně :-)
Některé úpravy byly až triviálně jednoduché. Například požadavek na caching dat poskytovaných jedním endpointem (ta data se načítala z jiné služby) - to vyřešil dekorátor s @cache; tedy jediný samodokumetující se řádek.
Na rozsáhlejší služby bych to nepoužil, tam ostatně máme nasazené Go (on vůbec provoz Pythonních služeb má svá specifika). A na ještě větší služby bych to nepoužil vůbec, ty si sekáme na menší části (což ale má svá proti kvůli Ops části z DevOps, ale o tom by mohl být celý článek - obecně není provoz mikroslužeb tak růžový, jak by se mohlo zdát).
je to tak. S něčím pomůže způsob nasazení, někde je to práce navíc a může se ukázat, že nebyla zvolena vhodná technologie.
Z pohledu celkové architektury se nám osvědčilo:
1. ověřit si, jestli fakt chceme pattern Request-Response
2. ověřit si, jestli fakt chceme pattern Request-Response
3. ověřit si, jestli fakt chceme pattern Request-Response
4. použít lepší řešení :-)
[já vím, už jsme to na Rootu probírali, tak to nechci opakovat]
no REST je sice pro mnoho ucelu vhodny, ale ma dve vlastnosti/omezeni:
1) architekura client-server, vetsinou specificky jeste dano zpusobem prace dotaz-odpoved
2) stateless
Jak pisu, pro mnoho ucelu jsou tato omezeni vyhodna, ale nekdy je lepsi pouzit jiny zpusob komunikace. Zejmena hned ze zacatku zajistit CQRS, potom mnoho zpusobu komunikace je spis lepsi resit jinymi komunikacnimi strategiemi: surveyor, pub-sub, push-pull, req-pull atd. To vede k nasazeni Kafky nebo NATSu (ale vy delate Javu, tak klidne i Artemisu).
Dakujem,
1) websocket riesi aj tieto obmedzenia naviac je integrovany aj do roznych 'standardizovanych' rieseni ako napriklad ten Artemis ale stale je to client server, http, ...
2) stateless je protokol nie obsah prenasanych sprav
Co sa tyka CQRS, ja si myslim ze v nasich krajinach nie je problem vyzadujuci si taketo riesenie DB + Index to riesi :-D
Ano prehanam ale naozaj okrem poziadaviek ktore naozaj maju mat milisekundove odozvy je CQRS zbytocne. Naviac si iba prirabate problem pri clustrovani riesenia.
Abych pravdu řekl, tak tomuhle přestávám věřit. Python je nejpopulárnější jazyk a přesto všichni tvrdí, že ho tak nějak nepoužívají v produkci. A nebo se to bojí přiznat. Znám několik produkčních řešení postavených na Python a ani sami autoři o nich nemluví, protože se bojí, že když řeknou, že to napsali v Pythonu, že se jim snad někdo bude smát. A tak mě to vede k otázce:
Proč by nešlo FastAPI použít v produkci u vělkých řešení? Spotify má většinu backand služeb (které vrací obsah) postavenu na FastAPI. Stejně tak Google má spousty infrastrukturních API postavených na Python (nevím jestli konkrétně na FastAPI). A spousty dalších velkých firem jej používá na backendu, Twitter, Netflix, Airbnb. Takže jak je to opravdu s tím použitím v produkci?
P.S.: taky mám s Python občas problém, dokonce dlouhá léta to byl pro mě jeden z nejodpornějších programovacích jazyků, ale v posledních dvou letech u mě dozrál a používám jej čím dal častěji. Naopak odpornými se pro mě staly molochy jako je Spring cloud (a spol.) + Hibernate (ORM). Přednost dávám Flask/FastAPI + SQLAlchemy Core (ne ORM!).
Popravdě jsem se v odsazení příspěvků ztratitl, takže nevím, jestli je to reakce na mě. Ale zkusím to vysvětlit.
Věta "já bych to na větší služby nepoužil" plyne z mnoha věcí, které se týkají mého týmu, schopností psát v různých jazycích více či méně produkční kód, rozdělení dev/ops, jak reagujeme na CVEčka atd.
Máme služby psané jak v Pythonu (buď nějaká součást pipeline nebo přímo REST přes FastAPI) a v Go (zase - buď součást pipeline, kde je vše propojeno přes Kafku nebo REST API) a nabrali jsme tyto zkušenosti (a ne všechny jsou samozřejmě přenositelné):
1. při použití standardního balíčku s Pythonem v obrazech (docker image) je pro tyto služby hlášeno násobně víc CVE, které je nutné řešit. Většinou to znamená jen zjištění, jestli to už někdo opravil a rebuild image, ale pořád je to práce, klikání v Jiře a další věci, které nesouvisí s tím, proč tu práci děláme.
2. bod # se částečně vyřešil tím, že nemáme nainstalován "plný" Python s batteries included.
3. jenže stále je tam potřeba mnohem více knihoven, než při vytváření obrazů s Go službou, takže stále máme víc CVE hlášených pro Python než pro Go (zhruba v poměru 3:2, ale to už je lepší než dříve 5:1)
4. typové systémy jsou dosti odlišné a i přes poměrně intenzivní testování (klasická pyramida) se semtam objeví věci typu "None object has no attribute..." apod. :-) Kupodivu v Go žádné panicy nenastávají, ale popravdě nedokážu bez hlubší analýzy říct proč :-)
5. obecně je Go (a ještě více Rust) striktnější v tom, jak se programy strukturují. Jasně, odpovědí je "však musíte psát testy", ale to je vždycky něco za něco (opět - struktura týmu, jeho schopnosti, aktivita atd., to tady hraje roli a proč něco z toho nehodit na hrb překladači a linterům)
6. tady by měly být nějaké poznámky a výkonnosti, protože za CPU a mem v cloudu samozřejmě platíme. Ale celkově to jsou desítky dolarů za den, tak to neřešíme :-) [ale bylo by to další minus na straně Pythonu]
7. co je +- stejné: loging (do stejné služby), monitoring (Prometheus+Grafana), alerting, konfigurace přes klasickou kombinaci TOML+proměnné prostředí (+ vault). Tady to vychází prakticky nastejno.
Jinak jak píšu, pro mock služby, filtry/transformátory v piplelinách a pro jednoduché CRUD-like REST API jsme šli do Pythonu, ale heavy lifting nám dělají služby v Go. To je důvod, proč jsem psal, že JÁ .... (a opět - toto není přenostitelná zkušenost a určitě někdo investoval víc energie do Python řešení a plně věřím, že jsou s tím i spokojeni).
PS: takto vypadá jedna část pipeliny (další jsou spíš interního charakteru a nemáme to vystaveno ven): https://redhatinsights.github.io/insights-results-smart-proxy/overall-architecture.html po rozkliku se napíše, co je v čem psáno :-)
12. 11. 2023, 11:02 editováno autorem komentáře
no já si udělal pro sebe tady tento skript:
https://github.com/RedHatInsights/insights-results-smart-proxy/blob/master/tools/generate-overall-architecture.py
bere to info z areas.txt a tam jsem narval obdélníky zjištěné v grafickém editoru.
Navíc to vygeneruje ještě jeden obrázek, kde jsou ty regiony nakreslené, takže je vidět, kde se překrývají (malý překryv nevadí).
Jasně, je to taková ruční práce, ale na druhou stranu za půl hodiny bylo hotovo, tak se mi nechtělo protlačovat složitější nástroj.
> rozumný ORM
znamena u mna automaticky jednoduchy a automaticky nepostacujuci pretoze uz poznam aj limity tych 'nerozumnnych'.
Java + Spring (oddelenie vrstiev DDD, springdoc automaticke generovanie swagger popisky):
@GetMapping("/employees") List<Employee> all() { return repository.findAll(); } @PostMapping("/employees") Employee newEmployee(@RequestBody Employee newEmployee) { return repository.save(newEmployee); }
Ako aj mne pride, ze v C# by to bolo menej kodu a bez statickych inciializacii a globalnych premenych, navyse to ide pouzit aj na velke projekty a samo to riesi aj tie ostatne enetrprise featurky, ako napriklad bezpenost, logovanie, caching, filtrovanie requestov, proxy, a plno inych drobnych veci, ktore pre realne aplikacie treba.
Přesně - taky jsem přešel z Javy do Pythonu a ve srovnání třeba se Spring MVC to prostě není vůbec flexibilní. Chceš použít něco jinýho než Pydantic? Smůla, neumíme (a pak sami potřebujou podporovat Pydantic 1 i 2 zároveň a musí si zaplevelit kód hromadou hacků a ifů).
A navíc se to hodně blbě testuje, protože to po člověku chce, aby všechno měl v module-level proměnných. A pak to vymýšlí svůj vlastní způsob DI, což už je jenom rovnák na ohýbák...
9. 11. 2023, 13:28 editováno autorem komentáře
Je to presne tak, proto pouzivam Flask. Prave ze tatkto malych projektiku je na webu spoustu. Pak potrebujes resit externi services, implementovat slozite usecases a s tim ti nikdo neporadi. U takto maleho projektu by prave melo smysl to ukazat. Jak se spravne injektuje to Storage aka repository pattern do tech handlerů atd, atp.
Jo jen doplnim, že Flask pouzivam proto, že mne "nenuti" mit vse async a pouzivat pydantic a zdrojak se dobre cte.
9. 11. 2023, 14:52 editováno autorem komentáře
Myslel jsem tím, že vypadá stejně ten základní pattern
app = neco() @app.get def handler(): ...
Kterej mně osobně vůbec nevyhovuje, protože nutí mít instanci app (kterých můžu chtít třeba víc) a handlovací funkce na stejné úrovni. Buď dám oboje top-level a bude se mi blbě testovat celá aplikace, nebo dám oboje dovnitř nějaké funkce, co vrací app, a budou se mi blbě testovat ty handlery.
Nepřijde mi, že by se Python v něčem tolik odlišoval od ostatních jazyků, aby dávalo smysl tohle dělat úplně jinak než všude jinde...
Myslíš tohle https://fastapi.tiangolo.com/tutorial/testing/ nebo něco jinýho? U tohohle jsem nepochopil například to, jak od sebe izolovat testy - pořád to používá tu jednu globální instanci a pokud udělám třeba POST, co změní stav, tak to může ovlivnit následující testy. Asi by se musel dělat reload modulu přes importlib nebo tak něco?
A to vůbec nemluvím o mockování dependencí - ano, můžu použít třeba https://fastapi.tiangolo.com/advanced/testing-dependencies/ , ale to je prostě už jen klasickej rovnák na ohýbák, kde se dalším toolingem snaží vyřešit špatnej základní princip...
Takhle se to ale právě vůbec v reálu nepíše, jen pro nejtriviálnější případy. Použij Flask blueprints viz https://flask.palletsprojects.com/en/3.0.x/blueprints/
Já z toho viním ty stovky blbejch Flask tutoriálů za tohle, je to zvěrstvo. Popravdě ve FastAPI se to také takhle nedělá viz https://fastapi.tiangolo.com/tutorial/bigger-applications/
https://realpython.com/flask-blueprint/
11. 11. 2023, 11:42 editováno autorem komentáře
Nevím, ale přijde mi, že vždy přijde něco nového a lidi na to přecházej, ale vůbec ani neznají to staré. Ano Flask není async first, ale podpora tam už je, ano nemá Pydantic podporu přímo ve frameworku, ale validace se dá samozřejmě provádět. A je modulární, jen nesmíš skončit na první stránce hello world. A napíšu v něm i web aplikaci -- občas to kombinuju, REST + nějakou malou demonstraci pomocí templates. Prostě je to ohebný a malý a hodně produkce na tom reálně běží (např. Pinterest). Nakonec to běží nad nějakým WSGI/ASGI serverem, takže jak je rychlej ten framework není tak úplně rozhodující, pokud nwdělá nějaké opravdu blokující kraviny. FastAPI bude rychlé, protože Starlette pod ním je rychlý. Ale async je rychlý jen pro něco a celkově komplikuje hodně věcí. Já bych async nasadil až když je k tomu důvod. Ale to je můj přízemní pohled.
https://github.com/tiangolo/fastapi/issues/1664
11. 11. 2023, 11:52 editováno autorem komentáře
Rozhodně jsou věci, kde bych ani Flask nechtěl, ale to pak ani to FastAPI. V zásadě jde o podobný projekt jen se zcela odlišným marketingem. Ale stačí se podívat na autory jednoho a druhého kousku softu a je to jasné. BTW Flask je jen tenkou vrstvou nad Werkzeug, který celý napsal autor Flasku. A FastAPI je tenkou vrstvou nad Starlette, který ale napsal někdo jiný. FastAPI samotné toho moc vlstně neumí a to co umí se dá dodat do Flasku pomocí extenze.
11. 11. 2023, 11:58 editováno autorem komentáře
Měl jsem to napsat do článku, ale toto není framework, který by dokázal efektivně nahradit Spring MVC. Pokud máte požadavky na více "těžktonážní" služby, pak je tady Django a možná i Flask+Flask-RESTX (ale ten neznám).
Hmm testování. Tam je fastapi.testclient, který sdílí "app" i s testy :-) [více o chování bych řekl někde u piva, je k tomu spousta historek]
S fastapi je vyhodne definovat db modely v tomhle https://sqlmodel.tiangolo.com/ , je to kompatibilni s pydantic.
Pane Tisnovsky zaujmal by ma vas nazor na https://github.com/mitsuhiko/rye ako na spravcu python projektov vs PDM. RYE vyzera slubne napriek tomu ze je to mlady projekt. Vdaka
Na malé věci by mohl stačit mikro-framework https://bottlepy.org/
Ten kdo má zažité např. Django, tak nezřídka i pro malý projekt použije to, protože na pár řádek má malý projekt s možností z toho udělat robustní projekt, kdyby to náhodou rostlo.