{"id":36721,"date":"2019-10-31T22:13:20","date_gmt":"2019-10-31T19:13:20","guid":{"rendered":"https:\/\/prohoster.info\/blog\/kak-dark-razvertyvaet-kod-za-50-ms\/"},"modified":"2019-10-31T22:13:20","modified_gmt":"2019-10-31T19:13:20","slug":"kak-dark-razvertyvaet-kod-za-50-ms","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms","title":{"rendered":"Jak Dark wdra\u017ca kod w 50 ms","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Jak Dark wdra\u017ca kod w 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/c159a36eb52bf488f3a70ea511690366.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Im szybszy proces rozwoju, tym szybciej rozwija si\u0119 firma technologiczna.<\/p>\n<p><\/p>\n<p>Niestety, wsp\u00f3\u0142czesne aplikacje dzia\u0142aj\u0105 przeciwko nam \u2013 nasze systemy musz\u0105 by\u0107 aktualizowane w czasie rzeczywistym, nie zak\u0142\u00f3caj\u0105c przy tym pracy i nie prowadz\u0105c do przestoj\u00f3w. Wdra\u017canie w takich systemach staje si\u0119 trudnym zadaniem i wymaga skomplikowanych pipeline'\u00f3w ci\u0105g\u0142ej dostawy, nawet w ma\u0142ych zespo\u0142ach.<\/p>\n<p><\/p>\n<p>Te pipeline'y maj\u0105 zwykle w\u0105skie zastosowanie, dzia\u0142aj\u0105 wolno i nie s\u0105 niezawodne. Deweloperzy musz\u0105 je najpierw r\u0119cznie stworzy\u0107, a potem nimi zarz\u0105dza\u0107, a firmy cz\u0119sto zatrudniaj\u0105 do tego ca\u0142e zespo\u0142y DevOps.<\/p>\n<p><\/p>\n<p>Szybko\u015b\u0107 tych pipeline'\u00f3w wp\u0142ywa na szybko\u015b\u0107 rozwoju. U najlepszych zespo\u0142\u00f3w wdro\u017cenie zajmuje 5\u201310 minut, ale zazwyczaj wszystko trwa znacznie d\u0142u\u017cej, a jedno wdro\u017cenie wymaga kilku godzin.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>W Dark zajmuje to 50 ms. <em>Pi\u0119\u0107dziesi\u0105t. Milisekund.<\/em>. Dark \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/the-design-of-dark-59f5d38e52d2\">to kompleksowe rozwi\u0105zanie z j\u0119zykiem programowania, edytorem i infrastruktur\u0105<\/a><\/noindex>, zaprojektowane specjalnie do ci\u0105g\u0142ej dostawy, a wszystkie aspekty Dark, w tym sam j\u0119zyk, s\u0105 stworzone z my\u015bl\u0105 o bezpiecznym i b\u0142yskawicznym wdra\u017caniu.<\/p>\n<p><\/p>\n<h3 id=\"pochemu-konveyery-nepreryvnoy-postavki-takie-medlennye\">Dlaczego pipeline'y ci\u0105g\u0142ej dostawy s\u0105 takie wolne?<\/h3>\n<p><\/p>\n<p>Za\u0142\u00f3\u017cmy, \u017ce mamy aplikacj\u0119 internetow\u0105 w Pythonie i stworzyli\u015bmy ju\u017c znakomity i nowoczesny pipeline ci\u0105g\u0142ej dostawy. Dla dewelopera, kt\u00f3ry codziennie zajmuje si\u0119 tym projektem, wdro\u017cenie jednej drobnej zmiany b\u0119dzie wygl\u0105da\u0107 mniej wi\u0119cej tak:<\/p>\n<p><\/p>\n<h3 id=\"vnesenie-izmeneniy\">Wprowadzenie zmian<\/h3>\n<p><\/p>\n<ul>\n<li>Utworzenie nowej ga\u0142\u0119zi w git<\/li>\n<li>Wprowadzenie zmian za pomoc\u0105 prze\u0142\u0105cznika funkcji<\/li>\n<li>Testy modu\u0142owe w celu sprawdzenia zmian z prze\u0142\u0105cznikiem funkcji i bez<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"pul-rekvest\">Pull request<\/h3>\n<p><\/p>\n<ul>\n<li>Zatwierdzenie zmian<\/li>\n<li>Wys\u0142anie zmian do zdalnego repozytorium na githubie<\/li>\n<li>Pull request<\/li>\n<li>Budowanie CI odbywa si\u0119 automatycznie w tle<\/li>\n<li>Przegl\u0105d kodu<\/li>\n<li>Jeszcze kilka przegl\u0105d\u00f3w, je\u015bli to konieczne<\/li>\n<li>Scalanie zmian z g\u0142\u00f3wn\u0105 ga\u0142\u0119zi\u0105 w git.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"ci-vypolnyaetsya-na-mastere\">CI wykonuje si\u0119 na g\u0142\u00f3wnej ga\u0142\u0119zi<\/h3>\n<p><\/p>\n<ul>\n<li>Instalacja zale\u017cno\u015bci frontendowych przez npm<\/li>\n<li>Budowanie i optymalizacja zasob\u00f3w HTML+CSS+JS<\/li>\n<li>Przeprowadzanie modu\u0142owych i funkcjonalnych test\u00f3w na frontendzie<\/li>\n<li>Instalacja zale\u017cno\u015bci Pythona z PyPI<\/li>\n<li>Przeprowadzanie modu\u0142owych i funkcjonalnych test\u00f3w na backendzie<\/li>\n<li>Testowanie integracji na obu ko\u0144cach<\/li>\n<li>Wys\u0142anie zasob\u00f3w frontendowych do CDN<\/li>\n<li>Budowa kontenera dla programu Python<\/li>\n<li>Wys\u0142anie kontenera do rejestru<\/li>\n<li>Aktualizacja manifestu Kubernetes<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"zamena-starogo-koda-novym\">Zamiana starego kodu na nowy<\/h3>\n<p><\/p>\n<ul>\n<li>Kubernetes uruchamia wiele instancji nowego kontenera<\/li>\n<li>Kubernetes czeka, a\u017c instancje stan\u0105 si\u0119 funkcjonalne<\/li>\n<li>Kubernetes dodaje instancje do balansu obci\u0105\u017cenia HTTP<\/li>\n<li>Kubernetes czeka, a\u017c stare instancje przestan\u0105 by\u0107 u\u017cywane<\/li>\n<li>Kubernetes zatrzymuje stare instancje<\/li>\n<li>Kubernetes powtarza te operacje, a\u017c nowe instancje zast\u0105pi\u0105 wszystkie stare<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"vklyuchenie-novogo-pereklyuchatelya-funkcii\">W\u0142\u0105czenie nowego prze\u0142\u0105cznika funkcji<\/h3>\n<p><\/p>\n<ul>\n<li>Nowy kod w\u0142\u0105czany jest tylko dla siebie, aby upewni\u0107 si\u0119, \u017ce wszystko dzia\u0142a poprawnie<\/li>\n<li>Nowy kod w\u0142\u0105czany jest dla 10% u\u017cytkownik\u00f3w, monitorowane s\u0105 metryki operacyjne i biznesowe<\/li>\n<li>Nowy kod w\u0142\u0105czany jest dla 50% u\u017cytkownik\u00f3w, monitorowane s\u0105 metryki operacyjne i biznesowe<\/li>\n<li>Nowy kod w\u0142\u0105czany jest dla 100% u\u017cytkownik\u00f3w, monitorowane s\u0105 metryki operacyjne i biznesowe<\/li>\n<li>Na koniec powtarzasz ca\u0142\u0105 procedur\u0119, aby usun\u0105\u0107 stary kod i prze\u0142\u0105cznik<\/li>\n<\/ul>\n<p><\/p>\n<p>Proces zale\u017cy od narz\u0119dzi, j\u0119zyka i architektur zorientowanych na us\u0142ugi, ale w og\u00f3lnym zarysie wygl\u0105da tak. Nie wspomnia\u0142em o wdro\u017ceniach z migracj\u0105 baz danych, poniewa\u017c jest to wymagaj\u0105ce dok\u0142adnego planowania, ale poni\u017cej opowiem, jak z tym poradzi\u0107 sobie w Dark.<\/p>\n<p><\/p>\n<p>Wyst\u0119puje wiele komponent\u00f3w, a wiele z nich mo\u017ce \u0142atwo spowolni\u0107, zawie\u015b\u0107, powodowa\u0107 chwilow\u0105 konkurencj\u0119 lub ca\u0142kowicie zburzy\u0107 dzia\u0142aj\u0105cy system.<\/p>\n<p><\/p>\n<p>Poniewa\u017c te pipeline'y s\u0105 niemal zawsze stworzone dla szczeg\u00f3lnego przypadku, trudno na nich polega\u0107. Wiele razy zdarza si\u0119, \u017ce kod nie mo\u017ce by\u0107 wdro\u017cony, poniewa\u017c w Dockerfile s\u0105 problemy, nast\u0105pi\u0142a awaria jednego z dziesi\u0105tek serwis\u00f3w lub potrzebny specjalista jest na urlopie.<\/p>\n<p><\/p>\n<p>Co gorsza, wiele z tych krok\u00f3w w og\u00f3le nie przynosi \u017cadnej korzy\u015bci. By\u0142y potrzebne wcze\u015bniej, gdy wdra\u017cali\u015bmy kod bezpo\u015brednio dla u\u017cytkownik\u00f3w, ale teraz mamy prze\u0142\u0105czniki dla nowego kodu i te procesy si\u0119 rozdzieli\u0142y. W rezultacie krok, na kt\u00f3rym wdra\u017cany jest kod (stary zast\u0119powany nowym), sta\u0142 si\u0119 po prostu dodatkowym ryzykiem.<\/p>\n<p><\/p>\n<p>Oczywi\u015bcie, to bardzo przemy\u015blany pipeline. Zesp\u00f3\u0142, kt\u00f3ry go stworzy\u0142, nie \u017ca\u0142owa\u0142 czasu i pieni\u0119dzy na szybkie wdro\u017cenie. Zazwyczaj pipeline'y wdro\u017ceniowe s\u0105 znacznie wolniejsze i mniej niezawodne.<\/p>\n<p><\/p>\n<h3 id=\"realizaciya-nepreryvnoy-postavki-v-dark\">Implementacja ci\u0105g\u0142ej dostawy w Dark<\/h3>\n<p><\/p>\n<p>Ci\u0105g\u0142e dostarczanie jest na tyle istotne dla Dark, \u017ce od samego pocz\u0105tku d\u0105\u017cyli\u015bmy do czasu poni\u017cej sekundy. Przeanalizowali\u015bmy wszystkie kroki w procesie, aby usun\u0105\u0107 zb\u0119dne elementy, a reszt\u0119 dopracowali\u015bmy. Oto, jak usuwali\u015bmy kroki.<\/p>\n<p><\/p>\n<blockquote><p>Jessie Frazelle (<noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/jessfraz\">Jessie Frazelle<\/a><\/noindex>) wymy\u015bli\u0142a nowe s\u0142owo deployless (nie wymagaj\u0105cy wdro\u017cenia) podczas konferencji Future of Software Development w Reykjaviku.<\/p><\/blockquote>\n<p>Zdecydowali\u015bmy od razu, \u017ce Dark b\u0119dzie oparty na koncepcji \"deployless\" (dzi\u0119kujemy <noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/jessfraz\">Jessie Frazelle<\/a><\/noindex> za neologizm). Deployless oznacza, \u017ce ka\u017cdy kod jest b\u0142yskawicznie wdra\u017cany i gotowy do u\u017cycia w produkcji. Oczywi\u015bcie nie pomijamy b\u0142\u0119dnego lub niepe\u0142nego kodu (zasady bezpiecze\u0144stwa opisz\u0119 poni\u017cej).<\/p>\n<p><\/p>\n<p>Na pokazie Dark cz\u0119sto pytano nas, jak uda\u0142o nam si\u0119 tak przyspieszy\u0107 proces wdro\u017cenia. Dziwne pytanie. Ludzie mog\u0105 my\u015ble\u0107, \u017ce wymy\u015blili\u015bmy jak\u0105\u015b supertechnologi\u0119, kt\u00f3ra por\u00f3wnuje kod, kompiluje go, pakuje w kontener, uruchamia maszyn\u0119 wirtualn\u0105, a nast\u0119pnie w zimnym uruchamia kontener i tym podobne \u2014 wszystko to w 50 ms. Ma\u0142o prawdopodobne. Ale stworzyli\u015bmy specjalny silnik wdro\u017ceniowy, kt\u00f3remu to wszystko nie jest potrzebne.<\/p>\n<p><\/p>\n<p>Dark uruchamia interpretatory w chmurze. Za\u0142\u00f3\u017cmy, \u017ce piszesz kod w funkcji lub obhandlerze HTTP czy zdarze\u0144. Wysy\u0142amy r\u00f3\u017cnice do abstrakcyjnego drzewa sk\u0142adniowego (implementacji kodu, kt\u00f3r\u0105 wewn\u0119trznie wykorzystuje nasz edytor i serwery) na nasze serwery, a nast\u0119pnie uruchamiamy ten kod w odpowiedzi na zapytania. Wi\u0119c wdro\u017cenie wygl\u0105da po prostu jak skromny wpis w bazie danych \u2014 momentalny i prosty. Wdro\u017cenie odbywa si\u0119 tak szybko, poniewa\u017c obejmuje absolutne minimum.<\/p>\n<p><\/p>\n<p>W przysz\u0142o\u015bci planujemy uczyni\u0107 z Dark kompilator infrastruktury, kt\u00f3ry b\u0119dzie tworzy\u0142 i uruchamia\u0142 idealn\u0105 infrastruktur\u0119 dla wysokiej wydajno\u015bci i niezawodno\u015bci aplikacji. Momentalne wdro\u017cenie, oczywi\u015bcie, nie zniknie.<\/p>\n<p><\/p>\n<h2 id=\"bezopasnoe-razvertyvanie\">Bezpieczne wdro\u017cenie<\/h2>\n<p><\/p>\n<h3 id=\"strukturirovannyy-redaktor\">Strukturalny edytor<\/h3>\n<p><\/p>\n<p>Kod w Dark pisany jest w edytorze Dark. Strukturalny edytor nie dopuszcza do b\u0142\u0119d\u00f3w sk\u0142adniowych. Tak naprawd\u0119 w Dark nie ma nawet analizatora. Gdy wprowadzasz tekst, bezpo\u015brednio pracujemy z abstrakcyjnym drzewem sk\u0142adniowym (AST), jak <noindex><a rel=\"nofollow\" href=\"http:\/\/danmidwood.com\/content\/2014\/11\/21\/animated-paredit.html\">Paredit<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/ravichugh.github.io\/sketch-n-sketch\/\">Sketch-n-Sketch<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/gregoor.github.io\/tofu\/\">Tofu<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.facebook.com\/notes\/kent-beck\/prune-a-code-editor-that-is-not-a-text-editor\/1012061842160013\/\">Prune<\/a><\/noindex> i <noindex><a rel=\"nofollow\" href=\"https:\/\/www.jetbrains.com\/mps\/\">MPS<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Ka\u017cdy niedoko\u0144czony kod w Dark ma dopuszczaln\u0105 semantyk\u0119 wykonalno\u015bci, mniej wi\u0119cej tak jak <noindex><a rel=\"nofollow\" href=\"https:\/\/hazel.org\/\">typed holes w Hazel<\/a><\/noindex>Na przyk\u0142ad, je\u015bli zmieniasz wywo\u0142anie funkcji, zachowujemy star\u0105 funkcj\u0119, dop\u00f3ki nowa nie stanie si\u0119 gotowa.<\/p>\n<p><\/p>\n<p>Ka\u017cdy program w Dark ma sw\u00f3j sens, wi\u0119c niekompletny kod nie przeszkadza w dzia\u0142aniu uko\u0144czonego.<\/p>\n<p><\/p>\n<h3 id=\"rezhimy-redaktirovaniya\">Tryby edycji<\/h3>\n<p><\/p>\n<p>Piszesz kod w Dark w dw\u00f3ch przypadkach. Po pierwsze: piszesz nowy kod i jeste\u015b jedynym u\u017cytkownikiem. Na przyk\u0142ad, dzia\u0142a on w REPL, a inni u\u017cytkownicy nigdy nie b\u0119d\u0105 mieli do niego dost\u0119pu, lub to nowa trasa HTTP, do kt\u00f3rej nigdzie nie linkujesz. Mo\u017cna tu pracowa\u0107 bez \u017cadnych zabezpiecze\u0144, i teraz mniej wi\u0119cej tak dzia\u0142asz w \u015brodowisku deweloperskim.<\/p>\n<p><\/p>\n<p>Druga sytuacja: kod jest ju\u017c u\u017cywany. Je\u015bli przez kod przechodzi ruch (funkcje, operatory zdarze\u0144, bazy danych itd.), nale\u017cy zachowa\u0107 ostro\u017cno\u015b\u0107. W tym celu blokujemy ca\u0142y u\u017cywany kod i wymagamy korzystania z bardziej zorganizowanych narz\u0119dzi do jego edytowania. O narz\u0119dziach strukturalnych opowiem poni\u017cej: prze\u0142\u0105cznikach funkcji dla handler\u00f3w HTTP i zdarze\u0144, pot\u0119\u017cnej platformie migracji dla baz danych i nowej metodzie zarz\u0105dzania wersjami dla funkcji i typ\u00f3w.<\/p>\n<p><\/p>\n<h3 id=\"pereklyuchateli-funkciy\">Prze\u0142\u0105czniki funkcji<\/h3>\n<p><\/p>\n<p>Jednym ze sposob\u00f3w <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/the-design-of-dark-59f5d38e52d2\">usuni\u0119cia zb\u0119dnej z\u0142o\u017cono\u015bci<\/a><\/noindex> w Dark jest rozwi\u0105zanie kilku problem\u00f3w jednym podej\u015bciem. Prze\u0142\u0105czniki funkcji wykonuj\u0105 wiele r\u00f3\u017cnych zada\u0144: zast\u0119puj\u0105 lokalne \u015brodowisko deweloperskie, ga\u0142\u0119zie git, wdra\u017canie kodu i, oczywi\u015bcie, tradycyjne, wolne i kontrolowane wprowadzanie nowego kodu.<\/p>\n<p><\/p>\n<p>Utworzenie i wdro\u017cenie prze\u0142\u0105cznika funkcji odbywa si\u0119 w naszym edytorze w jednym kroku. Tworzy on pust\u0105 przestrze\u0144 dla nowego kodu i zapewnia elementy steruj\u0105ce dost\u0119pem do starego i nowego kodu oraz przyciski i polecenia do stopniowego przej\u015bcia na nowy kod lub jego wykluczenia.<\/p>\n<p><\/p>\n<p>Prze\u0142\u0105czniki funkcji s\u0105 wbudowane w j\u0119zyk Dark, a nawet niekompletne prze\u0142\u0105czniki pe\u0142ni\u0105 swoj\u0105 rol\u0119 \u2014 je\u015bli warunek w prze\u0142\u0105czniku nie jest spe\u0142niony, wykonany zostanie stary zablokowany kod.<\/p>\n<p><\/p>\n<h3 id=\"sreda-razrabotki\">\u015arodowisko deweloperskie<\/h3>\n<p><\/p>\n<p>Prze\u0142\u0105czniki funkcji zast\u0119puj\u0105 lokalne \u015brodowisko deweloperskie. Dzi\u015b zespo\u0142y maj\u0105 trudno\u015bci z zapewnieniem, \u017ce wszyscy u\u017cywaj\u0105 tych samych wersji narz\u0119dzi i bibliotek (narz\u0119dzia do formatowania kodu, linters, mened\u017cery pakiet\u00f3w, kompilatory, preprocessory, narz\u0119dzia testowe itd.). Dzi\u0119ki Dark nie trzeba lokalnie instalowa\u0107 zale\u017cno\u015bci, zarz\u0105dza\u0107 lokaln\u0105 instalacj\u0105 Dockera ani podejmowa\u0107 innych dzia\u0142a\u0144, aby zapewni\u0107 cho\u0107by namiastk\u0119 r\u00f3wno\u015bci mi\u0119dzy \u015brodowiskiem deweloperskim a produkcj\u0105. <noindex><a rel=\"nofollow\" href=\"https:\/\/thenewstack.io\/honeycombs-charity-majors-go-ahead-test-in-production\/\">Bior\u0105c pod uwag\u0119, \u017ce taka r\u00f3wno\u015b\u0107 i tak jest niemo\u017cliwa<\/a><\/noindex>, nawet nie b\u0119dziemy udawa\u0107, \u017ce d\u0105\u017cymy do niej.<\/p>\n<p><\/p>\n<p>Zamiast tworzy\u0107 sklonowane lokalne \u015brodowisko, prze\u0142\u0105czniki w Dark tworz\u0105 now\u0105 piaskownic\u0119 na produkcji, kt\u00f3ra zast\u0119puje \u015brodowisko deweloperskie. W przysz\u0142o\u015bci planujemy tak\u017ce tworzy\u0107 piaskownice dla innych cz\u0119\u015bci aplikacji (np. natychmiastowe klony baz danych), chocia\u017c obecnie nie wydaje si\u0119 to zbyt istotne.<\/p>\n<p><\/p>\n<h3 id=\"vetki-i-razvertyvaniya\">Ga\u0142\u0119zie i wdro\u017cenia<\/h3>\n<p><\/p>\n<p>Obecnie istnieje kilka sposob\u00f3w wprowadzania nowego kodu do system\u00f3w: ga\u0142\u0119zie git, etapy wdro\u017cenia i prze\u0142\u0105czniki funkcji. Rozwi\u0105zuj\u0105 one jeden problem w r\u00f3\u017cnych cz\u0119\u015bciach procesu roboczego: git \u2014 na etapach przed wdro\u017ceniem, wdro\u017cenie \u2014 w momencie przej\u015bcia ze starego kodu na nowy, a prze\u0142\u0105czniki funkcji \u2014 do kontrolowanego wydania nowego kodu.<\/p>\n<p><\/p>\n<p>Najskuteczniejszym sposobem s\u0105 prze\u0142\u0105czniki funkcji (co jest jednocze\u015bnie najprostszym do zrozumienia i u\u017cywania). Dzi\u0119ki nim mo\u017cna ca\u0142kowicie zrezygnowa\u0107 z pozosta\u0142ych dw\u00f3ch metod. Szczeg\u00f3lnie przydatne jest usuni\u0119cie etapu wdro\u017cenia \u2014 je\u015bli mimo wszystko u\u017cywamy prze\u0142\u0105cznik\u00f3w funkcji do w\u0142\u0105czania kodu, to etap prze\u0142\u0105czania serwer\u00f3w na nowy kod tylko stwarza zb\u0119dne ryzyko.<\/p>\n<p><\/p>\n<p>Git jest trudny w u\u017cyciu, zw\u0142aszcza dla nowicjuszy, co ogranicza jego zastosowanie, ale ma wygodne ga\u0142\u0119zie. Wyeliminowali\u015bmy wiele wad gita. Dark edytuje w czasie rzeczywistym i zapewnia mo\u017cliwo\u015b\u0107 wsp\u00f3\u0142pracy w stylu Google Docs, dzi\u0119ki czemu nie trzeba wysy\u0142a\u0107 kodu i rzadziej wykonuje si\u0119 rebase i merge.<\/p>\n<p><\/p>\n<p>Prze\u0142\u0105czniki funkcji s\u0105 kluczowe dla bezpiecznego wdra\u017cania. Wraz z natychmiastowym wdra\u017caniem umo\u017cliwiaj\u0105 szybkie testowanie koncepcji w ma\u0142ych fragmentach o niskim ryzyku, zamiast wprowadza\u0107 jedn\u0105 du\u017c\u0105 zmian\u0119, kt\u00f3ra mo\u017ce zrujnowa\u0107 system.<\/p>\n<p><\/p>\n<h3 id=\"versionirovanie\">Wersjonowanie<\/h3>\n<p><\/p>\n<p>Do zmiany funkcji i typ\u00f3w u\u017cywamy wersjonowania. Je\u015bli chcesz zmieni\u0107 funkcj\u0119, Dark tworzy now\u0105 wersj\u0119 tej funkcji. Nast\u0119pnie mo\u017cesz wywo\u0142a\u0107 t\u0119 wersj\u0119 za pomoc\u0105 prze\u0142\u0105cznika w obs\u0142udze HTTP lub zdarze\u0144. (Je\u015bli ta funkcja jest g\u0142\u0119boko w grafie wywo\u0142a\u0144, nowa wersja ka\u017cdej funkcji jest tworzona po drodze. Mo\u017ce si\u0119 to wydawa\u0107 zbyt skomplikowane, ale funkcje nie przeszkadzaj\u0105, je\u015bli ich nie u\u017cywasz, wi\u0119c nawet tego nie zauwa\u017cysz.)<\/p>\n<p><\/p>\n<p>Z tych samych powod\u00f3w wersjonujemy typy. O naszym systemie typ\u00f3w szczeg\u00f3\u0142owo pisali\u015bmy <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/real-problems-with-functional-languages-efe668c5264a\">w poprzednim po\u015bcie<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Dzi\u0119ki wersjonowaniu funkcji i typ\u00f3w mo\u017cesz wprowadza\u0107 zmiany w aplikacji stopniowo. Mo\u017cna sprawdzi\u0107, \u017ce ka\u017cdy oddzielny obs\u0142ugiwacz dzia\u0142a z now\u0105 wersj\u0105, nie trzeba od razu wprowadza\u0107 wszystkich zmian w aplikacjach (ale mamy narz\u0119dzia, aby szybko to zrobi\u0107, je\u015bli zajdzie taka potrzeba).<\/p>\n<p><\/p>\n<p>To znacznie bezpieczniejsze ni\u017c pe\u0142ne wdra\u017canie wszystkiego jednocze\u015bnie, jak ma to miejsce obecnie.<\/p>\n<p><\/p>\n<h3 id=\"novye-versii-paketov-i-standartnaya-biblioteka\">Nowe wersje pakiet\u00f3w i standardowa biblioteka<\/h3>\n<p><\/p>\n<p>Kiedy aktualizujesz pakiet w Dark, nie zast\u0119pujemy od razu u\u017cycia ka\u017cdej funkcji lub typu w ca\u0142ej bazie kodu. To nie jest bezpieczne. Kod nadal u\u017cywa tej samej wersji, kt\u00f3r\u0105 u\u017cywa\u0142, a ty aktualizujesz u\u017cycie funkcji i typ\u00f3w do nowej wersji dla ka\u017cdego indywidualnego przypadku za pomoc\u0105 prze\u0142\u0105cznik\u00f3w.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/rh\/t3\/4w\/rht34wyibolrgracbz88tnqqhg0.png\"><img decoding=\"async\" alt=\"Jak Dark wdra\u017ca kod w 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/54fdb566b4bcbc10e06e51c47a3820f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<em>Zrzut ekranu cz\u0119\u015bci automatycznego procesu w Dark, pokazuj\u0105cy dwie wersje funkcji Dict::get. Dict::get_v0 zwraca\u0142 typ Any (kt\u00f3rego si\u0119 pozbywamy), a Dict::get_v1 zwraca typ Option.<\/em><\/p>\n<p><\/p>\n<p>Cz\u0119sto dostarczamy now\u0105 funkcj\u0119 standardowej biblioteki i wykluczamy stare wersje. U\u017cytkownicy ze starymi wersjami w kodzie zachowaj\u0105 do nich dost\u0119p, ale nowi u\u017cytkownicy nie b\u0119d\u0105 mogli ich uzyska\u0107. Planujemy dostarczy\u0107 narz\u0119dzia, aby przenie\u015b\u0107 u\u017cytkownik\u00f3w ze starych wersji na nowe za jednym krokiem, znowu za pomoc\u0105 prze\u0142\u0105cznik\u00f3w funkcji.<\/p>\n<p><\/p>\n<p>Dark oferuje r\u00f3wnie\u017c unikaln\u0105 mo\u017cliwo\u015b\u0107: poniewa\u017c uruchamiamy Tw\u00f3j kod roboczy, mo\u017cemy testowa\u0107 nowe wersje, por\u00f3wnuj\u0105c wyniki dla nowych i starych zapyta\u0144, aby poinformowa\u0107 Ci\u0119 o zmianach. Ostatecznie aktualizacja pakiet\u00f3w, kt\u00f3ra cz\u0119sto jest przeprowadzana na \u015blepo (lub wymaga dok\u0142adnego testowania w celach bezpiecze\u0144stwa), staje si\u0119 znacznie mniej ryzykowna i mo\u017ce odbywa\u0107 si\u0119 automatycznie.<\/p>\n<p><\/p>\n<h3 id=\"novye-versii-dark\">Nowe wersje Dark<\/h3>\n<p><\/p>\n<p>Migracja z Pythona 2 do Pythona 3 trwa\u0142a dekad\u0119 i wci\u0105\u017c jest problematyczna. Poniewa\u017c tworzymy Dark do ci\u0105g\u0142ego dostarczania, musimy uwzgl\u0119dni\u0107 te zmiany j\u0119zykowe.<\/p>\n<p><\/p>\n<p>Kiedy wprowadzamy niewielkie zmiany w j\u0119zyku, tworzymy now\u0105 wersj\u0119 Dark. Stary kod pozostaje w starej wersji Dark, a nowy kod jest u\u017cywany w nowej wersji. Przy przej\u015bciu na now\u0105 wersj\u0119 Dark mo\u017cna u\u017cywa\u0107 prze\u0142\u0105cznik\u00f3w lub wersji funkcji.<\/p>\n<p><\/p>\n<p>Jest to szczeg\u00f3lnie przydatne, bior\u0105c pod uwag\u0119, \u017ce Dark pojawi\u0142 si\u0119 ca\u0142kiem niedawno. Wiele zmian w j\u0119zyku lub bibliotece mo\u017ce okaza\u0107 si\u0119 nieudanych. Stopniowe wersjonowanie j\u0119zyka pozwala nam na wprowadzanie niewielkich aktualizacji, co oznacza, \u017ce nie musimy si\u0119 spieszy\u0107 i mo\u017cemy od\u0142o\u017cy\u0107 wiele decyzji dotycz\u0105cych j\u0119zyka, a\u017c b\u0119dziemy mieli wi\u0119cej u\u017cytkownik\u00f3w, a zatem wi\u0119cej informacji.<\/p>\n<p><\/p>\n<h3 id=\"migracii-baz-dannyh\">Migracje baz danych<\/h3>\n<p><\/p>\n<p>Dla bezpiecznej migracji bazy danych istnieje <noindex><a rel=\"nofollow\" href=\"http:\/\/www.brunton-spall.co.uk\/post\/2014\/05\/06\/database-migrations-done-right\/\">standardowa formu\u0142a<\/a><\/noindex>:<\/p>\n<p><\/p>\n<ul>\n<li>Przepisa\u0107 kod na potrzeby wsparcia nowych i starych format\u00f3w<\/li>\n<li>Przekszta\u0142ci\u0107 wszystkie dane do nowego formatu<\/li>\n<li>Usun\u0105\u0107 stary dost\u0119p do danych<\/li>\n<\/ul>\n<p><\/p>\n<p>W rezultacie migracja bazy danych wyd\u0142u\u017ca si\u0119 i wymaga wielu zasob\u00f3w. Gromadz\u0105 si\u0119 u nas przestarza\u0142e schematy, poniewa\u017c nawet proste zadania, takie jak poprawa nazwy tabeli czy kolumny, nie s\u0105 warte poniesionych wysi\u0142k\u00f3w.<\/p>\n<p><\/p>\n<p>Dark ma efektywn\u0105 platform\u0119 migracji baz danych, kt\u00f3ra (mamy nadziej\u0119) tak upro\u015bci proces, \u017ce przestaniesz si\u0119 go ba\u0107. Wszystkie zbiory danych w Dark (zbiory par \u201eklucz-warto\u015b\u0107\u201d lub trwa\u0142e tablice haszuj\u0105ce) maj\u0105 typ. Aby przenie\u015b\u0107 zbi\u00f3r danych, po prostu przypisujesz mu nowy typ oraz funkcj\u0119 wycofania i zastosowania do przekszta\u0142cania warto\u015bci mi\u0119dzy dwoma typami.<\/p>\n<p><\/p>\n<p>Dost\u0119p do zbior\u00f3w danych w Dark odbywa si\u0119 za pomoc\u0105 wersjonowanych nazw zmiennych. Na przyk\u0142ad, zbi\u00f3r danych Users pocz\u0105tkowo b\u0119dzie nosi\u0142 nazw\u0119 Users-v0. Gdy tworzona jest nowa wersja o innym typie, nazwa zmienia si\u0119 na Users-v1. Je\u015bli dane zosta\u0142y zapisane za pomoc\u0105 Users-v0, a uzyskujesz do nich dost\u0119p przez Users-v1, stosowana jest funkcja przywracania. Je\u015bli dane zosta\u0142y zapisane przez Users-v1, a uzyskujesz do nich dost\u0119p przez Users-v0, stosowana jest funkcja cofania.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/ui\/sl\/wd\/uislwdrfrvact0d1ts5icnk-4ka.png\"><img decoding=\"async\" alt=\"Jak Dark wdra\u017ca kod w 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/35743ba246f327ca9e8b71f0069a3800.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<em>Ekran migracji bazy danych z nazwami p\u00f3l starej bazy danych, wyra\u017ceniami przywracania i cofania oraz instrukcjami dotycz\u0105cymi w\u0142\u0105czenia migracji.<\/em><\/p>\n<p><\/p>\n<p>U\u017cyj prze\u0142\u0105cznik\u00f3w funkcji, aby kierowa\u0107 wywo\u0142ania do Users-v0 w wersj\u0119 Users-v1. Mo\u017cna to robi\u0107 po jednym obs\u0142ugiwaczu HTTP na raz, aby zminimalizowa\u0107 ryzyko, a prze\u0142\u0105czniki dzia\u0142aj\u0105 dla poszczeg\u00f3lnych u\u017cytkownik\u00f3w, aby\u015b m\u00f3g\u0142 sprawdzi\u0107, \u017ce wszystko dzia\u0142a zgodnie z oczekiwaniami. Gdy u\u017cytkownik\u00f3w Users-v0 ju\u017c nie b\u0119dzie, Dark automatycznie przekszta\u0142ci wszystkie pozosta\u0142e dane w tle ze starego formatu na nowy. Nie zauwa\u017cysz nawet, \u017ce to si\u0119 dzieje.<\/p>\n<p><\/p>\n<h3 id=\"testirovanie\">Testowanie<\/h3>\n<p><\/p>\n<p>Dark to <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/real-problems-with-functional-languages-efe668c5264a\">funkcjonalny j\u0119zyk programowania o statycznym typowaniu<\/a><\/noindex> i niemutowalnych warto\u015bciach, dlatego powierzchnia testowania jest znacznie mniejsza w por\u00f3wnaniu do j\u0119zyk\u00f3w obiektowych z dynamicznym typowaniem. Ale nadal trzeba testowa\u0107.<br \/>\nW Dark edytor automatycznie uruchamia testy jednostkowe w tle dla edytowanego kodu i domy\u015blnie przeprowadza te testy dla wszystkich prze\u0142\u0105cznik\u00f3w funkcji. W przysz\u0142o\u015bci chcemy automatycznie przeprowadza\u0107 fuzzing kodu za pomoc\u0105 statycznych typ\u00f3w, aby znajdowa\u0107 b\u0142\u0119dy.<\/p>\n<p><\/p>\n<p>Ponadto, Dark wykonuje twoj\u0105 infrastruktur\u0119 w produkcji, co otwiera nowe mo\u017cliwo\u015bci. Automatycznie zapisujemy zapytania HTTP w infrastrukturze Dark (na razie zapisujemy wszystkie zapytania, ale p\u00f3\u017aniej chcemy przej\u015b\u0107 do pr\u00f3bkowania). Testujemy na ich podstawie nowy kod i przeprowadzamy testy jednostkowe, a je\u015bli chcesz, mo\u017cesz \u0142atwo przekszta\u0142ci\u0107 interesuj\u0105ce zapytania w testy jednostkowe.<\/p>\n<p><\/p>\n<h3 id=\"ot-chego-my-izbavilis\">Czego si\u0119 pozbyli\u015bmy<\/h3>\n<p><\/p>\n<p>Skoro nie mamy wdro\u017ce\u0144, ale mamy prze\u0142\u0105czniki funkcji, oko\u0142o 60% procesu wdro\u017cenia pozostaje na uboczu. Nie potrzebujemy ga\u0142\u0119zi git ani pull request\u00f3w, budowania zasob\u00f3w backendowych i kontener\u00f3w, wysy\u0142ania zasob\u00f3w i kontener\u00f3w do rejestr\u00f3w ani krok\u00f3w wdro\u017ceniowych w Kubernetes.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/gc\/9e\/g-\/gc9eg-szouq0dtrxxr8jd6c6dyo.jpeg\"><img decoding=\"async\" alt=\"Jak Dark wdra\u017ca kod w 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/d584b13a1f91e9eef1e2e40c25e90052.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<em>Por\u00f3wnanie standardowego pipeline'u ci\u0105g\u0142ej dostawy (po lewej) oraz Dark Continuous Delivery (po prawej). W Dark dostawa sk\u0142ada si\u0119 z 6 krok\u00f3w i jednego cyklu, podczas gdy tradycyjna wersja obejmuje 35 krok\u00f3w i 3 cykle.<\/em><\/p>\n<p><\/p>\n<p>W Dark wdra\u017canie wymaga tylko 6 krok\u00f3w i 1 cyklu (kroki, kt\u00f3re powtarzaj\u0105 si\u0119 wielokrotnie), podczas gdy nowoczesny pipeline ci\u0105g\u0142ej dostawy sk\u0142ada si\u0119 z 35 krok\u00f3w i 3 cykli. W Dark testy uruchamiaj\u0105 si\u0119 automatycznie, a Ty nawet tego nie zauwa\u017casz; zale\u017cno\u015bci instaluj\u0105 si\u0119 automatycznie; wszystko, co dotyczy git lub Github, nie jest ju\u017c potrzebne; nie trzeba budowa\u0107, testowa\u0107 i przesy\u0142a\u0107 kontener\u00f3w Docker; wdra\u017canie w Kubernetes jest zb\u0119dne.<\/p>\n<p><\/p>\n<p>Nawet pozostaj\u0105ce kroki w Dark sta\u0142y si\u0119 prostsze. Dzi\u0119ki zarz\u0105dzaniu prze\u0142\u0105cznikami funkcji za pomoc\u0105 jednego dzia\u0142ania nie ma potrzeby ponownego przechodzenia przez ca\u0142y pipeline wdro\u017ceniowy, aby usun\u0105\u0107 stary kod.<\/p>\n<p><\/p>\n<p>Upro\u015bcili\u015bmy dostarczanie kodu, skracaj\u0105c czas i ryzyko zwi\u0105zane z ci\u0105g\u0142\u0105 dostaw\u0105. Dodatkowo znacznie upro\u015bcili\u015bmy aktualizacje pakiet\u00f3w, migracje baz danych, testowanie, zarz\u0105dzanie wersjami, instalacj\u0119 zale\u017cno\u015bci, r\u00f3wno\u015b\u0107 mi\u0119dzy \u015brodowiskiem deweloperskim a produkcyjnym oraz szybkie i bezpieczne aktualizacje wersji j\u0119zyka.<\/p>\n<p><\/p>\n<p>Odpowiadam na pytania dotycz\u0105ce tego na <noindex><a rel=\"nofollow\" href=\"https:\/\/news.ycombinator.com\/item?id=20394166\">HackerNews<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Aby dowiedzie\u0107 si\u0119 wi\u0119cej o urz\u0105dzeniu Dark, przeczytaj <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/the-design-of-dark-59f5d38e52d2\">artyku\u0142 o Dark<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/darklang?source=post_page---------------------------\">obserwuj nas na Twitterze<\/a><\/noindex> (lub na <noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/paulbiggar?source=post_page---------------------------\">mnie<\/a><\/noindex>) lub <noindex><a rel=\"nofollow\" href=\"https:\/\/darklang.com\/subscribe?source=post_page---------------------------\">zapisz si\u0119 na wersj\u0119 beta i otrzymuj powiadomienia o kolejnych postach<\/a><\/noindex>. Je\u015bli wybierasz si\u0119 na StrangeLoop we wrze\u015bniu, <noindex><a rel=\"nofollow\" href=\"https:\/\/darklang.com\/launch\">przyjd\u017a na nasz\u0105 premier\u0119<\/a><\/noindex>.<\/p>\n<p>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/southbridge\/blog\/462027\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0427\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043f\u0440\u043e\u0442\u0438\u0432 \u043d\u0430\u0441 \u2014 \u043d\u0430\u0448\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0438\u043a\u043e\u043c\u0443 \u043d\u0435 \u043c\u0435\u0448\u0430\u0442\u044c \u0438 \u043d\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a \u043f\u0440\u043e\u0441\u0442\u043e\u044f\u043c \u0438 \u043f\u0435\u0440\u0435\u0440\u044b\u0432\u0430\u043c. \u0420\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0432 \u0442\u0430\u043a\u0438\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 \u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u0432 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0439 \u043f\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0434\u0430\u0436\u0435 \u0432 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0445 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0445. [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":27506,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-36721","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0427\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0430\u043a Dark \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u0434 \u0437\u0430 50 \u043c\u0441 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0427\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:13:20+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:13:20+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Jak Dark wdra\u017ca kod w 50 ms | ProHoster","description":"Im szybszy proces rozwoju, tym szybciej.","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0430\u043a Dark \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u0434 \u0437\u0430 50 \u043c\u0441 | ProHoster","og:description":"\u0427\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435.","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:13:20+00:00","article:modified_time":"2019-10-31T19:13:20+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"36721","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 04:34:22","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:40:22","updated":"2026-01-22 04:34:22","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/36721","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=36721"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/36721\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/27506"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=36721"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=36721"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=36721"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}