{"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\/ro\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms","title":{"rendered":"Cum Dark desf\u0103\u0219oar\u0103 codul \u00een 50 ms","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Cum Dark desf\u0103\u0219oar\u0103 codul \u00een 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/c159a36eb52bf488f3a70ea511690366.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Cu c\u00e2t mai rapid este procesul de dezvoltare, cu at\u00e2t mai repede se dezvolt\u0103 o companie tehnologic\u0103.<\/p>\n<p><\/p>\n<p>Din p\u0103cate, aplica\u021biile moderne func\u021bioneaz\u0103 \u00eempotriva noastr\u0103 - sistemele noastre trebuie s\u0103 se actualizeze \u00een timp real, f\u0103r\u0103 a deranja pe nimeni sau a provoca downtime-uri \u0219i \u00eentreruperi. Implementarea \u00een astfel de sisteme devine o sarcin\u0103 complex\u0103 \u0219i necesit\u0103 pipeline-uri complicate de livrare continu\u0103 chiar \u0219i \u00een echipe mici.<\/p>\n<p><\/p>\n<p>Aceste pipeline-uri au, de obicei, o utilizare restr\u00e2ns\u0103, func\u021bioneaz\u0103 lent \u0219i nu sunt fiabile. Dezvoltatorii trebuie s\u0103 le creeze mai \u00eent\u00e2i manual \u0219i apoi s\u0103 le gestioneze, iar companiile angajeaz\u0103 adesea echipe \u00eentregi de DevOps pentru aceasta.<\/p>\n<p><\/p>\n<p>Viteza acestor pipeline-uri determin\u0103 viteza de dezvoltare. La cele mai bune echipe, implementarea dureaz\u0103 \u00eentre 5-10 minute, dar de obicei dureaz\u0103 mult mai mult, necesit\u00e2nd c\u00e2teva ore pentru o singur\u0103 implementare.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>La Dark, acest lucru dureaz\u0103 50 ms. <em>Cincizeci. Milisecunde.<\/em>. Dark - <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/the-design-of-dark-59f5d38e52d2\">este o solu\u021bie complex\u0103 cu un limbaj de programare, un editor \u0219i o infrastructur\u0103<\/a><\/noindex>, creat\u0103 special pentru livrare continu\u0103, iar toate aspectele Dark, inclusiv limbajul \u00een sine, sunt construite av\u00e2nd \u00een vedere implementarea instantanee \u0219i sigur\u0103.<\/p>\n<p><\/p>\n<h3 id=\"pochemu-konveyery-nepreryvnoy-postavki-takie-medlennye\">De ce sunt pipeline-urile de livrare continu\u0103 at\u00e2t de lente?<\/h3>\n<p><\/p>\n<p>S\u0103 spunem c\u0103 avem o aplica\u021bie web Python \u0219i deja am creat un pipeline de livrare continu\u0103 minunat \u0219i modern. Pentru un dezvoltator care lucreaz\u0103 zilnic la acest proiect, implementarea unei singure modific\u0103ri minore va ar\u0103ta aproximativ astfel:<\/p>\n<p><\/p>\n<h3 id=\"vnesenie-izmeneniy\">Facerea modific\u0103rilor<\/h3>\n<p><\/p>\n<ul>\n<li>Crearea unei noi ramuri \u00een git<\/li>\n<li>Facerea modific\u0103rilor cu comutatorul de func\u021bii<\/li>\n<li>Testare modular\u0103 pentru a verifica modific\u0103rile cu \u0219i f\u0103r\u0103 comutatorul de func\u021bii<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"pul-rekvest\">Pull request<\/h3>\n<p><\/p>\n<ul>\n<li>Comitere a modific\u0103rilor<\/li>\n<li>\u00cenc\u0103rcarea modific\u0103rilor \u00een depozitul remote pe github<\/li>\n<li>Pull request<\/li>\n<li>Construc\u021bia CI se execut\u0103 automat \u00een fundal<\/li>\n<li>Revizuirea codului<\/li>\n<li>\u00cenc\u0103 c\u00e2teva revizuiri, dac\u0103 este necesar<\/li>\n<li>Fuzionarea modific\u0103rilor cu master-ul git.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"ci-vypolnyaetsya-na-mastere\">CI se execut\u0103 pe master.<\/h3>\n<p><\/p>\n<ul>\n<li>Instalarea dependen\u021belor frontend prin npm<\/li>\n<li>Construirea \u0219i optimizarea resurselor HTML+CSS+JS<\/li>\n<li>Rularea testelor modulare \u0219i func\u021bionale \u00een frontend<\/li>\n<li>Instalarea dependen\u021belor Python din PyPI<\/li>\n<li>Rularea testelor modulare \u0219i func\u021bionale \u00een backend<\/li>\n<li>Testarea integr\u0103rii la ambele capete<\/li>\n<li>\u00cenc\u0103rcarea resurselor frontend \u00een CDN<\/li>\n<li>Construirea containerului pentru aplica\u021bia Python.<\/li>\n<li>Trimiterea containerului \u00een registru<\/li>\n<li>Actualizarea manifestului Kubernetes<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"zamena-starogo-koda-novym\">\u00cenlocuirea vechiului cod cu unul nou<\/h3>\n<p><\/p>\n<ul>\n<li>Kubernetes lanseaz\u0103 mai multe instan\u021be ale noului container<\/li>\n<li>Kubernetes a\u0219teapt\u0103 ca instan\u021bele s\u0103 devin\u0103 operative<\/li>\n<li>Kubernetes adaug\u0103 instan\u021bele \u00een echilibratorul de \u00eenc\u0103rcare HTTP<\/li>\n<li>Kubernetes a\u0219teapt\u0103 ca vechile instan\u021be s\u0103 nu mai fie folosite<\/li>\n<li>Kubernetes opre\u0219te vechile instan\u021be<\/li>\n<li>Kubernetes repet\u0103 aceste opera\u021biuni p\u00e2n\u0103 c\u00e2nd noile instan\u021be \u00eenlocuiesc toate vechile<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"vklyuchenie-novogo-pereklyuchatelya-funkcii\">Activarea noului comutator de func\u021bii<\/h3>\n<p><\/p>\n<ul>\n<li>Noul cod este activat doar pentru sine, pentru a se asigura c\u0103 totul este \u00een regul\u0103<\/li>\n<li>Noul cod este activat pentru 10% din utilizatori, urm\u0103rind metricile opera\u021bionale \u0219i de afaceri<\/li>\n<li>Noul cod este activat pentru 50% din utilizatori, urm\u0103rind metricile opera\u021bionale \u0219i de afaceri<\/li>\n<li>Noul cod este activat pentru 100% din utilizatori, urm\u0103rind metricile opera\u021bionale \u0219i de afaceri<\/li>\n<li>\u00cen final, repe\u021bi \u00eentreaga procedur\u0103 pentru a elimina vechiul cod \u0219i comutatorul<\/li>\n<\/ul>\n<p><\/p>\n<p>Procesul depinde de instrumente, limbaj \u0219i utilizarea arhitecturilor orientate pe servicii, dar \u00een linii mari arat\u0103 astfel. Nu am men\u021bionat desf\u0103\u0219ur\u0103rile cu migrarea bazelor de date, deoarece aceasta necesit\u0103 o planificare atent\u0103, dar mai jos voi explica cum se ocup\u0103 Dark cu aceasta.<\/p>\n<p><\/p>\n<p>Exist\u0103 multe componente \u0219i multe dintre ele pot \u00eencetini, e\u0219ua, provoca concuren\u021b\u0103 temporar\u0103 sau pr\u0103bu\u0219i sistemul de lucru.<\/p>\n<p><\/p>\n<p>\u0218i cum aceste pipeline-uri sunt aproape \u00eentotdeauna create pentru cazuri speciale, este greu s\u0103 te bazezi pe ele. Multe zile, codul nu poate fi desf\u0103\u0219urat pentru c\u0103 exist\u0103 probleme \u00een Dockerfile, unul dintre zecile de servicii a e\u0219uat sau specialistul necesar este \u00een concediu.<\/p>\n<p><\/p>\n<p>Mai r\u0103u, multe dintre aceste etape nu fac nimic util. Au fost necesare \u00eenainte, c\u00e2nd desf\u0103\u0219uram codul direct pentru utilizatori, dar acum avem comutatoare pentru noul cod \u0219i aceste procese s-au separat. Ca rezultat, etapa \u00een care se desf\u0103\u0219oar\u0103 codul (vechiul \u00eenlocuit cu noul) a devenit acum doar un risc suplimentar.<\/p>\n<p><\/p>\n<p>Desigur, acesta este un pipeline foarte bine g\u00e2ndit. Echipa care l-a creat nu a economisit timp sau bani pentru desf\u0103\u0219urarea rapid\u0103. De obicei, pipeline-urile de desf\u0103\u0219urare sunt mult mai lente \u0219i mai nesigure.<\/p>\n<p><\/p>\n<h3 id=\"realizaciya-nepreryvnoy-postavki-v-dark\">Implementarea livr\u0103rii continue \u00een Dark<\/h3>\n<p><\/p>\n<p>Livrarea continu\u0103 este at\u00e2t de important\u0103 pentru Dark, \u00eenc\u00e2t ne-am concentrat de la \u00eenceput pe un timp mai mic de o secund\u0103. Am analizat fiecare pas din pipeline pentru a elimina tot ce era inutil, iar restul l-am perfec\u021bionat. Iat\u0103 cum am eliminat pa\u0219ii.<\/p>\n<p><\/p>\n<blockquote><p>Jessie Frazelle (<noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/jessfraz\">Jessie Frazelle<\/a><\/noindex>) a venit cu un nou cuv\u00e2nt, deployless (f\u0103r\u0103 desf\u0103\u0219urare), la conferin\u021ba Future of Software Development din Reykjavik.<\/p><\/blockquote>\n<p>Imediat am decis c\u0103 Dark se va baza pe conceptul de \u00abdeployless\u00bb (mul\u021bumim <noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/jessfraz\">Jessie Frazelle<\/a><\/noindex> pentru neologism). Deployless \u00eenseamn\u0103 c\u0103 orice cod este desf\u0103\u0219urat instantaneu \u0219i gata de utilizare \u00een produc\u021bie. Sigur, nu vom l\u0103sa cod defectuos sau incomplet s\u0103 treac\u0103 (principiile de securitate le voi explica mai jos).<\/p>\n<p><\/p>\n<p>La demonstrarea Dark, adesea am fost \u00eentreba\u021bi cum am reu\u0219it s\u0103 acceler\u0103m desf\u0103\u0219urarea. O \u00eentrebare ciudat\u0103. Probabil c\u0103 oamenii cred c\u0103 am inventat o supertehnologie care compar\u0103 codul, \u00eel compileaz\u0103, \u00eel \u00eempacheteaz\u0103 \u00eentr-un container, porne\u0219te o ma\u0219in\u0103 virtual\u0103 \u0219i lanseaz\u0103 containerul rece, toate acestea \u00een 50 ms. Este pu\u021bin probabil s\u0103 fie posibil. Dar am creat un motor de desf\u0103\u0219urare special care nu are nevoie de toate acestea.<\/p>\n<p><\/p>\n<p>Dark ruleaz\u0103 interpretoare \u00een cloud. S\u0103 presupunem c\u0103 scrie\u021bi cod \u00eentr-o func\u021bie sau un handler HTTP sau de evenimente. Trimitem diff-ul \u00een arborele de sintax\u0103 abstract (implementarea codului pe care editorul nostru \u0219i serverele noastre \u00eel folosesc intern) c\u0103tre serverele noastre, iar apoi execut\u0103m codul c\u00e2nd vin solicit\u0103rile. A\u0219adar, desf\u0103\u0219urarea arat\u0103 pur \u0219i simplu ca o \u00eenregistrare modest\u0103 \u00een baza de date \u2013 rapid\u0103 \u0219i elementar\u0103. Desf\u0103\u0219urarea se face at\u00e2t de repede, pentru c\u0103 include minimum.<\/p>\n<p><\/p>\n<p>\u00cen viitor, pl\u0103nuim s\u0103 transform\u0103m Dark \u00eentr-un compilator de infrastructur\u0103 care va crea \u0219i va rula infrastructura ideal\u0103 pentru performan\u021ba ridicat\u0103 \u0219i fiabilitatea aplica\u021biilor. Desf\u0103\u0219urarea instantanee, desigur, nu va disp\u0103rea.<\/p>\n<p><\/p>\n<h2 id=\"bezopasnoe-razvertyvanie\">Desf\u0103\u0219urare sigur\u0103<\/h2>\n<p><\/p>\n<h3 id=\"strukturirovannyy-redaktor\">Editor structurat<\/h3>\n<p><\/p>\n<p>Codul din Dark este scris \u00een editorul Dark. Editorul structurat nu permite erori de sintax\u0103. Practic, \u00een Dark nu exist\u0103 niciun analizzor. At\u00e2ta timp c\u00e2t introduce\u021bi text, lucr\u0103m direct cu arborele de sintax\u0103 abstract\u0103 (AST), a\u0219a cum ar fi <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> \u0219i <noindex><a rel=\"nofollow\" href=\"https:\/\/www.jetbrains.com\/mps\/\">MPS<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Orice cod neterminat \u00een Dark are o semantica de execu\u021bie valid\u0103, aproximativ ca <noindex><a rel=\"nofollow\" href=\"https:\/\/hazel.org\/\">h\u00e2rtia tipizat\u0103 \u00een Hazel<\/a><\/noindex>. De exemplu, dac\u0103 schimbi apelul unei func\u021bii, p\u0103str\u0103m func\u021bia veche p\u00e2n\u0103 c\u00e2nd cea nou\u0103 devine adecvat\u0103.<\/p>\n<p><\/p>\n<p>Fiecare program din Dark are sensul s\u0103u, a\u0219a c\u0103 codul incomplet nu \u00eempiedic\u0103 func\u021bionarea celui complet.<\/p>\n<p><\/p>\n<h3 id=\"rezhimy-redaktirovaniya\">Moduri de editare<\/h3>\n<p><\/p>\n<p>Scrii cod \u00een Dark \u00een dou\u0103 situa\u021bii. Prima: scrii un cod nou \u0219i e\u0219ti singurul utilizator. De exemplu, acesta se afl\u0103 \u00een REPL \u0219i al\u021bi utilizatori nu vor avea niciodat\u0103 acces la el, sau este un nou endpoint HTTP la care nu te referi nic\u0103ieri. Aici se poate lucra f\u0103r\u0103 m\u0103suri de precau\u021bie, \u0219i acum func\u021bionezi cam a\u0219a \u00een mediul de dezvoltare.<\/p>\n<p><\/p>\n<p>A doua situa\u021bie: codul este deja folosit. Dac\u0103 traficul trece prin cod (func\u021bii, gestionari de evenimente, baze de date, tipuri), trebuie s\u0103 fii precaut. Pentru aceasta, bloc\u0103m tot codul utilizat \u0219i cerem utilizarea unor instrumente mai structurate pentru editare. Voi explica despre instrumentele structurale mai jos: comutatoarele de func\u021bii pentru gestionarii HTTP \u0219i evenimente, o platform\u0103 puternic\u0103 de migrare pentru baze de date \u0219i o nou\u0103 metod\u0103 de gestionare a versiunilor pentru func\u021bii \u0219i tipuri.<\/p>\n<p><\/p>\n<h3 id=\"pereklyuchateli-funkciy\">Comutatoare de func\u021bii<\/h3>\n<p><\/p>\n<p>Una dintre modalit\u0103\u021bile <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/the-design-of-dark-59f5d38e52d2\">de a elimina complexitatea inutil\u0103<\/a><\/noindex> \u00een Dark este s\u0103 rezolvi mai multe probleme cu o singur\u0103 solu\u021bie. Comutatoarele de func\u021bii \u00eendeplinesc multe sarcini diferite: \u00eenlocuirea mediului local de dezvoltare, ramurile git, desf\u0103\u0219urarea codului \u0219i, desigur, lansarea tradi\u021bional\u0103 lent\u0103 \u0219i controlat\u0103 a noului cod.<\/p>\n<p><\/p>\n<p>Crearea \u0219i desf\u0103\u0219urarea unui comutator de func\u021bii se realizeaz\u0103 \u00een editorul nostru \u00eentr-o singur\u0103 opera\u021biune. Acesta creeaz\u0103 un spa\u021biu gol pentru noul cod \u0219i ofer\u0103 controale pentru accesul la codul vechi \u0219i nou, precum \u0219i butoane \u0219i comenzi pentru a trece treptat la noul cod sau a-l exclude.<\/p>\n<p><\/p>\n<p>Comutatoarele de func\u021bii sunt integrate \u00een limbajul Dark, iar chiar \u0219i comutatoarele incomplete \u00ee\u0219i \u00eendeplinesc sarcina \u2014 dac\u0103 condi\u021bia din comutator nu este \u00eendeplinit\u0103, va fi executat codul vechi blocat.<\/p>\n<p><\/p>\n<h3 id=\"sreda-razrabotki\">Mediul de dezvoltare<\/h3>\n<p><\/p>\n<p>Comutatoarele func\u021biilor \u00eenlocuiesc mediul local de dezvoltare. Ast\u0103zi, echipelor le este greu s\u0103 se asigure c\u0103 to\u021bi utilizeaz\u0103 acelea\u0219i versiuni ale instrumentelor \u0219i bibliotecilor (instrumente de formatare a codului, linte, gestionare a pachetelor, compilatoare, preprocessori, instrumente de testare etc.) Cu Dark, nu trebuie s\u0103 instal\u0103m dependen\u021be local, s\u0103 gestion\u0103m instalarea local\u0103 Docker sau s\u0103 facem alte demersuri pentru a asigura cel pu\u021bin o form\u0103 de egalitate \u00eentre mediul de dezvoltare \u0219i produc\u021bie. <noindex><a rel=\"nofollow\" href=\"https:\/\/thenewstack.io\/honeycombs-charity-majors-go-ahead-test-in-production\/\">Av\u00e2nd \u00een vedere c\u0103 o astfel de egalitate este oricum imposibil\u0103<\/a><\/noindex>, nici m\u0103car nu ne vom face c\u0103 ne str\u0103duim s\u0103 o ob\u021binem.<\/p>\n<p><\/p>\n<p>\u00cen loc s\u0103 cre\u0103m un mediu local clonat, comutatoarele din Dark creeaz\u0103 o nou\u0103 cutie de nisip \u00een produc\u021bie, care \u00eenlocuie\u0219te mediul de dezvoltare. \u00cen viitor, pl\u0103nuim de asemenea s\u0103 cre\u0103m o cutie de nisip pentru alte p\u0103r\u021bi ale aplica\u021biei (de exemplu, clone instantanee ale bazei de date), de\u0219i momentan nu pare at\u00e2t de important.<\/p>\n<p><\/p>\n<h3 id=\"vetki-i-razvertyvaniya\">Ramuri \u0219i desf\u0103\u0219ur\u0103ri<\/h3>\n<p><\/p>\n<p>Exist\u0103 acum mai multe modalit\u0103\u021bi de a introduce cod nou \u00een sisteme: ramuri git, etape de desf\u0103\u0219urare \u0219i comutatoare de func\u021bii. Acestea rezolv\u0103 aceea\u0219i problem\u0103 \u00een diferite p\u0103r\u021bi ale fluxului de lucru: git \u2013 \u00een etapele anterioare desf\u0103\u0219ur\u0103rii, desf\u0103\u0219urarea \u2013 \u00een momentul tranzi\u021biei de la vechi la noul cod, iar comutatoarele func\u021biei \u2013 pentru lansarea controlat\u0103 a noului cod.<\/p>\n<p><\/p>\n<p>Cea mai eficient\u0103 modalitate este comutatoarele func\u021biilor (de asemenea, cea mai simpl\u0103 de \u00een\u021beles \u0219i utilizat). Cu acestea, putem renun\u021ba complet la celelalte dou\u0103 metode. Este deosebit de util s\u0103 elimin\u0103m desf\u0103\u0219urarea \u2013 dac\u0103 oricum folosim comutatoarele func\u021biilor pentru a activa codul, atunci pa\u0219ii de transfer al serverelor la noul cod creeaz\u0103 doar riscuri suplimentare.<\/p>\n<p><\/p>\n<p>Git este dificil de utilizat, mai ales pentru \u00eencep\u0103tori, \u0219i aceasta \u00eel limiteaz\u0103 semnificativ, dar are ramuri convenabile. Am \u00eembun\u0103t\u0103\u021bit multe dintre dezavantajele git. Dark permite editarea \u00een timp real \u0219i ofer\u0103 posibilitatea colabor\u0103rii \u00een stil Google Docs, astfel \u00eenc\u00e2t nu este necesar s\u0103 trimitem cod \u0219i putem face rebazare \u0219i unire mai rar.<\/p>\n<p><\/p>\n<p>Comutatoarele de func\u021bii stau la baza desf\u0103\u0219ur\u0103rii sigure. \u00cempreun\u0103 cu desf\u0103\u0219ur\u0103rile instantanee, acestea permit testarea rapid\u0103 a conceptelor \u00een fragmente mici, cu risc sc\u0103zut, \u00een loc s\u0103 se aplice o singur\u0103 modificare major\u0103 care ar putea provoca o c\u0103dere a sistemului.<\/p>\n<p><\/p>\n<h3 id=\"versionirovanie\">Versionare<\/h3>\n<p><\/p>\n<p>Pentru a schimba func\u021bii \u0219i tipuri, utiliz\u0103m versiuni. Dac\u0103 dori\u021bi s\u0103 modifica\u021bi o func\u021bie, Dark creeaz\u0103 o nou\u0103 versiune a acestei func\u021bii. Apoi, pute\u021bi apela aceast\u0103 versiune folosind comutatorul din handler-ul HTTP sau din evenimente. (Dac\u0103 este o func\u021bie ad\u00e2nc \u00een graful de apeluri, atunci se creeaz\u0103 o nou\u0103 versiune a fiec\u0103rei func\u021bii pe parcurs. Poate p\u0103rea excesiv, dar func\u021biile nu interfereaz\u0103 dac\u0103 nu le utiliza\u021bi, astfel c\u0103 nici nu o ve\u021bi observa.)<\/p>\n<p><\/p>\n<p>Din acelea\u0219i motive, versiunea tipurilor este, de asemenea, implementat\u0103. Am discutat detaliat despre sistemul nostru de tipuri <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/real-problems-with-functional-languages-efe668c5264a\">\u00een postarea anterioar\u0103<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Datorit\u0103 versiuni func\u021biilor \u0219i tipurilor, pute\u021bi face modific\u0103ri \u00een aplica\u021bie treptat. Pute\u021bi verifica c\u0103 fiecare handler func\u021bioneaz\u0103 cu noua versiune, f\u0103r\u0103 a fi nevoie s\u0103 face\u021bi toate modific\u0103rile \u00een aplica\u021bie simultan (dar avem instrumente pentru a face acest lucru rapid, dac\u0103 dori\u021bi).<\/p>\n<p><\/p>\n<p>Este mult mai sigur dec\u00e2t desf\u0103\u0219urarea a totul simultan, a\u0219a cum se \u00eent\u00e2mpl\u0103 \u00een prezent.<\/p>\n<p><\/p>\n<h3 id=\"novye-versii-paketov-i-standartnaya-biblioteka\">Versiuni noi ale pachetelor \u0219i biblioteca standard<\/h3>\n<p><\/p>\n<p>C\u00e2nd actualiza\u021bi un pachet \u00een Dark, nu \u00eenlocuim imediat utilizarea fiec\u0103rei func\u021bii sau tipuri din \u00eentreaga baz\u0103 de cod. Aceasta nu este sigur. Codul continu\u0103 s\u0103 foloseasc\u0103 aceea\u0219i versiune pe care a folosit-o, iar dvs. actualiza\u021bi utilizarea func\u021biilor \u0219i tipurilor la noua versiune pentru fiecare caz specific folosind comutatoarele.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/rh\/t3\/4w\/rht34wyibolrgracbz88tnqqhg0.png\"><img decoding=\"async\" alt=\"Cum Dark desf\u0103\u0219oar\u0103 codul \u00een 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/54fdb566b4bcbc10e06e51c47a3820f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<em>Captura de ecran a unei p\u0103r\u021bi din procesul automatizat din Dark, ar\u0103t\u00e2nd dou\u0103 versiuni ale func\u021biei Dict::get. Dict::get_v0 returna tipul Any (de care ne desprindem), iar Dict::get_v1 returneaz\u0103 tipul Option.<\/em><\/p>\n<p><\/p>\n<p>Frecvent, oferim o nou\u0103 func\u021bie \u00een biblioteca standard \u0219i excludem versiunile vechi. Utilizatorii cu versiuni mai vechi \u00een cod vor p\u0103stra accesul la acestea, dar utilizatorii noi nu le vor putea ob\u021bine. Inten\u021bion\u0103m s\u0103 oferim instrumente pentru a migra utilizatorii de la versiunile vechi la cele noi \u00eentr-un singur pas, din nou cu ajutorul comutatoarelor de func\u021bii.<\/p>\n<p><\/p>\n<p>Dark ofer\u0103, de asemenea, o oportunitate unic\u0103: deoarece execut\u0103m codul dvs. de lucru, putem testa noi versiuni, compar\u00e2nd ie\u0219irile pentru cererile noi \u0219i vechi, astfel \u00eenc\u00e2t s\u0103 v\u0103 inform\u0103m cu privire la modific\u0103ri. Prin urmare, actualizarea pachetelor, care adesea se face \u00een orb (sau necesit\u0103 teste riguroase pentru siguran\u021b\u0103), prezint\u0103 mult mai pu\u021bine riscuri \u0219i poate avea loc automat.<\/p>\n<p><\/p>\n<h3 id=\"novye-versii-dark\">Versiuni noi Dark<\/h3>\n<p><\/p>\n<p>Trecerea de la Python 2 la Python 3 s-a \u00eentins pe un deceniu \u0219i r\u0103m\u00e2ne o problem\u0103. De vreme ce construim Dark pentru livrare continu\u0103, trebuie s\u0103 lu\u0103m \u00een considerare aceste schimb\u0103ri ale limbajului.<\/p>\n<p><\/p>\n<p>C\u00e2nd facem mici modific\u0103ri \u00een limbaj, cre\u0103m o nou\u0103 versiune Dark. Codul vechi r\u0103m\u00e2ne \u00een vechea versiune Dark, iar codul nou este folosit \u00een noua versiune. Pentru a trece la noua versiune Dark, pot fi folosite comutatoare sau versiuni de func\u021bii.<\/p>\n<p><\/p>\n<p>Acest lucru este deosebit de util, av\u00e2nd \u00een vedere c\u0103 Dark a ap\u0103rut foarte recent. Multe schimb\u0103ri \u00een limbaj sau bibliotec\u0103 pot fi nereu\u0219ite. Versiunea treptat\u0103 a limbajului ne permite s\u0103 facem actualiz\u0103ri minore, adic\u0103 putem s\u0103 nu ne gr\u0103bim \u0219i s\u0103 am\u00e2n\u0103m multe decizii legate de limbaj p\u00e2n\u0103 c\u00e2nd avem mai mul\u021bi utilizatori, ceea ce \u00eenseamn\u0103 \u0219i mai multe informa\u021bii.<\/p>\n<p><\/p>\n<h3 id=\"migracii-baz-dannyh\">Migrarea bazelor de date<\/h3>\n<p><\/p>\n<p>Pentru migrarea sigur\u0103 a bazei de date exist\u0103 <noindex><a rel=\"nofollow\" href=\"http:\/\/www.brunton-spall.co.uk\/post\/2014\/05\/06\/database-migrations-done-right\/\">o formul\u0103 standard<\/a><\/noindex>:<\/p>\n<p><\/p>\n<ul>\n<li>S\u0103 rescriem codul pentru a sprijini at\u00e2t formatele noi, c\u00e2t \u0219i cele vechi<\/li>\n<li>S\u0103 transform\u0103m toate datele \u00eentr-un nou format<\/li>\n<li>S\u0103 elimin\u0103m accesul vechi la date<\/li>\n<\/ul>\n<p><\/p>\n<p>\u00cen rezultat, migrarea bazei de date se desf\u0103\u0219oar\u0103 mai lent \u0219i solicit\u0103 multe resurse. \u0218i avem scheme \u00eenvechite, deoarece chiar \u0219i sarcinile simple, cum ar fi corectarea numelui unei tabele sau al unei coloane, nu merit\u0103 efortul depus.<\/p>\n<p><\/p>\n<p>Dark are o platform\u0103 eficient\u0103 de migrare a bazelor de date, care (sper\u0103m) va simplifica at\u00e2t de mult procesul, \u00eenc\u00e2t nu ve\u021bi mai fi team\u0103 de el. Toate depozitele de date \u00een Dark (depozite de perechi \u201echeie-valoare\u201d sau tabele hash persistente) au un tip. Pentru a transfera un depozit de date, pur \u0219i simplu \u00eei atribui\u021bi un nou tip \u0219i o func\u021bie de revenire pentru a transforma valorile \u00eentre cele dou\u0103 tipuri.<\/p>\n<p><\/p>\n<p>Accesul la depozitele de date \u00een Dark se face prin nume de variabile versionate. De exemplu, depozitul de date Users va fi ini\u021bial denumit Users-v0. C\u00e2nd se creeaz\u0103 o nou\u0103 versiune cu un alt tip, numele se schimb\u0103 \u00een Users-v1. Dac\u0103 datele sunt salvate prin Users-v0, iar tu le accesezi prin Users-v1, se aplic\u0103 func\u021bia de rollback. Dac\u0103 datele sunt salvate prin Users-v1, iar tu le accesezi prin Users-v0, se aplic\u0103 func\u021bia de rollback.<\/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=\"Cum Dark desf\u0103\u0219oar\u0103 codul \u00een 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/35743ba246f327ca9e8b71f0069a3800.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<em>Ecranul de migrare a bazei de date cu numele c\u00e2mpurilor din vechea baz\u0103 de date, expresiile de rollback \u0219i rollback \u0219i instruc\u021biunile pentru activarea migra\u021biei.<\/em><\/p>\n<p><\/p>\n<p>Folose\u0219te switch-uri de func\u021bii pentru a redirec\u021biona apelurile de la Users-v0 la versiunea Users-v1. Acest lucru se poate face c\u00e2te un handler HTTP pe r\u00e2nd, pentru a reduce riscurile, iar switch-urile func\u021bioneaz\u0103 pentru utilizatori individuali, astfel \u00eenc\u00e2t s\u0103 po\u021bi verifica dac\u0103 totul func\u021bioneaz\u0103 a\u0219a cum era de a\u0219teptat. C\u00e2nd nu vor mai exista utilizatori pentru Users-v0, Dark va transforma \u00een fundal toate datele r\u0103mase din vechiul format \u00een noul format. Nici nu vei observa.<\/p>\n<p><\/p>\n<h3 id=\"testirovanie\">Testare<\/h3>\n<p><\/p>\n<p>Dark este <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/real-problems-with-functional-languages-efe668c5264a\">un limbaj func\u021bional de programare cu tipizare static\u0103<\/a><\/noindex> \u0219i valori imutabile, ceea ce face ca suprafa\u021ba de testare s\u0103 fie semnificativ mai mic\u0103 \u00een compara\u021bie cu limbajele orientate pe obiect cu tipizare dinamic\u0103. Totu\u0219i, trebuie s\u0103 test\u0103m.<br \/>\n\u00cen Dark, editorul ruleaz\u0103 automat teste de unitate \u00een fundal pentru codul editat \u0219i, \u00een mod implicit, execut\u0103 aceste teste pentru toate switch-urile de func\u021bii. \u00cen viitor, dorim s\u0103 folosim tipurile statice pentru a realiza fuzzing-ul codului automat, pentru a g\u0103si bug-uri.<\/p>\n<p><\/p>\n<p>\u00cen plus, Dark ruleaz\u0103 infrastructura ta \u00een produc\u021bie, deschiz\u00e2nd noi oportunit\u0103\u021bi. Salv\u0103m automat cererile HTTP \u00een infrastructura Dark (deocamdat\u0103, salv\u0103m toate cererile, dar ulterior vrem s\u0103 trecem la selec\u021bie). Test\u0103m codul nou folosind aceste cereri \u0219i efectu\u0103m teste de unitate, iar dac\u0103 dore\u0219ti, po\u021bi transforma cu u\u0219urin\u021b\u0103 cererile interesante \u00een teste de unitate.<\/p>\n<p><\/p>\n<h3 id=\"ot-chego-my-izbavilis\">De ce ne-am debarasat<\/h3>\n<p><\/p>\n<p>Deoarece nu avem desf\u0103\u0219urare, dar avem switch-uri de func\u021bii, aproximativ 60% din pipeline-ul de desf\u0103\u0219urare r\u0103m\u00e2ne deoparte. Nu avem nevoie de ramuri git sau pull request-uri, de construire a resurselor backend \u0219i a containerelor, de trimiterea resurselor \u0219i containerelor \u00een registry-uri sau de pa\u0219i de desf\u0103\u0219urare \u00een 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=\"Cum Dark desf\u0103\u0219oar\u0103 codul \u00een 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/d584b13a1f91e9eef1e2e40c25e90052.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<em>Compara\u021bia \u00eentre pipeline-ul standard de livrare continu\u0103 (st\u00e2nga) \u0219i livrarea continu\u0103 Dark (dreapta). \u00cen Dark, livrarea const\u0103 din 6 pa\u0219i \u0219i un ciclu, \u00een timp ce versiunea tradi\u021bional\u0103 include 35 de pa\u0219i \u0219i 3 cicluri.<\/em><\/p>\n<p><\/p>\n<p>\u00cen Dark, implementarea are doar 6 pa\u0219i \u0219i 1 ciclu (pa\u0219i care se repet\u0103 de mai multe ori), \u00een timp ce pipeline-ul modern de livrare continu\u0103 const\u0103 din 35 de pa\u0219i \u0219i 3 cicluri. \u00cen Dark, testele sunt rulate automat, f\u0103r\u0103 s\u0103-i vede\u021bi; dependen\u021bele se instaleaz\u0103 automat; tot ce \u021bine de git sau Github nu mai este nevoie; nu este nevoie s\u0103 construi\u021bi, testa\u021bi \u0219i trimite\u021bi containere Docker; implementarea \u00een Kubernetes nu mai este necesar\u0103.<\/p>\n<p><\/p>\n<p>Chiar \u0219i pa\u0219ii r\u0103ma\u0219i \u00een Dark au devenit mai simpli. Deoarece comutatoarele de func\u021bii pot fi gestionate cu o singur\u0103 ac\u021biune, nu este nevoie s\u0103 treci din nou prin \u00eentregul pipeline de implementare pentru a elimina codul vechi.<\/p>\n<p><\/p>\n<p>Am simplificat livrarea codului c\u00e2t am putut, reduc\u00e2nd timpul \u0219i riscurile asociate livr\u0103rii continue. De asemenea, am simplificat semnificativ actualiz\u0103rile pachetelor, migrarea bazelor de date, testarea, gestionarea versiunilor, instalarea dependen\u021belor, egalitatea \u00eentre mediu de dezvoltare \u0219i produc\u021bie \u0219i upgrade-uri rapide \u0219i sigure ale versiunilor limbajului.<\/p>\n<p><\/p>\n<p>R\u0103spund la \u00eentreb\u0103rile despre asta pe <noindex><a rel=\"nofollow\" href=\"https:\/\/news.ycombinator.com\/item?id=20394166\">HackerNews<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Pentru a afla mai multe despre dispozitivul Dark, citi\u021bi <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/the-design-of-dark-59f5d38e52d2\">articolul despre Dark<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/darklang?source=post_page---------------------------\">abona\u021bi-v\u0103 la noi pe Twitter<\/a><\/noindex> (sau la <noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/paulbiggar?source=post_page---------------------------\">mine<\/a><\/noindex>) sau <noindex><a rel=\"nofollow\" href=\"https:\/\/darklang.com\/subscribe?source=post_page---------------------------\">\u00eenscrie\u021bi-v\u0103 pentru versiunea beta \u0219i primi\u021bi notific\u0103ri despre urm\u0103toarele post\u0103ri<\/a><\/noindex>. Dac\u0103 merge\u021bi la StrangeLoop \u00een septembrie, <noindex><a rel=\"nofollow\" href=\"https:\/\/darklang.com\/launch\">veni\u021bi la lansarea noastr\u0103<\/a><\/noindex>.<\/p>\n<p>Sursa: <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.4 - 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\/ro\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\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\/ro\/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\udd47Cum Dark implementeaz\u0103 codul \u00een 50 ms | ProHoster","description":"Cu c\u00e2t procesul de dezvoltare este mai rapid, cu at\u00e2t mai rapid\u0103.","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","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\/ro\/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\/ro\/wp-json\/wp\/v2\/posts\/36721","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=36721"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/36721\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media\/27506"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=36721"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=36721"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=36721"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}