http://pep20.net/blog/2024-03-29T10:44:30Zpep20.net: Nic się nie zmienihttp://pep20.net/2023/Oct/16/nic-sie-nie-zmieni
Prawie 80% społeczeństwa oddalo głos w części na zamordystów nr 1, zamordystów nr 2, oraz przystawki do zamordystów, zaraz po emocjonalnej nagonce sponsorowanej przecież przez ten lud pracujący. Po tym jak odbierali ludziom podstawowe prawa, oraz szczuli jednych na drugich wyzywając od antyszczepów, covidiotów, ruskich onuc czy ukrainofili, których 80% społeczeństwa widziało w swoich sąsiadach, po tym jak zdefraudowali miliardy, za co teraz płacimy pod pozorem "tej złej inflacji" (ich kolejnego narzędzia), ludzie opowiedzieli się:<br /><br />> chcemy tego więcej!<br /><br />Z jednej strony jestem spokojny, bo nic się nie zmieni. Nadal aktualne "my nie ruszamy waszych, wy nie ruszacie naszych", powolne gotowanie żaby, oraz kurs na Brukselę i korporacje przejmujące coraz więcej dziedzin naszego życia, czasem nawet wbrew naszej woli. Z drugiej - chciałbym jednak, żeby ludziom (choćby w tym kraju) żyło się lepiej. To się jednak nie zmieni na obecnych zasadach opartych o masowe stawianie kreseczek w kwadracikach przy nazwiskach podsuwanych pod nos przez jedną ekipę w różnych przebraniach.<br /><br />
pep20.net: Garry Newman powiedział żeby Unity się p..doliłohttp://pep20.net/2023/Sep/13/garry-newman-powiedzial-zeby-unity-sie-pdolilo
> Garry Newman told Unity to "get fucked" and said the move has left him "furious."<br /><br />Widać, że [Big Tech zaczyna mocno deptać ludziom po odciskach](https://www.gamedeveloper.com/business/rust-creator-tells-unity-to-get-fucked-as-developers-left-seething-by-new-fee). Tym razem inba jest o wprowadzenie haraczu od pojedynczej instalacji finalnego produktu. Instalacji, czyli reinstalacji też, a nie od sprzedanych kopii (co i tak byłoby odmienne od dotychczasowych opłat).<br /><br />> Rust dev claims Unity is "the worst company to be in charge of the Unity Engine"<br /><br />So, Unity...<br /><br /><br /><br />----<br /><br />Źródło: [https://www.gamedeveloper.com/business/rust-creator-tells-unity-to-get-fucked-as-developers-left-seething-by-new-fee](https://www.gamedeveloper.com/business/rust-creator-tells-unity-to-get-fucked-as-developers-left-seething-by-new-fee)
pep20.net: GitHub mandatory 2FAhttp://pep20.net/2023/Sep/13/github-mandatory-2fa
> GitHub is making 2FA mandatory for devs!<br /><br /><br />![Microshit, Fuck You](http://pep20.net/media/uploads/2023/09/2023-09-13_22-50.png)<br /><br /><br />> GitHub is increasing the security of repositories by requiring all developers to enable two-factor authentication by the end of 2023.<br /><br />Oh.<br /><br />> The company’s directive is simple:<br /><br />## if you contribute to code, you must enable 2FA.<br /><br />![Musk rozjebany](http://pep20.net/media/uploads/2023/09/Firefox_Screenshot_2023-09-13T21-01-15.247Z.png)<br /><br />So, Microsoft...<br /><br /><br /><br />----<br /><br />## I moved to GitLab: [https://gitlab.com/marcinjn](https://gitlab.com/marcinjn)
pep20.net: Build the API with FastAPI top of Djangohttp://pep20.net/2023/Sep/11/build-api-fastapi-top-django
Even though these two tools seem to be mutually exclusive, they are not. There is possibility to omit Django's http server and relay all HTTP traffic to FastAPI's ASGI application. These are the goals of the new package [django-fastapi-bridge](https://pypi.org/project/django-fastapi-bridge/).<br /><br />![Django FastAPI Bridge automated documentation](/media/uploads/2023/09/juk13vjekenb1.jpg)<br /><br />### Wait, isn't Django too old for FastAPI?<br /><br />If you type "Django and fastapi" into Google you will get results that are simply misinformation. Speaking gently - they're outdated or written by persons without an experience (a real plague these days):<br /><br />> Can you use Django with FastAPI?<br /> <br />> Django-ORM can also be used with FastAPI but that is simply not recommended because it will be useless to use one of the oldest framework which does not use the modern features of Python, with one of the newest framework which uses the modern features like asyncio and others to provide high performance.<br /><br />The brutal truth is that it is bulls*t. Let the numbers speak for themselves. The tested endpoint looks like:<br /><br />```python<br /># sync version<br /><br />@api.get("/permissions", response_model=PermissionListResource)<br />def permissions_list():<br /> queryset = Permission.objects.all()<br /> items = [{"pk": obj.pk, "name": obj.name} for obj in queryset]<br /> return PermissionListResource(items=items)<br /><br /># async version<br /><br />@api.get("/async/permissions", response_model=PermissionListResource)<br />async def permissions_list():<br /> queryset = Permission.objects.all()<br /> items = [{"pk": obj.pk, "name": obj.name} async for obj in queryset]<br /> return PermissionListResource(items=items)<br />```<br /><br />1. Django + FastAPI in sync mode: 657.16 rq/sec<br />2. Django + FastAPI in fully async mode: 1568.97 rq/sec<br /><br />Both served through `uvicorn`. So... is this a high performance Django or not? :) <br /><br />Note that there also is an ApI. ("artifical pseudo intelligence") which will give you nonsense in the form of supposed knowledge. Be careful and "don't trust the science" (a "science" is a new idol these days). Ok, enough...<br /><br /><br />### What for is this hybrid?<br /><br />* To have one codebase for your core (models, logic)<br />* To expose Django Admin panel top of it<br />* To use Django ORM, auth, permissions system and other tools with FastAPI<br />* To gain from brilliant performance and automatic documentation which comes from FastAPI<br />* You don't have to rely on less known or unstable solutions<br />* And, if programmed in async mode in mind, gain from asynchronous features like long polling.<br /><br />### How it works<br /><br />Django has builtin support for protections against running sync code in async context, and async emulation built on threads. So you can mix sync and async code quite safely, but with a performance loss. To gain from fully async mode you must write handlers with async in mind, which will give you the best performance on the same ASGI server.<br /><br />Despite the excellent support built into Django, you should pay attention to external applications or add-ons that may be developed for synchronous mode and may lack protection and cause problems. Test your app well.<br /><br />### What will not work<br /><br />* Django middlewares aren't compatible because of different `request` object<br />* Wherever `request` is used in the code, it will not be compatible with the `request` object from FastAPI<br />* Context processors based on `request` object are mostly unusable<br />* Django's URL routing will not work with FastAPI routing<br />* Sessions handling (not an issue when using external OAuth2 server)<br /><br />### What's different<br /><br />* authenticated user object must be injected as a dependency explicitely (`user=Depends(get_current_user)`)<br />* serialization and model updates will require additional helpers (a Pydantic models coupled with Django ORM models)<br />* authentication process is delegated to a separate service (OAuth2 recommended), and can be based on Django OAuth2, and share the same database (it is easier to integrate both in such case)<br /><br />### Alternatives? No.<br /><br />* Django Rest Framework - slow, not fully async, old and not best design (which is mentioned in the docs)<br />* Django Ninja - however inspired by FastAPI, it is slow and shares part of not best design from DRF<br /><br />### Should I use FastAPI with Django?<br /><br />> "It's a Frankenstein"<br /><br />*— random python-like developer*<br /><br />You can, you don't have to. Mid-sized and big-sized projects are "Frankensteins" nowdays. Monoliths or microservices - does not matter. For such projects, where you must maintain them, it is important to have consistent and simplest stack. It is easier to support Django and FastAPI instead of tens of differrent technologies, frameworks and tools, not mentioning difficulties with hiring developers who knows A, B, C, D, E, etc frameworks or libraries. It is even a matter of team management not technology itself.<br /><br />> "But you broke Django!"<br /><br />*— maybe python-like developer*<br /><br /><br />There is no practical difference between not using features A, B, C because they are not needed, and not being able to use A, B or C for technical reasons. Also, I didn't broke Django in any way. It's just a mental thing. But for sure, you should be aware of the limitations.<br /><br /><br />### Example architecture concept<br /><br />![Example architecture based on Django FastAPI Bridge](http://pep20.net/media/uploads/2023/09/fastapi_based_architecture_concept.png)<br /><br />### Summing up<br /><br />[Django FastAPI Bridge](https://pypi.org/project/django-fastapi-bridge/) is NOT fully compilant with Django, because it is not using Django ASGI/WSGI http server. Features based on middleware or request/response objects simply won't work. But, with a proper separations of concerns, you are able to use your app logic codebase to run different services top of it, and you have all battle tested tools needed to get the things done. Note that in most cases when building a RESTful API (or even an entire API), you won't miss the built-in Django middleware. <br /><br />The really missing parts the [Django FastAPI Bridge](https://pypi.org/project/django-fastapi-bridge/) will try to deliver. I am considering adding an adapter for the `request` object, but it can be tricky and faulty.<br /><br />
pep20.net: Rysuj smokahttp://pep20.net/2023/Sep/8/rysuj-smoka
Legenda głosi, że to było moje pierwsze polecenie wydane komputerowi:<br /><br />![Rysuj smoka - Atari XE](/static/images/smok.jpg)<br /><br />Dziś, po ponad 30 latach, komputer w końcu zrealizował to polecenie.<br /><br />![Rysuj smoka - AI](/media/uploads/2023/09/ai-smok.png)<br /><br />Można umierać. Choć może nie do końca, bo sztuczna "inteligencja" daje także upust swojej sztucznej "kreatywności" ;)<br /><br />![Rysuj smoka - głupsze AI](/media/uploads/2023/09/ai-rysuj-smoka-2.png)<br />
pep20.net: Nie potrzebuję ery 5Ghttp://pep20.net/2023/Mar/4/nie-potrzebuje-ery-5g
Era 5G niesie ze sobą zmiany, które nie są potrzebne ludzkości.<br />Ostatnimi laty wypracowaliśmy nowe i skuteczne metody komunikacji - transfer informacji jest błyskawiczny.<br />Nie potrzeba dalej przyspieszać, ponieważ to niczego nie daje poza rozrywką, konsumpcją lub przetwarzaniem wolumenów takich danych, których wolałbym do przetwarzania nie oddawać. <br /><br />Nie będziemy uploadować gigabajtów jadąc na rowerze, lecąc w samolocie, drzemiąc nad stawem czy pływając po jeziorze.<br />Pracę lub streaming, a tylko tam są potrzebne wysokie przepustowości, wykonujemy w biurze.<br />A w biurze lub w domu mamy niezastąpiony kabel.<br /><br />Koszty 5G są niewspółmierne do korzyści:<br /><br />* tracimy solidne, metalowe obudowy w telefonach<br />* zwiększamy częstotliwości fal, tym samym zwiększamy zużycie energii<br /> które z drugiej chcemy ograniczać (kuriozum na oddzielny wpis, choć związanę ze szklanymi obudowami pod ładowanie indukcyjne)<br />* wyższe koszty budowy i utrzymania infrastruktury<br />* wyższe koszty usług i sprzętu<br />* zbędne koszty utrzymania narzędzia jakim jest telefon (szkło<br /> się łatwiej rozwala - nie ma cudów)<br />* i coś, nad czym niewielu się pochyla - cofamy się w kwestii<br /> ergonomii produktów.<br /><br />Ten ostatni punkt ostatnimi czasy jest dla mnie szczególnie dotkliwy. Lubię i doceniam dobre rozwiązania ergonomiczne. Manualne przyciski i przełączniki w samochodzie, klawisze pianina, pulpity sterownicze, kontrolery do montażu wideo, klucz oraz zamek, czy wygodny starter aplikacji z Windows Mobile na Lumii (który musiałem zamienić na dwuwymiarową cygańsko-cyrkową macierz ikon).<br /><br />Związek z 5G jest niby pozorny, ale w rzeczywistości<br />już teraz wpinamy do sieci samochody. A wpinać będziemy ich więcej, będą wysyłać jeszcze więcej informacji, a na samochodach nie poprzestaniemy - słyszałem, że już teraz ludzkość wpina do sieci wibratory. To wszystko oczywiście wymaga większej przepustowości. A wskutek tego **trendu**, tej szalonej cyfryzacji stymulowanej histeryczną i absurdalną potrzebą bycia online, wygodne przełączniki zamieniane są na niewygodne dotykoślizgacze,<br />obsługiwane przez przeładowane aplikacje niczemu nie służące poza bajerem. Te półprodukty są jak wystrzelone confetti - cieszą przez chwilę,<br />a brak ergonomii ujawnia się w momencie, kiedy trzeba posprzątać syf (analogicznie: tylko włączyć lub wyłączyć radio - bo tyle z tego wszystkiego robimy).<br /><br />Jakiś czas temu ekrany dotykowe wyparły z telefonów fizyczną klawiaturę. Ewangeliści tego trendu przekonywali mnie,<br />że to działa tak samo dobrze (a szczegółnie w Kościele Jabłczanym, który znany był z "inteligentnej haptyki"). Prawda jest taka,<br />że nadal pracujemy z komputerami używając fizycznych klawiszy, i to często nie jakichś byle-gumowych a mechanicznych, żeby feedback był odpowiedni.<br />Nie zastąpiliśmy klawiszy fortepianów ekranami dotykowymi. Wprost przeciwnie - w klawiaturach sterujących staramy się naśladować feedback młoteczków.<br />Do tej pory, a minęło dobrych dziesięć lat, żadna haptyka nie dogoniła fizycznych klawiszy.<br /><br />Niczym nie różni się pogoń za większymi ekranami - dziś nie ma telefonów, ale są patelnie. Ludzie przykładają patelnie do uszu i rozmawiają za ich pośrednictwem. Poważnie! Nie można mieć tabletu do rysunku i telefonu do dzwonienia. **Trend** zmusza mnie do jednego urządzenia do wszystkiego. A jak coś jest do wszystkiego, to wiadomo że jest do dupy.<br /><br />Co jednak istotne - ludzkość zdążyła zapomnieć o ergonomii i zdążyła przyzwyczaić się do rozwiązań słabych, złych, a nawet powiedziałbym że patologicznych. Tracimy komfort, wygodę, energię, pieniądze, nie otrzymując za to niczego sensownego. A kiedy zdigitalizujemy pieniądz i resztę dziedzin naszego życia, stracimy wolność, poufność i intymność. <br /><br />A chciałem tylko w roku 2023 kupić mały telefon z metalową obudową, żeby nie rozbijać więcej szkła które do niczego nie jest mi potrzebne, i żeby mieścił się w kieszeni oraz dłoni. Nie potrzebuję w telefonie ładowania indukcyjnego, kosmicznych transferów, ani nie chcę robić z niego telewizora. Potrzebuję narzędzia ergonomicznego, trwałego i o sensownym koszcie utrzymania. Niestety ludzkość bez opamiętania zmierza w innym kierunku.
pep20.net: Reducing a mess generated by vim-alehttp://pep20.net/2023/Feb/8/reducing-mess-generated-vim-ale
In case of mess in your editor window, just add this line to your `.vimrc`:<br /><br />```<br />let g:ale_virtualtext_cursor = 'disabled'<br />```<br /><br />![a mess in vim](/media/uploads/2023/02/54855921-98150880-4cce-11e9-8eeb-7b19df4b37b0.png)<br />*A mess in VIM (look at these red inline error messages)*<br /><br /><br />### The root cause of the issue<br /><br />Some idiot creative guys thought that mixing warning messages with code makes some sense and increases readability, and someone smart enough implemented it (to the misfortune of mankind).<br /><br />[A source of the mess in vim](https://github.com/vim/vim/issues/7553)<br /><br />The other one great dev enabled the mess at default (dunno why, maybe he thinks that mess in the editor window is so awesome):<br /><br />[An awesome idea of enabling mess in the VIM editor at default](https://github.com/dense-analysis/ale/issues/4396)<br />
pep20.net: Krótko o jakości bibliotek Python do ElasticSearchhttp://pep20.net/2021/Jan/24/krotko-o-jakosci-bibliotek-python-do-elasticsearch
Do Pythona istnieją dwie podstawowe biblioteki do komunikacji z [ElasticSearch](https://www.elastic.co/what-is/elasticsearch): [elasticsearch-py](https://elasticsearch-py.readthedocs.io/) oraz [elasticsearch-dsl](https://elasticsearch-dsl.readthedocs.io/). Są one typowymi interfejsami do komunikacji z serwerem ElasticSearch. Śledzę ich rozwój od pierwszych wersji i niestety, mimo już siódmej odsłony, autorzy powielają te same błędy projektowe, czyli de facto błędy programistyczne. Utrudnia to korzystanie z bibliotek, ponieważ tworzone są sytuacje niejasne, co może mieć negatywny wpływ na stabilność i jakość rozwiązań o nie opartych.<br /><br />### `elasticsearch-py`<br /><br />Pierwsza uwaga dotyczy biblioteki `elasticsearch-py`, czyli stosunkowo niskopoziomowego interfejsu programistycznego. Już pierwszy przykład z dokumentacji uwidacznia problem:<br /><br />```python<br />es = ElasticSearch()<br />es.indices.create(index='my-index', ignore=400)<br />```<br /><br />Co robi powyższe wywołanie? Tworzy indeks `my-index`, a w przypadku gdy takowy już istnieje, ma za zadanie zignorować błąd, pozwalając aby program wykonał się dalej bezbłędnie.<br /><br />Problem tego podejścia jest w sposobie obsługi tej sytuacji. Otóż przez parametr `ignore=400` powoduje, że szczegóły implementacji, tu konkretnie warstwy transportowej HTTP, przechodzą do warstwy wyższej. Program korzystający z biblioteki musi obsługiwać kody specyficzne dla warstwy niższej, co powoduje bardzo problematyczną zależność. Dlaczego to takie ważne?<br /><br />Status 400 HTTP oznacza `BadRequest`, czyli wskazuje na problem żądania wygenerowanego przez klienta HTTP. Może to być zła składnia żądania HTTP, może to być błąd walidacji (nieprawidłowe dane w prawidłowo składniowo sformułowanym żądaniu), albo tak jak w omawianym przypadku - istnienie konkretnego zasobu. Zatem status 400 może mieć wiele znaczeń, i nawet jeśli teraz ma tylko jedno, to nie ma żadnej gwarancji, iż w kolejnych odsłonach HTTP API nie nabierze dodatkowych. Status o kodzie `400` nie oznacza, że indeks istnieje. Oznacza, że serwer zwrócić odpowiedź o kodzie 400, czyli uznaje że problem leży w żądaniu klienta, gdzie klient może powtórzyć odpowiednio zmodyfikowane żądanie, a przyczyny mogą być różne. Ale jak klient zmodyfikuje żądanie, skoro dokładnie nie określono przyczyny? <br /><br />Kolejnym problemem jest sam flow programu, w którym zawiera się wywołanie `es.indices.create(index='my-index', ignore=400)`. W przypadkach błędu utworzenia indeksu, niekoniecznie związanego z jego istnieniem po stronie serwera, program będzie wykonywał się dalej. To oznacza, że błąd programu wystąpi w innym miejscu, a konkretnie podczas próby wykonania operacji na indeksie, który nie istnieje.<br /><br />Złamanie zasad hermetyzacji powoduje, że zależność z niższą warstwą transportową tworzy kod aplikacji, który jest trudniejszy do utrzymania. Kod 400 nie jest jednoznaczny, nie jest dostatecznie czytelny, a w przypadku zmian w warstwie transportowej nie będzie kompatybilny wstecznie. <br /><br />Interfejs biblioteki jest niespójny, ponieważ programista nie ma wpływu na szczegóły żądania HTTP wysyłanego do serwera, ale musi operować na częściowych informacjach z odpowiedzi HTTP. To nie tylko nie czyni programowania łatwym ani elastycznym, ale przede wszystkim forsuje programowanie w błędnym stylu, wskutek czego powstające aplikacje w oparciu o biblioteki tej jakości będą o wiele bardziej błędne.<br /><br />Poprawne podejście do zagadnienia powinno być oparte o wyjątki. Powyższy przykład, w bibliotece o dobrze zaprojektowanym interfejsie, powinien wyglądać tak:<br /><br />```python<br />es = ElasticSearch()<br /><br />try:<br /> es.indices.create(index='my-index')<br />except IndexAlreadyExists:<br /> # obsługa sytuacji, w której indeks już istnieje<br />except IndexCreationError:<br /> # obsługa błędu przy próbie tworzenia indeksu (złe parametry, inne)<br />```<br /><br />Kod jest niewiele dłuższy, ale za to czytelny oraz niezależny od szczegółów implementacji warstwy transportowej. <br /><br />Jeśli intencją autorów było ulokowanie biblioteki klienckiej w warstwie transportowej, to sens istnienia tej biblioteki w tej formie jest właściwie żaden. Czym bowiem różni się zapytanie `es.indices.create('my-index')` od `requests.put('http://elasticsearch-instance/my-index')`? Czyż nie wystarczyłoby utworzyć niewielki adapter, który zawierałby adresy węzłów klastra, implementację sniffera czy strategii wysyłania żądań, tworząc z niego klienta stricte transportowego, ułatwiającego komunikację HTTP z usługą ElasticSearch? <br /><br /><br />### `elasticsearch-dsl`<br /><br />Biblioteka `elasticsearch-dsl` jest adapterem wysokiego poziomu. Dostarcza interfejs bardziej obiektowy i przyjazny programowaniu aplikacji. Podstawową klasą, z którą programiści aplikacji mają do czynienia, jest klasa `Search`. Swoją konstrukcją przypomina klasę `QuerySet` z frameworka Django, i zapewne była ona wzorem dla autorów biblioteki. Nie ustrzegli się jednak błędów projektowych.<br /><br />W oryginale, tj. `QuerySet`, metody zwracają referencję na zmodyfikowane kopie instancji. Dzięki temu podejściu można stosować łańcuchowanie zapytań do baz danych, używać fragmentów łańcuchów, tworzyć warunkowe konstrukty, itd. Programista ma pewność, że każdy obiekt zwrócony przez te metody jest nowym obiektem, a stan oryginalnej instancji klasy `QuerySet` nie jest modyfikowany. <br /><br />Programiści `elasticsearch-dsl` stoją jednak w koncepcyjnym rozkroku. Podstawowe metody kalsy `Search` istotnie zwracają zmodyfikowane kopie, co widać na poniższym przykładzie:<br /><br />```python<br />>>> s1 = Search()<br />>>> s2 = Search().filter(foo='bar')<br /><br />>>> id(s1) == id(s2)<br />False<br /><br />>>> s1.to_dict()<br />{}<br /><br />>>> s2.to_dict()<br />{'query': {'bool': {'filter': [{'match_all': {'foo': 'bar'}}]}}}<br />```<br /><br />Jednak już przy agregacjach wpadli w sidła niekonsekwencji, i obiekt klasy `Search` zmienia swój stan `in place`:<br /><br />```python<br />>>> s1.aggs.bucket('per_tag', 'terms', field='tags')<br />>>> s1.to_dict()<br />{'aggs': {'per_tag': {'terms': {'field': 'tags'}}}}<br />```<br /><br />Oczywiście można uzasadnić, że skoro metoda `.bucket()` jest wywoływana na właściwości `aggs`, to zmodyfikowana zostanie instancja klasy opisującej agregacje (tu: `AggsProxy`), co pośrednio wpływa na stan instancji klasy `Search`. Jednak nie jest do końca czytelne, co dzieje się ze stanem `Search`. Nie wiadomo czy oraz jak zmiany `aggs` wpływają na stan instancji nadrzędnej klasy `Search`, a znając pierwotną konwencję intuicyjnie spodziewamy się kopii. <br /><br />Zastosowana tutaj asocjacja między klasami, jest niepotrzebnie wyeksponowana do interfejsu publicznego nadrzędnej klasy `Search`, co wpływa na niespójne zachowanie interfejsu wysokiego poziomu. Jest to pogwałcenie nie tylko zasad hermetyzacji, ale także dobrych i prostych zasad [PEP20 - The Zen of Python](https://www.python.org/dev/peps/pep-0020/). <br /><br />Prawidłowy publiczny interfejs do modyfikacji agregacji powinien eksponować odpowiednie metody. <br /><br />Przykład:<br /><br />```<br />>>> s1.agg_bucket('per_tag', 'terms', field='tags')<br />```<br /><br />gdzie metoda `agg_bucket` zwracałaby kopię `s1`z kopią zmodyfikowanego obiektu opisującego agregacje, lub interfejs uogólniony działający na podobnej zasadzie:<br /><br />```<br />>>> s1.aggregate(A(...))<br />```<br /><br />### Siedem wersji architektonicznego bólu i jeden plus<br /><br />Obydwie biblioteki są już w siódmej odsłonie (7.x). Przez wiele lat nie zrobiono nic ku wyeliminowaniu błędów projektowych. Wręcz przeciwnie - autorzy brną dalej w tym samym kierunku.<br /><br />Chyba tylko z powodu utopijnej wizji oraz braku mocy przerobowych, biblioteka niższego poziomu jest w większości generowana automatycznie z API HTTP, co tylko dowodzi braku sensu jej istnienia w takiej formie. Wygenerowany kod musi pokrywać całe API HTTP - wszystkie operacje. Ale po co, skoro i tak narzuca interakcję z częścią specyficzną dla warstwy transportowej? Po co, skoro kod biblioteki jest w części generowany z API HTTP, przez co i tak nie zapewni kompatybilności wstecznej, gdyby interfejs HTTP się zmienił?<br /><br />W praktyce wraz z aktualizacją serwera ElasticSearch i tak trzeba aktualizować obydwie biblioteki, co dowodzi braku spójnego i dobrego konceptu na te interfejsy. Dla kontrprzykładu Django nie musi być aktualizowane, żeby pracować z różnymi wersjami PostgreSQL, np. od wersji 9 do 12. Dopiero gdy chcemy z poziomu interfejsu obiektowego dostać się do nowych funkcji bazy danych, może okazać się konieczne uaktualnienie wersji frameworka. Ale nie powstaje Django 12 dla dwunastej odsłony bazy danych. <br /><br />Opisywane tu biblioteki są, bo po prostu muszą istnieć. Ze względu na wsparcie dla istniejących projektów oraz przez to, że są "standardem" komunikacji z ElasticSearch z poziomu Pythona. Nie są jednak interfejsem dobrym. Ich zaletą jest to, że w ogóle są. Można z nich korzystać, a ze względu na specyfikę komunikacji z serwerem nawet trzeba, ale najlepiej ze świadomością istniejących pułapek. Podane we wpisie przykłady są "pierwszymi z brzegu", a problemów tej kategorii jest więcej. Niniejszy wpis ma za zadanie wyczulić programistów na problem oraz pokazać na tych przykładach, jak nie powinno się projektować interfejsów. <br /><br />
pep20.net: ElasticSearch 6 - na dobrej drodzehttp://pep20.net/2019/Jul/9/elasticsearch-na-dobrej-drodze
## Wersja 6<br /><br />Wersja 6.0 ElasticSearch jest dla mnie szczególna - twórcy wprowadzają zmiany ułatwiające zarządzanie, ale też rezygnują z dawnych błędów, które krytykowałem na łamach tego bloga.<br /><br />Każdemu polecam migrację do wersji 6.x. Służę pomocą w migracji z wersji 2.x oraz 5.x.<br /><br />## Aktualizacje ElasticSearch - jak wykonać?<br /><br />Nie można zaprzeczyć, że ElasticSearch jest rozwijany dynamicznie. Tak szybki rozwój produktu nie zawsze jest oczekiwany, bo albo wdrożenie zostaje (z przyczyn obiektywnych) oparte o zamrożoną (i nie wspieraną) wersję, albo konieczne staje się przeprowadzanie<br />migracji do nowszych wersji. Takie operacje trzeba zaplanować, zabudżetować, a na dodatek nie obejdzie się bez downtime i sukcesem jest, gdy przerwa techniczna jest relatywnie krótka.<br /><br />Przypomnę w tym miejscu daty końca wsparcia poszczególnych wersji ElasticSearch:<br /><br />Elasticsearch | EOL Date | Maintained Until<br />------|------------|-----------------------<br />2.0.x | 2017-04-28 | 2.1.0<br />2.1.x | 2017-05-24 | 2.2.0<br />2.2.x | 2017-08-02 | 2.3.0<br />2.3.x | 2017-09-30 | 2.4.0<br />2.4.x | 2018-02-28 | 6.0.0<br />5.0.x | 2018-04-26 | 5.1.0<br />5.1.x | 2018-06-08 | 5.2.0<br />5.2.x | 2018-07-31 | 5.3.0<br />5.3.x | 2018-09-28 | 5.4.0<br />5.4.x | 2018-11-04 | 5.5.0<br />5.5.x | 2019-01-06 | 5.6.0<br />5.6.x | 2019-03-11 | 7.0.0<br />6.0.x | 2019-05-14 | 6.1.0<br />6.1.x | 2019-06-13 | 6.2.0<br />6.2.x | 2019-08-06 | 6.3.0<br />6.3.x | 2019-12-13 | 6.4.0<br />6.4.x | 2020-02-23 | 6.5.0<br />6.5.x | 2020-05-14 | 6.6.0<br />6.6.x | 2020-07-29 | 6.7.0<br />6.7.x | 2020-09-26 | 8.0.0<br />7.0.x | 2020-10-10 | 7.1.0 <br /><br />Przygotowując się do jakichkolwiek operacji powinno się opracować procedurę, z którą<br />należy zapoznać wszystkich zainteresowanych, opracować procedurę odwrotną, tj. wycofującą<br />zmiany w razie [nieprzewidzianych problemów](/2019/May/1/prawa-murphyego-jako-narzedzie-warsztatowe), albo oznaczyć jasno punkty po realizacji których<br />nie ma już odwrotu.<br /><br />W przypadku ElasticSearch procedura jest o tyle bezpieczna, że ryzyko<br />utraty danych jest stosunkowo niewielkie i ogranicza się do przypadku utraty<br />danych z kartoteki wtórnej (zazwyczaj bazy danych RDBMS systemu OLTP), co ma<br />miejsce niezwykle rzadko ale jest możliwe (a jak coś jest możliwe, to [zazwyczaj<br />dzieje się w najgorszym momencie](/2019/May/1/prawa-murphyego-jako-narzedzie-warsztatowe)).<br /><br />Czy można śmiało aktualizować ElasticSearch? Tak, ale pod warunkiem, że został zapewniony backup danych lub środowiska. Największym problemem jest downtime, czyli czas braku usługi, który będzie skutkował wyłączeniem bądź dysfunkcją aplikacji web.<br /><br />A czy warto aktualizować? Tak!<br /><br />## Aktualizacja od 5.x<br /><br />Producent zapewnia, że aktualizacja od wersji 5.6.3 nie wymaga downtime. Zachowanie kompatybilności wstecznej na poziomie fizycznym jest ogromnym plusem tego wydania.<br /><br />Wyjątkiem jest użycie X-Pack Security bez SSL/TLS, co wymaga przekonfigurowania węzłów (włączenia SSL/TLS) i restartu całego klastra. Pomijam przypadki, gdzie w stacku używana jest np. Kibana i najlepiej użyć jest asystenta migracji. <br /><br />Etapy migracji warto zatem podzielić na:<br />- migrację 2.x do 5<br />- migrację 5.x do 5.6.3<br />- migrację 5.6.3 do 6.x<br /><br />## Koniec z mappingami<br /><br />Nie mogę powiedzieć, że to mój osobisty sukces, ale wersja 6.0 wycofuje tzw. mappingi, czyli grupowanie atrybutów w bliżej nieokreślonym celu. O bezsensie mappingów pisałem szerzej [we wpisie z 2016 roku](https://pep20.net/2016/Jul/12/elasticsearch-nie-taki-elastic).<br /><br />Dzięki temu posunięciu indeksy są w końcu takie, jakie powinny być. Tworzenie bibliotek klienckich też staje się o prostsze (dokładnie o jedną warstwę), gdyż struktura indeksu nie musi być opisywana wieloma mappingami. Wydajność takich indeksów staje się lepsza, a zarządzanie nimi - prostsze.<br /><br />ElasticSearch 6.x zachowuje kompatybilność pozostawiając obsługę mappingów w starych indeksach, sam ogranicza tworzenie dokładnie jednego mappingu do indeksu, aż w wersji 7.0 mappingi zostaną kompletnie usunięte (z wyjątkami w 9.0).<br /><br />Twórcy ElasticSearch argumentują zmiany takimi słowami:<br /><br /><br /><br />In the early days of Elasticsearch, we spoke about an “index” being similar to a “database” in an SQL database, and a “type” being equivalent to a “table”.<br />This was a bad analogy that led to incorrect assumptions. In an SQL database, tables are independent of each other. The columns in one table have no bearing on columns with the same name in another table. This is not the case for fields in a mapping type.<br /><br /><br />Tak. Ta analogia była po prostu głupia.<br /><br /><br />In an Elasticsearch index, fields that have the same name in different mapping types are backed by the same Lucene field internally. In other words, using the example above, the user_name field in the user type is stored in exactly the same field as the user_name field in the tweet type, and both user_name fields must have the same mapping (definition) in both types.<br /><br />I dokładnie to krytykowałem w moim poprzednim wpisie.<br /><br />Cieszę się, że twórcy ElasticSearch w końcu to dostrzegli. Czekam, aż przyjmą do wiadomości, że ich API HTTP/JSON **nie jest RESTful** :)<br /><br />## Co nowego w ElasticSearch 6.0?<br /><br />Wersja 6.0, oprócz pierwszych kroków do usunięcia naprawdę głupich mappingów, poprawia wydajność wyszukiwania, szczególnie skracając czasy wyszukiwania posortowanych zbiorów, ale też usprawnia w wyszukiwanie rozproszone oraz bezpieczeństwo.<br /><br />To pierwsza wersja ElasticSearch, do której gorąco namawiam obecnych i potencjalnych klientów. Zainteresowanych proszę o kontakt przez [stronę firmową](https://nowak.tech/) lub telefonicznie +48326100016.
pep20.net: Prawa Murphy'ego jako narzędzie warsztatowehttp://pep20.net/2019/May/1/prawa-murphyego-jako-narzedzie-warsztatowe
Prawa Murphy'ego znane sią chyba każdemu, także osobom nietechnicznym, od dobrych dwóch dekad. W tym krótkim wpisie przytoczę kilka "praw", które zazwyczaj traktowane z przymrużeniem oka, są podstawą rzemiosła profesjonalisty, a szczególnie administratora lub wdrożeniowca.<br /><br />Stosując metodykę DevOps, a nawet ograniczając się tylko do samego continuous delivery lub continuous deployment, istotnym czynnikiem jest zapewnienie jakości. Przeprowadzając wszelakie operacje w środowiskach produkcyjnych istnieją dwie naczelne zasady: możliwie najkrótszy downtime (lub zero downtime) oraz niedopuszczanie do wprowadzania wadliwych wersji.<br /><br />Mówiąc ogólnie - naczelną zasadą jest nie szkodzić użytkownikowi eksploatowanego systemu. A jak powszechnie wiadomo człowiek jest z zasady istotą omylną, najsłabszym ogniwem każdego łańcucha, dlatego do zapewnienia jakości każdemu profesjonaliście potrzebne są odpowiednie procedury postępowania.<br /><br />Ciekawą pomocą w ich opracowywaniu, prawdopodobnie stosowaną powszechnie nieświadomie, są moim zdaniem Prawa Murphy'ego. Każdy odpowiedzialny profesjonalista powinien być w jakiejś części sceptykiem i pesymistą, choć niekoniecznie musi to okazywać ;) <br /><br />> Jeżeli coś może się nie udać, to się nie uda. <br />> Jeśli coś może pójść źle, to pójdzie. <br /><br />Powinny być podstawowymi zasadami każdego inżyniera operującego w środowiskach produkcyjnych. Błąd operatora jest jedną z najczęstszych przyczyn awarii. Przykłady można mnożyć - od przypadkowych usunięć danych, długich dysfunkcji usług sieciowych (co jest krytyczne w modelu SaaS), aż po spektakularne wycieki danych (spowodowane np. pozostawieniem "otwartego na świat" narzędzia). Nie, chmury nie rozwiązują "magicznie" takich problemów ;)<br /><br />Opracowując procedury postępowania, czy to tworząc playbooki Ansible lub innego narzędzia orkiestracji, czy też wykonując operacje typowo manualne, powinno się mieć na uwadze że każdy krok może się nie powieść. Powinno się też przewidzieć w jakim stanie będzie system i jaki będzie sposób przywrócenia do stanu pierwotnego.<br /><br />> Jeśli wiesz, że coś może pójść źle i podejmiesz stosowne środki zapobiegawcze, to źle pójdzie coś innego<br /><br />Zawsze trzeba mieć plan "B". Nawet zwykły backup. Często robiąc wdrożenia mocno modyfikujące dane, skracam RPO do absolutnego minimum tworząc kopie danych tuż po przejściu w tryb przerwy technicznej (aby wyeliminować napływ nowych danych). Czasem robię hotcopy zakładając, że częściowe odzyskanie danych będzie możliwe i nie będzie wiązać się z nadpisaniem nowszych informacji. Ostatecznie zawsze pod ręką powinien być backup całej maszyny lub okresowe dumpy danych.<br /><br />Moje plany "B" zazwyczaj są wielowarstwowe, przez co na wiele niespodziewanych przypadków jestem odporny z zachowaniem RPO (Recovery Point Objective) oraz RTO (Recovery Time Objective) wynikającego z przyjętej polityki bezpieczeństwa.<br /><br />> Powinieneś być przerażony, gdy dziecko jest zbyt ciche.<br /><br />Ta "prawda życiowa" ma swoją analogię w świecie IT. System wykazujący zbyt niskie obciążenie w stosunku do typowego dla danego dnia i pory dnia, powinien być poddany natychmiastowej inspekcji. Oznacza to, że konieczne są narzędzia monitorujące pracę systemu, ale nie tylko on-line ale również gromadzące dane historyczne. Nie ma lepszego sposobu jak ogląd krytycznych parametrów systemu w formie wykresów. <br /><br />Tu warto zauważyć, że skuteczny monitoring wymaga personelu, który w niego patrzy i reaguje na jego zgłoszenia. Bez tego każdy system monitorowania jest niestety niemym głosem tonącego.<br /><br />> Nigdy nie mów „ups”, gdy pacjent jest przytomny<br /><br />Profesjonalista nigdy nie poddaje się, gdy obsługuje awarię. Nie można wycofać się nawet wtedy, gdy za awarię w 100% odpowiedzialny jest ktoś inny. W opanowaniu sytuacji pomogą ci procedury i twoje plany "B".<br /><br />Z tego wynika jeszcze coś, co nie jest oczywiste. Musi istnieć dokumentacja techniczna systemu, z której pomocą inżynier będzie mógł podejmować odpowiednie działania. Alternatywą jest posiadanie pełnej wiedzy o funkcjonowaniu całego systemu i sposobie jego obsługi, ale to podejście ma istotne wady, gdyż...<br /><br />> Wiedza i doświadczenie przychodzą z wiekiem. Najczęściej jest to wieko od trumny.<br /><br />... każdy jest śmiertelny. Jeśli z nim zniknie wiedza, to biznes będzie miał niemały kłopot. Tworzenie dokumentacji technicznych oraz instrukcji obsługi systemu/podsystemów jest częścią pracy profesjonalisty. Zawsze trzeba na to mieć czas. <br /><br />> Ten, który się waha, ma prawdopodobnie rację<br /><br />Trzeba być wyczulonym na takie sygnały. Wynikają one zazwyczaj z umiejętności przewidywania oraz z doświadczenia. Znowu zabezpieczeniem są procedury, plany "B".<br /><br />> Zawodowcy są przewidywalni – strzeż się amatorów<br /><br />To się samo komentuje.