From cdf52bf6ff9d638e4fd6fedb0b0e2a306ea564e9 Mon Sep 17 00:00:00 2001 From: emacsway Date: Sat, 21 Oct 2023 04:44:05 +0000 Subject: [PATCH] Update pages on 2023-10-21 04:44:05 --- .../it/sdlc/models/agile/agile.doctree | Bin 165963 -> 173467 bytes .../requirements/requirements.doctree | Bin 55830 -> 56739 bytes .../emacsway/it/sdlc/models/iterative.doctree | Bin 20620 -> 22246 bytes .../adaptation/adaptation.doctree | Bin 60100 -> 73864 bytes .../software-construction/yagni.doctree | Bin 89872 -> 93222 bytes .../software-design/simplicity.doctree | Bin 90896 -> 91449 bytes ...lf-education-for-software-engineer.doctree | Bin 436929 -> 438839 bytes .../harlan-mills'-proposal.doctree | Bin 288248 -> 293110 bytes .../soft-skills/cognitive-biases.doctree | Bin 56350 -> 58299 bytes .../soft-skills/knowledge-vs-opinion.doctree | Bin 94003 -> 96809 bytes .doctrees/environment.pickle | Bin 2591440 -> 2607437 bytes .../it/sdlc/models/agile/agile.rst.txt | 25 +- .../requirements/requirements.rst.txt | 6 + .../emacsway/it/sdlc/models/iterative.rst.txt | 10 +- .../adaptation/adaptation.rst.txt | 39 + .../software-construction/yagni.rst.txt | 6 + .../software-design/simplicity.rst.txt | 6 + ...lf-education-for-software-engineer.rst.txt | 5 + .../harlan-mills'-proposal.rst.txt | 16 +- .../soft-skills/cognitive-biases.rst.txt | 2 + .../soft-skills/knowledge-vs-opinion.rst.txt | 9 + emacsway/it/sdlc/models/agile/agile.html | 56 +- .../analysis/requirements/requirements.html | 4 + emacsway/it/sdlc/models/iterative.html | 10 +- .../adaptation/adaptation.html | 50 +- .../software-construction/yagni.html | 8 + .../software-design/simplicity.html | 4 + .../self-education-for-software-engineer.html | 5 + .../harlan-mills'-proposal.html | 34 +- emacsway/soft-skills/cognitive-biases.html | 2 + .../soft-skills/knowledge-vs-opinion.html | 9 +- rss.xml | 20218 ++++++++-------- searchindex.js | 2 +- 33 files changed, 10421 insertions(+), 10105 deletions(-) diff --git a/.doctrees/emacsway/it/sdlc/models/agile/agile.doctree b/.doctrees/emacsway/it/sdlc/models/agile/agile.doctree index 629138ac1c157d374eaa8fbf618ecc7d3dbd9007..4ad5b12b53713d7eca590c0854aafd624a582d44 100644 GIT binary patch delta 21234 zcmeHPd3;k<_V?T-q5G0jC|gNcO6dwh#UfIQEDDrOS*)U@O-d5dBqS-NqQB5#mjdD| zTpc%bm~jvlnCir;P#i~RL~)9u$fDqe3ofWIC~m)V?#oMG(tyaw{55<&H0{0Tp7TBD zo^$TG_rAQB?})wUq9^FlE@K7iT7Z0e_0`|?K$b;6a#ynxM#qhq}ln|(1QH? z>zk0OA;xX4GC8Y_R!5_44+<-QW3TV&%KgzFP=PwO@&rMod8eTlH17q%<~ajwQ7}bX zKWH+$A&Me8`uZplqEn=9gNNv+&>!k>ESF4!hp_4}(!GPz*p#RZpF$T2imqV3C``V2 z+NlU_isUS6!9H2f0oYQ8EKxMN_`J*ZGaeUKOhMc)$P`7gDTbb8>{Wt3SUUt+?Ut^;@^f}rG$hahvO9=;b2VWzvVmW3XWgZ(V^Tt$wn)RbJ6JXwqG|J57$lXB?cd&K zOEu`T2JUmR1YC<&J6R9)GEj=Ra+}^7dxwVQYQ#k9sHv-lKNt_GP5ud)QEV0=9;_R! zYVS9BJ+QeNnqO)ElzGgfq3InU-7+-}jkIj)wJ=vYIQ1PQk$H|)jqPyVn;QL^cB)E8 zSC0?X@-B@ubWH*Ky;{i)k(Jy;O6Fr)?!LCCTD@^7cTH1y`OYY|CIE$+6!qrZRH$LQ zWHq)|oM8V9sPTGbF{+VZnh(3AC8nqKyV|3jY`!6M1vw%$n+LOZ)nMO_4EDGJHf%|r zgvfSDhpHw;k~eJ5lu+wLX{CGTiL><^XMM-fjZDGKV3 z^=o{>bnLH3v&iXh=z>{H(u(l-%Yun;50VW>j~Y>z2a;4>*AqM2XOEeJg_1o|R0RMr z$0YGn-JqzH*HDOuR-NZ)68hS9HjTV(Ilx;2$%%fNlsBneF3xVIeyvoszOR(;OHFu| zdiso~R^(RZ%hu?>q$c$uut8eBcx32Iekbi;+y}l7vFYiv*;K0wMB>&Znd*r&qR=m; zqf73NBy!c#%R-&IhfZo;+LiUxwdFU~O?MXG?yrcve_2L*k*_RsMG`r2d0zjJsqd=Ig~3&76eVXvQ6^CI6SYCSx!PFisWsN+drhYB5<#}a!WFsfOWC({ z)S|@KsTBt_dMjZGofXWEp|j$Viq{mf8a1|gXT#=GEQIMXOBMQ+D41lm4}Gg-Tw82V zIs6WE6lD)&(UGCDZGUTedhM-Id9P#FZH=}!@Wb{Pa#MTfJ*0{3j5Z97{Y@3p3&6JO zs2oXFd8!SO+#@};xnK9skxhffZm#kQ!v%bn`nzhRGGFJWmi6CsU@z!sO-i+)rjLHnfx51C;<>RFWFL^iJrJ5cRX|A*b|w4ha&XSfD*sxQp%$VrBCV+~TM}uD zojj|t0r%9!jYf+ey|*L&?}Y!;XEoX)o02$S_N${R(=w}mROqUqf&r=nmi z^(FYQ?E%kmp)iPuR-GTXApLF`Cy~St@<*b+XKmQut4T zjiRJ_H%ORNc+asLRHy=O^=F~o`|mAeFfIu95#%-|T3NRq{BSv&NpQRH$1B-Fm`#|a z6UWjJ@;no}24+f=Kk9=dV)aT<*Y1xJBgyw;PYD+xb?HkIntACs=-Bk#M~4}!7yP9Y zpH{<4!G7&=DjM%OJ_+ij4bNr zPN%$ZR1Bd0U8gi~_|DV);DGe`sd;cpy7}K#a9ZisK7la4k-M``uV?WwQp@R;kjS6Y zLY|bI7NdI-31VX;IGu$YwtV{l>m4Ia_)dbpZ6tq1lFR@})5tRi84PRd^ke7c%6Q+8 z!?5Ii_Q%1ALFX#y%93vH@UvT-(9nrnW&laL~rUAbu%>a@xo+m;}$X(dH{J24AM0#(ZKVx&0hgZ_ZUlv72($q1Jx`oR&1+yZY-o?1U@*F_2Y#%uq2+a z2V#(tFN%dvA%VM6ponjb15Hd!Y#@~RV{!01HXt_qB=4VyF(y{YE9y9XfzXRMg^v8m zcsS6xb!Y2#{QuP6rG~xrdwUhE5Fp_C_P!7z4}=;w>FK*LHD zg2%F8Jj~?ZWx)tmE;BfS45lmn2sn-7%AW^L{!Tx*jLnmYjv`UDLR6a#i(nc5HXCZ# z3c3GX>|dhvxAq6l9*{fU!;X7I2RkawgNOA#0%rM^0y0ccDly%K7~*W-35j26J(LD5bP?1X)us? z8UW*95cLp0gu}XBX*0^&dPqI%Sq7s>$JU0`EypY1?grHIq zkUD)**s6m1{L|;xB7Ls94AQWs!z>BKF)zj|B@LZKz7;QWDxE}P5Fw=g;!KY}Yh)uZ z+5Bi^RYWtOI2S+KZ_NLVz+S}KfG(jzYnzh0Spo-%2K`!SA}0a0_JLy z60qi%o{Q<0V~ccpuP7f_jJ`*;&ff?>2qR1?g(ZyT2o$=X5Jgr3Pa1_WTF!461&i6R z1oc7i<-BDqq`~FfXhQeAc{FHavJfJ2!U?P%4O`iD3Bqzi#=slw#sqma8a@`+^sRjL zSQrS`$sDdD4tc4nda#Uvkgiy*n<|qME=5;D&8J)q`&hj!YQ!~|i&hFz{rRpk(4^M5 zt&O%-ge!1sh?F=NeD-08@1P+uwDN}!-4DzR<%@p&_05wE@xV&P+1SUk!9 zz~6Kue1*l5|Bp9AKCt*ib;gTM%ybkP% z5MJB-c(AyN!8RH(6fFJ;8&Dp`@UgovCR;;jU-7?uH?C3eip;%0=6>zHG+X8T`TO7# z_L&$E^c+RYFZiB&;Y)t-0pU4fUI&ZOf&k~$pS=+^VwxoK9DQ2_Tz0ukrc9V>%U>q6 zlgmi|HxHt4mY&2@Cc|JI>JdzqxqpOrfMv-&yyRifhDO5Vhv8DjE|>cghttTxNlIdR zaWhzO?JIl)da`jzvZF0}1eb2iNsqudHYQ2V1}eZK1P4BEEA&=-mtcHB-ZfJ8t_QZj zT40_4&QT=A8N~U?b5O_XlSEY9_BU9|RtCThe;%?C?1{%=2=>co0Qebx22eIe@N0)! zh`AutSIek1+u&A>-j6^-l43c(^9lHzwTS6f+}iJd@=2^@z+263hzdKi2vNjl={$xbJ=C1&LG2qaB@*tsM1E|rr?nk@I+9cTxJSjLwCAc&a@zXECmGFERasF=T5{Y=`Zny>u z|4`2RcVn%-Iav;Yn@Hh525mU|Wmv&JPv*O(v2OhLH?Vp*6*OX&y!fei?MPXA5c<*x zy8jOGh1oJ^#gwYzxJ(FDnR12ynLTiX>AR-1v(2NeSeW(VU+sl_CFc{BSlPV%oju^? zckG3@NJAgn3s=ElF;v+bbxq;B#-i`yr$_)5gt3$0M<>EqUc&^Q`95?N7yVceqTC4O z^@J2rUQbAAueC|$7)fg(EJW+~-@x3duWPS$kNr>x^#b}8f%TlIgw_d$YO~kkGbT)8$Y*r{3se!_8pQ&9-CM8%w#X*<$&81lO)3*?sbZbb z2kx8B#v)DW2av_KL@6Wd%{@IX_3YK*vV%e7m1dp zLM89@$`;G{&iED7bwJrcHF)xOxGCEbR3qa%Sj~3mMZ$jZJ6H@asDLj#1Kn^iKLev- z2Y>qvCjTA!_VKoo6xgCy6ws^6?WM9|>Bc6FulXMCMn?)_Nm(WLs?6^A0ak07^CAC_ zz~<@T+csj|Y9c=AeqMKPjDKl7D+fGm#JpwI!2zU?WikQfopl)yKtSjG`$ztMyw|E5LSZI$rS-YgYX_^0(|cSPx5Mc83W^yw`258UP==DZkNAS1uZ zPxfQQ5vcto*=!Kt2A0TUgXF1FVL=*uHC0}E9wm6Yg9f7Gd3H(1@Xg6KnM#=`wR;N& z=sa{G$$R9oW2|FGVPCOn?cTB7rWN~nQa;O~Pg?y_{t{-P75-cESzNUKijM8{zq^R- zVOI%w!vg9Pl~|BKy}xWfR&|@xP{vaVSsCv!gw0~p1UF?_y28J02&)2ig^Vrn3Boo+ zh@ee*c`>_{Rjc%?X|Eqt^LK}$det4<`^gTOonl9|p9o1x2E+V%{&}uN&T|K@V7nRn zLr1YQOni5tfk;$xIZu>8dqD@K@kUN1HPWL%$0kFSre%jcwN)^V0C3B)hL=kZl-VLn@C% zIuNg%Pv|M~vLmFJYzJSYY!pWRuCN2LQ!X=SeuGbUoOs~QM-A5)EJl;TXsEOp9hGK- z*J-G=dL3qu$KbV?4KAy<%4oNH49+V2+lq~Dqsvfbb$h%>Zz_nL;qd;TWUWP;GP==a{R_4zHos=)uy{=)ogQ977U3HIFIBSVhoxx>xy6k2{tr<&KBulV5P!Q6T&av9feA{6# z_^f8EZ1GzJg2w5na2nkvL4@iFGSt&)_Y}llXEA%s24khyI^XK8%daqckj&+FE~ujl z*=?=#2=kyi76I64FbM-$3>7sV6imQtyp_&sGcqgnpyst!yWNLcRaYC`)?3U5tHUta z==K_}$&;<~-lDsO71i3At58!^zRHLipwXNLqsin}=AhDvin{DZFPVeDRoKndG(Ez! zCKTZ{c$|iu9Fw)G%34`t_xcP-Dy)mhTx2uB(&+NiFJyI^?Kz|oqMU2?=HwK_UgI!$ zaJtPj6Sc(K=yI8Hdm!*sppnp;c6&Yoagf17Cnzsul6^SKXflHlk&;BW*=Q$Q2oI`p zc&#|UPNxA?GNW8{3U8$aSqc}ba@Tl}x0rQgBRtArcX|*y;;wd9pos#gNpW)CO62b~ zoASukLIt1fu4aS9>~>l!4T^nHv+6oSrPFRV8|T!RJ$a}oPA55%$w}5Q&o{g40#j`< z6KRcI=}SAWAuEp!(gS@z;3ekKt6v=j=J zXA@l>O-)ha^&y&|e};yf$!xchk|nW|+$4wiBTJLB))B@GjVYKRFORdzTT44d;$%I(`9vFS({&Nbx<5rXa{4~>9%5K!Pfa!b1fOSbdHaF zgs>8Kw-Y_F(pZCWj-A5PA_fD&7CGUF%n*#n&|Fk)#F(oxqDP|6il-tXbSk%l)U5Kk zoz+6N99;%$wae-8STP##%S|#WBu2-wV%`w38kiOu?LaN6(4ow`}zc1nqpc!Fii6E4ZSA2 zoi=n4l7hdQYAU@$4Of%5It|y>xaXr+3c1%=-1KX}HA?4*SsN8t6-HS-?i!cK4I){P zDq~PZ!x*=*+Fa{&&+SD^MO>M6u32K{)2|ItSnn#6D1L9-u|6tqtoe~@ zruBsnoSA`ZZ{#xhVpPe#Ur{Ej>Y%WV>4jIxzF$!$UyLdlOV9HzlP^Y<>&!xhH3vvwD``tsZ<5})8|a|8Ry=9DoLPg#67BBY*JOS z{uYv|NwPTbrGpZ@fjrkP_B_K=CF|^Z_0P6w8)Aa{T}212SZ`Du_C-c}<$tt6R`EYO zLIPM8*h>3Ud+GlmNhn%g6TUzHC7xMl-Jh#eITq1WGyjEa@Ncn)KhNakqXV;xv4=m; zXB?I2Hv>h`y)c#kt{dfc|_Wi1D zzvBD<6#xe1;6V+b&0;@^NKrp8__b^=<@P{*BO|IWN1A*kcjpXN#PprSJxa~@$YGo8^%TnC<-#r}`o6yW*Cn^-#X+<6ll6FZ|*AfKo46CEHeUX>qa z$jrYb=GO}5(S2m<<-Gni_&c99o5kS+DgyjsS&n!$#_d9m3q^?M(6I}jLx;sOyYGmd zFNpP21zQS_$vn2oJm`CR?5{Fb)i?DRc2D`JH*ys^pCLY5f_z4q*)ljF^Eo68*~s4O z6ml7a&BADhWCq_8gZ)7U>*uh4u@0TlS`tg@EE`|_)y58;<;NQF6CZ2L(fvTfqxieE ztRM8@0~azww@6>WDid>KAThmC)sJ(Fc1N23CL3!77|XwMvvmD6os~-><#kQ;zKs0P zrw6BYrgvqeN-OnoJZBz@W!H6XdyWt$6QrKf0DWxxH)q_`S^bbVy~Ro2_TA|+V5reG z0X6Ycs3{sp3pLru&OFhjqq}h)dFxfTdT&o>Kr)l4#7!p_)z0ygmXy% zCw>Z?qH$3WXO4?a!6!z9QCr&M{F94~3^nRMJM+^nb|u@b#`xknFz#!^C|*Lre|BL6 z(`yV=CXFJfEdi+bDWHnRXM#|F?`G5SITHc(Ona!^JZx+z)Tnem&%;JCZF<|ZGe|$n z095=GP(|avgHSVSn2QZc=L77lv%V<3ov$|6 zFk>jz;px2pe0C!n5x~k@>hLWu!_EeFTsn`dW%64+_`vyWT)08Cgt91I4n_PVlpRFl zz;yZ+68UKC0_J0m07_STlus;Rt}Y>ON~j|u`ArGadFBE(JwcTQ7luHuJsb3;GIZI- zGM9EX))9JF06l&R^rF$Opr;k3d&Dn*$?-XyCZku3Z5Vk9t|qkO?^0qLiA7uR>+*Or z-J*JRol*JvJY7W(#zD%}cHl{^BfvK;WXlX!;A2eq)`MMW3|oKv-DA5_Zt0E8v4xMj zl`TpRQ0*p@)`nHeheG)tAM+;uw+vrUawnE|% z*Ma}Mn04+VPMSYa98l*Gktec$Y+%t#nU?m#=s{=5(9z zX2^|~N9F}yyuFk!+N|Dw9=enESnysucx)6dt&(oUE`qqW%Ik(M_$)<%rmt;g7s_uv zdBQT5UaBFz8p}R~2A#)Q2Av`c K=lT__`2PVk!rnUo delta 14515 zcmbVTc|g?F_V=7wfMI}{VRZumWl<1Nz@<_l7lLq2vJ@2+okmR*%|Jy>Tu4InqPOg+ znQ5lx658ah@8zq^eAr^8xs_>}hW6Sm`<;8gGw>Y-dB5rpzIo5N=X}n&=bm%!{eI`g z_YLn?8np9tD_iZ-{tLC5C&qQFK7so*kjQ!(LfJ~YUBX7q?; z9$x9Jhi5C6?=_08G=x{{y;A}Dvv6~3R--lgSUX$oGpym(Zq|0Ttm;BzOD&9H%S=<@ zNe1RHm`aS9Fo{(f!dQHn7ppRN#@WEkm2vDxbCSsh&6-&wtdZ8XSpg(q3`@0i4;v!} zqpTWhM1O1B{xindCelFc{Hi%sF;-o9H0$LT9Z+TU$gQ#!s0g-I?6{>3JWmQk(Kd@E zO^AUihhBsK65=fPnwCF)+?2_APdr&=ds%>phYGgVzqLDz_x)Q~++nb^&`sYC5CilJ9*+OU^Q)?#Zkyll|r1_y`hpx zy0?|ey<)D@qcs0l;De4q`xp(0vuTA)Yq+g($G4G=kBxXuhx3pP`XbpUf@IBh;^0|t z!N*wP4kSu)xd9QA{~nMS3FNKV3bgDX?XLUGeHr%3W!SG;2743BaO@t-(4OG#kW1f) z&Trx~T{qP^WN974;etx(*(Q`;lS=g>-IBe!c5>ygsM5+(kjPJjt)aY`3V zS9n96yu>wQjI~!ew5eKHrKHDpwkT#u9SV=I(WyxWAxCm-WhXoLVrNsI!YGYn8zhnq z5t2^ZfE(|JPjQmQKL2Cz0GzJjmuBM>_I0;OG|2bO!4C9fyNX@*NM|X*%{fBw-*Zli z;+*?_K-{1adqmfTWUXVfd)&lba==GanRQOoY+KLycv!1uY3W4dX(yqbU}^yVJ}F3oSLaWmFpHf{dxh=m)tda z(aLpWN3wMS(mUD78t6nSTC-cxA^JYVNTXc_Z3gJYE)HG_8G^0~6B6^EBJ!*G`z$Nn;TDb` z?z#-S*%#xJ;Y}6VH=00u#EG^+0U1DOSF*bk1~jH~ly#7+i$2q`!`2RPMy2$06G|^j zrFF$JT9vY-Ub0fz;2l*Pe5J!_ZK#UTnn&9>1*fiIaI%^wi(UO;V8f=2Mx&0MiVJlV za!*|oaj9#(KN>7!@`VClXiV$gsoh<*c4RQE4JN9!#xqO>Y1BnJs)~MZnq6xR3k#1K?XfXSrG}x_#<`ICm znP$-ojj7+hD7Ax2^Y*=fNDVp_C*6<%4?omf6~8~ILEUNs)LmyR99_7=BeK?E~Zc8r$2gfV||-q^yKc}4Nl$Bk>)QYawS zmUY0lm3Z{X5<|2`x@T`_Ej{#ZYef0f6S+&TLcJK40*#qkALO2~A9_)$pWr^si=bL<95?^4P6vtx@HW+&6YVsfB@3)k2!_ zu#2jZZmJdw9-*qG%E@A4y-cft-<|-`ENWk0s&Rbo6-f34T1SzWV-!$FuRwG5-o81o zoD{^eg8fFQsGhU`D=n;}fo{eMLQz*4HXWI7fn5Tju8O9=UOna`vjz^!fz@(g`|0&M z_&^Si0-T7~JY+eE`?45r6IU#&`7#K zdK2D(B{-dRziP&KPr}@iS+5pB3UMd#opUizFALv&yr2Z{n(Qr$EQeHA=y6ZluRymk&TN2qDe{BKN#k)-B+YTXXq7yvoU_hz({IPm6J zC=?jj*Eh|?@bk@XkW-!X9qox6Po>qpP^)uY#ap%1hp!;RT&iCJtNmdJtd`c_+MsnN zgcSm21lw8ZrQap+d9ov30qo$9v!I%F`)NAtkrT*W`f4KY@}!aw1>2eF=c$I{LWQhe zEbQkY?EKFLI8n#Fo4DU~a%cUr(s-$kyL>u3bvuaF-Wth9|LP52)y>&Mb1pdNocwhi z{^H4|{Knw7I*vDq<0l74b^e_*2xd0u&o}{JXD6D^%1aOp+l5VG?C9OrR0l5HP4-Qo zp2eBUZ3!&=&jd)KdGSss#M89M6)~Rry(FW~1xEJipMy-&!tA=)53Njte8{TPx}RqB zlUjRoFM!OpE02pENdGmMINHnUt@5tIex3*r>0N&y9aAUr0Eryw5E+0l9cJ<}geRb= zj^iM4%y4iF)xhIW!FOt4094j-93qZ#g~L8Z3mE{fI%)i(4z#dA5V5xxyJQHBv~?hG zwmAADGRJ(!rV*x9IQIu1lnPaFl!U~qBmJo0k&&+6s4|l36U$%NsQ(fh)&7PDe2Mra zfg9YM?=Zk*xK4^i?(pROy}_Rn$kCbDlQ{SWZ@4a=;x^DX>lnc~FU%0_EUz)bGpIAT zU01v-x!ex5VzRP7ahREZ<^!Jxo?38fam~(C^G`ifbFk*Ente5gYTjtWd`7n8qx9$n z|C7tt1V(Ib5M`SWG?Ck-`~dqCCTIy5ZIA}8Gs8GcFvwn;r&z$Oq?$Os%M5W5bxn4( zLD)sDBF1)C^@-62N1uN}z^`|DuKm0P4tZdIsaYe8KS-=c%xtsH?)N` zIK>}s3#s^#LO)CN|2XMiw}n3Vje*CtBLUYHhA)WWij(2pb}#||H1MP-7!Gtj+yPSb z=ZN7CCqr!%^n)PYB^vIB5J}gaCwc%s)t(Z}9)3C+vLK#E#1PN~g?@qP9h~%IF@&%; z_lSj5=&R5#5E`!Ehel9%ewULcc`x$DH(E+XIK`g3t{L$XfcGgY<#Z@ z_hj<;IOyZ*^h!Q2jv%h!N8_L_-Bk#IGT&Vm(+rN3Z{+>r$?7e9Sv))p+Z0q+h-0&Y zY9sH_5pv)tU)hn2{};d1k-!~x(jH8J6#UGa7bie0oKYr!Lz7QC8T5&?D7D@^JCUZ{ zRv4}k!%Zi{wL};Sdfqb$GSSm0FSf1|UCWOqlFv8t8%Z!4TJ!8qFciZS`nN=H>7?sA z!yriJk9LN>n5xik5WSOwzA7088?ubfEX@6qiMcWv445sMc}+6yhliZf{z!%$I8G7s z9f=t&3AoX_iHs?n<=8%yeniH^5~B=vbpCx>32feBIda?(Zil#4Sw<*^V?e zvnNyoo>ts9It{cwt`5pB?$dp z0(ZyAyY`_7P2i<{U;&zaToR6t4uR`_uki=%YIS&ll3~@&0O=kMlZKxeW>9_dg6_K@E=o*?NJd zh)*5>7okWxTrY=|_~B~?!i%`ohv%JxWV1mcR~N9kgJ7<~agEt>A0mA7q zbppg&>JL2GErs=aePp<_t}n3J#s*$-Y>)rPZpv;Aa(|>-;cyE}ns0+BNZ|ep;27n* zn$r5pkj8yWA*eCt)KYkX3YK6tJ4&|@DI1bR-liB5d5?wQ4Qckwg)j?nvMrQa!gjU??A@0Ez1c~yZ(IQ%0hGBwSZLo~1xpbY${BnL2OT_MpTXe; zT21b^8g@`AP-9+i|6w&ejIdrz=uW(|*NBx$;5XL7HL6x>-h+1UmjHpHM8NS)mT;sQ z)Gyixt%u$KpUWBQwdty`$+c0P`?IArj=k1$1NEVJ(^tl_zPnsCJDv4z1Kv>v&G*Ye zb$}ObhE9k+esYp;4?*|xa|TuI7O+ye8@3g~Fw9Shsn@oGkz(r2t&j;VIc$SSHO^j& z0Jj*Df>k-^FT_x~5<~B9gJpmj4xqh-p5AppU)&BwnBymNX2K3wh9ezlZ|#5>LR^~PQTJ7(xuKR?{vPTK1$F!`n60&x6Hu4@m%#V$fty(6C+mVUf0WzL zze$}7mivi*I@vc z3o8|=fc%AU%uyD0(-Be(-36dHe&hg^$zeiQs>!)`WJqQx;6+Hnzm)=8PS>}_*`uXA={(i7K(6 zYEArs4`Fd*+^0W;2f>Ta{|e#^Hb-?LcG2e{J>`BLBQSkiXQSweA>2OiWAFrs6;qYa z4(&n5B}Z!v2+;n}Je?i-E>ZDFs^ko84Bs?`M<~awKFgC*=No z>t_(&8295Z_avjk^p_(`mkL34FhXAf?q#RebJ%zIshKwfecymfMfC8me+ zZC5GCg89)}3YX^JfFA_dW50pBi0v%QJGD7a{}!&&l>pJ>b>f|CJNt+m@FNge2B5iE zKnWl%V&BWo?D_8~IK+vwmVDEPD9W;FZ&9oD7+-q}Y}9cHee&X~`)zoXmTbjsNW@1i zqVab*Z_F3s`&itv?c4@xo65FMbjooodx4U%p8Xz*Jj9-_rIu--5I3(5Yro&%Ib30p zAy)evEP&PZfM2;omt3X%$Q|fI7ZCd2DQ6QWr3!V3l_~PvLQLuj;Ol>9cC=DM`>`X9zKxh^v?-t@7X`1uh=wjR*vzPd{F20o)fWsyAM7Na81x$ z4{R&tT*ZOvE>FsoNc`;;e)ufHABr+ACP+d6w_5O3>gv}AVTyUR99J)Njz4Y#3SvPH z`G+7k_jjyz{lzq29!PH%mIh)LbP$}b=+-K;-25b^IY8tF;e*gq%iz_memQVZD% zu$SF{XUK>u18tw$f{|Lt-oa`@`c6kIA!VJNt#A0eBwsxL|X^Xbtg^_3> zX5}*?n$%#GHw(?f{oR7|l?I6ZLU3+Tg0rM8R%$F82z7&U+9n3yfvo~^TwQ|Qz+1;+ zw???_)>!N;js*?aPqoJ&+(2fDj&Pd*yRObZ@Hk3=fU_-No@6UC@s0mC4S&*<}B`D~<;+@ud6FQHOR5ghnY<+{2rC z(YMU$tM0>vm>F>I!!f1@D1|6ph;lg{A5;Xo#g9~^$_sxXehw?~gAd?w#HRz4BiK=) zXSyr!MG|;LQ@|HFfG=_b{R!G)#d9 z>p_^$i%BZOa_wUaF-L=s2l7)T7>pwnK(gf>TL*}%T3%vN5Q!)4MURU@( z^75ytJ}h#GTN22Vijc#ydQra>(I+JDALe|bYS(zoY2hTfXT@>ajueq<*OKbdH z_r*ZvT{k_Y+^>Y(FQi=0p>kQRi+NrS&fwdhLT@neni32_V^IAH`}3(YF-f($6d&+3 zr8Q%a6sf-~M0)b@5{wqEy#5US2fIoEOng1iOU~!>N->O@3i%x*^hmG{Cw^34_k~ZoK z3E7M>Jc~ZEWxu2w`LZ%JLA8QCqT&+0JgcZlt zR?x?}YAe1KR_t+DLC<w@du%^!FUJE@W05J+!1kkYdrsifSfLt6VB=FlPF)KUzwbO?3}jDia6=jz>L z!6d!Q4==++ezyV*m>R6QID zax89RqLTuBOn9BFwB4lxa-q$lj6~9RBs9XWbDU>#aQz^B(VkfB#n02HN6^Z?b~Rqn z%oWGfJe!z7Klc(+@@ABKJefB+|A}#h;s;?iIWg4sUon5JEklUzE&kjPUj`qvEfv?& z7i{tnEWTf{83}{UOZ<_*B$jIe;uZQcqufi#o?cXtuSlOO#4nN3%cSr!DY#6^Et6uG zNReey+!C7*RW`$F5+Cx0T2rlSt*H`^bqaxzKa02^zjL!mFycl*0VDrUf)RCGf)N$H zbu-&R@iC_OK-gAApAgcQmGnm|=3UhDz3b=~2p87j_o3}Wnl;PvDO^}JxT@T@Aa7b> z{;0|Mg@t(&$dKGB{@lwL!fRi`c$T2|;P1VR*}BCvqmb>=M`&!NA>xG?@BcD357rk> znK5l_ew8&+M9nkAM90zvA-sG8KBZeK4v3!`#*YgUnKwl diff --git a/.doctrees/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.doctree b/.doctrees/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.doctree index ca0e1a725145e24b7986dab1a0791a6bddc4e451..4fc81abca8ced4ad2933613510024d703e7b74f1 100644 GIT binary patch delta 3851 zcmcgvdr(y873W;o%d#ql-~+{l%Yq8%BC9Ck1E2T?HK@oC9}6t*-omczE=Dv&%%efU z2%NRi7%_>DG}cP=N|Yc1KJhh4CW^1L#x|Lz+8NuXGx@_h?fJgTuFF)XozArXu=k$x zJHOxW`@VC}z5L>M;J%hXO{HeX&fgr>G>+d$-Y4@-t6R*O_-x49)pk>o`4o`_A7 zn?i;%m&GZ$+zw~?NQ1;~jO%PJTYj-cDk`%VxNQ!*x!C3|C$QNq6`1W(zC|jutg{q5 z)>;asS8Q&p%`Q3Y7RlzeIL!>7WYFo1M#(U3jg45c9YyX}%ub6mQ!Og7*xd#xzg$Y4 zR%~;*%{Her!%^_F{4%Fq=dlK_@Wfj)6E=G)=vPzo*8kr-_h6m+OleDLnaydT6`;JQ z@6!Lt{$bD<36qU_{5CoS=Z%TjWcqje_%GY&UBQ1*`IblB`JwW*z<>bjFl!*j8%;Pk zn~qGgZ*(7i}B8R5%idbvY^cWoi%{!i8h% z;adWX7iU|C%7+4R+O8<9oF0VIlwPPwvnwqrZvX(+PRxQ3Y)|L(ItU5~D9fhdu{jJhi1MH zIV9Ai{Az|4;2|+ecztFP{OGNv*!YYRp2-q48th0P$YmX78(WfQyaN>df`enmnpdX;~y^C54ns)vx>|t#mdFEg=$sU z^^y~igiT@EHN_5>%j_)o$aBdhIv37a5uvES5?nzjMSt%=^P)S|V z2|_D#l_{Kms@#fiE{jp)(Rg85l5o>MmzZOLR_019B3I2CbTsT19x+6!XjLQr{eRNj z7k3+V%ERUV00_j@+sA^e#NqYO0ut?jAST&(4kMboW`itE=+@tFlNluDb zOu}Izo?LlWm@V?7*|F-Xuu#OW<|QMpP7?XvEaMXI+%3Jvhk8$y{(jd4fHGh7eIDg5-|z(+ROtELb^+>q(GOH8bs+5J z!P@10HTzhQM5DbkSi{y`uWa1g8UzZa?XQM5Jik8;&QOUSha4~pt;}i^+79Fj*Mf23 z6$!sPF!_a+U^-LvJP#6sf~JFsf)dOdjs@yPJZ+}O|KMctka|m95*iECr_>ekYUpwM zAhdrROwF_I9swjUI_#URMd#s<)F+`F!#exps9%>1 zG*C5v4f#q*%b>;fD~aM!x{T7Y6BZ)1xVdEz#vSoQE_j|^mX<$x50AVFOMQ|bHV%Zj z*xZ<@%knA>$IVCLdp~`dQ5}1RkCEEE9%^l$z6R?t{pjnkf%wLX3L)0@KukXNhsf>E z^HazDC^P9S2d&2o$WTm^h5G32rbK~I>{Z_05hQH$=T?$Fdl6{TG2tc>ZuU=N z>xqYvUq4UyhAMpbWCXxBKH;ICPggg;0zaJ-jp@xR!#%7~-XZcE-o5FMwN3r;-t1li zk+5AkLD{do(#qx*vw&MWUcgm{bjsgb(}6xHN;^$h+?GX)YH8c0gOKj?OyW$g_Bf8; zn=?#2NmNg~RQR}k3O`_-7E1?&V|GU>Bomi9DLyACB_hJ(@IlA=$QeZX%ofWCQHSlB zPhbHzvi7V=U1T!q&m`-73(Ua#XZt}0hFuz=IYs2taN4EeLV5`AD(kuLgi@8M=zJBF zb0+D+U|Q0|3-h6r*Ov0yR;n%WuMNF;MQBiKf4o=$2dOrb>e@OdK?ARA;B{?O_nxYFZXD#<_LjBBNX zyC;y5FxEsbz#2u@Xf_T}9$b3@^nLcj7k>)e#Aeb851&(JnNiRUqcxY+1l!Fe7F(f< z{X-*jt|)mVqim4pFs+&F&&vV@TIFgs+A`@{-bz>2d+PM#122dgUj~Ndp1Dl}b01BA zF#CGgc*b4DskdPqWYU*{huj=-`t+?Pcb<)9RL6T delta 3082 zcma)8X;4&G7UtZhUoR|Th=2&PgG~gB2r5Pd92Jozwri0f3Jusilua?iOb{_9kwr3c zS}QYAaiJ8%1$c<2L`M=-GAbgOF$v6~nMrDXq>>m@shXK&GUwh$H>AcN`P2RGchCL4 z@1A?^dGF*E&7mHRcDMGR%V?MO!W<=eZVNySK8jrnZ(>kX6kd1N(YQD+SfKvc5myYq zoivj^Zyl@A;C&?)KZ^0eujbW27fmm~mgi3>sSEZ1j1ZeY?p_`PqxN-dM1$sqabhYE z{eolR3;Wdc5si~mWu7&ukwpjFUbofSs%^8ZVKS{C4ec^|9KyU82EZ8~Cq-dql#7(Y zF%51ax1;k*x)b~ugkkcEz~-cAh@z-i8XiwvJOL(hFd)o%T*xpx(2~1#Ye9bCBt6dH zk1a`NF!N|1M>I@!73M5lrICXm+?o6UiX5&oIOZ%|H7_bvB7RZMpk9#nE{lR@;j12} zFHaSyFxxr~PJO|P)vL^AVtGSZkfI0Zqs5spz+;SkcJEoZDJ9Ewl5ZX*$Q}r?KD?A# z&iYicHG<5t@>zf{X;#hNIu5EnFE4S&ZP`ZUKWR0q!(Y~^K>Av0ng{mP^PWA$XKKnA0_(XKUYVw=e2lX#axKQv^6;@p23#dvFNp} z9OK8CMdIP;w(b*_t;)gra+YtG^8{b)T)zggF(x~NAGJ1H#K&YuLl%zB-v~L%z=lC! zO$3 z6~se28VdU;M>h+vvO>=A9CmIocvvJSCu_J>V-2>3SVPmwln=Jd)4-1A;y7&usaw#z z%UdxQ*XrR7j_o9DkK(o?i?O%G2Ee8q-f046@!8fKlr##jFpmxT{`%N0DXf1oSd-itiO_i zQvkHe2Ad~<4*QSCNe5_JqeJit2Pft3!6OpP6nHb?z5-`XI&v}-1Mhl?=yA0LBFv`B zRUBCeuv{RA1R@Nru5OD5q*#A!Z;N70Iy^oUfj_pbf}^;qJ;$R_M`xm*$1z&G7q7KPvb{P{ z5*)Bdm{t&v8_y(YTlo-M&Lo2cADs!JQ`U5pg_X&h=vb?5@&jU$GwFG|oU0<~^rs>? z!(}G+c9g?k$%!ezI#>1ws(x#bHJ(VvxQB_lXjjV4t^xK~hmUV~vnM(#Mjz$7a~}cx zo39p^{>KX^Bws4$#ws-5nTCCx+q|C;i|Eph>LzMhozxX6bY03@!>)_I*xiN9 zUoR8_^rGCWx?h8Eti2k8(TcZ9o`?s!6FqI*XA?05=*JZz(7k(>%fy=?0Ed-0=`4lJ z(DQ;|<02V7)sTv}d-gyY5t}e+m#cJ+qEhTpC%Y~J+pOBi6E>93dglW5Z0=*_WeeT7 z^Op;Zd3I$l^yr)B7CouE<_Ycd#F}GgV|LeU> zm8gM;0&wg5mBtbKE~5D^ng>GZZ9A;QvmpnU$;%{e3qP+hI(RQnd^j*4LkB!?N^!Vr zkAT%;;kOcZ-l&3S@#`Bt;Du%Vz8G?|jrkiKE$fGyF_geLw-$SQ8JjV4icwkDR98S>#>%G_F$B>AU2#Sa7i^2DB%O`=?|ry4wKlJQvS&5QTc5 zGOeMRm3i`h{N`?ydox`Sllt+Zm3uI1$i#ZN13zh&e1zt(t1S$=@z{{b^9&6e4HX52 z`K8-(i%M+rbpx8)1M&MIH|Rv;J^%1Yed8MGbIJd^d>yK5K7U$u-OB&ehRD%ld>CYu zk8;Ce6ZaJ#3?AMe)Nb!8-_n#kNOl}uC4@SMJcz@?Fi#FOsH_DYc1r0cDZe^pcBzIduQT}%RStkpwneq>u@~FIm zYc1tJ*^GdzayD;i^g?x#U#2JP-_))r8r`3WO$Ht-JPVsoxcjf^C$+NCz-4w+l@&|~ z?Grk6LZ(hg&@b`s6YO<@e4osT>jddO`3W8S$1!0-kiSk&4jZeqTL?h;U}Nwd6c%7R#sRF oY}OF!g7QyR-5Og8H^i#wruGoOWSR&Ep1}~K?5?~Jy3PJOfG1KVGV(_43tdGl_*d-8oc7^NvKN%f>kW!2EANFz*) zP^Lz3O*NHKElLfEQBh}N!b=+)WrOLW!5SN#WrJ#1XK|()VvOo6Dy!y#$_WfJsqJNY zG#R6Yrp0Jf(`j5(#a*(xi-yx$d@{!N$wq2T*@gri(_$$R1BA6W28%E=bzH=(_>jXG zd{WmYVk}M*T5Jj7hbV3a8MvgSW7?rfWW;G&mguXb#s=2*&-S#zQWz^@Ru3jy|Xs=1$U@q#%>?|T1 zvZm6B6dgC%6r&r%y_%}BSgb57m2A&8NW-2(*#r2tZS~9+J^fg!UMPC{u~fZKboO9X z&lfP5X?>(og;B>--O{RzJz?mYx+@FW*-m5@6pgW&MG9t0@`Ih7&dxNAwmC(7k7REYC;kctTz5i|*{f~Gk z3TGnI{Lmo=W*g@J>0tID&ty?=o!Hw}yHj#2%L$wb)xsARD^x5fB~JLhDgYn5f{r?D zctPw1K7_Eu5rEFhtYCh&!vaUy%x90FJi{YaxiMlN4h;I9m@O1Is}8`js^eq}n)u*s zpwzy~G=uZ~g~aY$dG$GgC_D`DT2#*<7R<;YXSii znD+f{CBK=#dJ}lh|FwnOHh~}q;8NRR!7iM1E`^=zbW#B?2b;kf*n}9o5ODL?p+Jj0 z#BJx2Xv^IQbP7U~02h|Dkb&H`j%p%w2{73i6$S;k-nl{;=6f|z-Q^<#a5~fgyStjn z^YC`p_~MX&r_m+VNh^njFgE&;?ketnDB$HYN`_##dss-$MBkYEyxUKN6DH4^;12Qz z@=TEva4Xn`=&X}%6hj@uOe@Nhl2bXtbGVghczr`h`KyJ5qi}sgtok(sW?L)S&A+^I z6t?xWTd(2{JiV^k@hSJImn@QNL|QqLoKX4&xY*;Z7%FmAzJl959^slP)!v|N;m*su z+~iB-;i(McGBY2q)rb}sWi_k(i1MBAPv{A&%q>aplRnP1s2=0UnP)bCRK%5^_B@z? zn*+;WCoQ*evnyPyqe$yz(+_o|`hr%QC9k6dKkn7>OW)dsb95}Sz^YJ_P-)>kD-t49 zSny;uIPOzYV}WYwbCo?}K*^#0%n$ z@y3VZ+TI}V(&}xTMa5W%Q!yIh$09s#4D}r=@Jr-w^p@Mi1jVZS(7zg^0Sq{8%fwew zh?vMg{3uC~fX=cgeKhVCp~q=kJ|ye1DK8MR*+sM{RyAE;FuxVR!2v4+@P%!P$bfSW zBMzmG!ckhX<3@D|CP~LY#&eR5l?PlITr7=q-b?9VL4#d}487U@I2gwHz${uE(;N0T z6S&TS91eWQTM2|&4&-t`EP5xvT@Dm70F90bvcNoCgJlZ)^ji-#!2;K(rEPr&?`Qg1 zy0fg5z$Z2a%4qUP{aHBxSp|Gv(PjPx0Rc+z2~BZ&L(4nb`iI+wyZd^z%i6d$rb%?l zCM70dUu7m)2V8cWaH+BwLT5b57~{%K{mJNN#iFFhm9%-4UPs#LEXeX3L8S&<2cVLP z>LhF8OTiphbl9I|TxI6s1xYpFYgvK`YABH|#1NrIQ;OFx*xA+5 z*VESBtEt+ICkx^++mm4RTarwjGYh^YnYWh2KpgO-i>y4#QigA(Ji~iwf;S!~%<}|` z%-mlI%H+K89SNQg9GA1n(;a@%RhRT1w=b#Npm>%c7LUlWY1)XAtor#rOpP(&e|#@; z->m$I`QGK{8y`sVCbgfk)B#4N6aD@!7Im0WU=X|O=0VWS^-cnr`pL#`LXjZQkS3MT zkGjdoUPEtNPv`L2{>~xxFjdwt$?I1}ls)XJnv??Cijz(2P=Xhm7vLs3T2cuL{MBA+ LNrh>=*HZi&4w+$( diff --git a/.doctrees/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.doctree b/.doctrees/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.doctree index 806d7aea8ca606fa5dd56dccddf599d0be13eca0..877e8bac77c94d0191cc233abeb22857b2cdc59d 100644 GIT binary patch literal 73864 zcmeHw3z%Hxc^;q(XaSkKiMjaq0@g~|ofTIj1!E9MMv;(-BhHK8ybsyu+(G#p=Up~voP`#7r&uo3?P~L(=7@7vu&!7w z*hk~$&N^qkbM8aUV94_QdU2}Zqg!^frdaUsN^owzYQ1!mnkcM zxNcAD_Lxk)D6K|<^xx72ZXT4oxvGg z;Mc9HSGIg>3cGxaFYV2M^#TFwI^V4o^Cm2=So{JuA5a85Uj{^9UtCz69~u()jX2vi z1##8|m$hrBp?p_|ACtv;CRjSJBSHsPPnL@~ZwUr#A_XMfz#k@Y z&MPgyjyU&63rL#dB-uErAcifS-PJRqf4akp_E?>cF34#@+PKnBVTYdTwyn`NJ_#^9 znqJ3<^F;bV%R-;d{7w}9!qQ_)k1hoYxcm~f`fEJ&;OtY7J6S^s#sMxQ`WU&7k^U+SjC&k1pO9qW4n1VWIy`?421FMC_}W#1ex`*)UG z5fA0RSgz6F%ie}%&o91)<-UQl45F_1zpvqB z2a-jXE(1H&W!*P+S@-!ym(lu57o)%BRtFH2HulgighKZ_;t{|TbfSAB_Vn0t(_&Aq z35%pp(tr>YU?SbB4}Ql3Xuzlhmn}V_QOUeV@LR~hkd{>d&dHBF|>8>cJ1 zlIy)!npWD^aeK4W+PT?zCA@}8d*ZjqW$n2*yp76k{_y0-8m@0%AQM-ebJkgZ_T00d zQ^WgQm9K*VwaRMBDud}8x~~CV(o^6MRn_$sFKOkws#doP#k{Y4$5zt~GO4+tU2a|3 zN3BY&Y>%oraJVY(R%$lbH?Vf9VjZ^8PZj^Gy5v>Ko#K7VSF@HUo!dui-~;VKZs@_P zRrQPcV$H%=1vc2J7W0@?t?pt16%Vs?YpPMx?@zlB50s_yj#ZtpRk5lH#k%GwF{?%$ zldM=6edzDV{$lND(0mz0KR)_+Nz^pEIe7T`h$m` zRWl9Sqf`Kx6s$SrxU*cjnk|+AL0fq>yISDS0*+bRKCJBGjN_{cFwjA_b+>}0&#I!Q zJV*jEnsTSHm}x-3^5$|wyL|;N5WU$|8NJ}nR;RH!Y=*s=o=d?F{3zbkw@jpZNelGBtpib? zNK6~>?O2X0)%#glsm9iNaqo&3mv9r=s~5m1{k`NB!XvtY1t#a>CQRwIA_YfB;W^lF zv{K&g)hsH$&ck)<+4UnfnY7X;I8ZV`IL)gYQ>BOSOT?4}mL}1Q&r-(#Hu8D3_yV*K zPeY7)Wa()&1}y~n>cs^WDI%6Wwe)CsQ&0%eyf--V=h2)zH`t^TV3dx7IsL@q^SPFb zA$Z?_Lq?lC@cYR&{}h2E>ZN`V_*%g8S-c4te$0g7^}WC$ntgALlc|2GpQ)M{sp8r8 zjFDWRfsx5w?yNcMtXQ~Cv}kIiRnXo{VT1~|6F`(F@M%6orN!e^#X&L~RZCCslUjUj z=_v)wnWqT%6lHY^cY=4oDqti2&M!R)L=u@E4e>gKz4;IqDfdDY#2eCpA@j9kMXnhiL?ISo^)L<<@`o)R_ zSSOYO-NszohyaWNv53bD*bSL;)Stq0Y>ygdM|cS7m{WQlzoDu1JI7^4dFZ$`hNybFgw|l*99E&c=rT; zMsvLvU%)EIRor7RyJnSaiIA9|Z^^?u~D^+HJx(e(6tLcV}tfXAnnj`1&EKH`(C5`*95`Z+73?E+*{zZE-+3q}gaR7bi3@P@R}USPIr`8U z49Ke)q6iz$1)&f%c@$^UP<#fPdOWO}KyPwXqBJdigX7Rra91#toOWX(znz&#TJ<{; ztd-dWYdpUIvl9M}adx(8`5=o#TKya7s+;N}SdUj>XK4oSkBH4cR-GoSW$dT|BT%#S zZ!l_bE*|)EHSiE?IK6-xABfpy$ku-IN%?u!s#o!muZE@_!=#naJYhY4oj}oS(J&Uq z%>sXO*TmoA!zxL9`;tWC+++`M>FdCam?^z|P~s_Pxb#~_U!_0Am+%N*l%>YTgucUO z9XZ00((mH;o{sUKpkYtPxb!V{X`aQu;)9;gV(E|A{Mv{XjJ3T_x}C@1?3@9B?2dG0 z8ex1(&Uagmk$T_7=Rmtp2xB2k82ATa^>|Iny-e-3@L%K>OwO<7Lkg!#+X<-Mi zanKXsKtg5!pI&Wyuj7S;0c^Vu#=Rc=-WdrO1C=g^rr117Jsj>{AlT+`zndfJ`#E#C zO^aXYJ(&q*Zt30+_ciEfz{CChc=Z$??)T!dCG2_GrVn>^M|wNl>@PXoX}!T~T8JOs zt+`mYI;@~BwpGOzLqM%oo})$^8fs|CMYRvLc+vOl@^qwTzQ?WR>$Y#J`z@%NE8vCm z-gb4j+6BdbLEL5(boS~Vm0|NTc?!x~W=FFf2%~&_wTdt5&(7_U6y~3x zM%BIg$p|vLi6~fu{Fy& zMwA#XGo=s8=BJete}DLU2ImMc-^(c^VEy5Kz-lT|w#1O_dTdP99ycR7If?5+@Z#dn z@bcruLNS~g3&@UNiMBF8?gZ)R#@q+e=P}n zT@1uMdwGO+V9)Ins65^?RA4y%CS_H)vy~o=-x9;|RxBe?7XBSszn=#Rg=)F3TpD>T z;;q)M5%;0L!TF%hjqg7Oyd{pJ!E5>v-bh4oISWuE%IOg7mDi}oo)0xycuN#p($4~P zH_xH-P=hGCHJ&v&fZ|OdC-V(3dQk1q@s14Y8~FcFyThisr_?M`dP#7dvC>m(?byjY zxm`J~qJn%8vv_{#$FVLDf_T0B*mb=l)TfbbP{0023M!ZwVAp=xo6)TTpPP(H4m*Of z*7{Rbh`m~RWK0yH)Sby8le`TV+f5|;l%@pXj(~oXcnG83(O5Ti*5jI0wT1A;4Tn9 zRhZObt_;tB1mwzu&d+Q3ku~Eb^rW7G;0e1*>}4`F+AWq@BusVTq}em(sz;N(6?F*5 zA?o4E(Mp+xrN_Adt<%BmmLA7_`gwgfVp@Wt+6KhyI`p+B8W3{)D)?x0p*c=mjXW?5 zXe21Y9V8rO+0k{|YHC!Ay&h6bK@KV)`CN#ruuLz0F}FCMlWpi_0^RL!n602*>qdl7 zO|b~Fcics;b3u(5b|l*GfVSic#sCxIvg|GtSs~KRZ;o%+RVtWauvV#{(EU{^7*fYo zDhNW13jt(Cd>X?06fs$Vub_3k#0a1m}Vgif5Qk;7x8-^Uxa`UNlC$BpqsSD-xAK zc0YzaAF-U3em1emZf71(;{pQf!%V3tjRw+)A3I5r9QLa!Um$HYq(HW0TnJy^8% zjfNzO6%<0!j4_~~A;sUJ+>^c-l0*(}-dMIZQ!Hn^K(J8F!HT$oZm@}DH33avAMImw zcL57{lCn!1{+!}W%UUo_M<$=E;jF+L1K14A5mAi01T?{x5Ie|Rc4wdjjzTyKwwX%8U4YS{` zWk_(^>^F7lsY4qB;j5gJHV|&5EZ7fWGM08Cv$V8HrVsCcSJ2Ub2E=dR)qV|#Be8eD zGNd)@CqN}H_ft%Xn|mg^2FSW&!#~y7aQYJHHn{ftL=uf_KlfH%n6XLU;*?jy>*YTQ zuB4BJX{n5z*IK<^{s&&|7q8zH<8{m3*$tB?4uiz6UafE5)td0`lmJM~WQpQ2GTcBs)bq;lm*%b6L95)8 zxeQaGneG@a;aJ;9!D;{@{cAcdDCnx52OJu&tu@h-%h>&`2%hBTC<^ zAqcm~KA8p zn(@Z>V}j}dx5i*)bvH#yv~=@`JeGLfJvOoj`HtG(m?~CB)$lzIk`uwJ>gKp@5u!KZ zo;`*28zd1yzs4CI&V@@Y&Q!OnGQ7d%`)sk`JKNR!w%#zr?`J*`xJm@aFdSY0k1*?o zr)J#-Jke@&pRY3je%31b2opzUBsFUzK>G-H8(wn7Dm>fh@rKYLkKy8sZ?_Slts~&! zHfJyuvm50Mzv5pKuc3mS^^rkneiqjl} z4+LpkWlK~$_m_eDvvs#RGs-4WTskI4#6l#1TMdzr@$d{O=X3K!Nceibf#5?1*6)&| z$1|WOd^aG2c>4Uu8i=^Z;-+k$s0TMcOcT?Vx9j$dRhLifJev1tJQRnO$#d2Cz_e7J z8e!vd@vvPkI<8yL;qHgE>mlOxWt*bDlDDSpyw&h*wg%SMZRAfvrxmMy*cK2bxdh^D zS%`q*mLJ4cAs~L%nd6c?M>f38Hit_zH+ss(rW0(HO40W@ATY#=S4y`?j=%`~x7?}M zE|Z<(P}hL=HG}_h#-DrSDHBqMNEy&N{B6{W%>ZdCbaJ;o0&@DjVUSM_&jJwjqHCVb5A8-R+&i{yKewZ>X41s2&PEomsq9RPV~xg<%k@s1(c3tEdDyX%Gp)P~Gq9=e~~>s=IL6 z@4%bc6egc}>xmrUu?gOaQ%l&cgZ*rS8CAsOh02vB5vLXWb-;3S||*>pL5c} zfSE9n$qjF9m*)|Rgc+o$UQ2C`m`^U%9i*c?C{ZLq9#_--TC!lkM-fp6k-iyLe=42n z;ws*&Vni3$3~0`^>4kpHbb-*`0(38hnx3w?532+B?!9LWuS&{JI$6XKyot_OoLZsW z{t0>=pbh_u0y@@uQ*F+1-+&IC6T@`E2WYGVkLjmC=N9@bBe%PcKowPA`L3I8*xZU>);q)-a;GU|TGkPAbxp!(sxdL?`G?OzrFm z`gl6F(7`$NlpYM?a!Y^Ns3*9KqBUd6!e=nr;>A`qzn&yLa%tD6+q@_iN7eoZ9~e~! z?%st2h&%3maF??Ed=68j<1f9t;lImxu+|kz3Db+4 zSRS7adT#^sldN9w`d-$xJT~5}(uq|%p(*1koxrgZ;*Zm{N+*O0EtnZdX8U2KVvcqn zIGu=5F*%gr7z0xb?|^4?CPTUb@=_&_f>3JQgFlCFh{L3FrCgyB8Oduxr!fQ-Uwng1 z30aA!NruVpAOJ`_9@!bvC4yXr(HS7s+W2RgxHj)-TVU_K{->Vo?L7TVNJa1y|BP;LRd(M3<5K z!S`qqWmnpJEY7rI_|nGD(plBimMtjsA%;^}wP^Cf#9%;@^wOa{3u&VZ$cc>ykaXcD8gdR zjyOd0Dn28(H1;i=Bsu`R4#pb~%VG42>_6VCzu90z%ZLJ!n zW#t`7J&t9&ZW&p(v12IDQlvfC^PYAfi2Y!_O{Ui0IirqosN20Om^{VHGPE>5m7%U_pXeL=#u-^dI>Ff& zID~dP-4IhhV+y~JnL=83(1-8xbLeP5-{r61)qZ_E`^;?iAZ{c=8$1A#A1MO>**&0{ z3+eCS?O>R>f^7re5YhF1>p(Y*G0|^y-Knez?>E@mSo0d(R7PjnRd>}g#oQF3_^gIv zqU*`Q*>d#;?B@myQDR~ha{clS1_u9rKgS`);E%M!;N8IBRi4D|iBDdZCyDRTKYu%d z)IiWb$sp({xZMAOLv*>^|8Hgr17Gg{2OSM~xt|SFz$w1me;9|F&~CllTlU~L(JW3R z`<^XZmO`?!K z8KHnx70VFEcKJyip__cgDxs2{KgR``!h8w34oK)I>&tHD6m%sN+oRfEy6e>ZJ(xI) z(-5GmRFY8J0zYMBC$(px6=9XFQB`P&FFk#y=LnTD{G+ALm-u2^Q*J{$@axp+p<^=Y zW?|A0r#+@GivH$) zSqswSaxpErY$xanyh=zIA+t(IRtX77MnXs;xqS7EtX{VIR$jeqwb{)$BMH0xKtJqu ztbv&XFxBAI*TyiOZD-cb*)d5{X|IWw{+=^y$p# zX|;fjxR|GJfZ|xWdy1!yn>m*f+WO$RZP0WGcMpl2Ocw-JS`0UYf z6MlEBDg#$MIttQ9Rp*aL+)S7{7CwS-wnM?0#n;uaHU_4o)}*S8B{{;(AMZRgtljWX zHZSrhIu1V+`p&{-Ra{%>wg~r4OoVBK#qp7TE625q3cL(aSxx-Yn8QvyC+S^_1QCzo z%RFaq`T;T(h4=;{otyTD)e{J_EQ?1Eyg0=r2JSHQ29+!nk_QhSwvq);9Bt`M1J_lf zE)TqDQfb^1$JHn?ZhCB17G3-_mjWO%9h`XW#Hnee-XFbTG3RhtdI@7o=(#Bwd&lSn znOP}wW_&>WLIE52T@pT6G2zPsg2!b&fDHDTsid$b`rSS(j$QQRWrB~eOCkVX(;lQu z|G^0kAKDFVfI3(&q6RtiG_fE!J3E`Re53~O@QVnjvf<-;+bw_0gX!N6zfz+x2HyyfrN_}jn7UOX1Hs+; zewY=3K#LY^Dz~(26^bPWJ6Gfg8noqCGPJO*a^F0UhH<6cVHEJDllC^E5jmo@Q`r9dkGl z!Uuo-HYVPQq?tvUu54M%%9C;=JXz^7aAIi_%}D9{jAs+)Aegs%mY>wsnojJKLM{Ze zNQRy1;!!cHK!r~IwstJl>3g8#hTi@NH11&wkGFDop)vmuG~IEUAKhE*#%JES+tpsw zR7+pOVG1C0OfSWQwpD@s0?OiA98tT;?fctz8;(0yJv)vfusg9PK?L~ ztKQZctXgUSRkD$)*Y9Bu(M3SKG6nSDj}|`*@q}_*9DXUH1|J~ilYgU#IYjC)Gdrc$ zwEWA^Rf=#FqR@y^vQC{%sWQxv&ivODhZfN4bqbmiScl)WD2!y3YJ|ls>B5hCT-hN| z#!roe7Tvy80bxZDNL$E; zD#flk&J3YVu`4(S2$Y=U>?ZWajj_Y%5N5nvf^Tb=d(GxlkcZHP?*VOd5)^X8DmTPy z1pWe5x;@Y_#msN#6lWYb3mmZ#mjM?Gl$1rl4eHnXb5SwbL%M5nK6lsi4s7>%`a~cf zBlxdsK}U(~at)P>6*aTbvE{qkF90z@RgaD<5|W`6E|YOn^f;~+E?}oVh>UgMzV36K zn%!cC4?cS8RvgJYr*en{8TNNQ3#RZy^?#JP*9S7}6YNTB*&iPM9`BR@k90DnhCh^9 zq#?9c-`ojDo4ct;gf@@5$>i3Vt*w_6PL%&aiHK>>A?l+<0Bv8@)onwfb3U6yucNaPvR1v%wMF`@? z7tb?YuR6>;38%a~{LVnb;QK|7GwrEW16_kdn06$ht5bntin`QwHR)R&?;sM!D!LEVOBP0;= zc62N3KJcOO-8=8WznwePP1|m~<@W72ZN2eEbwFUK-;4bUqo7MdaZK$+@UF_w<)NjA zs~6MgLfRfni{Zu_!{NDI#g$cDSsqvP?Fx!>40O<&>P)D6aV7pSFk2?MS^@9mhco=! z#E1K!fRfP{XRAynT5%>87fDb&uL0c?&Zqd`f->am#i>v^R<(J=7^;etrPfrj44P-- zwCB?fws-)SPcUiV{lE&=)yEo8V8KCn8eX_AqQ>EWS+POpFa{rMw-&nl(tDTRc)BCf zY-H!{KrO|iw(7=Y6O?A|?MgOpKNV!Ng>jzvLs)<`@4WnFyNYV3?+qPYn5+A(`M@)s zv>1H-Kk8XfF-6KpabNzt$PHbpeVAyk@*mkfPim@r3@d4PWzW#d_)u{h)p0Bp${XA&L{qzCwviYq9MkZdt@a zGIt|Uu+U~>nr4f1KM0|@18EKJl#DWwhn(45QrehHHh)a_HB1>3Y$Jt42^LFs5jz;~ zo9tTIF2FvEeK19POeef5;Gcg`0U4dI?5O=9~c-H#&@ut zYG|_sS7LGD7OdBO7|?$gf9zPKq7Ud_fsO{Wt6e_;^b>c+)(f&nz=zx6O|`XX#`MfY z{PuTi8<^jbz`Sh=s5@5*?Ar$i`+Wm|z0VX-DU@HY?*aq)x}*J$lfO0E?98ELXWnVD zCI%y9%y4R@_UT6l->32b`}CfeIGJngnL3?q+Mct!)KyxES$A&zztuNcoVO}iC%mKV z3U2c7TOuSp*%jKRxy+P8KiO`iCk{dm2m?4w5WLy!sjQW3%Q~5mfm;7Cv)D8hdVd?_ z7n#E#N9MZBt-bS58@&H{4yP~TOUxHFK#X~PF*C39h1$oB@OgAJ;EnKQyxOm)MgJ)O zG!TcoAk5ZPU8E5MIxV}FVl78{m0O}CaD6Xgjxqe#yKYYAghUKwyvB5{o9t40JJ$r7 zKG$iT&qvcbpOuusB4C}$Ard0=ANvBak=RBf&I?G z!M=9@u=goOrXb%cMs`R0QzJ$elAY;6jGSJneVQ74pK1f_Q~x}5YO7LWWOkRjGD)!* z$^P1LNWs5c{Hz2ylb2zY2rw=P-P^3vXE^Ty!x$P+!+uB*+V!PX!wWx%r4!Yuh zMr?`q{wGs=pSJ$}&%_D?LI1%11LDd^cOp6*QNTs|IiyUaIWUzhE|U%rW;-b{f&b1R zVITb_)o!La)P9jkxd`;C9XXNBjwzJk^k@}f0Yu(DjzQ;0`GAg?g-)Bc;4%eEA{;*> zqnQ~-7-hDD|7GkV$|)Q6O6`s5*4@U8gCuwO5f(FT#5BeY%U7V9d`hrK&3V*yU_L%p zvBxNIqDRIb*ecmi6~BsKr;dN5x0cS(ht=r%5r$|Q=HNpg@Vvr$BC8vnI1l&*b^Fa* z$8OxV?ejAG z@1KqLJFR{y4reLPsUk+vp1g@8CP4e`et>2=8+|T@TUWlzR8H{_w`08~u7>B$;uk|j z58Q{sbT!a1!JCNcB(P(mlUfSoSy;GGJd#BB6fs;{5mYx4vmm2iLL`<_A+=~KdkL02Z+pw3kU<_pP?qQaP{CrJ)4t|^&L3q>`SjHgot zEznUawNlOVg&pfcax9?AR78^PsRI~T3w55Eh%m1(XF*m~#>_^DZRM)aA(HU$d&os% zAbfiR0M-@L!sWBLr!b=J_)A1dba0SCSIBE3VYgHe3d{Pq8oo7mOYWwe8F8U)56o>q zZYPe=&;c(<53`_#QQgQss_q-sl_qKP*tsHDVrZNGa|Zp>+NQ90PapUsXF2V#@ZUH@ z_gK{bo|(nKs-{0gM*}K5zKd7;wU8vrj@Gl4wV6MM!%t{a%QW$eV77rNt4HsxfAo^8 zB70W4(*0QG;=U(D-+1R+mUGENO^Ry4CemC`cKijci*wjXMPiUcm;g|daba-*$pWsx zD_1@wL58G#sfMyK7JW!^~ zFJWHlwQEKm|I4+fc5AsZzVMRA=A>%XDr+*tKUU z19?z>i&YV8#Urj17Jvk7sX}pj8YLtV4vCmUaU#Xbez9DZ*O3?Bu9xRH1ms{A_@ltO zWedV75paos@;S8D!HSTHWx89oz>Ts}M4lY@-eL&6M}b_XFO?F|0YZ{=YWsp)V;#gK zUNLmvorWlmz$DwM#hLDN5KNJlT{{J%l0vbJm?2(Yv+gKnr1RVp4&wg`Ptu{g%Zy1v zSUcjPDF08}b{T=~$O(j2m|0jJ(g7F{9*Gc3c`7v^bd|>9OjPawi;%=WdUUNSKy#Ed zEL5x-Jc}^|)+h>HaJF2PtmLI-64I4lu~ zNc|!*9m%dDz#hKCBaDv145)^%3!Blfig;3~oEgIW0RzU{nWacnAaIRll~24$)rsya zdRN&9*n)OUieh3o3zM2g;YfA&_zo0`lo`>z2PG+3bzzj?K{#xqe#D-`H&!ku@a1*D zwJ?REkxDv<>MdXg)IkS8(V=F@=#T0NVE`#BWT+X}Eg*WBgLPd)#Gc2{q>0=Vu7))wT5RNq^DlEBypU{{!N|9Vr9~He<@m8Ta z1AtTYw`>9IL~51lr4|Zf%VmkHVHH?-fLBp*17$j)6pEtqp!q=!P(djri5~JS6blUHIYY(;9cv9lN$`g2#p>Ky z^lY4q7Uf%b1bBimX^e@vK%-`3tBO8~U(Q9_$kC$>0}!f(G2b1-e*nsmZb7p}_@t(R zE^#&`bA@08lTIj94WaT3ae`qHQw=OsJ=I4Lr6>*y)(Bh>!pvokO|#s|hES`r892mq+4eW+qGXH|z< z{Lh20oK{p`E@R39V|`8A;Q4Qk@6vtF_4{z`r95sfjM0JDSakJA#+(a{fNI!d$c z=2dPuV{>$|v|iTkiZpufKF!TNU#8I#Zs_UqH70QXNi9z;cZnM#bzkbn^mQMtXNZ@V z<^hbZCQoY8=S94P(PMUU1`8YVuO?F(B}e%sFm2;{t7C7)iMrSrPylL`M|l%@l$c_y z6N+JM?Q8~F(v;w?lij5VQ|~x<5)7#^-5<+Lw#1bMp1t?rl@I;jOy^Akl%PyG-dHIPh}B(cV;7uETSJhb<>NGbu(99zxW*7D5RDc4U$Q?6%_4~ z2oL(~4@7v;TjRtCxxZ&Dac(YM18_uk$PdLYiXC!(1?-TSE?>#oA%7FYi|DZ%T6UV# zd^P3P>+UQS`mkR>+dm7nzoqRtv^&6QG;S(ZjCupbtkF95GD+%u(||{V*bFRV;)ZJ< zMS@o3FU;F8@QB$1rnQy$uI$qD7CBK9B)|`nzm)btECj2;k7b%E z&_f*-oM=5Xj<8cJFGb%AFqzOw8C9^Z7u3$9sNBtTwfEXnzPcX{$u*dKbO|$5*q%k< z>RkRNsa^Jgk686W)Sk_w)^YA^Hc!JKeD>9r*dQC`|HrDK0OBguEg}A zoo(fv9nM)q#x8Ah3XRSina(@kZ3Yv>8OhD_p%p&O#>Bd>8tH-hIQJ1OHuwCFF_9-u z3PQIHMstkuy946JzNu3L447*BplZg1e)^;Ul2Tk|*VdKKh~1xF1(Q(}6ihR-d6uF* z#UwYT04Wakg$zgx4tC$l&MDfxtGcYz*sE7F6YG4uBi6NR$C`f~CI8y%-4(N|gpm-9 z%Y!5Yeaz>(!4_=i+CA>T9IbeMl0 z9xfcRigKt$e-rt^y+z+gYWK{GYGg0^+)U@8omKJ9YH6@@9~vMeNxX-kz_S$7QO{Pu zdRg_E2D2^ZhF}~7-<6rJo(fsb(3z^pT0ne(&(KxUz?#NFmHB%POy2<=2^KDBOcuoV z;@sJzaK7_ZsR36KTTdTQ;>6{qPDhyShO^qY;-(QQ0&RV4SU64rKv)wo^%IKvU773dG1 z5)vFSEkCs4%<34D452}$Wa2y^(CSU0ZwdpbS#0UbSj7zb*T7Z%SAlGr zLBD-?!0RVMpusyx^mOMA^`rJTQb&CwUR75pn9+FzM8aMsmu7JB;ujWQ%P}O5nV689 zAkHq(=9gsdSM@XZcsqV8J&Q-9@QtwI$rI7{;JM*LJfZvGYYf#Bip{xY7tF+Vx}Sq9 z$O{KaKkA03?k-sHtp-OKyVSD0b7ze<9GHzh#hv!Lq}LBir%|7=zUzK^5^$%Gh1kgia+tzfqr!0ZtNQ$4B~NnW~rSiawL2XFq{@i_eUm` zl|#Z_K@K7n?dV|da~059v#uLSF- z8f8>WZ3btL$wD3p>jrZ?gCZe35pMlf*>juEHe)*QGh=a9&We@ya4U?37StoQnZxqX z@K9?@9kyurCWNgDZhrfrTy7ly(|P%ImB?{~(AY=2^khbg9t!J)Wk}eFlhCkDQ9jXS zX09HA~+DV-#$VZxz@vnx)6^YWJYlWAgK?Rj)RmEd3GRUv7ou$bKCS zLnQrIKvIHTPF<{M3mbKbzK{bEkH)n%~eUt_}w z>K3fw!(Oq5oqTDTC3eJ`_Y7}ehRS7e<_|DbTb%hr{?HL;-o4B?Z7}9f!;ye7S9YSp z2EKeJGyZb;LRw*G!gCx2VEzd@8W3Op3a^^@!ZCvLL5g61Eu$cw-)yBco!6GZmPO2s zKyJYnKI|1+*vYq-Szt$OxxPJ(X?Ncx*VHxVcR-kT^M{TI)5B10aAqVN3^>y@EkSZY zZOP1HIkdrMwnv-yqN4%P<`%qaq7BDb4sE(FFM~Nt*mOd>1#|eYSIl82S1q%~H0E@^ z^-7aK!O|h(Avnc|)8qY@UmiD07TTa`#1uNin$1auD_w`1Iq}`OUS}1Sqyn9tXu7)T zz{Mr$e#H5_bFCfaEf@)|*7*S=+4v1)q><=v(V;hkOOxx45~zM^o8e;2VX(%?VXz_i zK00jV{YjDzgvICW!sOK4WEE9%n;&nMs@Mi+ix<4JZL4AdZJcY-z?^h6-DuokJtENS zdAsRc$2~YZ*vQ~qXwN6Z=lg;Sq983?>yk*#PTN-sYm3PX-%{)mp=!#Ll`bRN4$SH2mqY+s9z?X$DuP zf1I@8=Tx6Wkaz()1;Ck8%|lRn2OOBvy{wa7n!z=hUou^kJ_`g2HtK$pIYe(?o&F*7 za&QsX-~mt$Kt%IVGq|vf2=<0GV*}y^d_Sk&0N&S;ov&V)jKb|%uNiPy58Kf+mI;Uy z3zIcqc=2e{Ss!e)8ooQ3JPOVMA_o^18kO2)jCcU7JYab*7zoSk@E!65(5-sh{^U{3 zvl|6>@@R!9brH@A3aL$+Zwi*+lrf>9M$van7K$F@ys?mQmghzX!nrQE0E=N#0)2*o zHDR;K=_0(an@D1E1wUaB{TFQt zHrDJ~a_qU73;1LTX$K~GID#u9#Q`3Bxf<$;yVaaqpBZlkm$Riz04*mG3Xkpau^s2( z`PdCxZvi|v)~EBC?)fC?{=HH6OvgZ!J#5!=Mcbd2F>vh19luh>U>lI;5vQo&JIy`k z1=j#4E0gi@jOo^-S0jcT3oi2JP_*voBm@7;_y_!5i^9P`_Y06c0SE144V-HafVxz^ z>#vh#H*bZYy(TUZtj`;uEFi?&hZ{8vu@SRFF<`)7(}82a9yib0zX@Tugrow5G1CsE z`GCCetJ9}(txzT449fHsaD?YD1qaoJG05e4v^qQqnqDkVqUyTN?ult%%$~XBo?V{S zWbIh6#;zV|Lhlirr^yMlYWj#AIGGNW75MhdHYzyxd`oX2i=CN z@-`XHaWU2&O3dGqOh9@pdfv)da+{ZGYw-1Q{<#8qXG-5)i{^WrPdl$Tzv_I`S#Oaslw4rq$brxra;Zs>KPLOtfz!|!(m+wMb2$~un$ z90iD^YPby>BgIXa7bZUMg{Z_27__r5Aa|K&sIvmsUbOo=EUPQ$ye_7VQ~F!oO>lk;203l44_9s!c)Djup@#~*mO=_nrmHcP`~Oqi3U2@a delta 5680 zcma)AeNcy+ar{6_OBBnMsj*tE7C9_)^3mlcexNkd%+f>y zMZu{3^hSO`&P+i~Cb#^^G*L6NX2O~r%}QMJ$F%yGnwnLs#x*m0-+Le2>jRem@VMvf zy??*G&u^b|?%mR5Kl72zxxumH=oc{uou>p$Ro@Y>*q{hky8`%(^AbMhOv5K#_p3j6 zW&p%uTS6}Wa)=jPYUPk3Cj@9XJkOa4$uj;ti0^BC?_JeB7T@2}`5E z(hU;^^P9og*9DkRkf=VD+-!#$%uIb4YH@37Iy^yPM&r5EeEZ`R9W$zsnTIVSbK=)AJ3XaL3Ra`OKQdAHYkD~^l(H5Qv-Nl(BLgpu$if3hopGCJI=42w zE*z8`ayu>vh9*iP@ zOVW}>4JaFiz+@*=GV(i}b{+f|`r|d<%I6C4Nr~$|60QsD6tm?|E#xi_O70&6kjo(| z7c_DgbaJD4B(k`?s1!C*l*Z$DIBN#>jM;!ovi5-sOEX9Bbi)X5kbG=HUu<<&b}~S+ zG3T?$Yn)*hB`*%(!sg%=n8c2F&k$eA zZ<2h4XY}5hty%E8OJf_I%R>)`RxAr+IHDKHDY?qSv@e89n_ckl2%fiu+`gqKyf>&7 zWphCY8&3QtFVVCU-DTLYRFce_13Q0B&Uo-@`lv4>EIC+6isRmmFAq1`Dwj>B4KWE< zE>3WF=|+X>mc=XFBHM<==O#PurZ9!-#AUaFn52!wm+}ak(yqqBS35%^9R9hsi1>O% zbM@5{>!K~ff=ALsDTR3}V5nvRxectE#kRh!BFChadx-)AQaxuiLb|Ef=i;K}FNif- zncS+n`w-FlA9> z%Hn>)Wx(hxqG(j(%(YAK$K?ecBc~P{zIiNJwCG8BIaIM0icXPnHQ%6fRla3MDKiXM zCZo(U;c}Q(a}K`y{rKPlYEyY3{b7Y02U*0(ko010=|6w8HCFsrE2FcVBK>T`GqwK% zFP>;h#m_cA1W8!BeIl;ew1CFCHdP3(U0Vh3Qq7oiC&HCaY=lD1#aUMk(=?Zkx+KWL zH|u7LLc3Bn1ad(09B;|$AtOrEKFM747JjMzlFeUcj}qt5XG(mQgX|$YKKM)qgb2Ow zBwI?31Iu%z-H>P3huP*mB}C|D>i65u1C&u(PeUCAEp}#6u*TW=#g^HLy!lDn*^I`t z_5T?Q8~)?%JG9F5LS=KTNa?9qr>OC)+eT1+Tc`_~e`CwPM04xH^2hWecT!yQ{?tm( z#>%arFrNtZJ3IsMDiO=Yo*niC({8nbAY1J?Z*lf0c?^lF(Y`!Xu~yr!wJjoRK3f#3 zQ+K`v{_`AIyWjNoeN<`xs+abnrL-TAX}u9%#d2mL~enp_0Q`Si)Ry4 z#ZuI>EpG$RRjqxBx0>dzYwjew_jm0VaSnX5DFvH$cfc^R$i9Fs zvAv5GhkxIb4RKi8V!aKnHKIl}7sHvT%u%1%TVWSP4y7jz0=e={wAngZtefu1^<}e15-X~iL zU|^}d>@d2}r;bZ7Nu`0v);sX2uH^n;SF5*K`~R#1PpBi|9I@`}|1*Oke-J@#dNn&g z3OORuyvX^a@u9Zl`!t=6R`@R*IN^~1d}V?Ed{FowBJej{q_xCx#-Y^y@;-3pK5Mz- z@ZCfC5Rav=MQ(ClXJ5JfQP=lW?CC6^+xx!P$M;k12h)l30ut8wJ9 zDp+Ok^Yx0g1Wz0rCQ6+8S;YZ1(n?Tw<>Rn7KEjG4*2DEl!yu}MxCZ($wDNd|@b8XJ zI!gV2#M+Y?@PaAn-w&E}r;#*?-<JD< zBwdi+?%xUjR##LPMjhT^mv%4ONkEZOJ>7q)S|g>p;X1U3K)0$te0UthR+oMW=OL|B z%8M>2f;S=wI$L={91gf)Gl&Z=KAe@49_WV4Y=Yf^p?KSMmvSl=CPS9;V=O#KR(wCq z=3oA5;CPNg{FxZ0Dc#B7_MY#}Q5u7=EKQ+rJSk2#BAjtvNCYv|trHyMWNpFMI-hsE>6gn{+9fK1~;V+^iA zXda6_J$CyLMkt<^?yRRNw_BOvgE?ZJLHw?0;vGJiY$blLTlv}t6U2RH;-!NUUt%V% zy*itjzd%eFIf^+CYRuhiatA}0m{%u2vDjoVucJxpIiP%&0Kc#@-|kk@{E#o24dzOf zAAgR*Qvu@=B@`1LUiI8b#-Aa5wMmZO_kw!n%PwJm__kHw02&82^v5eDS{k-79p9c9j;g9tK*s2q4u&w)+e zUjn~SGuZgrE-8?Oz5ji%1FA%)UC`6z<16&31+@qnUV(W;yDjryL0UOXpHNwj7^6evB#q< IN{8wH2cz%cd-P0o2 znmC88nbS-9MrVUl5`<=t-tDq+ErQ<7)!J>A7F1X*oaELkxG1)-lJtC|&D-L%>UHIl zbW@GGqRILxhLV*lR%qF3#hlev$$qf1y_OB`$3QxR9T?0J_Ve}I*eQ8za5MUTGz(->b9!sD(EThiy66>sE7xAtpn}siC%>vJsH}NiSvz2RR%bX4i-{?ju z=Vr?|2W$4YYMmB=bJg?g5~s(-s(ys?V--0r&*E$_SQK!*vraE5;A#l9&8*4c;Mj$n zwZ*o|xmsGqQEwJ`EEZmp>O6MjciO!kx6SF`T(I`T50cxg_Ua5^Rq8P~7Z1zKOT9 zrg|68H}DR(#OjMN7tM_}3ukBLJkdbZEU~lrI-A2r9h9^IA+{#qKd4FbE}j8VQIEee z2P#bO4^){073N~OkiU0j%J~%LhZ%s3;*z@K@Z-B$ss%=WY05JrO^~=JKrxkKrGy+5;XT zLueOtwW0$v;;9u%eRCh(SdK`zBgPL}W6axvP84JO+>I=6y+ZhMs5N}AJa~jZ;t6iR z{V?zdzrSs_t8KeOXqYMfK7|EW7;^+)-Jj%F$JEF84>_MA!Xg+U&j||^ zXC#Om4O}PwJ{l*;sKXa-zXWj0&wX8(+(Q*vLbRY2GKH~Korm{+Z5j+CkA4ZmVi|}f zCL z-{nk-IYZ^tTfGe5LzbmOgQgp$J>*O}n4pIwv#=jJ$q5!37<;TAGPB9^8Sq51Ew+!( zpZE`G#*i%;uz~E)2BUvSa|@Z91C#v6o0pM~b0D7lEDQAHR5m30hiJ3l92t@eIZR6| z>B)pH@?I_&$&In_7qVIplgKq4w35WU(5dse$|=ox^lTp)nhoRBlc^+g9NZ&!^N@1J z)o00015&VLf9|k@HpLyScEA znHqt-PY<;z`TZf|5gGX+BJ2AgW2#a~AP-hDOI7$96@I({+>A8>{)_<@r_}TZk4I$q zza#vT|AX&%Ya+BWu#J=&A$O=4Km@faub};A@XZS$VS;Fu1&Go&otuLxWIbqx-cumpbm1z*%5+$19!kT0CLr!Duqb z1cmS>DK^1G=0H3)%xM3bCv)Hpie8NK;+6@Pr`EoKSr~{NcGhrMy?X(Fuzh6Hz|ytRbm})C#iG6$n5AP+!jIjx=I*R1%}j{2)L;~ z!c7Vx)o% zxXPb_WlVIUI>!^0>OA)h%x4BCl5x*M1(Tc@euGJ5%W_~z>3m3KQWKRom{kpBX}1wl zli1H2)Fdi}Lk)nQR$6r@`Lr4qG9@Z+smg0zfaP16NcJs&rP7!Oz3h=+R4Xy>lL4tb=RdZB~i? zmrt>MN(_+XrI51nI=!@97VFSZ1pE>x$~2kusg)9Lz&{>eJOyw!H}bs@tzrOGZQ>j> zZ4-YNP5)A`HW{l;#%UE>$;(SYKZ0J3L>ZLMB^eYaR7clR7z}t@IKK?u(2Prpijw@h zPiG9$iDQ#U#(Zqj(>0J4uSErpvCJg$Z4KUQOc8b^y>`hX#ObK<#Yp&%GYcOOGV!~l Ms7)e&TMkA41H}>O!2kdN delta 2247 zcmY+Gc~DhV9LM<{eE0EqXb6Z(qVf=wO;8p^aY0B)Qx=h)iY6-4^)g0=Oj(&QS|f#~ zUG!HrnK{#96OD>Sg7=qW7^0`tx9;652Ev2+6WkVcp_rQlr z`BEwS5>W)~WhL2uw>rc)E>*+cRh^=2O?n|2OC8^`YSPVQD~r?xvtn zTsLgQCPrJ)2neV(W6W$$zS6zzllG^MXxcd(FN?bd{hW=y;+{c8sjx*4r@gTw&ECJF zTuK|#k-?)4Plj=def~A<+#B(t!yxwvd?SWBRWTCi_6S@NX{wftbgX6R^>k#41gEM! z&9!mPF11lKDFb)JOl=@$Ip6rFzdhkaP= zGB%IK68be2BkAqYC>HfjD)u5=j=5uzh<3V|h9ueb+-$6&_7TXS@G)3TXGU_#@iACP z>(k*PuNNVrSr-{+nYW`muVpM2(3niFo|1#*;p}OYF20cIbZ$vT;JZUzV*a7 ztQR6I$j-f$)Y}RT;-#dQ(Rt1dp)C`!3W*ezi+qtRlQN8R92mwwZ^R>x4(DP#ayL&x zy2#VvA2~dsOE`*lPQnm)IVXaw@%*?q32re*XG=<1XLeN{FP>^@&O?@1rsF?xe5s0y zxFB9~1L>s&h;+yvJXDvDSl3|LGPf$Dp3va#FW^);Jshmk@N7Nb3#Ot!O?w1~BMg=k z>YG+J4Kp34VLInES#BCU8Q-CI>&?lS0MRVFNb1*hUM?_f2N%{Zv|?yk0Tzj`g6M1k z#)>1l<%^tfShw6J2Vcul-rud|9jfJ!E-hc67xOXHCEMlf?b?Kw2)BGk{HN_Nail{< z&>{C(6g@Nwp=w&xcDQ2LNBLj_xMcEB{t^ehm@g*#00kOQG8=^`rtPyaRm}7Q z3jKh267Zbk274E1?*i>DmHbZcxpPr2>V4j;wfC*Lm@XQFXh5#q zAoc5)tVrcRh@*t=AlF!@DbWH;raQzwvGkUq4^jmzV;K2_z9;qVb2rDcKpG9 zZJN-g2~ydo2qMb$;LuPDIMPM+`S7?RTxyH)W`U<4U08r>oTTX$7!=}k2LxE{d^goJ z_NBrK^r3YXd|tI1w50-Np}`zp*<^+DU?$dBA)hTotiagTA&YS}aFwj9sBLsURk5^k z$>JJ$wCL19~Bw z)0KYDwaT(VIW{P_h6v@>pv)SS(OS!(cTA*2%0CH~a+UY4a^)Mi^|Faxz@v0~2|gC@ zyQ!`U@nXAM9a~4M(3}3Y5b4?`dst|_=ce9OSSk+r@(w)63+uCwQyPt$>e^=(RW_Ni Oe92qe+;p=F+5ZFChqbE! diff --git a/.doctrees/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.doctree b/.doctrees/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.doctree index 071dd933ca7e24a6b63536bdbe576a3f67ca7636..4c1a3053151f449d7d4745852994ccf998dd7b62 100644 GIT binary patch delta 4122 zcma)9YgAO%6`p-&?j4vJ1#MV>0yBU-Y-CWu2P9F9B*x zy}xhodmekXot56YC>?dIfO|B3#XU7;{`6YZZgHi*(T*LUX-_N{$ktwJlizaqIoWpsmf{0OD0NLWuV~&iCO8+C}p`pr{lR^>Yi)ApXl!3>}94a>Lvpn7BNc7#HjRGu^rN> zW%U}e8{yaxXM)qc+!^jn;?p&pv|F*W>EBoXi5wQ9q-i*>o_Q&RKqI}eCY_u|{~)mEi_Te;lQ8Os1h5Hn;Q8nM37v})u<;+B|W)sU|CZkgnstQYnFBl z!(Ra}U=D?{980&d=;*E8p_Ln+B##XA^nfH{l9(+UY&2wGfBM>n5q)!c@cW`(+brR;PhW;TMprI?- zu{-+HP3%XgqouC~d5oy~>P$G--Db>yx=xx1Pf|QIf<<&`gq7M_%yI#eNpx6CoP?@t z)c@>wLl1X4vMfZ5{$tl{$YxD35JqS1-avFRt~6@eWAT5C`E+gPWtvgyp24J_Fv8{d zW5;srD|;EQP}M!DKq6(_B=YY#lU1e(``#tP&~=ow8W9Qy>|(C3OqbL?)st|AM!0!@ z63Nh1J^i{LOrj+RtZKpQmw*=i@!w>U%)*mlB8N{N45PaaT%pSjrBm)heUA9ku@Qr% za!$2HP;KNRkG=mSZ@rt~DKGfV;bFb0qPY_GG=No@z-kKqSp;8v*ap z%=>{f?dD1t#-BxYaEbPPFkF7Gi>zmakJR7a`c8t$7{TW8Mo>rJuG2Kt8?O z8Vn0?QvQ@r&hw%Bd?VO**zQ}1upJr633)hl2m z+^epKKzvK)L|>h*dQiTOfAAz=BMBtP_qu{WEqjYVn0l%`17vZ>WYVVg%<2L#voCxh z<-|#t04&i0akyFJcJ7(wi)Wnts4GZ6@Ac-;f%`mx5F=Ud%MYXkqk{l9E_GW?5I{(! z2Q+BlVhaSyWUmMG)xb0TVY`7G@qm5;tUd<6Vzq(L3U4!8D2z4+3fPw|O@ugEP}H*j z2Emw~TjZ$NB5Xl0#FMLBd_*j34hBE}Pk3#*PF%-8_l;nfM#$G5)=&(8hb;|(Bk)jT zvDCR$5m7(x#4@Sp8)))g;rVoP=B*=t}R%e1z3;e3`^b-LlFYZWpSr|Md>`D}W zdr_=UGz77W;n2i>h=xKr3TXqFEg62}-^20O?rD)wO2`b8R_P&VI+fju_`Kxv}tqM3{#%5hGJK zr+g8}eh*!;02$KB!eAY1h==EU7HYUwsF>(P5 zF)wMky*wNik_R5^)A)iYqhl6&A7YQw zVKO;o)|TIk8rBt27&Wsq8E_Y_v16GKM6R1f)5}^jVKlTdTNWgcHZ$KnA=u%5X~vEd z{>7}>kig87!ET+0L9h3g4}v_Os%RgFFuH2)x*I-W^^@TRL!d>cW5-e<0D@WOR0w55 zra+P@f}`4%!LqU;oNb!|CNjvpce2gW*j$2bIJFOqu{rXQGP^fQ1U;0(DAS9QSKb!#CchAs zqx=hxp)#$-)(Z3y7AV}LT;he}1kEPib_KD$)4|?z%Z_E&r^6Ch#xioC66)Nyb0CGl z$L`2k@U_0Aj*D=HDR1Dmhcxr<79uqpZQNTC}*KOvJ{pT^Yq27RAQT zM`aI=p2g9}{CHO8m^%K@82EeE_JwH)x;(Q?4ET+0EESdoL$?EdW>NCUXd8uH+{^h_Uo bske*~dL_9JJ^h50y*U@6VKlok7n1)E6n;Gf delta 3562 zcmZu!YgAO%6?UJQd*>N4HfC9YVE_d|M+AhCSF_YwA0Wh$AZVg-e6-^f6RgiAS|IVk z)Cb@Jj;|Oss7PWoUgK3)jFQAe;EJkRU8cfmx_>N;^&b z(=9Mk$I2FBmY&cOS)$FM>Cl7DTIC57lsxl!Q@ul0K|<}a+KSpGwQ)iSOF(>Y_7dA{J>z>5W z4eNhF=Wld!O6GRKbNGZ&;56jSKskwd^e{letc#V1O}ljDkXGaG5TRtttB^IaGkj|o?O*j>Bn2mwkutoN|Xy*hXc7MbmTv9 zmOBzHdgmk|GB0$nJXathFJZkR(Yl6ATaZ)Ef#>MAwfcuomMwxgPqRa?x3GG{+)VuKH$GNW(#6ns_az@s~S>;2;F(0h}_W%SStYJL}xoKQAY;P)k3i>->8EignC+> z;aQz#%VOvt%C#sY!tw;PrCzT3E*u3SdV`JkS&01 z0toqH6hILNoLIKJ13`nfqR446(Any9^x}!c;7sd9rs*wxVLs0^%{HfNc1_BzmZfH> z6jJYTrlpGa>_r0g0yuyG{p0y^Xm}$15n=&p447k}HBF;~c|TTKE>Io)^?8?cj5{@R zk|U%!5Qc~r26O1)3l8P((hZYp`3pxkV#b0_XE@C$w&`EFYYIKq-WQT+Ra;+2?#}^o{>)h=#WOm^ zyr{+ejmP8!VqEPnlHY3ZSq@J{m?Rl-2_mTBW-kc^97@bhhmO3V`JEF;+3mN0RBOmr zh|t20fn>7=ToNwL9W6lK(~y5WaXG93t-@vCy=MtIArSc*B1T$vzKonR;sJ+mY1Fl3 z8E50^Q+7l7?1A4v9%%9H-0yo4Pk*?dF5eYDwY`LbG%tx0L<5qC!BBYGEYu*c|RB>fww*mQso4cnXZ}>`Nn|xTDmC$V;z0? zED3wQS*YGlg5+RTC#sGiwE@AVWG-0KRWM!sJQ=D1b_l^tB;Ur?ra%SRZ^rw9C8RY^)1gHf888*PF?S{`f`=OO!vOPdgu7O)2-TQ_s~D-ilLZ3}kbordtULv*@@Ne0 zr-lrNbOKqO47tL<-W&nNkj?IlfF&>v%}MO-k&r{OEu!h*rq)b8$8O$o0dWtKoYHdD`~AVaayqql40e&awOYS1Q~``Q6$Ey zEkO+HD1!bP7R7zrV@V^=pI-=eUpc>Cd=>l)d#DPnlhq1tu+XihD3foSg&(aLUk%$k z0fPIB+;nD`2qjR=7EXkX*ClH5zRnB6e@UO2wPyhq{={ z_hJ=i9(n40p}Ar)MK38oPN7sEDnD9LL{X%!SW>aHV%>m}6z9n$DUs{`4>C5F?=L?@ z8NE|cSb^6$tJCYhZN!R_B_#_>yi?j+ig3w8lMn9AV)fV}-211g6^>cT>rI;;6BgCR z+@rf+AM@CZgruw-^YCuwkoc^e)O0E)ueg!P$w`Shsk4&IBeQc-)8cbdGt$l88Ce6& z0U5K+=@~iZoD6etYLbt6U`kHT%8jb8@>SB>5(#X6J?{CCAK;&A_T$lSjWT zfwgMMa`C2uY4x8oE_rPFwm@|Ign8!uADJ>ZE;hEhc6|QZ%#sx@HD$R=m1XhFu-Y;I z1Arx}cCA|LTKuO{D#=Z0ld_*`i(Fp3mb-Hbi@aGcvDk@TzJj+Nm^$*!ftdL`Z2X9nwDf9k(!;8m70*N>ZztmX3w78EiFEGR%&)ea!$9zj5OaK-FtNR z_3Q52y`OJN#_X;+8C|o8(RGIWp?Xg0I@Jc`E6dEwoG|y@mqV&4dFF9R@o6qDx+oKU zbVGx6E4||WUo7jWef)Q(Da%Sqo77^pYSqG`eAbjvnfbD2d71w|w%M3g-O{{dp>+Ds z^<~rMzpZIvZI$vr3$d&pbI<$VRB%np`<%LHZUXgB_b2LG7wY3)DHEo2NO4N>3QcJj znwyY>FMG50Vu@_2XKGq%xY;zsS+(AjfMUNxPg%47Hq~dWF8bF7AAJ3xsiAA_(bb@o zwkhpGR+RelR(SQHX$NmL8lQb+y2#qf)PAK~ppctKxb)YxysSm(fU_~S7 z$eWGEHaA&w{FcEL9OcUzvS-lE8Je;HEOLeBSkDP|u`q?gU!7n%4;YP^Cg@Zhf7k>o z*;E~$4lr59hp%^Xr+Ar{SS>vpVV_r=fW2&$&L&@HGr}1juniLPAOdkppaF+8;29T4VQ*_YF1kP$Qfda^&zzdrP1_ifUylWFhTr@dbvp5gU_WEX0}8wRO9gjo$Bj5Wq85Acyg zAl_*JgH_~s_LL0W<~wzAE|9dkLB;+ZI>?GCYY1QQ{s!o21GLi>eq+NF2ygC#I(XU* zp63)htr2vSp&a_0*Gp308j@SC@U(h71=|>#CZ)Zd3uS`DngpuFt&;C*kH%yVn8%jr zbVd4Iari&mT8B1<6O3)t5ydj%Sq&%*!m0^uh_iZEd$eq__)b$uV=M4hOK6Qj&A^|% zrENak3>vyxgX~%_;=X#UmGw?D*vZ&g&3|6m6lTV{VL zcI%Wt%LPF_k>-OiQs1-BsB=sWJ2Yh7Ohc;(juPUB6V0%Y%LrME6slT$Ra)L6Sl42(?p_IP;0hmYkb(`;0x$TCMQGCewy=Ry z#G;O@u?%V8^~9m=Ad{u&1V6NcNEsnJmkeb!<5?GP)&Hy1D<95 zv8+G1a~Ur?<_-z!Z4YYN3y$){5Ui^2)RY;PIQJ%>W@yft7fc6OlIA2CoYy5M-ky`u zms~0|3@W0q+;oOLry0%q!zxy!85E^#*(n(X_KZ#g$f=_SZC@$&5x?{l|p2R6;$8^(B87j(dNpTCc ztF>2$QCl2hp!`F1y@wBnk9dHA3K~I;QO3w7M4>9HJrXs@4rLuRlE!U z<=TFU+E{~9Gw&P0u!6sDpgu5MOA3Mg{4;|T7z!5l0UitmZ%zpm>3}4?TSM{>gA@Fw z0l95JdXIs<{LfH~Um~bugu@zkTSF*;f*h2P-)bOaPBUxZSenFnt1w-}C&xh`?+~VI zYv6e3Nio|q#{-ioBtsmMjOKVNQ7$HEc#=yOH3HTSR^zm96!dU?Vk9oZ%qR%pQDMd5 zhdZ}0J3k(>$A#Gq!$;IGY>tNA+(P-u33Z0H%*tb+GvnEYX|WSvD|Ni8IO?>NLe`r& zDlJPvl>*JJ1rwn+=g%obQ|tN3wA$b=YlQX7Sg6aW<0%FuQH-}GqeOd`6sEk> z+;JHG0=VOjc|H#eT-=oa5v_leF>(WZpn6|msd*K- zt_kiPy=53(|8>>@^jJHE|x}kb!)K zd&;0CtA|C|G=M%VgMq9L`e#*#FWV#K~6N@eI9V^Dn>99$T$g+3_&44MqbPV1q0S_6< z4HAAfgH~3%bb_sEutY|vd747iNj{Y9B0KicbU4DwCHpB{odL_(mqrFNVFLRcpPLD3 z{BuM8k(8gYlP}MNG4A&rUA~V$WkOf>w}y?%g3+`%dR%TFOA@VPZ7Ne_L%4@$xI@eE z496MS(2kqKb?<*Sn_5{*Y%>=+i%%q`nS5?re6xY6x?L>Ifmn~hj;O)m_(u+O;KReQ zsEP_PEEl3_x>cx8C2F88ip_#tk9bE)d^oP1MMGe6I9B;_KfE#vB3PoPoR*YWTZ(F^ zyJy3E_vMbL#zIJ7H?&RV(xzV>NY5;SNgl3a9U6k`ShOyJr+N^EK$75;WTZG-o-4xWC{CdO@32R%6yE_L3BLrzOFY#dUiH%yvKS$T*G*S3)0J z!l`nlf-d2})!@snYS4?TA&UK|L0?PIMF&u7KE$+y z2#2On^C}Yk*FeX5j}JCnA~3$f?o4vN5C1u&71iO^%!fb}qohZu-&B_gmI zp~i*wg*1VsJ95$^u&5Bav1~k12ut})gHS06GpY$yMbyTQY=FK^iW~{@6&?-Zo_wQW zOYLCZlNTGL^O96(LmJoQpd&=S!YLsHIbuL|h7jbi0r^fs_E$rcL;l6EnSG5_#juK> zH#D0{U_3jAH%p)~KNq2Asy3xCiQh63>?ws{8Kb5u3e}qMdkO#22HxCSxDlo~(HRkY zjk>@0CL%N*XI;4o+Aw<1stZ!pXq;NJUoh55Y87%uu9JeFTq2#&OQh2;(6ADOOJ3Id z@u@beq=0eM_|!p}I^X(1t&-ATg!O#NIDGgb6tOs|>+O75<~&K|%wn+WHCpR5*bIkh znm@G}j(%Bm@mSg{8>1|g}o{P``Biw?auyTE5i@>!dmx})vCt} z@{^dn58`Myri$VIK3Kut(|P|P^FD3|xxF7IxBSr&Qu8Vjj~{@h80t;d{H&2D4$$a) zMI-M?UCysYl@Zk^qrv1UA~k>xbpy z-4W9%5*u5o4ftwIh84nj7X$OB#CY3bsES>1$eR%75#q=SiNu3%Qga)tSxt_>R32uq z{*tU9JJ!u3aFET!t#8rEORkor9)-!YJpb@0B=M|BJ;?k^D%0(hJKu(t?$0?I@Endj zMn&?XhJAL7j>I+@`9F}9jdqlG-+_O)A9bW0#mwWdl#aVp!L~mErTmztV8&@WoH}Ah z@jVHJt-p7q)VzvZHvs)k!T`*;OC7u4l776zKmIwTImIX-;s8((U1q%;1q-2AQWIqh&kC3~F9QV*Cf-Q}^*) z@1wy9A3!SaV1R3x2<#PQ+t7x72w!=Oas-cx!p8!$#wQ%$q$fI*m zB`i_GUd~QZxxr4Eb`}=Wf%UIv;Wc(#D^Ha}GF>oqsetzUZ9{32$~SG4&8=rEpg(iJ z4zM`SQ z8N1465= zpM+l zrEU~j0y**{zX{8ZlS1xe7Z~0Ra!;c|9@6N0K0=NFHxJg zgSRfzwOJEs*$rhnyJp>c34%Cljr;CVE9iO|^0;RV?!FAeWT*}pn#%M|F#aL6glo$1 zA(~N%o36lU*C#A$ZoPX2xD#DI5K>=z;ojRcqJ_m^&tKpr9v`FEi`RZ3TT^w$+kb@# zZQ^5$Gh`Ppb9|23uipT_-ZoC`H+m9!@;rnszs8(ee^>WLQeMI~;yMn`Ui7=0bC zQSB*zX8i_hX#p1XJ9Vrg!yU6sU7*}yYcRfn@WgF5Xfgf^B1>lhjN1U?ZE7CPzn{aorHF^gE~K;%~8|@JpKSOXc?t=aevd| zFJ=P1_BY)|QK+=-rFOiHwz>7yhwv3+d8PBjG>jI)74v*q-O>jlgss+~`AiI{w`77* z!@P?bLj>6_li@WcLaD*43}f7iBU#01@AeD$?QWJ zlg^h+PzPs^bH|e=F`u2+x^xh+Bsc@YY?Gpn5Mk77RK{zB7*MyyK-Nv$x7nL@z~in0 z_(B_hJu${vxvnSS#)-D>x*cY;z@VWm|G|6zI@wVETY@hOb_t_MKx$FyeUw?E)saa4tTJ!@MN^R zC~qP*uzRuqid^ni`{9cXnh0O)+)UKvcMW=YGjW!B$gLh!$YYy}buvPJjl=HhJi5v} zZrbIM7Q!4JyA`jhOp%vsbFV)J@vnb<*Po z(h@)S5~FaAml#0}R@qJhacw)1MdyS{ z?$(|f+HNg>tG$R}JJG#^=*V{(^6pZ;-A3NrdZYst2&<6#CG0CH?SbGU!r2!Xq9-9{i@laoy9du@N^eqQ-bh;qCY=thrQTEWH@p6$r#>U%;m0=@pN~Q zAwyM&k$&PC?lV~*vz+l0elmvj5Xm(umiC~^8*HTT>M6#$xK1{zrYR2TCYst_VUSpr za1ZHTy~&SD*b~jY#A+6g{zIv8yxmLe;K`G*>}lwM&-WHH>D>3X!J-{cH1xfsKGsgZ ztB=@0ACV}%rLVZk*Bdr1>nDoYTCHDe=zB~3Dm(pK{l!kUPwG8z{s8e4KWykrpBAO` z^@+;=fT8ar^?U5}X9iO1KBx0vG)P$a_lADjV6l=_YJH`l?<@6R+v$sjh&`NI>9C>V zFD9@oiaJ)hzbNHSQ}E^}(UCb}n-Chk`bp^{JL%40;wA1g1%rl*_h^t*(xD^7a^BgH zcGlAVQrdBfQR?9%#n(K13U+!%++>kj6+BA3!Xpe-gi>L{NE&Iws#R)o-WVVf`P?b! zKS#J@!$6TpC#WjdErBAC&o}h*F*BM*yV-Wq($Q2+WjG{A++*9cC?!~|qRsiuV9}id z<>WwV>1I3O<`8j&eT*@o;vqYuh52EkjD3oo$A}ITNFhF&M8!NU)zy8vgwqr#gEyU8sQeV2G^B*kpzhQ&%#6b~aH*Xn>*CWK=+$&c1h!*3; zM&3FWgQ7)y8LGxTM2bCQZ5wxVq$uPgWAS({wXTPeRLG-a^#SS^QDPP!r3q{lnx|2T z4Y$+Yh!$&kS}ZPz5es;hk#VO9BG@G(*63*c(Jw{}z_%s{7oK5Q;V-S2ZbuqEQ6#Za z+%Zwiv^W2|1?P^df@Cbh+O+JMPa{Ku?(im1!@yM}m3EO~O=5L2kc!=?DB zop@!OxWF!Ba=f_0e=)R+62xkLHCErOQK*KSeu*@YJu*_zd1V9axRbkMs~N&a9%oM# zZKXtIGeTzbgKaj}15?E|#=YZk-*oCc>yl|;Y8QtOl1W9OQjL@NUSnrLL= z;YziUhs0sv4Dq=Pl|_Bh#C@JjhmZ36g}8L_4;iCAJEc$}al>3{a)EZp!VIy6^Fl+F zlqH7K0JI}ZEaGbo?67R{2H!#nex%F;k-=_(tnCw9&i&(hNBom}xL zKW)H|&Z3FrWAvLVeE7$PG)PKM*-0yB)B5KI4xK|e-8H0F=TN)9rKPtFX|R-Dx09Zm zE0TDVcpN%Uu7ixVSu6}Xs8{?I;wz{q&zhN=d7n1oNnZQ zZ@nnu(+pX(lqJ^4cKL7Z~gQf*%(UMLccZ7!O& zCFtAVsv;U0UNQ2SB=s*P$X?9sGV8s*-{*Efp0t`{hFVTt8uY2napOO4=__CNDCC$xOrsgX%^OcGD%DjAKTD~$XUzwDz%*j`#LoLhsxzda_w~ zVLNr>=g@Blb=A_u;_!2==^8}1wc9`iv`%DaUTKqEAmPxfGY1 tU{T_B_}yzFf;PsAu;($s^9h2Z@Z%j~46S06@T12<_kSnERj-Qy{{;!HdjbFe delta 12032 zcmZ{qd0>sl*T>ByXF_5N36h8;5)rY+zLeU@BAe_9Nh}pNwjhnv8qyFA8WD$56-BAN zmTReMS}jT~UC^qEwy4&RsxBz?o|$=)-0SxBN9KBFzMnZ~)-&@w=AYclzjmLO&+>V` z-9G!Lj2$um%j~cGZCBVl4eLFz_gnecev~==vAwV>>9OC*{JTBWVSG(6G6CJ{uL`bF zBf~$#E~9ydZ-(End8Pe$Gki(FR=zVBogJWp?+wPhK-K|$Yr-Cqr3}f6M*JcbEM$$@Wpw_>-W}&V!VZ2d7=xT( zAHN)ox11obGOtZ-DBypnydb<$8&YI}sHJu;GF7!LkhOhfUE9Svu$wmy(Y3gl*Vlzc z48N@j^>JAsYmPtHgO$t;*EfKc+>J^}qw^)kHN?v37S1r54+y~vn|Tu!f?4fJ^u9A> z@URf=ep~|xW`i_nkO6vCg8Es51~-J1I+H`FRUJmG$cQTnZI0!h&=^x2LT7y35FB|{ z2=4JCGYX`7qP2Q~3v^-yXm)|_e334P^=kp}eCu+PTwySOQ+v(dGVJ}?6(acN5cHYG zgV59ndaImR)=;L-GwlK$7Rf5tSfhd(!~6V{fjVuVe44;r{spPr;4@ASuew1ynX2|H zl#~-z6!T(tc!%-7LrNL%B4qx9s{AN#`xo^m|w!SzDTDl_uYAPn|u)Km{8p>;NC|NCUMn2&QtGBTW!+#Qr<|bu zJP?-!&{%l03X#>FR<09<`V>|3vb_f;_kbJxykW@Hp0J!#jxt1+kj=AE8uCdMMJ<#| zd%+R@z(D^680zI=j|>FPAyeCrTv>*S9Bw?pvcCpR>=$U$gC_jL2!^}u(GH7V3^~W zJFG^H>`}B(w!}S|_ATqIcy&eIirFgy$gEt=cGx0q%&uZ*t>&IMeF&`NZyW4Qn%!q8 zEMVI;d&vVnmTww{Nx{%prfRrvm7uaJkTTLOgvRJO19U-yPK3Zo+Le@%<)Jh}FBpw> zK{i?k{<#&xd^8Nw8GEX<<{shDig5_nQ)NX2Y~oK1^;6yC+oTnbtPuFiGW-2JARO82 ztO=IKfV+8n6mZ6a3{FKfyv+l{ar<)nW-?Xo?2sV;@XEeZ?lg~qS9uH-kehCtM4jOy z49KxqFwwKXI0)cznt|toso$cl85iPUGoNQL=3{X@?E!@bV@U$M#^!6re8Y}i(vCS* z4CiLT-TYx9?cZ#t@&&u4KrlaG5Z+6HPJCzhJGWA3iQQ=+c1y&&RS30Zs6}v{ILS%2e3N9~=HW(ak#}4O%m1hj}S9F}_Zx zUV0L)rx~SknmHVhCOy<9{YlTHSN5Z!Gv@&ja#3tzjvfmq7)3^sVGbP!PE2LVxk^RU zv^PtLAC`}zRgoadF9rT7TSSPR(kG$X*w=8L0guq9lULVF!r)E!xz(LvYO(kv}>xei%rJ#SHJ_`&4m80 zXiLHfWD~%Pt<|XMTj2$^+5+`~M3q{h>?T6I>tS2e;Ru{OkpjMB8g+UiM6vfRP{$9zzh;gYAY133S@RuoM6rj%p z8ViH7Ae{3^+%pFPMY*K>YelIw6|OR0yfqcxpmkMA_D+M5ZY>C`)-moKV6ld^h}0YC zfa$QA_15J*vLTOChT4iLRg?K6S(Q(uoXnLy67(`0Vrls6%M`+nHLA*iBsL1`&VY%0 zl%f1sDo0u=AJ2eDmqoU&F2a$yG%A*8*wI`F;fuAa4#y>>z=ATtb(<|vT|kGC6piw}XIBe%&jfpxV1=^JhYXk5wy4=SFP~Q6`G!?D z@?jL4Yhl%CY1Pb1RN1SL_SNJ z{MZ&%^(YSeE`rvztDFC16gn@0`Ro%5@aGa-ZUwGc2$8NgZNWFAFtP{&`LBkn+lwf; zshJ72u}vW~aa@s|;gj(m(SEkTpOyHZtniB#!$6l>(Kf@T7FH~#t*36Z4zOQ%4SF*t zyk7vV#W_iFkiUIPeyeL=IZ*Dt2E$z1*pk{{L=m*+LD71kkex$VJ54$-Nr5(`j3toc z5@AbJQ3s>ZrvwJ_qlQ&j0tM`_LW!?r^Bu53Enfk%Jg?ZIsvgDRu2KlL z7>X4Je0M3l%&uxXy_S%j-`K#{tb};ae{JDakK!<|H*boqkuC%5hU-2bhY-bU4AgZSiuIX-W$XkY_Kj%R(~s&`3-oBjl=jgbh4OWXzH(pShw+n{*Uc&{BXS;;#vw1 z^9(_+Oi>p*y$O9dWvfk*Qne|5BWoOMQKP#V*1^m>O5dJZwFoVYH_*AW+#h9L|LQz>>!NJB zJY0Ewc^hpsQqFtqphax9%(0F*XXC6L z;7ezN^*bPkb`)~Z2sUp^%VsLe*bL0t319GyF*s-!1o6#e{1lr0OFx8~7{3c#@$8pe z;2FxJ?W7vzD$G{Og zya#Dsw`_q`kK&5l@%mn9grB?z_4plwFZRM1cH4sgKgqvg#lN-}=D0Y<+O(M?X6=KX zyk4wa1Uurjeeg1`9jg`rhr1F}Ggi&q8CZM)Jk4kJ(;0)7^~(onu5^l(n`1`|F~c0* z-VoiBqSlonYHAPceGp!AiL$Lb3couDX*`ZFZWQ-UJ_PxExPiGZF%ednjKeU(Wx6e9 zI(~DQ_O9GmJ!-oifq4G1f%#oxrdnb6`%vhLwit}X_3uL*Uu$pzj=}=I+Tc8poKh=} z_XqNbVaquji$x#M%sOUpZhS!N>iY)g56L-b#i5=zxn8y9T#d!R4{3n@KvH9Xj^@`4 z&YzNV#ftM%IqYLK(BmVz`vF?u<&F8Zk6;Aj*!yD`%Xyrd!RU3EqT7G1q&~-?z$GBg zW^e@Hk>k`NZ4KIhPw4J55Q9!qeDSw5z+e8>@r9aI9@za;SmP3EOA5tXpTc||X^_^O zfKmzv6zQQP(VhEqq)jJbnad5(K&upyoN43@YS z+medo&~%#at5+JRJEv*aF43sR61B_*b?XdFcHL)-+82kJpVKONC=Tz>C9A&q95UDe zjrvET-m^g+I13kDFWI6lku~RF1^>=ys&VJxJZ_~ZTDYWqG(cX;E&_5%NOt- ze`ZMBzNA~%Cvn*CBKXQwZe-%AG~=PAR?W?JUr|pq$Mj3k5HEcNX5KO$v)0oLFaH|m zFhA^j5&XDcydFApKck`J9d9fMO8?_Um`!ghNWXoUCL7#44Azs|V*ZM&w} z`0;o2HeofDz6xFVns_YhXSa}}QJ%^2C8|815uvSFVonfJawD7XF@auTJiQm2sL%p8bBC8(76?x!=3UFQd0|?Cg0h~Bb(0#Gx z2k6hA8SI*p{f{*}^+#Cg=$Bx$d>lsp1dS}tpZ@6m6J*l}$@;!>Gp!{l&E$iYoGer~ zO3Lcv@!0hSWIEKA1?WFpZqUsqrBuQV?QTNy^DPTF=_YMm#;c6qZ_*vuqy!ZMT(pP* zGNp0V?OY!#ZowLshqHc$LSA6_+3hwY^92c5CyKR`sT%VQq#<*)rLz)LTbld*Lf5B! zmmz!m4$S4-6438|)J&8rSwks%r%EOr6bhAz_3uJR{pSpFHJk1Nx8px1=rF9YlwV80 zt@mLazn`GP%~8LTv5$;eJs&`l%*lNKo-$RDrkj?Pl=bi_IW@+~VVL4%qVp=@hLQ7m zZEXDqY+zn^_7Awj{StNm-uaVmLw)e`C(weD`;VZDgNFopCSnkZmdO5wi)@Jb^54*u z@i0T={|Gj+U@Z#PqNY+bs9NNKlONM-p~;Ep{V%v+$A2hfnr_IuKB4QNEG^H{a!)Cr zXerNnN^(pzlUy*q){rJVqf7JEiTK+yy24qlwauiq)IwWYBG&O^iP(vWJN$Se`fxE5 zcRr(`-F>NW!DC!B=j8^YTr<2RhP9m1=pmn*zUJT;56R{AZtur6#fwdxlPZrEZM-cGrOp^t zOJwl2M$unuiT*AAqbOA;pH3T9diR|g>K_I>iZtHe&|Ps9LmK}-I_%*jM(}u}YTJ9eurX7UL}`JZZwRB~uw9pSD0a>u!K1l?oS7W!rN%DSRwb=9n$wR3ev z7Y85NT6L1D2A2n(t1IU6jY$|;PYmH(jhar?69JB!E1M|_|5sPgal5{7WScQca+*ud z220Mx`l5`VNy1!bk;5+}=_?K21_V8ugcBNwm)Kb?^_9}kETrbBhGGKakBz$TxrhY* zR}u!hia@%UQ`PxN&F>Z({M}V7VV*dzk=R44+kIydgrgf1#tY9k7VWuLvYwUxQs|Lf z<*&PWb`ufK*dX&6H(_G5^(kqFhdAptB)M`}SoOq^WW5ArG!=7LsxIHeQ)IFsnC~e9 zIOVGaprx#8fMr#I&4dS|^UPo`@j6>5l^wB`H}zpYj`tP=c)meC;VsV5?YOe!q>m_) z8S`G_E;3c<0EwPwiT=5{Sj+gaWGwI#$JlYL&1oSfIhI#?;e(OB!Uya73nyM~)O56^ zn21+>MFZULFPg}!2ib7X{6%5YDjj&IPa0!6FD%5!?p8^rVw#_*>r{0KM#Y?430GN{ zGP;#C`e?P$9=NF$^_eqv3KV&~QHq|BHv`3R))0HP7DIW%6s-)D%6chPo#uh8jhIR| zpVQlj#k`N9?9f&uvR=5jt!T-6r66k}dhl-5B6oB9b^;l_06Ec~>U+shz0yHMv(fl@ z2a(K2)3YVq!#pTR3}bv|3i{;GN%E79;#VrMrxS6hgz}}0v?$dQ9@kk+w&NR9^uqM8 zn;7c2KE)V6Dd^o*q*%U)T%V%H(3$RHFh69NGO&jT;*^uqL%bwY^~uP?9%2$dYm`{k zQ$)+0J3U2fnMzx5eRBbPZM7{PxU!d6#P3tBFNh=jFGE|Wx0uQw(0_UhUzsXD+Dkv~ zS!#Xzh^_Rc%JqSwAy)Jew|KJ=`Z)LaMX{Vd0Vo?F{J6&mB^Mo}yfLzYq9uK%Lwl14 zcIYRzv3^>Aub=pZ4<4aA)@gt!WdpQ+fT0hP`WLPA0|(MT9xwHu@kxgC>L5|TGPN|* zkam>PaaK}?Az~LR)>VHtMEuNGj*xo|efl$0tl%Xh@P#nyLQ19UqLTzHvjX^ph;{6c z27DPJ_V5o30}h0We160LP^ti(CBSS2_#sTZ&#r60d&9){{H6i;C|qpdKNPAzNgf0v(%p*A(rv4M`G$oVP@ZI>CjZ#Z7vy7N|m&i zlzwR`9h)Xz<4;H8?`dKd9jMb&$oKW>B8)#9iFb`uNneoCe=MaDc|zc^QM78e!24-5 zOFE9Gup&@1PLCGhyk)A2hh(Z4y(Pmp)uPKj7(*>j*XL6H+F0?B(Vew4VgE}sOdN}c%ht+!8RAR!idOzHUMzCUN&U|aD<@U=&`y&`X3KPWx*-i^Ik+%W z_)-!%LiFU*EG#s)njkhac2F1IFj4rT-y{*{xUaH?`ncmF^Wggo8~aKdcUJ@4%?&40 zj7@Vv`4vBnRDIf7gZ zfym`w8QQV=Vi><*XfJ4Ou+)BTrA>ZSEaZQarV$zb@Kv#jKS|Sfg~tnoi9a#`k2D}e z0{*lDTv{lmP*gQ^5$)Z6SX@BE)}c_u(rKmrLeYx*r0Y=|DwUq;7K0uZi$xS8EnO`3 zG5SPF3a7s&Cep!034;w`m=q4O5SkYki4;bIUP+oP6>)S}QIae}GE7P)Y6MB9GSPxjEJfN@SP{)?iwIfR@)&mVb+N#8SGvtz#jbQrD;7Q3K3(ydVlkWVN!Rxj zQ4+EvUEZAVchmK${)6RWf!7zdoT^80MeQ)Xl$yPwM0nuq#S}eX((KbE#Qw@)M@#m3 zE4KOQ3PHCdkJ9mODTOBgXw}4(qL}|}sD?|`gDRD317&3zfG~j zKdY$Ax{lJpdHiaMfjUw-`cT0kUY2V&N_p6t3eZQBLOoN5=0@g>H)x@y7sM57Md#;F z&?C|BO|jFyzI~A!K6_KR)}53-aV&j;WtuRmMh#O8K6+F5)2CnF>%<@Klj#xVDfgN5;%U$H2GPVmi95tknC)X z*hJAh0U7isyQr45Z+iXQDfE)F z(!@ok894hLF}vYSDpF|Tt>oVW>Tf>Q*&;IIrMZR5)Iw!up)#>hnOCSxD^z9`Dw7J8 zIfcrULS@DxWkO+gMt%9UTeFNnYQ`{Aw)xx^v6qdN-(_pZW_Ww2=q5jl*(K;M0Nd{tewe#Ubf?c=Uf)BZS&PvnQQvsc%NF6xys`Ff;ZYMt z%Pq~M3g@u?y4;J^IeY5pu`4os=|z*tQsaj&?h%m`(x?g&s)a89CB&zD HM9=>N78i$$ diff --git a/.doctrees/emacsway/it/team-topologies/harlan-mills'-proposal.doctree b/.doctrees/emacsway/it/team-topologies/harlan-mills'-proposal.doctree index 9aaa49aa06ef90d4bf1c0c570ab8c01d4de3f1d2..0024d42d65f7ed21d40c131cadd891ae9b7c8d85 100644 GIT binary patch delta 21979 zcmeHvd3aRCwy(8nr#mA_IsuZ9giZ($AYqUx%tK@d^C-yNBn_P=6B!r`F`yzu0)ibV zKx9-p`@Wk$y35+-?7(cc7w=(ezyFq`PR|t`9;|kiz^mYlvE@-nmSj4>-)$U z*X{<1>*Qo|mT~jUXU2_^lz;lx3(THf*@diQcS(h!UIr|HKHW3Fma?RBy z#N207Y0-Y;^*Il7=^+g$I)zQ>+N>K3k$tU#Y=Dy#gm z@p~rrMpa=f7XH=sQ?tj|`&DIDS$3lNSoW1Hv#!uWzvOq^;fQxMaU=|mr)n-%rLcIh zFogw#5XLsDZ|2}d)15~uA4`k~WH;S-feBcD9qX~~g6roFsLBd>N|WP$;j zYgO|OJ}r?bwQ_#X0_L*!?G%_qKd~t>RoS|CCWCa%6_;48*VdB8)2oRvwsF^?>@Zh! z-!zyjkweA<*-RfFLExiSe77`Ut$CO zg`{@$F7N9)klNREV?Y44si~0;64%3<4|TN7HGg0xy2BR(Tbqs{jB~xKVOkTmzOq|d z0E4$Ru_Z-o8Q{3;c9B!Al0lc?Qzb@M1UQ9_s?7M@;7-A==!}rcs}mYAxGvS>dzC1f zIxknIO_~B&+sUUp{`|J`^C=6t#p0uyJK~2q5{98_uel1Rk7ZG=KI@YGjFuLk=hCAY zSbW6yM_Gr!p43`OY}kR_Nz~rP?=4BZM5P{2xejKByN1ko90$(#&W<5{smz=EHZu=# zHXiG`uraPyv-Z2%=X46}k5prjNwT_r;!)O|vBH|&4U{xq-Q8t$SHPCat_IcYYJN`h zV9WYivR6J=@)2WO3E!=@^_7Q8@7G|x65eMBBCV;s@4@-p@^bCweoJkP9rkYia^>c- zT>vi|x*JB#4QZqgv%l9AW`rd15{9}|x+`9h&AyWYjiNGd-L-zCyRYRAQ!QgI5GBml zwQ7BpG4C+B+O93Fi}cXiQnWjgh8lJ!xT5Lk)`MM}R}XfbSQk)Nvwy66nk7*)x5n-e zD>2Zx&UNtf8G~&8R(WOpGtAPvHg7L(=*I?nx9sg|_jr0;l-nPl$|h8&?6z@WU6iXg z&SqIe+1L<*`jtYkc&|C6w@LZ(-Naxudpt;uy?uGSB=NEb38n0@XvnxMC_&?E&-XWANHg)z^$>tg=S#fKX=(FpyV^Syj ztC8$2jDEHCaX)gfLY!!HOMMW*c0DMX-Q&adDSbRBi?+nEMw}f}MGwiMUlLejVDGA; zrLt&bbG8ZC=Ty{%ZP#11WZi&WRutt5CyDI_c2gCtpdwM$hCMEaRSBzKhoqcHIZv76AkE7nur_5!}JeQSPu>QVc>1v!L-J!BE1Le1u$AxgshhpIIN6S*p9Dz zu>gzRSCx2XWO02E`xUY!^X?#P*INx?t2o$wWgzp}fLJ#Dm*H##uxn!AD7FL2sx?@w zHyzE)0E<U-ZyP|njt){j}dhgJ;S<-kypNV=w8QXotyNLV8u{Ll@b6t*UAMCW^ zxTGZtt#SgGa98UVlZG-sXA-06QLkKOzwEEyH zb}eBRTs^7`8S=7(@eB(+zl{B=S$?P`h+evajb!Y)6(sMyRFL3TCqiK-6qM=SAEXtIC?3MR)ElQ0S|JuT${b@AC2UfD6K+Ex3x)iMru(NQwn&yt{-4C)#A9kFC?}8(uf$38&V)y^Ch!ENq};Y1z)lvSR9}nq{#)` z*CmL-7jS8S1m`s#hBL>)3#^IvI65n_Ji?oZJ9ogjet~ffwks8UA}hQ?Na{b?eH`}5 z+Q84S_IZOR!M{VVJ!UW^clduZnDW};;|k{eOX#CWSJOw&OE52{2;I%pqRY%rgG;ho zaquUmdCy8m^tXRv12hW@tYw%M*Vq>3C*p3hs(l*^6zn?70sNkQou#lF`p)Ytm|5a# zw?6qRn~#CkyLDWkDE^Ig2mF?M_V+8=E>0p`#W!PpT4H zMK}+w?g<~Wg~UyZ5J!9GKx1h^39=G>41=wp|IR@GTR}8({`dJ&R-QJ&Heee(#aF3V zU~#y9#1EPP+v%yhE}O&!LPLgYRyR_}Z&YmPR0fUvf}lP$sB_n3(o2IN4D?q*VFatT zd-@m=ymxOW2vKd=XegZ5Q^H^tgHHq1V90F>^VnC!gq$A}RIqF*&V@nCxT-+;DT37A z$|8pJNzWE+C}$|d31Mjfi7|EV!4$=@KwJRFiMIcQfY8A=tIMsHOfBkKGP$**OE-f`U}3iXGxY0^~yfAdkLaSda=HkBp)7}QEp8j9;W0R91A8H(#Z5Py7UC~j;T^ihf%F76u$ z!^Jmg;D>Jba~hY<+v5_3h`ZUduFh<2Q!F*4VzZA}gxl&h!ywsO zW#cM1=Dpqv79*U{(cF$WcJr4v91Z{*AliRIoMlskj-g!$Y7+A9-mU3Z$AMoUF2t$Y)Qzf(^&T0}4J^wIGS3!He|QEg zVX(R$P3Z2qcDWeffZcUa3sWYXh8;DCgPhQpEhoXcvSP8!32oQ`*}1svL_aLnuQ*`< zuv3bmeu|;_+3*QtXI0riS*Ds^R7Han*^OKbsA579bP5_GOQex7QTO3>@I}eEK;>Rm;e!CWf8JDNncY0V*^-QPesru!bu92 z4x1=iFM|76s@S~JzLsc|G;H_d_tSNn*)^uz)#)wir6HSwtQy#xI5> zm=TQ8EmjmS13$5QF{*BkxV#ufhh|_uM(7$#h?B&ahoBH91&fhR=wOy*<5e%vGnizH z6@!;RTi@o?5c$*}SOSsU@+AGloqLs$?c$k-p+}+<%d7G|&k_-4fiQ{6NAykea`nB$ zYGYO;W^aT<*j>e}zvX^xQ|^~R>FLLcEM9&o-8Y*&~dKb;XcqJm^R#z z`a_RF3}e5FCpN$y%MB8$y5ut+heg5FBsYbKE04njhCB8bAciM84N0{Sw^{0t)FRqF z1+7g|(8gl+256jIQ_yr`kvOQm$-7~gP?B6TOz4*2^d@+Ou}->e3%D3dA+9=_G6<}L zXuA!XSBaXx4fb%$@Q_+EcGv-Z>s6ES9`WD~3?CC~h&b+cBHE>hY^j*`6vTKtqn&se zE>=7RSL^D1?bDE1z4sCkyc0t~X^q~CZ`XU7yZ0MA;m$gG@4X9}*VX&{UC_09?_0#7 zT^Q82)#!cG?RwuWd+#sJ8)nb8r5DV#%}>tDw`XLg7iQ+>)U>ry30k7It%rxm;cAj3 zgR3lviKmv$Hlueqx6sE{@>G*^8~y(Te$b#XhVdkQ`EGdBhrK5~!90_+uL75zTM6GY z_61dRg-P`&Gu1>t_yQy_c2!cFvWWU8)$8{mqHP#&8J&n}0A~xz1>nARkr81eAwtNx zW~&a1aJi7M4@w|9R82L1+XsOV87e;B2cJWmP|?oB8?ts{!6tpSVdD=MSS7w+xjTGBM~CxECfGc#{?0)mLC0WEglyUInX~ zRa3>@A<$IRdkvbi$>Q`;2*msO)sa(>mC1vys zQ*PER>^9*_Qeyw8h>@s+(Z9k2P^@$ibjeEx^YoD4(2Jl9LD2!s8>xqRl5d&A4;0sK zKr!yb+nRU;Y%~=0)J@pIo)jZ~$L!GRUGAg21o7zU&{GH;j3{g+%Wo>fL!9Z$<=rsyP{Bu7*U1Qhx@<}HBd8s_%X1Cs{j!nu3RSF z#D9hs;mVc|n|WKsb*Y0(ch%o<`s;#l!x*v1?MG9~&ld@$2mX-j)rjLcH}bkv2gq%LM-e zfqWA{2?|CIuw6NTT=(Y(^UknLRfx}mQ76hXn&^HZJeI*`gU`O9{5U*i@Y%z{d!brO zEIgHMRuU5(NxYM=H%R_)&)g=Aw=$`@R!j>+#UQvGw`F0x5BluMFg_bT3RkmhW;hS5 z|9-f8DMy!~hCZY66%U8=Q6~6Cu^F_7`uGPDV#K>38aLwa!L{(3VWv_Md4(C-?EP@X zKyfrrK?a_W=0jOS!MgDlqE!qJhVc5Ldkp`XHKnqS=9dTs%jBwJRV+WiSXX_dmEXx& zU)4&UkZib<4?%^54CV7!S5X|#6Yy(uJnssf>Z_65zW!}S@_y9|8APAlgyXH2Ox69X zM)%T)4>jfQ`LMaNCiH-+QOc5$e`_nAp|LVq9dv}M7uPpbls5-a7+5Aqt5cj~S z|s5`f)p`9pJ zbm57fyjPBY~Qdw3|0@nJSTvf;;) zd(0D5yQlQA2${gU`hHkVwBMCzU~Z@;5O1-5H^lnAmRR2szaKX666-4^fr{r1rtro9 zi4D~RHDVfn651O0%VzLq2AeEV-)zH4i3sJ2<+JJBr@F|Or}Lu>hBs76+{@I*;D&}% zU(MiKV6t}~_S$_A0hxxrDYNZun;#UMmk_c845u=lJv);}a(GDfZT`uS&waBXP_&rE z--UHpO{?|C3_jXraUHfAd_-mQ=4w!lR{MbavUqFH7UnVWL^dB!P36k!3iTim4;S#P zLQKoyXW?}N_U>Gs1#cO!KjrdJ1=~Tvw#~y;29nBkH#MPU$u9(VM8QEt!`rM_WydJB zocTg$qkT$5%50v=?hve)$2=MxC{E7i!S!#T=2faj&V9eCuybiP_r5+O>9_&0#x((0S%a39}#*j`STyXWxp>`qTBZ-a3_k?KWw3}(7P zLf+8XJZ=L^|C&75Md7`CRP|KD2=VT{Jc*5>9;z~C!y>BkNMW@yW|Jbs_m~4TQf9Zv zB>50)#6a!rLVqP^s3dXgP==jB3;0}M3zV>w)eJHd%sjU)v{Ll`hwIjbpQ7~WB2>2Z z!oSS~;-)fUZvaSk9$Uy?_OtA&sl{vh%!hFm!YVzCxRcJi#6Oqu{jf_(XbK{pcIfBJ zc`;Z{*1{1vkMJ+>=0=rAxM5C;B`bN0x>_7w$%`|gVlbbL8?~S)3FtQZCBgp%J!Erl-;Ys59($Xmwr}9#kd7YG*YOTGY}c;C zfiN*rE?DE{0``jeBRcFHU&W^!yK&0m1J?78f#r*Y$N2zDVHHW$5H5L~zXZjS7q_hn zF+TCeVqq=>nwt<$d66n&W$Q;b^1fhMR~sgB3qJr`s==%i^|oT+I;8@00wJw-BT*OD z_&Rf7vdc`VPF!0TY~#M79AQ8HO5AsCaqvFt$yeYM+ zar!>A88MNmk5a1*%X0GztW-E7wC1X+MHfgfHD^pSkr9<_JY>dJ~OZr ztDD5bO_DXE2)RK+IWp57QXRJZbO#co7Z#zfkY^D`nK?zdMFnUFJbIGKM87FT#tYCD zk~~@@v)QaOb92#p_M8GcS!b>TT?jiT&#Hx8P&8vkW;!}eA&RMJGBEj{lTl?@wbItcqhe=f=AfRcF+`18TgOqO z>|7jXxidtc*Lj$DrXQF~Z5bK)s8F}Ko=(zpi?V18p^?bNGPCot?BoK(iko>Wj-SkQ zsxHjUbGs}umP1}V9fz4WA1G;ZvNe8Msx8Nsk!j1Zj>ExZEpSjvav7zB@gv&wkt1}d z9H9lS($s{~bX$&5-`Y`_oz-*N)T!|_QU~Sc*a{s8HOf|yT~ttzo0DW6l$mWEntm77 zWM%mK%UjZkj-gc%r!}VZ#*pg%M8qkjXmX2?^WPD1N~L$y9diCVB2KB)qNDfte@A)$ z7j#$pUlgwYsO|>-pM-0#Ra~;1Cj~8`)7#Lz+XClDTyS~3^Co)dEu;JY26r{p{0|E5 z?txQf*SqSPw*S|#|MLv%S^ajCi(JuvH$KZjL%XzHT|>M4ihG8mwTGM||BGgMzyHV6 zyy5fJ1eOc%|6kWNUJ*Xcz2OmQyLo--4r%Q@?%vX}rTn`~ArTtN z8^E|Ixe0A!uf7WVBR!9;qi46NldG-i{xdW$eN9y};<;QN-sw+*IOW3??dai(F*R7L zx+pnL&9A-7oBpBYq8DSRsG51$j>?W+sSP=YM_}#{QyV=t;l9`Au;9J7@W~bB>Madc z`Id$Xo1+01M@*J{b-;PweM{CzY$b!dE<152PsTi&v6pU)d+GgNd+8-^*OFJNhj!6V z@5Cc6%i5}9BOPKFul$7%sh&;TDjMwOE!h)29JqrlOuG4sa`c<7wO_hXROi4(CDZh94UU~?x z3fF8?OsNy@sP}jQ-U^Ra3BRY_=U+p^XqE6g`~go@3BMs?>U(?$T}vR!=^ye0`j$Dl zbOH;A7Pb?3JuUh+C*G29366`8xE(HmC~c}WG}{#`>LJxjMg*aURFM!bIz)o=kO=!b zPik5t3Uxs*usiC}3ui*;0r_FL7jaG#8Gq+ft;XXkQ=_qHIz8v%etdqKUj{`^_~dLR@T3R?3uCgMw!g2Dq*F)d@CS7;q-%d1c^ zK22=usC5+O7kLb}(RW?sZ)%~dH_Vlf#p6>oBpYH$)n$|L8PW2D^3-?yJgkkDhjO8X zs={le{(K1!#$cza51B*t+mTTmcZqmyQkdvS-*cUAWQETTPx}0hBeL=tf3LQ3HR?5-0|H6G4Ts7S1+*LdQ zmJ?r|IDLiZdGf`V#g=RQE^1bD-YQm-dFHK9DXZHkDDQ0|g`3KlsY+C&(694RKF};i zop+W}2k|i~WUU^e{RkamYThGxK+$+HAzQiO{}dC86%(PLeXHpvv(|;fSjCEY33W3v zMql8sZ3IX+N*^{##|3F$0?al_SEy1kFGTwRZxk<#)w=qQG^7x_L$z#J9-~HZM~gNG zR>!Cj{E0=2#$5V!i`Iz<=cFapIq6Qf340In_F=O}Ms6R#1sUjH#d z8w!?lRmD})(x^t74ZfE4a-W@?(=RsC@L}OPsDF#rj>C0H9cvs|5mgbrF{RqWDCb0I ztk%)IfdqRiMh?emv07t%HhWbY&6u?}s!FAhw_>%k%wmmo^X+C(f5oZ=GnOdZc~6|y zSOM``PUG55@Jyjy9UPnO|;H{STcHS_F~sBL3LX*fT`)fi~44^)4OoxmB2IFgl~7_6p22pvH7U416(GC+#jGkTHP>>4s#R5r{R> zgLUh>hSIzXVpSAqFE(`6<}}$^6$L69ii|r z`EDf?K47}4kJd<^*@Luu)&Tp&0Nd148^qvCLs5--Yhw^HueY|IeWD;kRQ1r zb%bmN_&o6Gp<0xFCRH22Ak?bdVsJlgG=gmEr>z4&s|f6)#nJbcc;3-OAU;;*3p*Rj z+aw+T(DYkFQ7_>bY%F>X&~`x&gu}Zt_zDc-MZ^r$4nlu}mEbfj30di$rcHxhR=Lbu~dPB5+{Rx}uc{ODrx810=9W1V>u1$VSWN7s9gMJ}OPoNgbdea=hQqifsbn^*8H zL-ZWAO+Jl{KWJ5IbJE0!KWMVFIca?04;nMJqH=SNE!&=%Q9y50bjl85oj0hTjm~>% zAkCqVdlAL)s*~PI=lIxp6u+E@>EmzoZh@Q5Qu+M0d}KS17QWf^As5AR9XtiQRmtrd>Z$9xnUXCC~JkwXRx7e)i; zO8U5hk~_y@ZBe-&DW-6Kp53FGrBX9xQZe|6QkF@blrEJzDUPim%S>057^W@^1!YMGTQTA8Kkch1an;lkzh>-+rU-pkCH-&yC(nR({%)(yYg z|Mqj6>$Yqe+vzr`zWu472CxY1=R?BnTkD6}cLjOFKfxaD)!6P9lw=QU@HV`!dRGO7 z*)745ut)a7yC9-BLL>W{&{WaAnbz5UtU)__LWnnfqec%59%0`X5@o*;+|C{nnqp52 znQuQC+L*=KTSf%ik9uhKzmR2WSUr2c(18^z!d5Ug0=tq~mOU?`2tUt8bi~hy$O&v7 zwkLR=EXZgS=_>?sp8A16DIbmqb&m4*4r;MdCC4_REk@a z{A+jIAod{Rzd@9XfM6xKH#LAKzKDo?I|G{uJzme@oMcVKY07o=& z{t#>9)*hQasrVv$F1LS`J2L+OXDQg1##-4!$L?X> ziO%u}(zS9^{?>QfSrf(vR5R=;dtDfIHyBQ_pB$Uwn^Bw9mt}z>*jz&Quo?PKuh=>F84aepDU&^lP*W?$KR1J0SGbPW{-MtPF=J+U!22k6RowHmJE+!-P^usd2jpfm0op?JGF8%^R%~Indk_b zZ{0|VX#3G*54Xoq(*IOkd}$lAMwn__-2UpShgoA9>Il&Yd-Uqux+s^g&Sq_EQZ`%D zvo6Z#)=XjX!LkoZb1Si_~yEiGAEyfhAliZDr+S_YGVHC!^12FpD5xa@QB2G z*|_}cIVQi|DD@Ov3~ZapY>jNMRy01hinIMBobUV8rZV|x>a(*8>6VSu7~7i~=2i5# z;BR859KiNPm$a~X*pG4k3Vt*D}V~ zTE;-rI^@xF>a#=4e($_leG_%l-AkX{>`LL@G-$Eq7`j*pYPt(KU@F%IvUG zc3~(QCD*2}Ix{b8H+R)iy$p#jy(pYhRHjlI#kPf)Aw=ANoRzXHQ96{p3U88COQ+ z?e5~(kGz5SJd15&$3@W-Y%QEn-CMBxm^+o+jp2y9=s$sn=*xz)p$x7lf~`pKlOn*F z>7UJdShgD$MAZVt+5oLtTqMpvTNHj!(lJU+2bGZ{wjuR8{r7AZQ_mXcQQHN2!g!X+ zSh!%ttZHcr)VEJyGZ_SWC?D)VQT+5#lbA`fCc8k0rwiE~)}aPMvi`<2#yBJ!2yaS+ zpJ%Y1U>)R&(CulqmkqChFi4~nvx6|m0C-CRw3*FLGHanLK-gTIG{rRl3ia!A*`o{! z6@uj*Lcoz#alw{Jdb#|)D?44{f)qy|%Fr*E$DZJ@*+bRG-#yQsXFCa?si6IVc&U_G zu}0p8p}{umo@MkG5>xr z_DVxJZ?Z@VN8J6NqVu4P&K=9xQTND}p0%UXX>}>zBBBJ_A~M#nJ&+~^a-@uwdb_nO zm04ZKi+Sr<3G|lK4s#NfG-plqTZ(gsShD3KR3uSS*bWN&dbR{|J(b5hZ(yZR;Hh>* ze{NtQCP4AZJK868Zz#T5&%!)u<Cel3(=R?S0)(Z|RxX&fr z>ci}|oArb%+-sk)V)&*8+zCDF2=ZVjlqru9fMH4_kbaZ&a>gB(z0x4g8)s5tyY71& z^CftAkzT$hsHr;ht<(SdlEr&kL%nK8i%2`m&O(eA1*;=ALPei*tPDcER3<+9gu z7JHXCWcuYA#_UEzCb^5>YRKfYi^t04P$fnv(p5$1d5Pj86M;KqnskGCXz-cjDt7$F zH0Kp*oxcA!) zMvx3mMF#*MmZfI`tOt)}4?U#nbp5&p0@zrhk((;FUr?Yd{eT%Z0GnCee4CmDHV5bx zo)819w7Tz4ImFK!f*2O44kX{Z)QqAz3NU?qJqU#Qb?%2u`hDt5kB>NNJVn#$;CgDhL-C z>z{`Gs>@Y9rXlQO0N#{f9D)2NN{%N0qQ$e|VK$S@w=8-_Ec9eh-&;fvgf`yZs?|su zCmO*7i1n_v86 z#g;N!bAvbftf93!W-_HrMc%5^+uj@AVQ|&pG&d7w!EXkq#6A#(iM>xBXdQ7CRg|G@ zjyn2o)X_JioXRuD;CK7LD)6kQ9Q=G=h*4s85tD8}fT-*PiPcl13XeG#dWh7e0NR*a zlH?8vpX>+wfHe|P10fx-@x~qS7ZV0T9Oju71A#N>P*3{jqsP!c>H3Ms;8V_e6MeE@ z8X=|EbMntmkAsH=3vlW-wWIE#dg5qk2i5|E%xMxb+*Np@mZ0W@c;qy*wz0Y>9c{bB+104({WR1Yhu#*Bw=7~7@V zdO8g~teP?u+0}`ZTTjR~??+`DDng64es~J>W$?X}NX0}S)h{QKb4*A>q}QX z@ekbfu`oUFS?~dtE{dLmr`aRo*XJM^dikK=!bFexkOtLCH09uw#0 z!$7~T$jC@pg9tHQbblVELb{KN6xo)dxImZ>=@lW`l|l=5HyVh7>QhP~m|LHvKb;ST zyNT5cphMH1*zPz*vHg>X_gk?V13%l5YE`wV(BW_VLeUi)YN(KYAErk zq4NbFad9;agNwB^{O&;-Ryu1KDRNdpWMXX%b4f-L!F5A-+VGwvIc0dyp~8W+u#m9; zz5jZ!Gge>pe+OsIC<3#JsEyF1O4pGaVF$M+`no6?`xNGhuvfFDrAP4_v*R=qu-_Ns=_J@*N&5#W$XfabcT7A9E>4O|}yH{S1E4 z>5egX)AizQu*8j3$QUr^k>yp6(zD-!8;l*Gj&xL-j-F!l9q&LaV<%O_j3w$X6xYvv zMN|Nf4>RFj-)5!_KNh|vMp}`C2qD*%CGSEB76$>lpqTwhKuyJ-U6{Fk_Z6S+g73iF zPehw}5FT-N*^lRA-|dDAP~T52dAIk#AX+cqgI3sI@*Ya&ght}t`_P2769*1K0Di4K2+d4W2spJS z@b-N$9Y!0#c?7%z#v7P12Ov^mc2$^b_d|H~Zaz;pg7yk{gc5!BAzUW*Da?IJ;%OxD9%tZik$D)h;AaE)vI0JH7z@*z25|AefR3{k z{R_IW%L?wYf-54pAD!Vs#PE+H9|El^41&bjk6{HaIY*B}OR@PA+?#+n@Co#UAgd~4 z@q67th&N9sD1RJAhoCA1g7qc;hLvXMW>p1pkK<5^bqhlEL6pcZ;SuVR#V~#oiuVjc z>13tZh6kM$U&1U;z_duEw`msjJ*C^u!VrMzM&n%7_}6(@05IQZd{#Ancma+vSZXxR zSB=Lm!f6KUjmA>hD1Q10Z$|7;ZQcuHo08$6aK8kX;e9I=NUFm4r|Nd8Fr;{$tkf=- zEaom=xD3teo|AIE;GC0l@~6vyw<$!ED^LtSS!JnrE0C?hEvx8!172qL zlpE^Zgdi0tov8HeRK2&jWz`FB!ce=lsJPSkprJj{{aoP-i=PwKl$U`jjvw1ZE4@Rks({_va`5sp7GqD>p z6Flv&qG`o_*uO>6&>$`U-hhiS{!xb0W?yE>RMtj-H^P{UuCNz z#>c{|29MVa9znq8!gj+z9|I4>xIGKJ4|`1^BArBBM~EA1A?lp}6TUDIzcdi1YkaQ9 zvfqs7d*Zgnqu{i`AOnR&2H9?WBKuM?z+uEd_?oyI9IeG*sEHqfdj^At0+d+>n)z>F z4p2Uw>CRiINSWhgoY&2KsA%rNJ=jBHr#~77$4WIekQ#Sua?wBV;AspJ4EXw9{1~(` z;DaqZO~Lmf_;@kXi$~g@uz0Wp35;L+ExZMb6E`fp381NIZLE7nNT;CJ<@x*+Z@vZ~ zD?kOrt12L5?LN|%r@|Q3AwKs-tEfnc(f{z}c(G-+A!jQq{}|>QawhuoPH5P1{=6HT ztyD%jQrYx6Vb7HE;np`YfHyO#MO5?)KyM5dm3MG&HzR;|!N}bcz$bwoAR~8hAomG; zE5K2k(eU2_}x?R$V9QIa#$`A$N zye;zI7|t`{H^o0Rg8RVD0Fe-Z{^o(oQo9HY8)dan63O>5)`M~(C=K#dzxP4v&kZyz^ki>-jTIVF7rRPbD5ZwNK&O*{Lkd9}G0f>C zKqB8XoP?YoaD3#TGK!{uDOdJP=BF5KTT^+u`zD8oBUAZQ+_$1(L&S|#{xlpg#9Y&s z8;=rN3BM#BCC;|xp|A@@O=Ah}nV*uFo8(^&oyGj5mVy4hm`9YDAEfalfXjwGj}qLE z4q;oj=LPH!CG4*Dd@^I=Mmugi=|X|s#pn*)s-|(An4Qk!s@Ic0P%k>G!td&{sxK70 zi?JnJhZ(Dkolw_VorB6S_Lou%JeC!c&Vs+bt|Pw!tT~C9?0u5BHLGs~$I&i)0Y09@ z9$bw_aEtjX)$KBUn|`219Y4uZ8%#gS(?9763O(o zYyjVai%XY*Jl#@5$ma+0R1@1RP?Qky^-w;Gec&X{{9)V=6I{oUynoPcDLmeOs&Q{< z_wp=^;CE^$_Kl&~4^Bubod*QR$$vw<()P0+@o-g48*OzXJ7w zRQ8#b#~T}hGLyb&B(6b3C~K9^bGchhrO)N^j~FBd$>io;Nj#bc8IkbQXub~GIrHe| z%7X~VIrLq9Zg^7xxhNqSVD^+LY)w87<}ga}HvekqS6!0?kL6!N5q48eGQ*G~dK}kb zt|5o#c-}-!tAVPXA3u&KRTm{Q#M1HnaT+R*1aA?CLd2uvq{*V+1b!M`F<>8=h_%TZ z2JD52+)u%_QLs^ycmpDpGZnw(QvN%^ty6F?Ip_fkuVjo`%Tkn0M*n1qxXFABd>bSe zx;>L|p*xLcS0^oUp}V8f&e_S_om(rb`W#mh#UF*d6Wk7RK3lI05)-EJ%Yfg~+lz|0 zoBI`qH&+$$^9;-3Sv*`knTEgQsW=Bz;tIMB4|tufcx3)X%AMA4Oy@aZjcwo%&0yb6 zjGDy<)I29h5+Bau39JQis5&1>Xi#-N;_q_CmEJ&{pAQMfA=iI70&*h(NdVWwf!GF8 zPd`cGFrUmf>BYPV*f6E+jz-YH+e|QnB@C7bzs|v^&#!F@4@Dzw;k0&P{Mb6Sj%c#@svJf0ms`Ui>n23Jclh4|0(BtpiF6K@+Qfi(~td=&jRaa z7aTES5&s^qS5*1d0kc^YE#^(@8u8|0UdRsCHDdS@KDLe#`spQn9m6x?Dkja13lb!c za*n6dX=fc$e!Z0MVLw&_IGzb@Za^ki&xA|?O4U2d_#9@vP!3#uzn(7HSb{^P(@NTiN~$xyI`o4#^JI7n4Wl~ zm^cwE<`|N#Pq0c@z4f=(@UCDja)t3&&-cNc8ZbrT9yJyPtJD`uNK+h0#3HI;ohMn6 zWe;S5fqPKoZsc#lhG4bIw0ebq09%69D%1E?-cqH=48d0MjOwJjLF{~$H=X8oSzy8K0c5KGoAc*^$c@g_m6upk%NFg(N zQ^Li;GO=EH9rr<5B76%^63KgcBK#peCDv}?KEAiAtS0@FsBhVerM1-@;&5A4W?R0G zKUy=h`H9MXJf8WBE+6sm>hpV_kO$!W&-sV5`EzR(gWUjB%;WI5spj=(BQ z4os!)><|?@Pl&ujSk=u`U2UmrT2mY|2 zG4tI?e1^%I(5M9YY~8OXjdI8?Eg%0i*UcDLRWzmyqDj`n&+|qc{ae-H-B)&m8d>1E z3%ElYR4tKtpz3zXnG(;C==&e|PR7PmgPI2^iF6F*<#>t^s(zl%NLkMDKs0?Z-3VpyXT2kV?!8@v>*=J(X72d!+R0*K2s(xl9 zZ@Q|Aba-kKEWUn^`-nfU@W@7vC-{cb6Vd6T^Xt+30lsuAz7O46=_op0<=Iij)s`b@ zEn8>00^+#ZLbqeEMZTybzP-xx@Ua4^8Hr2BVW*|zIF58G{Ic~IuJOYbxL_D);vL+H zTyZi`_+4HP4U}+~4?!aRxx4&RO>`Q-O*BNBDTfq29xAsxJD7GJuLJcrYsr53s@-We zeg)c>z=CDBw~e|3!=%^cQ`z_MbZM(e+sKk6fq5(u#D}Sz(qz+HW{t6jRo6J`>Y}=! zNf?DjM3U`qJ)$u<9@IyBXdaAZ>k~Y+hDJ`prgIS|m2;T-!86`LWjKG5n(-^WwE=E;>5nYwJ%zX|R;D^An)_?N zunp8>Y?+Hxw~G*Rm;?U*B*Y9Q#IFI`70qMW%@Ok5g@^QW!CD%}n;RsQc@}ZqAEplu z*H#0jLD@LlXlxm!T>y4YH9n&n#ef*?Cc7rvyyvSnW6nPxtBr%ZVQP;0G}5L4KBJd! zx9N>Eeu8!FLK|`<$ zUw;e0x!X5hn;Mf1jyq&&;W({!;hd?OXf&0vMNKqwGp!i9gv))^glo9+cSL%p>GgvC zSu-sYtbMDRtE#btBrOMqgi~qhXVkVtB@_2mk&~cZ6}y^iUUdyU*k0YpNHq5Klnq3p7`rFNQG7rKb5FK?~+U=ENB9cA>waB-%M zHogvW@kBC;x4Aa;6De9M;3%0hmO2UaeF|oU1BO7$4T0os|HQUhe3T#E?lbk7x-=(0 zs*DO?4`ZghXpqWx0f>q^DZzFOmkE~Ju7fzyR?CJLK;4acEKTbG*Oa%mHPd|jE?4O) z>$KHiUu+2%x6`y478ZeQ)y;}LyI;FJ=T~O9XxRy8z*-XEJ_=5!taroJV~6qWv~hR> zd#0T>nT062bwpP`q9)yE?X~CeNNi9Ct(>(~bnA&Ou@>Ev9ktQgBPfg*r$Zj=sYo{v zY4=*B+dFB~wBbZL>k{7f%T}Zti8QMgX%xP#3RAI>4m+krsHaiIG{9IFYd@0mue$Cw z4H?KFZ6fC0geKljyD$Wj-hG8wPOioBy>8kLSZlCcA0g+uzP7uDS$(q;He4xJ zx_pS%LTtz0>eVYstnI5c1RN@@_XY_ahIkab!I3g}^)CI;9gv~8ut)Xm{@N%80}cG& z2565d{Bpz}v%J3+BTf%QxgJ%}j~dY12)bu2==qOnUig&P5Pa)ktp|g-25_UtHN1gH z7xot*@PcZYrz>C_C1u`Dz*DP%$t5X&Yt^r1**DZg4;rRzg{?|k*rr4izYo*)!`p^r zKWAwPnEC2Ip*=|i)1T1d>03&(lcagwkYmBUvCMvoaah2FTeNd^(NvBYP!?QxolkI~2Dh?2k8MsL06pRsMgFWXxB z*h()q+_TM*m&xV*@jggt>rEfB3YUfVXH<{NIz1JyGTO#b#r`YaF|sYBU*F-~1KUpe zH4vY}+m6$(o%j&T_8a}WPQQYvs`v^|Pi<-Rt2G`V*s|!?FZ8Pz=HTZcVzP!BWmO^z zk+!I!Etx)kqL1s;D>IHvGC;ZKJ|=A2Xw=u%8Wk-p_aJjjoiTBAwLwayJ<6mx@Dp__ zla?rzhA2ZLApbIXp}y2c`j<)FOKqfgnT>QVllqoPUCX4NWm3m7sb87YtxW1wCUq*4 z>Xb=UN^PV@nN*=nieG9Y(aWURxaj*9&%w=5M1D&C>iiVxulxzh5jTpo;ZS0Xnk`2K)~S-%J6%ir9~=M*od5s; diff --git a/.doctrees/emacsway/soft-skills/cognitive-biases.doctree b/.doctrees/emacsway/soft-skills/cognitive-biases.doctree index d1a4987dbf4ece3058112962289b939455ed0e17..dffd1454a077830ba0c2f533a72efbff1b487bbb 100644 GIT binary patch delta 3264 zcmcImYgAO%73Lg3UK-?KAhJ+Lc`71v=kib#1_h%|4I;s}yi^s<8bMEZDzi)s0 zoPEx{6?L`^?Y8zs_T|U#RNI#XX&s1-&A@a^g|);|Z)vbJSw6AUvR|F0c7Ua3fVG&} zo2*5$-MU)&d)!)LU2QEM%HnG*P3T(TkA+Km5CLgkzBriRYp3>)QX?nbcX+&iJbTup z@kz}`!9PCCe{|UMXW6ZIhjK?89|h==eb5jr#@aJ={~vLMuPu&COo&NOOEc>oW}Ee+ zH;s6W<#Twxe&dIX(!LJCGrU=Ua8nz$MGkt!CQSI1b(-__gY@P4KtlpW@m3GCgcv1L zP&h$os787eoJFvGm>`*k1Q67Ql|nuAC+rkNDKj*T;0uj_wqad#4~OzeH5eX|@zMzO zY(m>9zJeF&kgA1XLM%v+P@|{#7urEFGj<5+fLnML`I?!vs0$BZ|8IqRv$0y}3-^eL zxG-EmRk$nmMg)3wP#c^4Otuvy*j#EZHviTf#3Xm%W<+=oKlXH%qFNOzO^dW6xHeLh z%A!UPM8^pD=kOnBe_OdSJ~4R<;^L)(=oy5Lx0U5l9rGr8OAez%LMB6{^~LdFp2&@P zNOYJH8^Xr5vG0@Y?b-n(hq=d*`N)gwkM&v~ns19Z-w<5UPOuMPB6Lv2^^y5*MTp$+ zHjCVVoADZij-Gwwxj>Uv=rBcC|xdcbYYb3XX8iM;11nKW%QwYA%nP3@r1I`mg z>GpUBg2xjDyrr{3ddCFgZ+7EOqKKG@Cvba`0Ka#(qB^M*QHe*8m8`-2fo_Z@(vm_lr=tY#TPZyW!pCW7u;W zW)^6%JKr7U@2!Qn!h{X^y%AI3j;iH_NJ(}>(@GJ>WvR#X zg8dr=DQK+|!Rn1BoLW~;oNyc7FmLw3f%QKTcf{>cb?Dd8 zoyu1A|Ahj}@t>X47%o4^;OhDxaWDoBL76&$bW8PpNviTX>As{QQMA>QMmnHaHMqw} zcIGq={NOun+DOP8xfUGTd>{WXi@30*mRaQRIZF5_7M{k#VP955w(#}s-06eAm0cw} zxxmhChw#}h6MS)o)bsUeeGjD>t(XOZKud$1sqaBP&xx zQ^jX=tRvL*B1u5f$-YQC+Y{e?P*0~j%6A!j4*TG%y$sIcWhaAjQLeOFKUDwj-_xs}Cm=*^>B6&NUu{`Z>u9i%97#4RPY@ z8hT;{w=#XQldWqKOEQ2ts{*L66TE8&zxiKNBw<3SsrbdPR zcXcbdm9fiC#-761=PK+O|ARdRt$$d+x=+?WjqBf7FA;i_XON~fPA2q(lH$fE7rB|G zki9I$43^@slHveQ@y5#qz}oDAjOI9Uozu_i?wF^|vppX<+1T*Un;pT*>(t)x2*%Ty zXnM)+=U)b$2s<+b+BQ4-kY}^|D|5>I1XD{;A6MsJ5V<;|wIzgjqPk-+p0+ym zl4G8;xuLp!5X#&f?bDe4UhH4s3&P4X=c(w7+}8Odq8ly#3@vn{(-}JS1^U%Jl8TSp z(#aG?7mU5_u1G%V&Cbm>l8vsj-YB@_1HW@+WHIxraqnC@_Az_mSxN?sS|5ZbDs%$J^! zi#%Wbrbc z{7p^^GjiuGU2dGWME)u>$N}rPe|^5bxBQ*fPanlX(ee5BWGPO6al-yG3t58dW|du_ U;gSox*!rRIdLX%gyVpnj8($<6X8-^I delta 2480 zcmZ`*dsGzH9p>KM6?R2IAqB+>R9R3=R%Qnjd@Mx7QV>BzQ6chXSwI#M2_hO)R;*ev z9}*=|tEqq*D|q1$H3YCVfUg7}#73!WwQ&>-kh9x|U?9-0*7{^JBPsiv}~qNcpY&+Kd2N3p9# zL~39-J3B)|=paQ{m>YdaQ4ukQJ(?Lpa6Uvp_U!M-Ln*k7cuyWSk#qk|(d<2&{lm13 zpnImsio%QpfwKkNc=-YKR3SFlpLpV{Ij@pg$PM?RCKb92<8UP0pUzNm>Uew|?m;5q zJhx<=57+Zl4VCarLM|jFJZK7sM?@6KM`)NkDZss%V^J58K-S`)#OSGRH)$D z^js@fGT_hWlY}0U0!(EoQ3(Vo^C}TC|285cjqGoht_Bt zZpPNZEk?wVxE3s2AYkXhok)na;ZN~LQ5+}YpTBX&_5>#cyZN9g!w&7zX1 z0QFR(u+#;{cq==&cq&26A|q2LS_z^O1XjP)o6sm_M!;e#qL*Jn-x4FDlfJ>~r2>kQ zyU@Mt_jv!69*jwvhV~VM2ul|6X-WsgS8VW2y9V0|5r*_9v|sUDk!5(RjRe1GbGGg{37TZmzvbb;IPfyIa

T{Y$Nz)hXKej@wv$019I|yx;wb=Eyd6S=0 zaHqq4q+QmNK&}_Y^-f88B9_I# zUgt;S$Z?{=y~D0l!noR8uJ+U(_j>f|$M$x1n7Y}WojdAC=!=SkL6%^ecftt`a*)qt z*>OUMK^BovE)u~-{2iVVf#w85dZP!fp2()@G7))AQDnKqL)_8CpX@@LGYPFyqIRCV zPpg&L*I5mzf~CcWU#nXJhedLe%|A1VsrPlWJm8rvU-C<_d4hS+Jkji9)-j2oqA*^dd>k}U6X(H zi#7|m%?r@AAE%ELmpC@iK7&wat-R{t9UatND>q$W=Q?SWKV@Xld$J~;TR7rwk1x@} zv&;XN4dS^$9x)-bJCH1vEATtZ2wf!Wvv2KVjinYNdeX?7u=W^7NU*fxySd9AH1+sv zlK8J0$xpqDV^SMoLa*NoZU3*+rbSBc6!M-dB;h{@osxx;xlrq~LZRn-=q)XD7qZFU zW!9~qu|DA}1L^;X@%+9>lFLoG7)74Q<)#jm>j;NSm2{L&J~J*ldH1?5RnxILdG|J5 z&LJ-N^0J@r(d#xspy$f5`*FwTHAw;VrrTHqF(^yUK5TR}uN)6vgxTMW)L|zTba@*6}>N z_p`D8cLp`Ucn&vcC3G*L2= zh24Ij3jT~Qgn7K>KEGM+@=Nh{?aI{r%+;mV%p&RY#Uf3plJTv@W@qVxX1sYipNgz| l-;!}i{L?cEnEAkRpkcYxiK$Fv;hz6p#2)KZvmz7r$PGd|0$g#nQ zLA{u-SZUH)YivmldZ~*KL{A%I^&Gw1*w+3LjnST*HZ^F~q*0S}zI)k+kE1nBPRbw4 z-I?ESX1tW`J{ba&C&N&5ND3&b85kU;8+Vbja1_dd1Z)4ft@mc+Ry+HjC~CQ6)-! zmIQ-AeD&nhjA-h8Jrr(;pPrZv&4%yyBw3i3Z*Y<>UR&D5+id?Ihe-WKhY+nN6E)Bw zmYq2Tuvv_A#R9vPpX_)`O9G1_QaJrSE4Ke}Jg@=^|KJg(!&af}Ot3iNtQ}yR_~M_2 z3_!#gAASO`U5x&yg<*FfK2|3i5zk(JSIhRGVAhD>-G3$lyeWQuB?n-am_57?V7GYv zs#VSQBC1;_%$ghzyUB10l)^h=|IG;+=o4JGcCjL=zf{zHR6Sn!{q1g{?~Ynnescjh z#l3e5AZXiHYgF>zOI^{3&(xFrr4T1@JvulbWPi1jJ%rK>z3k+G?8G|QRN= z8#bZbuh?;SnWKaO?2#kbA^lQcg2iBnkLRSGhj(&Phe3V=qxnit*xlc2*dquhOejSn5LGQine((H-t{{TE2D>$T{LkL3M$%X~g! zep3bMOoABpm>dLs^~jJ8#)%1E{|s1Vj>yj@uYpc)?C?8sR0m_7E(Q+!F+F;+r5GlV z->^`EU82)MDzisV_AZ8Jm|c3I#V}DQdtXCNFM<$8)RWE<;DireHIZR0q-l<006ipD z2X?e09JQsuaVOf|0L&S$Kav{){?1JXh+>$FUa{sBl0P8BCa^KXdeWK%)7aBgr1a7$ zCCF1|n5zRn0&$Q^ws7!-b9o4Su7@C50)J6ZdpM}@W5Nu=*ZdPCG6LEmit1y8>~0&1Ex1zun(Hxk}{tD<~$Jxk!o@& z8I$`lLViJFlAw^ROM!Iu@ASJt9yA{-@K2m`r$RT7F=+_Df@&9;m;%em{xnF3VRAJM zrot5kdX40zqI)$dUj$DIfj#5c>xfqwNq!ns!YElx-b{f|_NFYC-CU>K@nq&SSfhzF zs#L3ma&4&4mor9~eT+a|A5MpUn60>|*P6(JbO;E{LZb5O z@{{<8+}qCDbXe#I&w3;I5l@xfvIYWk?DTE^qxF8rh#9&BO9yD z)5vPl{Tzg8Y(=0_k%P~{j%FOGoTY4bT~&4Ea_*_}hK9OEZU*1jSid^MYON`6XsoJT zQTLZ(;$Rt2qq6ZpoO>dZ2`-NIF@;qqhx_XC+BTb6dvX-#)9-h%LU zMej{`<$4952hdR_dO}ClRTT*hP1bpH78cC1<`xvqTd>$#QNFsiDxvZDM#Z|7lYWvQ zZBF2%?PzZ!UhR%Z`$*wJC{+()U4$($W0)bMG6DXv5N5&&61@nf!%3Qh9Ok(3?g4Pt zNC&`FGOiGkSv}3o5XmouU~1#S5{T8xvO`9BQ^NomDug-ef4d#s8gZ1h7%~_?6Ir_$ zQb0q(?eHXdc@azjAmw%l^UNCvAg`4`GFfSZMAksP-BP@vA=#TO`^@9bSOl}w$tLAk zI4(99qv5t9Y=TU(zX;+X+sD_8dwk7ReEoC@M28xwuT(VDRKeRiz%sG}sF0jr0#jHS zkVGv^5~R!O(F1ry#J=HKonaR84o+3QMcJx+CCMy?c;R(R5Y*GS^56w>z8H`EqEATA z-xJc0X-Gw(CK^rsgQBTdqLBgBo@koyi)Qh6^sXwa%yVII{2GJgwSo{cn&~ys4qo~6 zx6vf-jcLBC;d~aeNRt>VwB&1>@4-0ga5;A*K5lDvHSyv6uQ2Vs?zE4(zf*kzpfGvH z3GdnBw0ZutVsAa9Aa+aHBU=1_>+rh^!)hFV#sKAJKPT6v`I&FYzq>RO9(Ej`L|sr4 zMWXBwA=m5SM5TNYw0w`6cb<}+bC+zag?r%m^9ko1nCKeN<^|A-o%K|V88G4koJd|M zg%D+?_0vfhu6OLC+YHwgIaUgHE0-EVn8WYbcZHztxw=r6k6?wR0- zG?P!4!c=C8S=e$ThUD5oZ>BK!yB1BZRYMqQv4e>nP2-7>1zY{qbjCoqqLxFF)d6Pm znH_S2%s$R3EsGSCK_lEI@0EdzDK|T}mqRRL+<>qS|4Q6d4P?tQT(uu9gByPS<&>T2 zD8qk_QZu={5}pdlz(YDpaN9Z3=~Ej0u$jqB9>(b?z8&GDl!pWhMYhYR4Tw;wHZ<{p z^f%8$K9u?&fqGD#?en^I$$T1QaoM5QO!S5F{d|Mfpgu4CSqZb6pivM4=}=OjI)P zuAX6hk7=*b%3EDWEwQnbu|G7mvdjT%njWN77S&YK_uacLX#Ugwv3Kt|zu)zhJl3+cz9})0V%5<$Ltzw=$XDv@Ju{AA9wSc;x7X$0xuQR2?NjwXo27)$jkv zZ^v3~@Oxf;{i*%H3;N{K$&i}Wp@Ekj^kx79*GJp5_DeQ>$C(63>$$z{8oT!6*-SK> z0kS?RhZN+91c#P8bTHMI!LEP!X;8*Sz3Ac(K#P9Q*Y!-=#39MfUcqJkk8ch;q|Mx( z8@B81m&O3w^!{CWz>9j>Py2w~df#9CHt97EY;p24Qn8zIfD-J{Pj|=J@w(Ra*Dh%v zcmHj!ONcBxql*QRsXrJY+<{7k!xPsB%R_)XY%}8z)n- zj48^>;8VfJgGr`GYc0H;KDBXuFGOQ0*!Hj<>3t4paB4AWHyH&U3}9?u*k?b=eS6Jp z=|EphLhD8^?vRcNtCjRogC||#WM{%0%J3kX>b!6padGH&v5P&f$T-|;%<-Wjl6ARg zd@63G3&YUBeis=hQByJ&bBBQx%b` zF^qN5g;ZpVNbzYH8$NSc8md@^iPFZmIH{i>1;VNNk=NG{*g%4{6iJ#qOi&4m1(z#UmNTW zw19S}BOTw+m+82fzRN^DWn>@|-_nu{jN*3l&VEn!J8_&gWg^|)$s?T-(Y+Kq7BeU- z3z^a-VYI?`3d#Wbbu8*ww@eRbV*-9AJsS(<7XwSBh=|970XGdBhqsv5&Fh;?t{g;p zJno1H)u%?PiRuvbw#iovUk)CKWP{z|0{q6$@VIG-7ha=n0v-kPyRCMXO~gEwA%Z2D zrR|=G>F`tDBy@0$S=m2(k?Zb8p@S8K$emL;d3F!^*=d|yV4R(XQ8o@T*?;w7KQseJ z?5rlN%lD7zwAAxSh-h?FS5{UmtX>?{g2Sv~us3d|+F964r)KjFu#WsixCKqLr3CR* zS%hq*MPzSoyT(L%Y8DddWD(qKlaLh}N^)N}l-Nb(#h4e%zy&n%0OlAXF?2bFkvfWz z;xGY?7Cp2gv6`|MVsX zHd3fLaU(S+EHx(J*!60jD?=``DKw%8H$$S1GTe_oG_oA2EJo=mLX>h{5m>AuHq$8T zUxB1Jn>bujZcqwIp|mn2J4^(#qJ(PUTy3e{M&DH+HA=0#+O$AUNKdZN6Hk-oU)j*N}qgQUIRdwwgv)RmGyp zWpxi%R*Qd{fQZn*1JI0Wq$LV&gUMTMa#q)<9`S!PP)%0Hsnf(6JF77z)(qO<3gkAy!La2d+&^rVOkPW2KYd{ov8X&NNK}Cwa z0D@7Ug^r(!6oV)VqJRzf#9k-@{_njr@4Zd@&hLNDJ3IHz+%omfo!NP_m7BJ)QyaIl zz0I1kbZcezByqT{5oT@c=*t?3D{GoHvf8w0ZMB;nVdZuRwe}`=wpJyzwYImY$Lfo$ zdwM-1H-B2rLMtmd$!ZfHFD}gps%O30p{`ib&4>{{bu*gs(mo`1M<*l5x}W50^^WT; zCSPq>w|04HaL(-PsdE-&FG|dvYwhaVfwi_`x-}Lv&10-RAnaQAKx=jzKkLUHbv!wVwgz+#Voe2`5)v(Xey$r@d1(hL zW^7YyP}2}=Rr`^CK12KTN*mm#ytI{--KLTCM5kbuX&q^vEH2#%sVk|wC5b4eA!~}r ziZt4bf0CN}16Cg^rJj}9*4O$hzP9CTo+Of{gdklvkO2C|a>L4N6=|*M){J!{t*uic ztut}StiH9gZ9S_p-j@x=Vp=~Y##%wm1FhfMH({|<(u<3l2UyXG6Idf)j1YzYp}e<% z`fF-^)Wg?0(k{%>;(A(Nr%YgjMQ~>$O>|oyTMLx8wK7LF6e|jY0<7hu{2-!*IPiUV zL(Aw9#F8jufq&@!qVgrk-S^$=K>gLltom7>^oXN zp0egrB8@lS2u~uSoU`-X#23uVW`8E>UdVnXB0piq(=2)5OShc;y-cCj>UfSLIIiZnN(lpQt z%B(H^d6Z*YHxXx=@g~-S77eVI;saSLXuamvsgAx@F0^Mry8vr)N=@sn?upi<7WFNW zl5U;r(Ux@(EY;{>&FoMY#!(iX(hp0jT-%Wogeh+(UZq^n$tYksZs6COfU9CZ8O`8-CSeN z^kAnmJ~ksf*qItdW@|4tW|Udmi-}jw{vPbJ@sZ|&5)XP|bGRAk!M?w$xUTX?X0A=+L& zFeiJl<*%Dv0V|=lKgJK|n9DthHMdR(@DW_Yj$y&}ze z9;{*GbLJc`mb=Fs@4*^UDPF91fEn$@p35@_d$8uiZknUK*jCdV z2bxJ9EaBlzW-kwxm^a#N=*14LGMjm@r0qYMv%T1@XmhLwYq#|wv!@rknP3i7Sjnfy zIy@I)HuofUK3`w)8WzgBLrr)U4sb zGN0*WE^=cf$1;D2F+01_V^glzH{(56&VeT8EDtt4s)sq+gB3h^*^KjG3mY{y)4bU8 zSIxy9Y)Q*qX08WYHZ|N#@L(k+H!quE9&|-kqPfI_t$L%adCSv-AABd(Z0|{1J!OSi zeU~78MGrM`QwJ(}|z1U@^dB-EuSrXmKY~V>O9rv(lc(K=am~}kZ+EKro zO}yB)RpvY|cKxs!?!h*cPd3|lu}}A#lRVhQkc;M2FE*?s(e#+$V;jrCdmU1Ij}qI*Z0_dP<( ze|^A=^`vd;Q_EcF#a4xz)4kZSAI+5>Y%>oqZ+oO{?s?zr=S^EyWG?e!2Til2trxxZ zgIVmsL{>|)kr!Kk+nngdJ|1q~^r+ZUyU668v@HYkOotaMy>AZpV(-s4CwQ>O^iRxt zaUL;`jrqy!?oBKoYi4<|%BQSF>B+u0d9E*yvw{X~)Z4V4QD9{a8qF41FAdtkBCYhn zqiW$y1O%ni(ebu2Ga6cFGM=zPGLF}2)4DK!MtK=oc@%LZa|0d_11jQ^x@5x#_B3L}J->7G`9MOg|&6+sE$wph( zMs)JUagLcjJZgeDDETjG=}18 z(ld&lN%ZVR&t~)-Yn_>~$*P=@ZuJ9>S{P@gO-N^qQfm-CJTKjvn4NB2fcQ9y=`bsu zIQ1-pb*y{k zC9bb&76|KEpAtw!TMU896IwXH(6m8-<^Y0wG7`r>U}&Hrm?Q(V$bg|qg#axw1ZaFA zK+6gN8fFO4219@r6@o?>l$4Xf0~Bo{1Zd$PKobQ48c_()vO<7H6auuD5TIp*0L>l* zXzw6ELk9ucGzf48f&ix_2yo_tAeDl7r9N|W=gz8`GpBr6d7K$sv9{p*S|V*Mb5v|z zbedV+K5+=Y(|TmZjwRcfHD{4SEIQ6YD&{WR&cwMsELOBS!6GU$O91WBlR3n9Ct34~ z&MN_RGy^pGJFQ_w*eXE3=?&=RPxVF>e?ACk)#nzRN_=Y>@CyOP*D6 ztQ>egd)gs(C-97lvzq~H@`Iyd)0TIb__7gDrFGykvu9&$Mu!)Bq zV#1etrHp^YjsBjl1fo`0ClWnP|I| zIjqWcHO0N5P%EE44^)k#fl9mxS=F9$h;PezgNk)8gV09j92G-$?`M{I(ovE4N+lEP z2SAScZ{vv-S^I$T&mn-W9SzmlvI6MedDbDm`b!V0xc3@hb6km3Ac6|6Dvl4bY#G$Dy zx?=Z9h@P_9QBiRE6J`ax;;5Kjd4XAr?>odMKdo!UlOKb)wR1sNVSpA@vHTN2KQ9F7 zJZ6s@&u4QD{YYXW{CSBrPe(GmYS zT&CA@_3&ZuGHdrb7#!=hMAz_|kZf%&b-2R(*hyyn@~T7JuF$%y~3BXhW->a)Gfnz_*-K8n`|xq382xg()n-)PJlbF1ga4iU71 zHF8ai#)Pu2z!Ker-DK9X4;`+qvFtiy30BtQO+>4idV*_CGgPtpFNgSfC5v=r#34Fu ziNh7tg4N{KmggO=V@sQWgx9BmhYi&{8E7^c& zrs_Vfz3tg~up;{%u3a73=WO#tNLc=&KG5}RXH;=@yF;Y!)|+xAOrf$xo%Dq~hPZXa0t>W{iLFyX6dE1Zjp0cA?N1JC$nHk26C)8zS>|wog@LYmBpB!@^9#me z%F6c~)}c4zT-oCh`)P&4y7YFWtJ_4xx?XpLl_p&kJvo9SkunC8l z*c}Q91*bc>&gDRY_}U+&yiQ@S{gX7gTb~f@< z6oZK6R~xyy6d+6QN{8$3LI%S#`g4bM?^cBCr(z@<)&m*@1{KKK|F&b(66j;E&PRqX zE~zg6)Aabn(%0aPXIWw~n3P5NbLc79dm;p^|41j6(1XLP-eSN2nJSZ;r@|%7@--s-D>`b zAj8P|q3}Ro+w6xBde-J#glZtP6Crf7&C>{VM(A&ZaDT{*s|$}=2#r8!G(ry`glk3f z6@<_!H!mWz7@=DAu>avkkl7JH+5|GEA{2&kWe6=n=m0{v?_>TKq4pRT9tIEG?=jO5 zLLb*GLZ}-;+YsuD&u>8V(P1j?JMZ2-ZQ6AatC~T^NU+w0Rz(aD;p! z;DPG~vmHXX5-=wtgi8Z+Eke|l-$n=*2hescTG7-YXin$aaT(6ifB7}a0z8DLZ~~&J%um4=0E>#Lr){P*=ZlPh`?|<|8g&g2*>Fv6+gUA_KnXp{{{~71$zO zm0QqFfr7wWCE#>je4I^|xNGoMHco+WJ;|mk5U3W~84m4GH4*Ikb0?dssB)iX*$VvP z88%vhY0t4o6nN=*wpoItS6rG3ncMy%JEGEyUS>jpk-I%vdSnkPRu=Pq74sV6dRBRMr;?bow;wEF)dvm8?X8&!1sMij+Eeud}R)N}Br#Tdk6)zdO#c zv0hyD_vb!iCsZW$_s7qB%p6!zvbHcJsS^u0LOt6{a*3l zHK084AynBf*Pto3pU{J}470V!+Q%b+Cu^d<&NcSGY%uhMu1107THRS>+yIsZ$zTiK zzQJ086P*mBiK?mgPe_QkYu3+fo=SRoGLLsP_!Y}VNl*jsB&rOu5chw_e32-su~mPv zi3<1DnBPt8eMCf&RAVK#s#21L@VSHIp46@Wn?0bvcaL z@MKN(eb}m*CaxyKm^v8F-xEXPwF2uW~JsMrYCdyV<)UR-tRXQKIADw3LLbrTM)@%#_005)Fgi*d1_DDyWa``r7nd~X^$ z(WSmQ`E!eNVOwiLd0Ynh-#ENMi2GQN2^Iqh3tK@#lX1KNce6H&C{szB(VFjVi2i@IGGehY?*Y=3Aqp^= zvdf9QHxom{ zuRDi94PdbAwH|zp0tfemQc|qV4mV5XU=)aSS8wjaC3vh4hs7?%KGcsNP~flu*bynV zQMxDghe7-^6?-;==PLfU}h)Mu{nH&0)Lp! z=PR&yCf}{VB$LAwK(vSQJhVe*b8ufM7D@`f0fD0nd7c74DdJ!#DR%fA{!5|OP&sEofOFQ| zN3n@(_l8Ds?+S~YwZQd5Zy3>M)&kd|G$X{1*4sD++R4F6%WpVWhHlHi^&F=5W#hrw z5iiyk2^)YtYXTVZ$2Ra8jCFA_i_e8IItsc7?DR|(siUEHmqXm0p{q_ z&6uMP>bQqKYzB$rTR`NYASg$N$6!$8i*d(T{aU#2$1Js=EQ$5UnBjwQ5JCBR=W!0x zY`yzxL|Tcjv=Ps51xYvVgZ|JbVK5eb3NsJvXfF_b&OwI1*~aTL1nsU*vmH1eP$bRX zPwnLC5_jEyii79srjKy#dxjtL;%Yv4@;MwJYrh6fxLGa=Uw|x3`UYHyi!VT7T8LeN zT75VHiT)gHSZM~pl>ZSgad46AI-%Nd<4d&K1&rT2A@5suLEXLm2oGunQw47GU^Sp2 z!w|PBFvN`t3~{N8;Ve<9X)#eqF85oIP;O_?YM2(iX;SsjJ-iES3zmVYf=xEjWH0Z( z*-}<)-Cn*o6!%E%Rx`s~AzKjwY{gsqaIk+@+b9rkRq*}dOdS~LkG;l|8CxNGz0c!Z z_g;rl0mzlHTAZuG#TQY^YkHh(#9O=+kv92&_`QR*H?RV70vmkdtNl<1t=>{u8F&CH zaI$E)nZMGGkGe(<* zV&yH}a?Lu*dw{o?iT=Vd{;J3v0xrQD@A7DdpuJ!G^B>+zMN+@WeIH6EiC+JJUz9V> z@#B29jO+Iye@Halqqn8$p+P|9_A@Ig->lqU`TCg^0Bwh4_0Lf3E&G=zWQI_(R`bo>c|Bi%bt*Gwn#O5zhHiRlge2Bb)!>F*#*<9hA)PRAr`2qFR+nD&_JY;5fwO&wcnWc2WJl;!W6(Qp$gAQlMzRe#MXS&~CQc z4!F#xu^>@&ji<6e3_1(SFA`%#ZhOtIi72=NjnvW3cKQl$1qYIeE$M%-tv&14Qv4Fi zeE1kUn`cP^HB7w2s`6qf+4rK&=PDb}8v#y5E8>Y-COhbX-;6X>k>&qVflC**L8@5i zRl$}?aoJvRd}3FzGh6E+;!54VC%&uXCzZ_BYxP)mTuOq82I^;X1^1UCcl^M7#k_Jb z?D#^H-|QyXCU9Z?AZq?=H`_Rk_<=WLVS?QRlhAJycwT60cxZQN5`wzRZa(z}*z1lq zsy}b=p1d8THqldAcWE~gfC*bBR!S;^Imt@u-VDAeqvl*BbI3*_#Ysyfr09{_qxmWO#YU2 z+}se>MbCcFg|(49wZCJru*@f(mR=qfCt+&OTUTL)2k)BLc*%3}8t{xE9zL>%h-%WZAR-*=-yE)m7?U8v3ehiGv%Q8xY>&%1L6x8m30NoFE z0n}|~@7gp02WfiNrm05)%*^m2jr}7v^ll9r?n(`}m4@&{(6IeQUQ_U4;OcY~jfQC! zZ;>L3CTo-6czqO|8y6R98R5Jh{DT80H{c~*f7x`^+zPH7&H&c*%4D9IBCXNSTX`%W zlp+VjfD{q4$2}eo`f3mHd@otB*jiId;dzR7W{MmaIZ7q)QXlM_B0EB}5$;U`JSV`P zQ-XdOp~dp2m5d!q#*>QYL=t#B_#%;?QRL6IF=F{?MScRZhy7qtTlA^%%@4XEbEF%B zD8N|x{BFvoo$$KbSzBAgud4h3Gv)6CrRz>}=-r1~z+~Pz2#OWcQ`X0aanQdT3szt2 zEP^cN#~L7<3Z5rLQD5!&8_bP(s(}wuT*mKUt_FCyc;B8ftLJ~$L+aBjC(P=2mE}$< z96(tYzi5Wxk7@Gd(*RkBMLnqynRT_*(5Xl}^;i&1ZQI+Hqug+JW#jP*zD;GTXM~2c zqPH+x5Kd*AY^)VM-D`!2i_!eJ;&k=`&iA~W{1|9OmmnfiYtOHFscb$S`_4q<^H{79fR;-(X@fqk<}DgG46^s5Ki@QbZ)36^VW8blMS_2tfh@3&chMB zPa7%DH3E(-I|sa^OJ*51j&u(P*-b1I4*tWo`WW7o=hJBv?o^`Ul3`G;wnER=_NbETNm`uNPH2AeF5JjVuV3r5TQ~)qan3cS%YKYUZ88F!!lE7pSx&}jB zOO->sMk?h6(uOqGUgC+VB)CqTwuCoKmBs@|Na#H&box750iC;H!==0q`(X%YDR~({ zjQ!$P3#}KM;~}th3tp&5XQz_IV5Vr(N?Xb{+lYM+bYr;& zg89}?u#kdlO2M}iv_h-oYD4%7SWIV-|K>y(Io**#8IZ0b zxPvxJlupuc(|d$e0s$&9rIN%y_2kXNwP5vUDg1MhAtHLfe#1zc=B~YEyL7_16cIOB zS!!#-^=53n)ZTNN+`D6?wj4Mmj1DIBV`82h?>6&zLW;dDxj$;7xLr2x*KFMTB=-kl z(9e?Mj2`0AWUVfYdn)T57r^4wQ3wb8GU^bZj|OA=XW+7|wnl3sWfY{na2YF?2h$5pMqT0H;UOJy5a>{Bm2`&O}u*^PK`P!LP zm2aPU0H9aJnUm3>b*e168~2gb3T2?&MZlbyJ=|Tl5fY}=jXQTAP2;`^XC6j<(Uq>s z*I*UD@=R%TanAJYsdEd8bMt4URMF7Oroq27z~LqoXNLIHV?AuzlB;SXE00x)R(`K+ zsoPAo6dmg0iO>A6}l9!=uUD3;88jduLmPDzaZ0^in$ z3~Z~0&{?bXdOWXzy}PFhlT_G?dV3HZ=fE_10HhanbaqDU8wQSRVutn*3{%KRDypCY zJt6b;)=s^P+%?C;i2N^=yNaivOZ_f$Hu+=CUZ5W(~x?qKRO@j(rKc z9*z6T>7qejDosPoTeZ?OQ@I~Yx%WZT94iOspuRLX|1(T`f_LgGXBCiynHFb8Xd#|E?HW^COELh+w_y;BXlUto2~oFif!3X`UF>pYN3&MR0lf- z9@N2bt_o|(jzK4R=nxMkn6+djPwa;)fERebezJl=BC6+c{p8H|{&O&I<7rdAN@ZZ} zOR~T66`*`PEZ`v619iN0sNY2rE^P_gM%AG)VNRjRD zCtKnzz_BGxP6xO8J3IN|jqu(+=o|~>Un`zVULLAKRE1@DOqFSw!WX;Cv<}LICuVtk ze-XS<8-=f)VIwMQE({Atf0<98JS~y;r}WWO64r+Z7)XY_QG$M+4f}_WDuV2Mtub381wAAMJ78iDUZbU#(4dwY)7fQJvj ziWn^t=V~#mt~j#XZFqwbPUVovUbSIovGqKy5$`$xm5&wA&jaF4HsbakV#>j@^Pxl& zl;p+>phRPB#G|SbM=#Xs^A(EN)5fsr1} zT@Jc$Edht2oAP%-KJHZ>tgl>@BVO_RAnYt+5AC`Xdd4?i$`H{w9d?Z_T!{`57nXuM zb=k|rzLa^oFhF+K0Fjjhge74`IL)SFg;?DaNkzX!D# zUaF{_UTW-h;G4q!_Cs12d)3BK@(}n#uPBaPUJlAl$!d`Qsg3%N)gb?4Mg5VN+S9AS zvGA5Ovj}AWsi=SRQg0ZijS_iIEgt-Xm`$>p!=yckNSD=IFI`r%yI#J2L~950yO)~w z*^(7?=W5hbOSMRr?V%14=Sra)PgK<7ywtMOK}%sLgeD~%I}vumcVr)-De7YftRC

{}bv%#E;~ zzM`nUQd#^0aO@U~ET~D}L9*wA>R|DwrM2MtAX!_muTHNt+~jx5VS;I4CttKlix<}( zhZ&cAlUOf9%xhq{R&3T<^1*fnU1)9iK!|}mEUJnhDMGhEZ5G<8AKjug7s1;={NWbx z62L26Rw$GiEBGB%ntG2zg>1L;uYMdPZdIjuOtAww^{Z7+fVDhoC%^Rsl<$xt-|r=- zy1Knpo5sJhlheK_ISXGao=aXH8pXS|Y3;EX*_llk;e0FHT zut&LXH*{4>FWjL;!0W}GyTD{O!2tF?6E%OhpM-LdvlHmkZS>@FgSkigK2_+ce)wQd z{g8!De;O?PVjKUFr@`UYkv3xfO%L&Xi{|K^(hIQ2oS{vA4chiKC4+gUm740XRrXN&Y z@Rz_>2+xo`7o>)W?JsG4VSd{Aws(Fam=*@WMh$Z8Wtg0v+6N6nJPUR~_wDhjyFrHU z*2eR(cA+1=qD6?r?sfdcx?N!2N7=*=moSOX%8)J8;1z8wUsg>(d#H1ntEb`G7;m0{ zi7KsqhO`Smh@gGiM!w6=es>=k~+A%RpWulgt6T=he;bAe@RaNc9(pb`t~N(~Iek zLOfZCs{20p+?_K;OdojD0Re8WUVC4sZFXG2pf`#qz%iVmLMFXZOqQp^F#(Q{(7JqP zCb|A?5*Z z{9&1~P|S#Z5t3onkh>`m;BJab>CVum;_XcSqVGX)q@GraAC`(A%oJx{(C5kpQ`LV( z@rz1(&`VG&=au$zz<@7~&#D}sYwyl6{>y~<3U&%c&YljCVSR`)%tPd=2~P&tGYmT) zcwinYGhVKm5Cxd3uI&)2x?dU_xET~EKKwqswpH2F5a|b@{u&LD^~c1SYiM|y8~)H> z^bYN+6E<_G4)GscFbXI~JsyQZ3|BeI8X^bsx%XffW4?z#y%3wDs0xS3qRxg8-^LF3 zKR%I#6hRa(<7N8wv@=Hk83Sqf6hjPN2qC{enXK~D7kw9$9b*c32hv^Xk(!l zV&@h0xoXt^ISISC|JbO#FU0ODmfO`>GET!QhbCEaxX7GirtruWkIIsb)G&(*3)=!K zKGL4%ef~v_XFPeTqE3<2++BpCGg=y-Y3K30WaT+oBIbKoUR7h!&uWwSqyJ*Tm!^D; zQu9zXo>xDC`FPL2crYUIp8_-FCI9B9?DNEo)gu0Uj0n#&;R%r&zR3) zsr{?s`KcPufb*Kk!-v``8PAvTx%~d%l0vx+t$|Z28p0ty{ za|ssxk1KLfjr{OsSVtbVllQ-(b>s&W`P)^=@yHne#!mgw*IE;PSy6vkm0Fzs2FmUO zZyj+_Lp?O*TiEB;#J->06J!m9Q@K0$c;=eN+d1}rr#WEp>*avMFLsW---G!ZWao&! z3X51+m3VaY^>ENsg%yhqLe@~ZrvQyY^T%E^I;rs2N@;u0331zqJ=e7?ZrPPkdrkbW z77F_|9!-2LoH_6~%Xr3!SJ;_0`~bfDUK{;xqAw5=Z-9?@)=qlvhSp4k{id8+c1jlE z!(p?fp%g%Jb}O^ydip=S3)N zM-W@i|6rT)2Xy6i)z~6oznM7J{11*#{?w-MebqSRzcAqaHnF|@KiH_Be)2Ci{GSGF zO%mJb|G{?S7SzT~JKK!gu<-jsa=@z?Pkp*8V)h+y?(2`RwFFhfFLyvuxY$=ySFcm* zA{^?wNu$^E;>stiji(JR|E<9}V!I4Duo}s_+SuXcNliV~!!h$7Os$jc9B1!AN1R~e z7+aO&_(Z^{c90$e?}EJabAt6aF(4c^<_}MUJ^Oz#EDX_m z!eJFJ1LZ0#6mm60Y8hOe=}B<-s?qPN3-og&eW9109~>!-+fFzqrs|j4&Jm`Mge?%S z6gcJ{AifIIEkM&^B~3WPDZ1 z9?^Oa_K>99_8X6957?xZRHgkeMsLqv@JJ0K&lD=ylVPYK@$O|4 zULnCIN{v%nK=Y52WVA&!8dyDULbsNXpJg6O+oBiN?3BwOShGVeX_MliR(b+#hfqmC zZm=lntow?P1Q=nDdo?hDa4Ih!BWp6KwVnkBK)hVEy1CJ)KzAQ+G>HSzPTc(o&E&x zVCSR>t*yxF0rn(OvdvW`xzk>6%17IY7k1EFg5OKT;K`v5H}Q&&x`QvV6W{F!gJ_{7 zo>!HacZLaNo1GY{HV#e}kz_b;YnS|B7s$pDJ2CGH**GYP;e4$krlMkVW49b38;E+! zfN-N=b7NM*Zz~~=2zWL77xDAo$J+YGn(q22IGMF`5cFLjviFaAVrO6X;13xmJBXeF z#<{bN{DBm`1#U>VDPd9rIF%=klYPV4Q(q{q^?}LAEj>a^=nL}@5S%gjD3O(__Yg1i za}!)k)!T_V{UrgF4^`v1tpg0WqAp3(quFj-7H*~K&0!+;WPv}gGJCd@Cch!9| zKu_X9FxMPC3;vj z>RK7lC`)bB4`=AD_##C;zZ!K}CYbB(HtM^XdVRiCQ9o9V+H=&M9ksFGNq6zdNHzHQ zelHX4JI@&k_57WU{@PG*Nv4f<(_iw^V{z;I_sK4vwJ3Vn)Z%%wtDIV>DPqQ`+N}kL z7IKg*K`c8DC+H2qrmEh_IKrvi-HiA)4NkdvSOxBlh`Hn3wgN8uR^-&du)C-Z_UmJ? z^>coN-T_|LdD&--grzMeNj^C=D9ywZ^Cxi zcovP(dx7coDtWvrgBT0u;+TyAycYS7dOUmQ$=U%A7nKdiIvR&x&}P6N4g9q3a+?e9 z8iG?lRLF3D*wMP>6~h0VK$BJ|UNm9fe9JK5ydeJJ7y_KXnobl~Ch9AB@I<+>_NU0o zfvWgTiXuyNaTiRG(M{NBK5(M6-k0~v*N?p4L^)E@CQ92_vvTW3}E103E)4kNx6A#aZ zPBParvpA zddo%|fEN_?XVs{;&4EE%V={J&QS?Vjx*&qzQ{;E5ktfcBS)*Os&d6oeP^4JC`v@?)N}v zApCpP*@_2fbkGkz7qD0l=etREU-8mF7;`U?SpNKE8g9^GF6`Iq$Ky>dxWApCLcF^L zalE+&!}ba#|MFMp?@|Y|V z`J9jsG8WIsI2ylW{sY%Cz@=ijoM+4N8~+~st>7P-^Si)-FSl+!=iggY>beh)@lvUs z@y6M*|2N2%Jv#z$+)Dg$B{WW&ogC)=03q51))T8A&_j4H#n_`7n79=a^mJ=P=|>f5%uzgX(FQ*f8tPF@q%Q0V^dUJDMt zA+m*c`U5zX|C24v+c)c>Mc~S}Ox{j${89#sfFv&mPncqRF@_fc@}XYRV6k8wxLBE9 zdU!338erR#lv0L41ZB8|jHAx-&>7GSH_VOXk0^1YKL*VYOOogYu+RW5>@Xi}(0lL~ zy+pFFz<>O_rFt6SRK8=1>@LGCy(>Ry=YWchfIm2SIo_+vaj{&V$$zfKAz!P&|NOjc z*Q>H^+^pA!zi99eX;ZNhqQvpX^uglZ-+EA8c&k;QMm1jTgQGm0Mz=pk%j}Gc0;>7=L7$asWVNQsDNp5vA)>X2ojT;!_mv+X;jhu zp3x`rxM|YD0~HGAwWi7OcKZ-)$iQuhUEpjp$vk=(9Ek}^=2#_j^AWg*fMhzQ%%7jv z$MX3~CQy;gQA*~J`_O;z-bL70CYjOyU`r^OFDRLR{G*4kd9rpPK$q-uDZJukeJX!f z2?uf#{;U!n(hV|ZN4ZW4a4mprq;???sgrik7H%jSkT(&9jRJdezgl@ylag5KMl z@owH!Th8= zvW7!*WEZ)qYWxpX=6tLd^@4S3la znuI#?g*T!A(+lsh)2V+3zRHuuPcQ2s*4{Cp;{EkJocEb7j#R=a{_NvmahgrXuDV;m zy__x3nL+Inr>Uc?OH~dQK@L2BU3>YkK9Fzol7@*e3tqB5p=h^Emo2<$y7c@PNj>vP zPY<#CE9ky>KPNw@M9jYg{r9Zmu9RgJ11|%G3IAHcH3bCNfosg562ZR`JSFnMZySa4 z8%kHD)OAYfI-BEub&r=6z~Q3ck6~P&oeuh%%#d{(HAAjv=2ffP46}*U4FT%Tl)7CX z=+k-f4B3>xOM|E33_04Ls0aQW{4+mU)J%iBiRMamC1LRDrAVpEm+BgZS5s%V^0FzV zb(c-KT`FI8QXkD9QOZFQDbG{NbGJaf;ytPOw@55z=N)P>bwuetD0PcLPr`)_nIGws zeXq}e?()M7oCwzPUr7o0foWoEC2U_^P>O(!6uqMqEn5tygz0r@*h~?;MxGMpp)+ND z2F;WX>m-qI7FJ@(K=QJ_miL-TO_%VAzMQv$gTVMVN+2b{fiq?GwSNanfHzw4>A;2k z(AWEf+}II{4jK@59~FE8j_gE3m(KG++fFX4VOth{ez2KEeq+N*t0 zZ@^EeT!2{0#V(bLJBipw@Cr1%gooG6l_mW=34DG-6#eRT+z6&OL;on=A!$(ac##cn zr`YcGQ~!}j^0M-TT-gMEBK@*HjgJOeY=Vio)C6Jo^fc>MLSr#-EDr&<4b-F}3+56o z`~b9@NW8`6Ul-`L`zoc(aT}b=6*fi7l%jOe{#$(ke?ckQBNb(Sr$53Tlk$O*Bc%kLnL(Sc4fR)gTls z2R=O(D*r>)1=-Z!qZ*k~QGJX{5x?|+w#Jh~cxy19qm&&_fu=4bWt)G8jYHHFi=C-j z8S!FEEF%^l!y(e^qx&xDg3BSwILKT<-|uhTO$ZV#pMWher!7~rRjxok=F0y#>^0JP zCcN^6zpJu!_BgEFj!?Gb3z&nl4u*)sX-1T_y-jW1@Zi@^!= zR>VQ2@*SztaY$7JT^7T`@?^DZhru$2<|)IGN4+);?OwH-z)L}~2Jre%4Dp6e4Do(W z4Dmut4DmWl47*cJMbTZNbY&=A>50_x?o7Hiv%9RlzIoK9@wfGHyj7kuOnKOht$jD0 z)bLO0Vr6?C#`2_*8u1q_yjI-Nvw5B>MgN;HRnJtV$dRRhGYR+q*5~pvpuwKAS!#i? zHDHNQr=3y2r(^Sw&h z^=MGGTPb@W zsoa2M%FXjCH$NVRLc>i29B$m9neD?PkdJ>U}dt9TAu9S8MCQ18{%cP)e4K{ z$HMlL))Y~I$(oi(-GO1oeE4TE>V|)O?~H;V9kFhrFcpsRkTs#d>_4N_Pwx%tciPl% zlj>PN*R2R+C<{K0B|L$TQ~3BumGx7p?_Pal6>Ke%zHL(96H?!822%(AAN-Eebd7_i zn>I~<%obUiw!9V=6iZdSxv`PzPj~dv{kt*Za%*E9Z=O%J3gf>;>Yk^U)Om>Wo?cqMKcw=oC z;%0CGJVNnN4)7v<_}m8%znVO+qU zKH>1z&J?4cSQP@pBBel9aJK@gU@6+wR%tW5bL=k2p zL%cH7@DWK4qo%dKdvkffceKg@2&Ei!DUdDj$3bv9=?|KlWfr<0QEs!PvQZ|p!EeId zy={%peBVKZ2b98NRBG{eJ7WvqrBna|saUI2jNH%ZuZrxN)X?kzOc>uO>0hft-Z{X7 zT)~};Nen(a3JU7rBN!i{g|dPp3*Ba502Hfwsf%M^pa!7R+Sp&gfbtsh8eWE!|pLpLT9Z27(^0h4vs${*&SEr;)>5K!XG80IIUJt*Db~bm1>3J*85QQ|Xzw9GVqRkn^u0W`$0FW#pHXhKowW z1oUkl^YJZ$64erCvcN3VDWY1YHKw~8>7rj>`2O%MrRt(obzZ6J+Yr_jc+P{jFOsz! z)CdM~n<81ut&3zWf7=L}>#P1oD?SFuut1ZfDp)g2;scB100HWqW8rW!1bBbbmX5F; zgYV<`gG%<~PEb=TmF(q8c6+!XM?5;nNarsq*{?|1iw7Hd{Bb24sHuA_QNj<@0^#_L z5dMi09u=TAd(J2Yr=^yk9+v|2Oq2$9vVKtT+(95zgT1s1zYrA zr5L1;;uEB}yLfV#5l&x)NROpYLZmagC=dd?G8%%JGKj#S4t)axBJpZd2=E%&^bopy zHoYcYB@2;wnQXcbeenS>yj2#0aWZHn1H2R!A_HVF4E;ht@nS*<@?;Q+K^^+014QBn z9nu@p?UI1u?Trw0!GO~@901Fgk){lqV&FsHZGbdgMkdQ(1qKFPfCy<_@v8t3E|(lr zFbJZXmmm@^UP||+FEaq9A;##N3=q_n*iadC#DLRx7$6PrK7pW~4Dj;{fQ^>{-iZV1 z2S^NVekj32ABi@`K&LM)KqOw70ztG42Fn0%nSjVKGN>toC>h`%?Ll@giQyktfU=nk zX3JnK1_u2#AJXt2*Cn73|8$-1PyfeG52SA3y zd@}}mi!dR*?h`t4&IQc_>vj7A*yF!5TD+K7`Lx3{_1QTR{Ybe0FODsz)8D;b? znFbhK5iP%05(Y>P4Q!0c28_ma4vpst<@Ax4Y#P;ow1(tt8ox-4V_bgRB@m(NS4Bfy z4qbqZw1bcWM|F-_f&mB{20=CrZ6rXuAwThgqnw6p4h?aj!~vg8BODMM@7XlYk!>jw zw}VFxJs};3em3!AdP_`4qd?<52cIQWcr*s|6_*^U2c*r!C^R+lTPd(lw&c(gqtKYh&$pljA^VX-_sd`+8XWn}7PJ}W@)CIF zPz2Vp!Ja7TtOQ{7AA)xF%c~c zeVQeQNFb_2ew78yiu@K!Er4>U%8&sqll?Dsl!%rEa#jO^Y-$svM9V^UC5KuF($TDB zlQ{t-ju7nMNQ}lseqyBrEz7^&vO`=B84@JM!K>ccAyhgQ9_#Q?hL4x=5v(BtnjBEo zR|aTu07J8qO%?}bp#dVhlS5`_LU{=#WfK`tHz8`YK~*&8kUhdEwf&3g&^7@}@=R2K z777rI%O*30#28s+;}hA?Y60cwT%=6L_6O_*!q9{vA6hgrWI6PN^!~7elue&w!E_WM zKiGoyEr&kNLYb5MOc;fghEe~Y4IP|QbI2}&lCnHhg4Pibw3XRpBT)?6I{9IhHn6LZ zLq-$h?Hdgkk5&}p(WttY{1}gB730++9i!01LjA|d&%>al%^`b>WdB;}V&XC-!?rBV z$9S~Lkl`Xgvgva%fM8rU8y=fBrr$U9Nif1Lb~jD2y0sc6%YUoBrS3P~{PUkeUQ zM5~X9I3-kZ{4o*d0?3&QmIB!{BOs;kAan<7!6S#Z;(%ZbAlWoY0P-RsSxWBz*Ok0K z!Dvu|P858^mfXZLnz6kYPAP~{x5xyfj3$_BQ4xv?doxWlW%NWUoEge!vOx?dk}{fg zyjV$~;+Bax5qT3ss-%spg0-rGAvf}kgs_YzD=&tV6=DIDhFL-kCyO$3B(|s*_{rf3k#XvRe*TU5}$scfp@UXN9vM;^5L-sBnHR%2#F|hVJ`qFyGV-(#Lm#V* zo`^x=O8~8}NU<);$Zb-IfT2N044thq@~^xY+JD4)6CYA|u_0B`+9(X`v5ck}q(rQw zj9e%;T1M8;i(wz~V%ST(81@n`)<C$05Ku7= z))>vKFe^jnBv(c{Ks00H5T`j!&V1bv#fFfJ&lH5n4ADrzjzQy?W=Q!hM|54KuZvwv zF0Rq)%Oxy!8##(`_9>BW;RuXG&qgj#Cm@8?M!i}tc&8#d4Ier9z^0Xk1??#L6>?#O zrcHh%k)|sg9MbznJ0)EhY&+_rW?NT>nMMcJG-wXQtj6eIfUNR({9FaBT;bqihFK4y zGR&|!VtuaBE+&GoNP6PIMmXI8u+wY+PjFBh%@N<^8u4K`!~w+&Ly#$hY|+Ft68vTo z2A;(nF~&4n`=fga&M!r5G>!fo5-yrXLMmN6&Ui?U&k>(fZ#p}#6`ud@hitadQh4jW^*({@V zFnXX+mJl!P{#iy-KXh6Z?GLkzetxaIc(>U`zX)trV8bp7!7y*?6SIw8kv(K|o(v*o zDk*L-$A}Y+@?p~)a*>vA%)#)je4`tNH}m23Foa_Yi~$%vqr#sHj3J2kDl|r5xTO#_ zv?2Vi(13$Pb42eVqkZ58cQuio2aAmEm~^bj=!2nOv60}D3?!w^MbsQ9{J3JH114-N zHu{9Llo<`RW%PQnk%Z}x;js}*WxBr%x=1pt$F*~etVkSSPzm`mKv&n@?l;Skr_Ez76%<_DAjUXsgBM!x?-vB0~v;y3ycx| zQ)~pUEPz+%kdU;{D8}%ag+>O3e=IZ#F`T~05E%Zm$XFy>w~y$#)MzhWU2J5?h%_0| zb%`+;DM4bgcz21BhKS!%*~ZrtA zYnc?>XSp%NFUZTVeYr8%PxIn`EjLC)4)*;-80%*btn6AZe_PwZm$o391{j+DHk;*%HzRx>@Il7grmd{hE96A66UP z{L!IzTZ6U_8-0;~@x#VQ_;OG8w~Z#^_lJ!{e{}KPLntTU*4VY_8K`z z{GBj|Jnk+m)k8<8k&Qf$K~mUucTx_$Dsi))avJH)sO^H&a^~dD$WM+=EtosEV0OZY z!gBLjHxtS0@rcpd;fZqZlhQH)id@56#PyFDtwL}LhUm_=yq!f7EE{A8(^9TW`c5WcMpJk~5Tngsq; zMQ5inV~~HYjb~k%(J@{QzF`H^=SC09%bhiAPPzGyn=OalU%4yp$1qZZz8Y<3g>vq#GOM zT;0Vo8imEU1?AA|wCc3$EooD~vy4K2T+Z1E{HQSDLuO^?i(ZydS8Ojg;+vtr3Y`!A zSqS>dKy8XQkP^^*|5R@D3`R#Ai0XKwQ#Ki0O3;UfX!I!|z{Ma0xblHuk_^yI1*}8{ zxb6ZB9d!uM9fm;eYP)x`(SwFabc-Rt1rr2)WT3X5V> ziGqo6S$S#T%IuTy@fGJ14C>oV03j(gv!N zHcp-NKHf<$?3}cCaFWaEq<8U76WvQEtreUlv6FgF9&gchdarq}?|sZL~RQhIZ1%nv6;fDoE+=_HX(=x`+vkibX{C`c$Gh_Ha7fQkhWqJV-Fks?Y^d2KI> z@SU02y*t}NK3~7*|L1ww%{@EkH>XTFQ+5^_cNjbd>GV&KHt9h+2^6HGvLIdU3ex$W zARQnE=|oSE&g}$g`xB(IJwdwI6{KtDL0Z>?bmcrqr(%M%z6NP^4boL}7->4Zp-*2^HRmO)x8gS1ix>0}6ai>4$sGDs_Akk-c_t&Txj8-sM7BS`CFkXFSY zt%*T8ff1xr4M94X4ASvuT96KNgR~9?X%!688W^M%Fi3}?K|1^n(&227R=yyudqG6w(Sq=!vNPSI;*h1Fs? z57f*jSBue}8L4>qYS<@~mWo%d7VAXL0j|Je&^<7h{53BXpI(R1WYDaiKM0 z@id-77$Mn$%=wvv7G$P-li`?z!NW5H%Yit2TEGrLg8!#!qS$Up&kxN^fsa3$@&Lq4 z4iSx;oG^OqkP%~s44sr2SPf6YhfhndiX*d&7sZFxh*gA0{M{O{1Ket@6=#Q&wgoR+ zE5_n;YsG%PB%)RGWZZb2Sk5<`{Aitw2d@+B`pCE%#>9A6QsEf<_ByewuLGfUhcIxR z_>_+ff&)F1m+xFS6lbj$D~1yS-nd>YhjZ79Eki%!aJMY6t&fb61AUV5>MXH^k8UUE zpNu!IE%5}dutBWo>q{OFgD}!tFdC29AjbJfOBDztFCUxP0bkw#!jZ9WU>poi>w8M! zxQ$}GkBoN%FC^pIGd$h#nvG&JMwy(9FK-mbBl>t68Msx&11=V?is!x})?rD~l2^8c zV|~J3g{*0^MS$|Ec$EEEl8pa+Rb0e=EKA0-I>4skdz-{KFHO4=$8Hu!v8StGP}Rw^ z5J$ZxmSRuW;wG<&>)78}_|j|QewlK;LIlC%cNcGoFK-c}y<`j=*s?NP?C7I^ZqxMG zm@QWGHYN{u;m@`TT4E*Gne+iewV`YI60JITw-?yiV8Y!%C*nS^kLWH1cJ zb}u#z*V-n=Au<9CTp-kPczo%|B6#dJv9Xs@FX5fr#HQ@;Z}3ms#9ltq8V9a}vggF! zc=L9#o|jU-!&kP8Q`z5l@W377T$b`@_!iRVaERc89b!X9`6U_Oy$Yj;9IbzkniIjJH_(s?}vECPH{L(3Fp|}*(omY zkpW`BpR#=8(RjS>4Y8V!j1U7#3O@CQIGOz@n1To9dTQacUEovtxNr*Iu?vvMU@=e} zn2*)NU3WuCBBRAX>6GOgKCXke?}ma+Muvg76r8hL9E9kP@(}E$PsFvGlz?NBULt3K z`NI0(eQ%1Dd}Op3sGPEV;ODh*u{~mfkBk!o36OoQN{#TWJ>VcRL=4nP!D}C{Q~_Vy z1HNcTC=Cc`VLWD!SRBW^CB`ypV?r&DXU>99>y6Uz<*+etiKTp$p;-!E@|O4b#7FjmQ^=Sw&^-k|+zW+>3@FgXP; z-!E1{^v5)!Mj4_;aeQgNSiwg|c7a(bxZl~h3h>qexPy%C0`pSv!4YAxIOPBcOGbBr zU<%GUAU?ra4hf! zH9{Qz3y*rN+1+6&;j}H zJ}6%nSN#A?N5(lYl)({I;hpREKLGbpO3_sO;|I`2(;p>LaqSNwNBX05DvsTul)*DU z1a0W)7;&k1$A{vFzIp_zYU+xM72wMl$Hc~rkdR7Bco7`=5p)9MNs@Z0xa(4QUw^?z zfEh(7%~J8MCU8XF*^eN966OS2r>^{1td}+e#0`+k@M-fi1B=M7bp03Ul(n82o{_$k zUTDg7qPV z2p<_MR`4_2c`#G>saPqEX0nh$d>w*V#0Zx|ge8n{HAEmY(~#@+5Md=Fd>10DVuT+; zgtd%tCq&3f1{VRy&mjuwxPkBsA+S!H5q=L5wlTszLSQ{NBittht^1}J4+%l*y(z)- z0uVyIH{>D$p%Wb-(ViP9ev*WB+6)zi2;VS50YcEaZ;BcjB7BFZ92YCnkyhXbmbz%@ z;T=XO5hDD|2&F@WUl^fGh(LODkSR7qxW@?PLWKK_P%%V!s2Q|Mh!PIX4uDiA1g&GI zgqnmvdv1lLs1qU-WQ6)5LSaT|LeB(ETZllqb09n&A~Z{ZkseT<2~kK-4un30(2>-^ zwv5n^5VSs=rWim7T0c$+g9t(E%PCCZu#>4czl<&-d!5Liz>m?lXtFm!a%;N*!( zlM^P4PM9z(lRmXk0c#Fn)w+C&H9tg1XSoGKgbapV9%s~zi@|F@6a8Mo2>}%l%BR7w zE07*aycqrh!csz@p}=wmw>(5x$p|Y6fdvSRuqs3#)4qVQmJqZcffBL^L5mS6;T0gH z(V;!W2$Zs!B+)_yO2{SzEkvM%?S#N01je#6L?B@Tp=HnBm!~#NZ{Pig@25x`CEselyiRvT_9YZYi76GM!!WEW_8X|nl2nR!i8;o!$ zM7YHWheHGsYyjx{Ap(grfN+curjUsQh%qST6G|b3zZl^JA!u<1O>v44LSY7gd`<{7 zY9N!PKsXyB6lH|3LWB~G@O6k#8VKcq=Q5#afd&P+N(fr8K?rzUj#%3hsE0@Ahz(m_ z4?Rs_h~E){7I;wp9|%EVicR`4NIFQ3{z6m)&)$i+=6V#5JD(9d`0GQ@ z0ncvW){Es5c+VN}Rdi?~Sn+Lg64D`@bXM$N^*W@{PDwgJo{=pE0WKAx(UX&o<6CFN z2k0UPaQB=@jufu-r5IK0yg}z!27W1CM!y)3aL2F2dM3ivXm2~^E=fUizB3UoYoXM} z(s{9X+1nwqGkS~j;(Ang67XsoMHcb4TOO;*r~n~qVz;^=wt@q&W?c|pMpd}PAbouJ z50C|3b_d?czK+L#Ef)1uoJ3x6Yp57`mzzY6uWA@pIY2?+6W}L3afR7tjKC8d;MGfF zMZEl?*uvA+2GWXxG-7fzz{)AlllaOx(T9eb0lEm^F*yd=AO=igXVCP6C(DEw9cp;A zuRWS?MyZHbT@fq8Nv>3-IX0-71{9nzTULjHQ{&+4YE2a%+G54?Tm?KhRg;)#lMQd9 z)kJWNYCQUo1Bv@qOz|AGF}`OuOUG-l#&(@!qbA*a4K_qvweeool=vE+aQ67-oTof) zG2ZV(-pNMEh`R;8iMjzw++#|>0Ndi{$0jrT0vs&!lxkM0jK4d@5L4<#mrq1 zUjnLUybWSZ2!bj`q|p@PA!pncqtPo?$m6$R|4)_;a;;`8FbYzZbI_5Wc%@|GM z#3GGjMcS-cKnmJG)DHg@=ZZyE^rdHoKxPrpE5M2-;GX+i92zERgg_zn>fhqCVR%cp zHv*+wGArklStQGBA*7{pRusL(!q939YZ)ij;ySCk#qaGcpsf}rd{~y`!pB3#iPF;J z)@8hn66TZC7R@zb9L#r0_MQ^ZAxjQ5oW#=30JMQDn4(5Sc(;cMx#~xSye&QGlm*Sv zK4qEE$004X&!i&Wm@ssSW8GNXyA^%M5r|{a4MLz@=q0?Vgm-=n$3iSZH19$SO&7qu zi93|^?nU=3C<=!%1*Y!&rA;}LzS>dfc$3iC_d6tPV)x>`MLboe;sWKo?LCQ8aj$aTToaqCIcqQ> zIszj2DjSc!>d!#qID8^LE$u~&(q2nvA`MEzicZB{!{wC25f#13HRcj%T6VZcdZ7sz zS=0e(zz{ntdc#DB8Q!es-5j&R5KHIai&<)Q?|HP&NP~&!TrpcQ6~A*;E{!-C>}r>K zOvq&bN9#uY8s1z_%w7ZCNrINOy(7^fBaKypy_y6ZjJpI4%o5;bb-WGHSqr#h6=`DT zRGZZGjt)cDIMz2CcwZHM!p}7HHb?*A=-vPHRly%M^tSNanM#7=CPm21RJsJ8v>!5d zbkc}1us>odKHMM0;s-4h1+a)3_>Z zcHA}1Y#fZc*|eNPjw|2P8!w>h7Ia6uwKmx;8}DxhRk?|U(^?nW>P)mQ)NrZ`T3Ip| zcqmo#rsCayC~aC~5CblSi#9mQZykA@)sY7+yqChEvAEdQD}|%J7I_^tZO?@61!-yN z?$yDY>_H>)!`jip+N_iJihw5OhqaT5HCtVr=xr>Zc?PSR)5Tj#K#L6urp;TEZr*mJ zd7IhIJIph08tW}MK2jRGaP3o~o)PtlV|T1sz~+;$aP5as2mb2r?S^)9a**+-_e)ZG zyW-Y|q@v|^8V~g{%{5=$sabQL@}>&tJtHM;5GpzK>`yb1c~l(Pz+V&J?%^#PnG0EH z`|=esX#N~W_4L+5XDrB$p-fMPe0my*Z~PJk!msfMZ_0SY8hvo!9-we%O4ME{J5sA;)1URO5m0?z0urh`-p_jx zHRq_b$dB*uZSAcBZ9;leT)R_rQ~XPRZ(&dU>3GRFsk8}%bYYG~>RF}+FNsm4Y#!)8 z9Y^={)#@kT=+h}#YI-a`j0V2(}uAO^M<(n1@Qjo%pNeII?qbCN=r^}Kf*I>k|Gp<6Ya zg^@dld#Az&e5#J{);6(Pn%N~ex4#T@ayBfO-;O{);dh)&cWN$Ga#6)XmdTWYkrUlKh;*4Wx(;zMFyqnGU zW_eA8q2#ceZc|SpijWkwS_s?LF6$j%UXHPas0Kwd+-W3A+%7Si+YW3zbh0LIUVYb6>v zn+a?SG3JaM?2xNoSmmweLA815p{-Htto23+s4+*TjZMZnZvtrp-(Bb3=Bb^A1M9s{ znV6xCi7!rMNeYyvlYW6{c8i~gAFlV7beus?n7Zg)8i1sAMq@44ItduJMU?BJ$2O+9=Yxa8qCp(y(wJMIjEx zUGB{$3G@~|#)57wBwKVYT1Xt{Lo}Dz3dy7AL(D9eHmcKBR!EXhdhd~#dGsl74r*x; z*D>bW&SY*nlLdh1PkYmC0pL?J@x&bO2Gk=zfUh&aZZq-5t3n$%^dA;2WKb4c|L^GeTh=r#}7qH86!_E)209nhRDV{R>{xcKhJ^@=2`Nx`fOK7 ze=?uz=rhekW(Pnv|Etg5WIl`j%DV~XdDSDAyvx1lHH*BC733`@^ear=T=m#>@76H% zR(@Fbn^?2etGB$p1e{gMr`JfUf!@&>+zYiP&cAM;cbS2Lx4oGP7%1ky-ojFu6}#y7 z<;mMHTE}xOKYAZ#YFyDx_LksF6VcuLuzqA=-R$!f6w$-{upYOtR*di^grSI8=2j}& zDF({XSk-q6`4qAsay-(vRY2t}ypEOnEaQ!x#a3F&%woGedKC3FFC0Yx=qiL}3%v_$ zYeBXagfDe2_byN~vaKNGs<(>!R1fN9$-*)CJJ0g5ftZ88AFaXPMHe;}{MDpEFxfbo zzu*u5v{)_!n?!0y`386*U%;`~{bk$d87_C48|VQ&)bz{%-NpJl1jNa33LB-6;5$Gm zP@=V%`s`^>6Wll2*8|PttYQS#87#1#Z9LR_Jua}m3V69{{W889VKK|?DUHw$_SD4s zzKy&))jXNH4yVNVRFq|~Vps>M3g387iuX0~tf2+RVI^eitk6nGgtq`plER@Gwc~u1 zaLeI-e;KD$k!#F7%V)9ZffJVY!j939#$z@CZ4>sD_cbaAb)s=yUllLckd_+lOk>}xBKk5vthpA}?_2uLi|9svSpQ>Tt@ng)ry$%^ueJAe^q@a15bcae z`xhoBi?n0Skv4gzjl}da!F&3>Cw*%QTRn|t<58V_V^PHH5UBY!h1@fn7%ZYM7pRB3!)ef}+TAx(K&>rUj)ml* z8B5*zw6B*3b+xdTcWAE@ML0g2tWW4F;N)j~H^9?KQEw-7G7%;Q#-`w+QcO4=CHZQ9G>2#;c0oJ z`KqU3+xYnSl)T4ei%-oQTGPbh(>wUs5?@bG(R{_HSM~UmzDP9|Vu(X5qDZu2qQ5y>jW$X4&)A0-0H?y+a#K-5l(Dg7gk0SNnbvQ1Q9> zXo1>kau<^I z=ZS{?Wa`GT*U{~3cHqC@^RAlDcfaaO^McQ7Z}W}!qeT{x9UIi{n%oN@G4*+|J-#_% zXjOiAdzyK(Riu(eaf^l5YN|dVHur{27t3aSUECZno(q1?>zJ&ib7+#~rU z%|d^I;It&~_}n*7Ky57Oj>69g2<6X(I#zW$HE!ILlgmZ52R!VJCSOM3*2>bdM2AfP3A;i&Iif!c>S^SHYu zU^Z>G+W4w(mVjQf;9DDs2_ZK3Mndn(Umx3GK5RZN_@}QS66YJu2R}n6 z%y*f#DLCJlwh1RQbnw|nF}A!GT{;csr)l!v!&Cn9H9?%Tw5U0HQs=RG(i{!{YK?|x zyV;6gswXe;+oEA}PL@!N+p;k5Z(lpqnzNb_!+u6%*zzrmhq^ns7^7MR-l}C!u*3G{^QmQ$w2tiHRWU6xsg@Oi~-Xy3AZxsWvI#Zz`ZQ zMj~qizkEJEUC*JfKhA?*&kIMLSJ)5x>3Nc?8ybgB29~bwl=xZa5)eK)~W_Sclk&^xc=#B-3n|dVd;2bvfD4Qpl9|1j} zlz%sRXo2Q}nlEsmw0{xeP~6SC&TJ!XMiAF*<2Nlzax+e^hB(~EdwL19mFGv#IGI^2 z)iZIk7W;RP@jqPzg22tS{SU)XqXk9_P5KDOG20eR?s^Nzn60aAxYlU_p3uNw4<%Z_ zoL2b~w`pJ<@sa-iHl8OIu+dtep}&j`c+dj8s-eFY8j>I2?HcevGw|X@{)#r>$qVp@ zjr@(#)cgSN(10hJfsZ!!SB1vqPGkQF^iqCsUe|DzP#pL;?Xp4s+U9-A-0)JjQ$2vD zP0`4v{y#l2JB*whs-QZjg}))JsT+x`b#TW5wv@%;xEJv^G>Jnpywb*h!yj|PfVaz# zi#K=jzieBxJBPb;_K!wi8La&DzHo-vq&D90G7|CWlCo%jjp^G3Mre?)#k<7an)D~s zdx`$V9>j_5uCmS)Qu$stf0`FP;N*6lbX2Y8y4}k^Qb5YWeAKbGL%eieBsRS5SU4?H zf0dTsI4uHN*@d|9v;KG#mmlbNHRv)6*#t@Hg{;c`_gQ~ITg_;&5SQu;$c^%Y{GKkf z1^HoLe__ObvX}Uq_?H3x8)%`C##-rSE@b`xBVa})`H!R3dBTu6BgY>5eccsMP-$~< zXOO>tSjnX#g-8SO_NESOi^Kwu=Ye6l|XGjF)eY=3*y--6~?pRa0YeIPMW z2k-vHUqt<3wttrpGtvOijmQm0@cy~}RFrI_v9?AdgX+S0e%Juc;kb8**DQjl{ssOe zVKIvgd?r1`9!O=_oXAmc>yKQwI-O1|UW&R*+w83{?@}EMN zIH5@k#*I_XtHm?@4Fq(aOF|}!9L@QQ)tv9G@NW!9zj3^-4dgvDZ#Mp7wSOH7d(o)l zgw;AJ_n3#Rr1W7L!Sm*x+m9XULSO+~?#x_u>gQ@HN zPm*26hqL@cQ56fCqv66evaP7-p-1mS# zh&TjyyBE_exEmy*JrzCo;ya6cj>V>wl~s7#-wFL@VXfe_&J|^5jh=$3NAo8)!lHEVd+rvV`#MQ9m4r(Uc?8C4?Ry`1_Ep zJa2s9f8JAf5ia?mzq*OpvX!SoC^uTt9ivv=m$s6gs}?`zA1k7MoD_ExU>nyEjzGow zriNUMt!&i8Nl9hu;hHt&!V!cI3J0CDYl#Pb-m7p5-4 z8&3Mmq3K-K{OZEwMJ}ECf<;EB?kO-0@BYkR+Hr?qCCya*7UAzd^T$6*$||S)PuU`m zES!GI-yLmq5ptcIklU${32cg^4xaU9OdXsNK>kMvs#ePJuko1tLjnTFUQ$=j=H&%b zaH})^kD&rdXCdr8&dKf?Ayn0D^%3)Mwp!_&AC@W4TX?PQZuJnGdui06ZF1(Se}3sN zD4;u*OdPeXq2**lfv#@BdH-J|CaAnqsgE97&>Y*HS{mA4OkJ>8^^5*d0I}*KM17Iz z`DktGXb=(U^pLsoPSKH`M#~0v%U||?=s^`M_>Rp=J+p|~5m9w5tX79K3URqRL|5Ks zO7o!hZ|k78iH2?C;|I0mC~MoG*37{VYCZ5-i**l`QuyIDe_2l~8`ZYXdsKTqG^(XX zYAX-{heowzOdU{yc;*DXk5d^IXGATo8h$=XuxX2h3ziFhD8L z1Zo@A`rPnWM&mf27-QvT+E{tC@lmV@^1yBFc|2=F*fBq+b6#?zBKycy88~BHxVHW-kE`{r8sG~WPZ1vb(KOA9noa1#G z(sT~7xmOQeew#URRT#Zr@t`Y~OdO{)y0{rNSB?0?zswVJ$3W4&Xbk`VgWtIa!~frm zG}L{FJ4IJr^e34h<6vlT=O|2fS7GqRy{M>~e&3(tK@p41&7Nan>FEXqh2`sqesXHc z-v3I?1XR|7=2%vGX=qW9n3fe9btdG8wU3pxdzh4kn&yYKubDL)KmM|WQAZ1_wQ21i z;-Y28anGNwkFD%HdW>Oav5x8nXk&~nUa792@Cym}IluHV?&+5t?lD@p_$Trfm*HT0TR>VAB>S+Kt*^~^4>-DveI)Xilfp|(S@>70X8Zs7karx#D`-f zgufW+DeNh-1XqZas+!;|e}WM27p#@+`OZwbqm;xovUuBDs}Rp{T3k| z`{dc~E>lM&NQKB7{!{8mHGDCj8gTZY1X zfPk)BV7T)zK3&3Q1UYfsXQt+A+8qNtT4QgtkbXh;E$G(PX>o|ly`JgFcI)G9t)ykB zP=>idag41p+>D>A?r$y4@W#X#D0Z9Y;vOBO7i^Owl{4_g4pMhi)!;R)cvQ@AnH;H? zVN8y&6^~iF;Nz05o|Jr!QxD5D>0>h3h7wL#_i$2YvfE9)|D<#Pc2XN+JE@#CMyh~Y zB}xr(&2ExpQ~ucu{A4$&2I^;^n3V7Bru;BYd41;PudY%Z-1!TS@6Ka`z#=iHe2Tg0-ef-eWWvBvenN@ zJ^_7fL38ZGvoy31ATcr7${Er`bdKjFUHAZ1nu;!SRN94)O_NHKjxnph)IvCiFZYL^ z=Q8ld{ZeagkKe{n4({gFrLY@Ded{@?emHu_4X|xBGvw%2u%h?)8*`@9?TY4HTqipH~A0;*OG+c_W^p{GJyTu9HL&~^2L08zp3FAgfkwVNs zBXgIgXsE3L3M?fJP+44mtW*$HRy z#T#Zymr!ReZ&zm@bayuXYnF5Z8q$wvOMjr}EMSgZ%sU#`vyeDsm{B}u$S^4!)oz$k znqlB>G0eN6EZhyFi(xm6`uTh*PCzTT%v~*W*xfSf_=OM&fN5fyqvGlpL8&6_&@nKb z>OzS{(qQz4k%ra5xa8QDOf zeJ!yD$|n@8#%rY`sI~>oQQ6Nmv;;^DWg(Y+dZT52SkG8lORSgnqQv~Lo-?y%9#J)oS9eLR{`9*7dPjCs!@7Q99&7V=b9D#@`pToE%U(Y?9#2=IIs`M^9aJLjg~9 zeNE~?dcsXxq|b$z3V4u*T234a zzIsmO8dAhbj{DSdR_Yk+{{442?a@EO) zq#_=)z(`7~vSaJOf9q(cJQn;+f+R^F_u(yTD_zJ=G(1d$eAu&chkRc(DsTJ2FA-I8{B zP>u!6(Evp)U~1pnQju_UB|p5;W?pUm?v91k+F!+nxZF#+?iQPuVKM2h6y`xfrn${< zG*rBnlMMyR%EMoz?WFY^@FgmaOZ+Mg#^ryP`o$D6aP{J9EQR01>wlLTq9`McwaY1z ziEI5K)q51o>_4Q&C?QW6`kgXP8u!MjyryMAz#~PN#VU_m&>fv$(ZZ@G-jgZ|F;5%3 zPDWV%C(NYuHPTp(@N_0#{Fl_~Q82gvk`|-UdBV_>syS)gjZoRFiB=TnSMb`RQ{AC!9TD4Pq) z4Z>sIH&E>U&&BtO$b)UW6HnsNMdc>wl)-A6qB@@GGDUSh)0m>wQiUS;NL@M4_gmvu7?#c7`>lr9A4JLL5myXo#dB<9 zbsk&6hBh{;jQo;-+H)F^pad7%rG&36D@T@YOP*Lh8%Ub4CsyEUW#tLz83#_WWKW=W z(#~$?5paz+l@^6t6CQf%R&)3Zz_Qgov2rYYPlf}df!QZ?-Kr zS>47zRF!X_I|du=+8ncLt7Y~5BeU9BT|RHyLf~16S0%`aD14<+jOg}v#1UvQb=>~$ z315lZ)|5w^_{jvl<0?u!P1eU&(#;Jnb`jF#Xf>mj+)c1aTVthqx3)Y)K(#pOh!-5Q zdtA$|dY;))H`J>qzX$>Qd-Y`a9zy&4fIp#ux6Kn=|N2xn=NB%VcSo4ZrKMp?Y!gPu z2lX1t13W0nBC2Db-$4`Aj0-4ib93SP$?P-NkEK8v@W5p#-nbqWslbhoI=Mmc`$GCweNUi^+p0 zq>j!El*`wC=9V7)1>kZo0AhF8Pa4`PP2d>?tfP%BQ=7?+&{5N{lNJ*=7Wv4fQp4N=b!{WG|;R)*57IF2%P#1AiOuwo#d&s|pAr8iUB+y5*&(F-*+Hj~ShGL%hQR9XuW%BQn(dI4C2Hq^|RK&IitgZ%C zi$OKbqlIJ;q76bbZMJ%4h}=#g2{my=BZmRM>;$gJ+Ml-@$xiu)`Ex^O^_p)RBg$bqRsJ@(Xtn}neQnKqLrO1N0~%(ZGuK?w#s5f zspMKCpNUY-LJ_^a2`X%ZDxF`|PCg8O*{I3X)Xpa#-pB0Z zLmq`Fb#OkD1uvQeC8#Wyr)vos?*M|wzY$(Ty*gPgW)G_Byv)8QT8{@O)u-oF z5^6Q&$W%{hx;%+FuO}WbMed0&PKOg7>%EMBo(^S-M{#vrvL<4!msuc~VB}#qPK7`) z(Jtn*E{*4LBgChu&UP-IrnUl&?!v}(L0TY<3q^X*u>++OT4{goo zd~p>^ce1@=?OP;IhND9{4M<^jtPv9(3NuxW#jX;IT?1kYj$7p|!R0>1jggO7!y(wU zMXY9d^@x>xfXKU>#Gnsx;U#i;PsMyio880oXtUxAz&ja&fl#zb;$=nwS837a$4lgk z=x@$4Mznd7MVl4=G@crjh5SXM%``3WslHUMLS77cX1Sakh6=8N=Z^|IW@#ovkeKvZ zYBMauVosU-@Gdm->IcPFv+!CcK3@#6(Qego6M`<5S#J>V(J`W##pn>2snRu5Raz?- zBwy%l_^RB?k2+gKc8t)LXmWSZO(pD*w}zu<^TV5I=GDK3Fx@AHYgz%~=}4!-+|ycWHiAHYo-;K5ZaMpjp`S2wyJmp6k(e;k+LROz$%LE5Y# zrC`E7SK;dR%%WcFT4u+he5%#&uG%k+m7@ZGrM_*d45{OHYss@ zWOT!SS!Ro2Gjd*=V;R(a!ugvn>k7Z(qo2#2%jf;JF)asLTiEvtc?gPMZM0lQp(-?m zow`-lc%jp6*6o?5HfXL@*k`k9_YD?k649-$WQ za$k-%39b)jTCw1#g|_*YV(+ zAbP)4f>iML;Da8a3Qj(I0u=JXc(JfR&q)|vke@7fo*0;QA$C)D>Ta|JgKv0R;42s8 z-e?YIBExr2YQCFkJhcNR?xwy|-~C#?7Z$V3p41q(=i;+h*9vrwY z%S8|A2H~}wa$O!{)AA&~cO6z|PPu4#+)c~#7A+sOlC)P-_I*6%ru;XR56 zP>3v!D?_R#x=j|C9xDEmyqJusH~lQ%6HxS;P!Xs7hGW-%K!Ym@iD~mv=odKyRm~6U zJ7!k+fY`6lBR5%tGk%q;qGlWf)m{2cE@;=i(HcDdH<^Dk!0?B>B-{M~)|4qD1( zI$NEe;^+a(fa(LeBh3@7tL0`r4C|W>AIWqN0 zOc7Lzbl}~JpgqDtHM}UQAlR7kGsV!K=u0c_hT^CO;XPd(tpMI(B@n#mXw4X}Es1_b zxmMn9N}!` zzfjm~Eq+)BwMTsnJX81Bb1m&23l9o|IS*;V&|yQyj!qgeCNnS?@9u@-@Pigg1nC_k zhoB0Mz2kXJlf<>^#CoWb2XT_qe#5b?*12rW6tvaR4Uqufb|TyIzmJ(?$Zfa7Ovg>r21FKeo#0UmAfue3ySBX3SIw!4va`OP?`6`GH> zxM%w6TK4jo)0)q>);#E`9|tX9j^bUnvOe1e?M5HxhxMkFmF9XbKdiT`td-lLY@1PT z;;Ze@HgwB^$a&&=9!B}Wngg^}c$Z#aB z?aI|&sJ>&n@>n=qSMITn?O=vG>|k!_xHm#i+l^#b8;|SiiS#6{W25rFdZQXPofm65 zXBcuj={&g)YGRATU&bHwL5Xhf~I+fra9bQHP_R^ zS$sClfA5QG+cf`J)BICId?(E(_Cw8Wnty>m?1!46vj(e4^Bfn=uY@#r9b$Pjl|R)~ zhP$iEdfHEFuG!Abv(gTQvy&zE;xk8=m1hNzRlYtp~HoBllw{ar(ca83VKn*MNi)n8BB%&dRZ zP!w--_+(AtsfN%_3NIcCErV6zx$E)Cp{P2VZ}6HFp6#aaQbS?aQ#nOV;i;O!aCcQ$ zPdm}9@XhB@2Z)Vo4o88QeTIxq`jJCDZTcNvj~AcvcSA=FUXy8HQdo%gAp zUQN+`nxb%bRa8&=rdd%a*$Fn!{;YZSKZf*9nnO`8inkoLHnF8*vrqI*=Xf{Ri7*yY8ifUP`RZGaqvsL@= z7}VNU2pVMJPGeC^)X3m9>0K|&rB!Rg^k#)14quHb8;948b2-{o)-+GZV$B=eT{YL! zR)I9Ed9zJ~b6>B}`}>Zx3s~N2v9CpY(kao6Xk5f&FB`joG&E2g;&`$NswCX|X9l`W z!B0*=ql-DteBu)mP+8$R&Ygh9c?z&O*H(1i&UKDd(x+StkSW*CAj{B{>vb~a`q@M} z<+{Akw2H!U^39zjY^9UV^2fuyII((icCPj{3e z2mjMgg3wb?>A|N1NVDPNLO-I+*@N z9bAC;mO7X&H&6#ZgmTFoO#h+|u1!2h9ZWx;P904Dq7J6(8`Qt_FX~@<-YxYn{FMeD zc_AXuFTqd;)4!;L=|Q^G!SpZcV7jA}I+*@N9ZX*{qzfbc_Cv`Ag)}juk%QeKo0n)UjhmROiyG~|+v?PHa$fXLgO;>Vxf?URs%TRL3 zAeZ^%vWr}{kjrP}@*%n0A(!jqQjioVFS&GUMy_?qr7yWWMK06HC52qJlglgQa*|v= zAeSG>Lvn2x-7L&KPgIO|0e z>xtd4yn9+h&Ru1=%;W9mb2?DHau!4>1mRA&C(XNBJLKS2-koU#I* z_~(F7K!C{= zfhMhG-n_>h5}_x5oIyGs<*%pFgwMs5mZRoq3MVF6jC0hxu#?`^a9AdKE~I>VCMdsx zDqj_!$wZL|bI=wGtY8*co`(gBYI$aCWczc{A7KJL{lYv?d!Snhx1k$WjE_g{?MZ6i9a80x|vXOLx_HofU-cC&3p z8}KJW4DIv){)(YvYVIPV%V)GyR~GuSawTfw_fblhu!?_R+imr zv0Ljfh?qhAX!f%ryNzbIXW6Y4yFJNnmDnwX-6VE<-+3hiQo6K&F*sTh? zje=V<$i6rGS()A1vD*}O8^LY~>{guJrn1{Eyl)+v=t+77*IbX{1@lhdh*YxEw>W-l zJ(^f}#4CCmOa6kkmu~K@6t1K`_84AvM=V3;01{3R*VE9{oSqej7YGK~I@^gf-j-M5 z3IR}{FkILxapeO>YS9T&7olx4_Hjty)XHBzh3EnZ+V;0Q8_*eLC8r_oKHlG4_!6U6 zP*la`+yju2mTW_~2!J6i2~PV`Y#II^^4F;^#j(m(jtf8el~~tI5u*HUJ$EPK8QV}3 z>_0D-V4HiW?efmB5M&rJ2}f)~^OR$JCU@I=+b)k)_=8S&xV@Zz{o zQ^lt|=M202qF4=I+>VNP`r0siJ7b>Mfhs98o#A|!#mb)2nv~ORh*O*qTkJ$_l#R}a ztFDNZ@K-xg3D0^P+!_OJ*>9fK9^&Y)gx2tVZBhboEy*J*w20{rg0dWo1G`W`Px2Hz zbr))wppZeewFI(SY%biS@~BsKp|CLJON*p!6O7e+qq-GwLD6dRg11nna*IbIHJN?E zCJgj~@5h$A!9BK%S%QiLA12u*#QbhgX>1d`iIa|^B6ymL8YmCAgrvN-kHVSrK3b;)^2AZ6et>oe3NH}VubflCjAr_E21L**TU~Vwwvj2b zxeU}JAEC;E@*+pVchAc0aN|$VlWaRv51e!;st3OG32bMYy$N>2qroN!-1;&~EMgcn zM$go`nZZb+$z`*<_DV;KjHzJcrEt-D&$;9`?S{-O*6JL~e7E^HqR03Bc>=vEDEm#i zK|OFZRXoFgOEVQNcnWP+j`6IKJ+hohHw^a04B$8eH2rjL({UgRC3y~ zN_gN`C_$;mrM6c0>YMScuTZUgAwv5q;UAhP3Ca_BBVIUlgX*|Xm_sVQd`}bxfxfzhMvzCBDhn= zC$6FD%1$dH*Z*d&ypN(4UP5y z-1Iw`LW7oR+%K?0;21vn9U5Y0ws^6To}0TDHG#}70nz?fFE(Lboc%qjPYwm%e;ZZs z#N6jJa`56`cMw*>UxO!lb7F~f?&I7aQKLt}wD}3GQHtjULmkEoa zc`^;Ku&i{}s|WPgHIQ=B%xr1Kp44-7_nao!zwWut%yXS1lngR}xL8Q>gvG>fF`6g` z&)qMgq$yRoG}hV?zePP)RC&hpD4-`xD32@6@&sblj2Fn=d0m(pV*rpikM%u0czC1l z>Bp08eUGQd7W~QIouk~PFD^*5$k9-{Le7w>UhDE$eq+{VW zn;U`kGfe9F%t&y`&c?^XDyeUlSK0}-8TEClucFdhP_nGZ+zw^~xi>>zvxUtey$tsa zN-?!uWu=@Q`Yp9r6{V4&?8_H)9|rxV0Zo?yidI)vfx{EaWzYktXAOVn1D2+9L4 zTXlCGrIw(0vyIBhM!$MF`Qio^S#4bD+!*nZ0BG5yobNl^__ob zVZ&A69!w8}cK(q8H={uNV+@f+JY`OJ0o<^Sl7N4DT9G|4J#o*-!Rf`7DA8Yt^HE^C0WN?q`{^1Yy};?uZJpN(RsHH*R8(L3#xkIBG# zUq|I<ulp(=M#9w^s&G7UXm=&H0}BjUlh z->`}m@HdyETHrF>l)}PAT&tTh$P7igw8BPNpP*%qla?xtxDykM6q^e*_nKPMw+US{B{d=c=5A*?*QSP4C%3VS3vAx_)B;^kO=PBiHC6-G_i<;y7%w%RFGb(^+J*n8+8~NB{ z>Y;C<8hX@I&nOM$w9~7>4hLgT?>YVU>0LRqz#y|@iEVObo__cATlBAt*wgRi%sKrQ zA?3`YlMmyD&2(sTPi5%T#9e+K>?#8}^(^*mJC>86 z+1KibIm+AN%IbXardxPdE>uT(w_{kkCJR!p)M>DMmnTf2} z7O%lcX>=a=$0~AZ^^2uSORwoWjcVK~O(x+{L$%aHF-tJBEbe&AR4sCaZ0f zW$wN8Xc_!P7l5XMC(MC*lr2!-z%(%f0UsZzmv#!&%^Z5xY<+6g6#Lp8;`>5cd&$l{;!ncQQe2Zo*}J>P@AZ@{I|TtQ|kOM=3}q>-z3ds(LO$@qz=(snST9{#$vGrO1?A|wXX zY+U)EGFmCYvu-@7@C)O6bOv|5HB7S-Oz&ZDDcNS}gwu(j_hBb6RJtHoe%>kRG&(=g3i8%q9TLmi?@ znxe+^!#`)ev;#u^SIO8RXAuPaB=#qR4;Wx%;D_PS@dLCmhwUjHp2WgPVGbF6r<7(BdndRL8jSx!iZ#f1vT#5I=n$geWp<;O*~>8lpb=t*^ruxw|t}|*(M6#*p5qotTb14bG$G^XiOBozTIV_@a^r!L}7S= zX)qRhZjl&o|B{grdLCo)Z{Cg^4?#!`>oOaPOSFLnHk1)!u5)aiJ>fR`cc^gWwGN=N?So$Y|7njV0Mk6 z1$WRr%Qc*)Z?q(~qV>PVVK->^s$ROQOd~U4&;Ftu@F+X2Qaje5@0irvATg~$^L_`n zy~DFwYS8yOgL@RAVgBoC-ll5e+W%FyfR^X~s|bQ}i5Jy1R=UH4KCf%p`A=npa+_zh zX!(=Q;I5^H`LAnvmucy}uMC2KaKwEjRZ(8IG&zp0{DsNvhs4yC-TsDvur$wVQSvvP z!CgrW(@Dwn2TF#g#_J@4Zt{-EM*peB z!y;hmwHL=phog=S`rpjj=4>cxdog0UpbX_vXoK$aMT}KO^JLnfAM-`f@gVF$tBYlS zL^03M*KwRb;-(qGt=UTy1XoGYrHFApWg(v>m841}NV1eCQ%P<`h9v3WS@^ozws1tl za5KBB6k+aC{9Zibyr^t9We2TpYlpZpQFMdp0B4nOA!hGBbdtI!Z0A1}6Hy8;C=)TR z2n+&Z;|I1GJ7Uz(A+c?fCQKNcf`6_q$E7h6qtqClGI~^tfddA_#}1kto0v2qWyF}+ zC&o@3HFN@HKfRW$l#uyZShs-n5VFz%izEx+@BOjOhNq;AYf`i3s1bu|Oh~QSxnqx~ zTG#CKRG-dWd(|A2lsslcjg(0#47_IS>6dGqURope^lBOK7Qtf7yQkm8OP0a`k>B+3 z7sgd%BJ3yB9DSXgQ1bz2Ev@t#yKQsv8!-`WVywsWoFqIEFxw5UmlYCm?bwJ)=B?GI zI8Z(og@aUbszh+#sVr<;y*`hH*a&*~9KhCaTDMM=G}nEAld43N_I&U8?eF?K=a<>po!NPO^Ue4Dzi(zo5A$-TW!mT^Y3~ji^!5w&enookkKK|z z=G^0&O#7oVKiT`)59@~(;Yx=V4LkHk-sx0(^4P)T_>b6CNN#;ewuMVlbJzdkCxeYfPbXrKb-B`f%AU&p-8@3A_P@8u)%Vl7ol$_rL;uz@uOk$eQnaYHaY?Wi-+D$$VYgD8Fs1*hl}%aat0ybnPx z#l#*jv90SS+Df#U0pSbWDt_ z=$MF!j){+IMaRTvV4`DUXPoGmh>2}PV*8TlmxzgeiG?}QFJX?!qGKXT9rF5l z3??e{{AE@1O;aqFXKor=;D*1yzz3&V)@1G-THv0)zra_fSr%nJG_=46(h3}Mgid;w z#SuERnX&WM{1s(l)CZfborM|tp#UxG@@zbKJGMOCI>VBG4sQI}L9wqQ6IYy$GoiY* zbxOL#$JC_xV*uj!vC~3i#i0S2Cl3xiCP#=4TBq(TP72r;4(hA)&xyQ4&&fGA|8?SX z^wOdks1*VPML~enVXP%ySe{#^A4fs}JURBM<496v6(;K*ESTvyk`FUQc~kK|ie0Z? z7V4Ka{c^E>`AE-MrQc=i7i;o35{G^p)i34xrB%PI(=TrQ64x(d^h=(8>Ci8q=vCzC zcZ>APO8uhhmnHh;Gd*X0@;H(W`qOUxvPHlAx1Q$`{q9TpWwL$=>z8W%a=m`}Fa3o~ z{jN^GtkEym>6cISEOYg{Rk-l#IhJ{jO2h_sjdHIKYt5mcckeAY9TSgk#Sw?aBB_

rOEn?af|D~ zt}(a0yP~QHHT)>~n9h6|*j2_?EwmKhwqR8j|7n{gKckcXrp@BWxQ2h)hBK#Hc=cRM z3;n9pTuar8lgT$D;!O(<%Tv45u&OotLZVYYADrGg*%eZiV8l#+aZtL0zc8!TQB0lw z#h`==zUTYdC9@1tof?#A^{6f-;tDI?o`{j-SIHc7aLm9i7eCrzb%}C+olKykWCnKC z^38{xwIboQWCEQLGq7viZ9ltmJdx&=L5~@4?W$oscfMtGj-GKkU(s7LU5wKiBP(Aw z-!eP*RrB`1e9MFk7k@#&d^q1y-AMCiU{|qUmcl_L=yho!1;1KsQ0<-Mt5v*hfu%X4 ziuW$CROh~JKHamxQk(mhdHciyOU^JE0he5fl?x;H& z=#sNGaIwl_Ml7il-;*rVaq=v#WsHa3^m)55$u3o>SX)%}DrTL>9dz3yYsKg|f z2Br?ET2D_b>WYLFX=9HoB6ax{_eLam+>#b?^-5GO9{YPWmmE?ysvehf$z7a^ zawj&oJ#H!S96<(bi&i;s7p(MPawJO_Jt0*h;-U%+Vnl#6*J}?8HMSp29l`6#NK# z{pS5_20Up4c=1u}N#4Rv{0ls4hf&)TCwJ+40l1W1IX~``q-M7onB*q1$eK&-c4>0B zPjSoW&?5aIQ@hz}{o!mTR>At@aLgmc*djIPmO~Ldlp=5-2HBcuxJz~SNMWzcu7N0F zdL#9g!+qEu3`*>B$+J=ERr|GGiJu%%SsahL-Lj^2NBwL`pX!fB6g4P?QF;%?QD)t0 zSTAdh?CuGwe$^Xe3!@qi4AnGY{4SRI6c1b0jM6=FSW|;d3{40{@vA;n(Sxo-mokOWXLr(8=Z`W6u0DOf&fI5WcS%(xmyV;)Ig1|YOk;3 z%@ZrE{HgjeBl)Ho^$vdPkLt@4f6A1G`HNqwyfiLF`xH&>jtFL$+%makQftekmYI`!)P7e)b%kZg z)b~(~PPXud_i7igcWH7+-uXh?Xu{E+3Xqyz8 z*9Pw}k8P-|OH5l|c|~~E@?~&U<8QC;*CZ2ui(p*mn>ihM9ck3eSoS&oB75mX;n$F3 zx$pEL{`ldlQ<;%y;@0m}eK`C7dmHw&ziZ2K;+8*F-EQOW{l+?`{6brUuKdSryWwXJ zG}MXBD16HS91?rlTbG-d_*vDf4g8R^Yzn{OjJ2GlJG;c{fMebuXBR&_(Z2f13%dLv zEHAKZpmWQxjt+k2(SkaD@KnL*Nq;MMe7f4UKQsI1{LJRYvHPbNj^;^K z?_F)X#>#*82MCLh*LJF$f4I%Ig74pqa-QicDN6hxZkw9RKiq?du^qO$gm1fT_b9$; zR_!I+7A_yfJ8rX8={X}`wcV1#FFV>$!S9}D&q-9?VH-K7g0u_%V`muD4}Cg<<{Uk7 zgz+nw-Q9kJ#qSl zg8ZK5ysOl3FG*j#)Wepmy^7Stma?E4fx_|N6{wMb6qLL|6tjLwV*y#xqG5W6Dp;=R zx`HZDAgeu!SAhbgdV(4hML;6iObb;ITvSwyg=974ms!6YMsvgX*)ddvEbU$(4F2@L zS<9{o$dMk^LyAR_HHLQTnblyIDuq2FJNhYJK!;Vo)=YarG?_{6h|;G-VlFIYAzLV{ zZiu155RGn)=)|`?ms=9=O6n@6Mk7$QGG1@j(CdE1?`K*x5Rk&kMwww%Z6y}h*wQAQ zFt2aEUC=MRUvfA4h;DaFV#yAzl02TUL4CK1E{6P4ga|>c>GI0~EpCw2gE}HiQ&}5? zw;J@$^C;cjiaY9$2o+1@Me{;LGf^-UCq=|_(!?|dXlt(=X`7TRp*e49kOBBcWEzlu z8a^o$0wSitR9P2D#Nz$3-|s@Rf<*bj1JyKiw804sxJxh=bdH}0BN!uI za#&T|%pf*;7Kni~e&|1MRMwi%QLsJnlLwZNm&pW&&`O<0DQna(`mafSGK;4Xwwd%@ zUR!8hbF&#;(kBO*Lh}V(g-R5h!=y+=XH|(3FtC^*;B$alglLfj_66smEuu2L!#z}A zmyGg^AqFkuf|!zrhBH7MvOcP~d;KwU5CsLnn=Bdv4bcKIxxJVQ7($vx)H0Ka2hT}D z*3|p?c`L%HN~tch_%=|fKRBdhklZMlP)9#FM$C4P9P+C%*)yM^Jk-nIU&%_)0}?l) zMZ{u)^qODoCyIMOeZPubSr7)OhX#|{D`XB$2DfasWIk~#hEfdy!x2gp@&-^d43HC0 z03IRPF#FAEt%emKLOJeXeTv*qWY>iN(SRxmt6*2R6on{2nivByYm?J+c;O_3hdF}> z%dLQfN!kr-13W4l>>Nb>hLy>>!)id(t z6oF}^Nzw49Uo5YUuMDd`*)4<>qMoQbGMgnK>FOwK8B7YQYfVp>qDcm6hh>35TbxuN z0IT6>NGJ~>P^c#tqlfI`uoRH{p|$!fY%~&P@l?^Jj%Y_`eMG|w6l!oK37t- z?}3^zyk$#;D{-u}aCa_e&atCs?YqdSW7=~dZAsEV$m(*=9|v{oOMt4JU)E-Sn-8>Ev-rQSv=!cV z`fMJ*Vy=Bj#!PEPmQnT+Uy<)Ly}l&b3eH?75->=iRVm=*!uoFoLl;9ab?D zCNykVn5yDiT5JJ1`4d*mBlnlh=5Kd7^CvkB#>Sp7 zWWD0|fO1VN91W6hOH7}^?1iVMTqQU~^F>SA?hIuZxgni{fQ5ZPc%&WySb*8OyCE$g zU9@=ejZ{(4@=)_AEJ`B9AEURDNQObu7{x;8DBTLQTbdd}^?kC()T`pt1tb3&l?4

}R)u1;CEfAtop(!C0d7;}@94E;^@*FBi29|}S46Bm6rDrzE1Kx@;gHF)S;M0T4WwykijRq{dMUNo>8~xKR?5L1}n&^iE0<$)vJSiS3gX z0zHXVl4gn?kHxZ7!j=p)(vyV+++X<03$8Kd~jnj(%9?F7lCJxfDA!l zo#zR=DnWNNEQUb>9KpnL6Zi+8)7%B#0aD?i9XY^~08E5q(&iHpP=HAC|Is_isY4(P z(@KX`F{a4`DLVtp#1YKb6Qa4=!IgS%iA+5#}K3dM-+gDM!G+8G+yx<2H z?r0pfr2A&2-XM*wKq6@bk!U#W*y=ErHUexp79?U4Z#`T$IX_*&wt8&~IJpY!h#ZN4QMuyY+N^DE*mfW!Sh~1Uc6m90q{;Tv-zOuC>YyagA3m;!+jq~d|t)2|V zk9S%Rk23nhwdK}Td8SBYiD#EvH)QayC&p&+ho{zG%LnoRqtpq7E`IE^HNcOZvF_)a zm)NgNT({NUmiad$%Kf|RAIp3R+x+07OZacC-!Yy%p_R_nFmtdNLzV<&7L7K%77Cm_ z1Uf9>dAuDt2w78mm4C>ol|{J#6yHHmNRW^1eXF*|+_vW35L z$H;1a^iDRiRU-$q%_nb0O+eyYdZ4U?-+LQdm-zgC_H@xD`_Aq@k4;mQ zq-ADj-Eg#ovp#yu-plt!$#*}Bzq&ocnfP>x<;W+a4C{!$lx<~shFc$}^;9e>IIyR1 z-(w-MFo0hV)E5RszEMWL#M`F|-fYPkHjVFG)^H&6{<*|i;}TbOG(-yc${*UYENh6D zu%aWxKHnT`sJKG#mqP~*Fd<@14uK+ESRf%gn{`Kn@cV(wbjy}x1!*Way9{51?v#RJ zfJ7rD0^G?nuC+V)t#YH457boVmkMjL-4D){lrYxO+`V1VFo{--&D^oo{Q0XIa}zIL z)9{(=99GRqk~h1vVmR`0Uv16V%Lt`CzBc@`-NWCg+D)%?ls2S6E z=q+m*|5H=VB^lHC(M`;exYkv(eNjeh;`gDNC55;)-B@$~bNOlY@+~_p^Yhbd%y{2Y z6Q@DY9X7D|fg~}j;Y92uv|v=2yDm2P14`qBx=q+U7T%+Qe^0e#5^;U`x;u%^}|;^kA4gu>x^HNk)`R7|EMQ zv&Og%y-gq5(AK1(q-LfMqET52=df{F2sjK*YV=8`j}BAC!tHo!K+>~G4kvQBcdKq; z->7j|iopIvbs~lqgPSFQfpzzwc$fni;gAgXGHEj%FD6M$p5l~;607y_v9tDW)C)P8F?1$?HyzMbqu>k+D+YA*`+QsbPzl1HBr)Um^=N4TS=cgC^*i zU{=AmluD>rht`5RRD1W3832mIU;(uTQI%e5W>@8tEsI?cBn~RvGE`kl@Q6OY#{Rmb9N+RaciE{PINxBu=DW)`#Hf@u@EM5i~4Kx+Rh661S)x^et zWlDf`x)+o5=Ii;`D!$-YNu{~$<>0xy@p05WXY0!n&7JJd0^YLUQjs{bmc3TWo4<|d zOY7MWv-tg+;F7a{xuH1m<34sei|@G4QIU9h6Z?4NtPeWRw|bpzLX5KE*875m`-=4DrgZ8r zSKCrGZ@qhZVdC!TMZcV2RcMHR{;6ngj`?2j zozhg9TbF)Rg#X2fr5}}idTRJQiOA1NuPZoD+UKv7_E^r7w(p(N%I}{i?YH-p#Xqo3 zSvCY@^xjpTYFy&0ca=9SH4C`&jmlKo*5hwfCXT-`=BXEEHYTY$bPvPGj{GDSjO;it z%oc{NYn@{gYn|2i-c`8l$svryEyt@@3AEzpJwM)uaQ5-{+v> zOcR$)9*zMy{JBnk^hkDo;=}Fs?-!e8KYn+5*=O#yUsYzN&3_~O%k6T+&y(@K8y1?THC%t}AG!I@U+D>I!H!H}6DON!-jbfKl>>R_7K(jL zvCmPr@4FN$qGvZzY%RqWQLKq#Bff)RHN{rbGupT8d+;!RQ&Q|x_U)vHv*_V%6!TH+ zPKr4xwuxe!DfSJDeVJl^ChMz9Pjy-YuA>H97{qkYZ3DHLNA`v%22DYlwo*HG+Z zYSt)%coS@7VXQY zXY@mszB-E0mSo>rO3e^4dUg@TUZ!U=DfR}HM?Ycdd!C+MO|dG zHzm^#So(@7<`T~+Bkk|^y+g&&hJ9ZzJ)=FxzBv?IPq9T5quu$wI(pYiv5AO9qg~Da E19c#Sa{vGU delta 111733 zcmafc34Be*_jqUSy$MN>O@auC7X%53okTWE5F)X}z63!ol8D%s(5i|x+%T$&Zu+IP zG}>3Kmg=fnrB$s~tEzjo=w4O*pL1s3yEpXn`{(n?n{#H)GV7T$bLY-|XVXr0dh-r; zpha`*YOAiSy|pVf-pX#_Yi(&6Y?X8jx0bthuN>uSZ$`cK2ne;wj(g#v(1t zh_NoE##lWQ62#H-x{vi<+Yk}eTB~dQ8<${pnAw1@O#pdOV%!bgU!2~{4XtWzq?Ml5 zz*+_xdM0$S<|VcjX$KqB75}c`hSjlc2FnxdXv>z?uJ{O1H?w6ZaJ07)6C*aI2G=Sq znp`lyYHe5XP=VILs@L7u%1-sOc65%g-cLxgUg{QQ9q!zMMOulm4Xh`-`quL=E1gp` zy`5sqLbje(|IU7_6-u-YG!JCqTSgk;mK#K*we}T(tAcc^Ra!tm+2qL{w&qv@>)&Kw z>v&uw%O~ApU`kY5RwZ^dHFB-@;+t7!hdAqe^QP9VxEQM>(bu}%Ce?bsZ4Miv3e%;r zC^4b~t)CKmSbIA}vt}awG5`8?CQZvPnpzM)GkJT>M6FNtsGW zs$=EGx3n&GZ*Fbr5Ngfu5^P=T(a~o{;pD2dov9SN+J{-?oqX8{PrY@phIUR12r8JF zKWX;7`~~d_%dFVMLB2kNd#Cpr*xQyO%fpTG;PK>f#E!z7SR8iJ|mi?{5 z4s}G_DBi^C-6O$zrAxSVpp~z<`E+zJaHV>hG|Ji)+l)negw(Qr?AXFu-X;=iqK>sM zH5v+2Pwf3!53t%LMs7-N6IkDor*@MkPqq$ru5U$j2@s!s07StZ2e53c-ehY+^H3|Q zZI~6(sWpqn<`iQ>gK9&C=Z72P_*ze`#y1himPXgLvO7dr?VuHYiI2AiB)0QRYSdbdb%`o}Oo>&Z?5B5{yWpRdib2DR*ls#zRWr8p3% zVTWyO)$7tgpPfH7-%3vi5ornBhpGeE!y!2WWQAGlyZTyPTGg=<+QqUsh-qRy);iEi z>lSW(+@+qU;|_wFOA^@!8(`(P!8};*R!9|ZCB!DOW>&i{k=WB%C&)^3>$4XA(3wK5 z_3b-bvs2@&hkI&=E3ZyJ6DlQfVK8WimT1OcH z)_V!9A&22shm^)vSoe^GSVs{o*}B%MxmDiTS3J-;B+v@z;<6g_2=bVd+EzfvhS-Kptz{`8*6B1KzIK$S zv(&MUwGCmdVK_ARRCRAr_|uximkmJYKu&uFUlF{bv8@bLeR^-;4RS8)+`G zv1uQhIX3o8xtZd{YVl#_E$)%xSL!x3Z<^nWOU=LSv|k3B1H5VVPK+{h%e`pux@2>> zjopYcr+Tr_?0#l#8{0I^9BN}fg_PaM5ne2^O`_Ss#x@6_` zSm(g=CbzNTfo31T%4OSk-ji$wdlQp>eb}7t#WH{X+4S*ZeQ#!%t-M(O2jk4%UM%a? zre>BG8<5xEEVQw$=S|bbK1eZ_AXZLYZ(yCSW~4VUd(6*fFE2JI@p*HQjg_@Ci@aD) z|90j$8(Z_88Sce$FNT_9yjWhMW=^rOUv`=PKJu#?164jx9WA z`gyVOGcTKAUMxRokXg&dCcS4a^X~UaHZ{%}I&6lu>#+nW<7o69{|`HxE;SZv<(irMg9JG0D__~RzCnK{qKo(?q!da;ml?2({dW;YvK zkz_`BvBy6D#hl~C9{)SbZ0p6!_a+6J-M#4EwL8tRUTpt!51L)Q*ptTt&30bwKytX* z(Tg3-9BU@p*ri2g3orI`%K_#L8!PT;-eqIukEfdpz34N)PBSNYv1fa~Z2sY`nP=ZS zZ#M9zx$CYqOKfapW3#S}ZT#4rW@9Isn6tdtb9Ysn&222De4JTeqw@mHnKriVakH6? zy_;aR_F{*_ZkY*Q>_}Q4bE1tcZefnHv1cZjvu*6ki{@l6_F`;$xtU?3`SZ;i-txY< z|8+CnPW#%=O!i_gMU=G*=d!v6PO#(>P58TWqR(uYS zf$sp|r-SNP4-cBISAuP{#^!ui8%-TjCdu_hZY`@gw+ZWMt_w5-at9;nv}y4Xx`#X0oZ?sKCVb@g>EDMP;+wnk7@K*4io7jlp#xb7*@=pmjYl z)>=0#Nc=Fcd3~$RutfeBx5f>tU<0jhhjsBqvjB9~f#Eax+KJY+j*YET!(*&Q@V_E& z7%TC{ln-yuMtQMmc@bKr+1830Vb#Wgj;gYyJKtl3ul3Q0PPK8UVsuaP&MHUwT5pbQ zXpJ11!BSMr80+(q16aB@J!51zOY&kPM+I6}M&+`2D`j*qmSfEt*B?0Hm*3*n#OgE`2xZ_&B$VTgeMW6Ix&kGgij!R!`Lh~op2w*Gl3r# zJHVeszmfFYi++pfHynShs7YCD3PHUHl~E}l+b-@mUVSX7B&r*tQaHtO+u`DAx%uqvP#BfSpz0#u{p%omVU<)_swZp zR!Dx9wR3uw6>DbkKajDn_127i<>;0!sUmL;0(37SK%Wx=^!6Y?XAuJQ_8>q{4g&PA zAVA*@0(8tEKyM8KaK$h{#|i@UlORA>3Ig<#Ai&ui0vFl{2nWf)lmR+A5Q#nw1n84M zfIbBT=rBOgNCr4b0#-`~IAa5rDg&G{0mIo50-X6Ez-ets)!IhhWzOn0A>|N1O(vuH z1`G`+1ZXiKKq~`5hz!uI0ETuS0-OvWKtm4!T51T;&_jSW9Rf7i5TLz>08KjtXs97T zqqwBJitH$$Xlfx)m4cQJFtp7OpuvU!Z8HRD>L5Ua3jtbF2+)i|fc6stG?fsP$N*zUAAN=vpQ~fi8d!$!|FlhJK2_TkoMKvtYvlA<&d`QO_zxLUTa(( zb`M}n-f~rcwBiV}_OEwUyH|e5#M{e(JkF07RX42wg4#b4c`cC=&O@vJSq;j5sm)x~ zN7w$u1g{0q>Gg-17_ktbeU(R;csBx|HJe^#;+uLP>4i2txB8VTkTl?wOYD#5+12lF z0j%^ZSM}ztFEFt`1gLs-;?1fzZv){!mIM0fMLno`+IArO@Kcv~^0MBfy6+B1tn3c5 z{dWDutehuYV&+$RaCO&*fokFwSM`lYUS`%?hg{X4J@z~k4dR%~I=#M@_-8Ow$_I}F z(e`Iu)ndt)IiVEuIhGAon~TQGGw9e4&JUh_aG?! z!XMCeBUpp#Hq}6{J?s+g{?P-g|2YKMH#?y!o_&K^N1k_8?|CkSi_*D}$BWND$3#VE zV7xUR^uK)sNGmE`)$3n6%`D#?E>Y`}FW5AP+9V3lQ2|=_>IdHg{gW5Ds>h#wiCOXcUDavl zK4+r36bL>I(OlJ2J_7p7JpnxxuC=Ys`xxkrk6q%yhFVm0*9(xieG+8h#;2E<$ej<+ zt&2}H>&u^9)$d<=6{>x$tNQuNP#x(5K}6g3TFdGqUxA1h9&=SM{RTSBC*vXhXg94z z^*!G~eCbwKb?+a5@uk(S>bM_)aZMfw^}TwWS-*V}Q~l$$mzc;ags4+LUtl775J2zz zdV-1ISbz@y9?h*2*Ic4*2ctoC{l7rq^p{-Xt)W`e>fdkdWSeoI94G_IPi{h5+Iz0* z2XDQ=tkK`ZJhPZVcN~%e1PN2Mw(eD&0ma9Ey2Q>Rt(AMW4yZVoDU)lvQ+yco@s>K^ z4XU(u?xD3Xy$eTtpBC@#>4*57sepg-oR;iP4?z5>e88VNqV;z7tqZs%F1y5{g{*<=b_GC))J81@|uzPnvwNs%7!p4|dz#1WUcx|}t1XU766+Ajvez}Bo5 z7n|z?m=wp-xV8Ma%e|v51LLr$Ekr(*zCg?ASo}Xd&Ha5x zlytKpQ10u@K4RkKAfSBrDZRh@dRI*PCmQhW)p~RHN8J(M(9bch-G`DfZXGnIdu|GQ zlUYA4lg7hcnuaN#*8y%EtnOYJfLqV3aJhYYF&Kj(tyydcT_D8x;<{=jKk;@Hs#?7qR3skn}je-R6XnQF1 z(Pv}b`C|}W(G}2(&o^`@k3+UCzq{OEWezfNUq?vT^;R4AKlw=a z3*6@lkY)MnE^GYRrf&CCr28}y3V=i1y}c0eMoWQj+;j$`cu+57;WmA ze#TvQ(T1M+5<=)TnLi+ugHQt>_(?&iH$u39XO<#_j+D6*A@r=ww-Lg1hxr#mxd^rJ zg`eRF4MAusLdy_Bx69n`3!7@RL1%u9ks~nDw-)?#LZ~A`=%$(Z2%(E+u19DALN6fH z1EFsbLeI^tUmJcR5XwLZ{Wr51Azag#+Yv%9&OCt-x^?B|?+7Mgq{|O}(7Q8p5JDf& zT!K(%g!Uq2AoL+Z=>D0yKm4>oC=nra0?ly4g z{WMu!_$flDEkfvanxpH&rXuZwnX52z3`RbK&=iEeK*)tqy?XG2E~=S~5N>&yg$SXe zYHmRYJy-J;gkli7h7hj%%*a6aL5JAvk5Es9<{^aJT4wp92xcO91|dI$ZXpzgP@5q5 zLI2krfzVQf?nMZlVe@H(<|1?vA@q#RfMEEkhfp_!8Y46Xq45Y=2(?7$7()GVQ`h_v zLEN4)8->6RdfjFwLg-_gWe61`^bkVmaGR$P!ksAdZ-j6c%8U(#AN0e`VF(RG=x&6D zAoLVM=$@Mw5Q;*mc75!Ba}ewdAZ<07lMw2Tag_*-Md(F@x+3&FLhTR=4}%}vRWf@a zgf6c+3!xSW?LcS-LMIWr3!y&|T8L2daQH!A*&JMsAnqKQ1fd^o?!!2Atj+TX;ck)X z(*S;O8DVxn2p0zC1cY#uNg2Ma_p~(m}YXm>Io-hX?gliXbF+#X}G4~*ZYX|cjLb#YPwFvlGhEM`R zfe4L72v-&6YJ_lO$8;k^n>yx~1Y&YfWB9>!it`K+M+=>Wk3N z2;pkPY#IqaxSTQvAQXbo0)(0(v>Txygx&{e&RV^!c+%`DgO(=l_7$u-6T4>VL0cZ= zA?`)1Sva9#VnT@?;(lQbYe9G`x8FLJrIPBttA)6iu4kDFFZqpyxPRKf1}i-6JxDLy z$a*V${5TNx;U+JAPAkAOs}vsW-nE%6Bhp|2pds35kd^*|6+0r`r?;Xr0y&jL?hD)4 z1c|$|x3f_SeEvaJ;H2ujla)I0qq|gjgWbPB#3m{(^AWGC3y-qlDz^7-R-wSpA7`5# zV#LKski(sO*vl%t^a-{_fsOXF@d{k?B%7tcx(8StE_0u742n4PPpG2aPqWrCU0|ep zWi^|u=x-ikGZnb#SvG{gQ1=&Z)>FlHIn3rM@YwSVe15DM_tQt%UlJsVV&31N=7X15 zKa~z@K!g7Y)>$m8=H09<3)+eH$5~(T{s|T%b{uC%8s|e#S?gO+R90FD3)rz$vDq}y ztgOm5yNiQA=?#5o-svu8)z{X$U9Ymv;25vai)leCF1-fA-o00k5d&Xm2O8sqew#3y z*-==E6ox3kB<%G!u*=-{r`}maeagDxns}7R`wN8qae}=rwsz(!0hY)4VnP=lBMzK| zguS{^jEm%AvCuGL-1FaI@eIKrk<(Xe;68PVb(Od~{4^_9;Nxeoafs@`R`4a$-)GHK zQrTIyQYB6J8QgoN#gF*OV}4sz5B&4*it6`_zNrIEblIwe6K}_*S~~1|Mmvd zM*FYWflzdgoOPZJj+1D&g@?obox9%Gur?6y{mqNfMHVZ*1=d41f%V$A?0{JH4-eF` zO-0#G z{2(sC4u!bOeE6Flq5!VDb8GP#uoM~!{SbCvo)vEogMR4a&l|#)%rI!TgaAHPfjjDO z$Th{*smH;D5x6vvk5=IKK^*!F#r6#03l(@Ol;2?DLb9fY0IYXtTW5^e*F%dDFNO2h z#hxd$V(aMIK_a6e?<l=yDF`#kRZmChc5yKDkLPy)#55bV2 zkB(y>J#-AwKgSTga}0;75Z!UaJCTiOO0GTfNQWM&rSFb(Kt#r4c?;ej_R@MAvVyFA zm60MZ7IM|Cj}aq|$3p#Nv{jbHTC=ISh-eLoIX&deC+=$v1bvTrsuy;??ib-NL(R^Q zgM^ngtr+*ewut>Y#7%9>4~XT47E&7vi8&o6tr?;KQ-(fo$H7=1O@tcSytT1-G7;20 z*dDkWwdV&ya82Q?oosV~9CZuis9Vv2!*u%YYn}|jCYvety$+ z3&{O57s|Mz3*_qU!A79i!60k>RMtW%YvLr+{CqIZ43+r{@5XyD@ocnKM4NQt^X?$% z$!4HoKoV$(uhxq#zg?rmC&>`sp%;ZNDIJ6&!MJUpWoy#?UcdIN8%VFZZGJu~`;Mr_GQ;8Xp z%XcdVAgCh(78v#2@k97D75Q-yk8-~;6iWwE!UP$M_&n^dbEafA0@D$-E}e3=4&n8N2Ouyh*VufPP8gT*JYN2hyf zb7u1SD)xL4FH+!$5IRgTyv;Hve0J6Xtl?zMIRzF(QH)^Z9xSV)hJo;6lF6 ziB~V;k2>+0OL(EgAOB`4=TgX@%lK=D)uxI@f(5BJOC|w|3*F)Y{&s< zD4L7HEDpZh-`_*0fj#F*BI`#^CRI$|3_Uqo{QV+7?EYX2X6WO8`7p7|pGSzN@>pYW zVk_^v`FR*io$iN%tcUR!gnI&LDsc6WA?!zjH|2}b5GV3q(l)tY*v4TBeco4%daK=2 ziQ@6?ki8r~GOg#uy)T2S1^e6cMBZ^d#(jAQZv;E4$H5SguhU`|+IqriPJZ|yo+WYj zt%vz)l>~)r;6C^$f5pR!6Y+z)afHlx4lEsRn2VDCf!^_lp$r%P#}72deFvw(0&|Yr z6Ic>M8b8{tFk}@E+sj8Vv0ymV9B$!>xP2fjV+6G9)_qVRVIz59N05O2AxgmA6by0G z0z=%gzz`R`7~=94!)~OhDYD5O7-Wze97rmc!QEsQ20zKW!47LOv@&eJiDm~N2mhq2 z23&stY%p${IE$2RPLN$~g6wL49z+X}cLWM?xSAgkEndVva)^Ut2B7kK{&@yR3*l6) z)o#8(;pE>8JIvSG>B?F3djacuZ<0}rdx7G!BapYH$za3#zX%zaAJ0b%P~y!k-p9Vxct8zRIH*f~x=g`x;MIIQ5^xH?Xvn{>+>Fg7nMZI>BekxV~@kdqt-c zyr&rUxYk1iy~FPjL%V|p9GdoX5|$(`y~i^}Y!Z(Fzy8cAo&jeW^H1}xl5ouzMzpV4 zA2T?I-pgcX6eJTk*M#2)& z_Cwy9-<2eSR+#qrALmtllkwiD7=08*}1Aj1LYRO`|oGh{Dc_xoa64$q}bRL-` z&YXo1m~tQ2()q`*^7;ty54#J>{!2g9sv|!CnEUX-P8q46@J4))k}&{eT!V34=K_!7 zrB1Sy7kCUWR%A1zDpn{GKjjwR>?9;#9A{F#Nl|Z587oYZ83QGrj8PlBd)=sSP58)% zzv`3|@HubBUzQ?7r_Z359QcI!VQGlT{}N2|-#8i0T;h}YmrCa)rPD)x<5#1ZszJYG zN2Obrc^vmmmNlp+%Nq1BeRkfjjkp%Ve0aQ*2iFL^wc=@M^H8lnuWB7S7~w+|o~!a* z_b;QD%E&aQP+BtJeg-d4k|!$3z)6xiNlC1|xc)6q6_Zr5gjAJMBpPweo~R|YAW3|{-$Di4Op&eUF2}PaD}(z-`k|E_&18|OCl>4 zu|I+B^b_g7!=MFO!QzFVcq;epp(?ZoRVZU(`BnZii}%un3EUdutrcBMCtaR+`8wam zava3Ckl+IqasQgcdwv1`WVVAC*VDYDhnN+wWiUz0A*4ElY*W{}1jWGNfAu$>%O3VJ z2aD9z@HWGOoZ3wTLYjb)AxpDUDc-Jx0W%4Msv=>>W$kW$RIMoJDK7h1O1*~}G5kX% z;jEHyriW~g&%X8SVBnKp*b8{*2Grw$@AMeXQ)CtXt5|L-mY5kHe+C`_u>{ExGZQ%C z6-Vn75xs{`k1M=w(t;TPckporXr)5jy+=HYW`aOWmV5iOt)E5H0Uw(pSeO{IklB~9%1RuV0SE@8I5$%i^7A4Nq(lU5tDmF_Kam~dW$l39p+Sg|9K=U@1_P{?)|HGN>n7oZ+T0K2V9{738Mo^P<||H3^z zab=SH*k#S%!8r0YILZXi2>D}*rPb>!1_lJ>cqip}y7=dH79w`;fny-!s7`$7vCcTz zJ5IxU1K2yV1GNS01u2^H3EY&=?GAN4wn8t#9Xl)STsr?v=?uCbCi|aBC%Y=C(bTgm z4$htJaTyCwFQGbFsFo>;IzZJ%is*2tqtnkaf0jnQUSxDMLK@;zBy7WQ6^>Ei6xq)) zSw2+41ak_Ngbmyhrfq}$P7s+aDqmziP{r4yJWUXe@u{NYX-`e#F$p*VNSSGT1}eH( zW+u>rtj~}z6{8U0IntowX$o*Rh^bctEe1RdDgiQaktQeKPaA0+*%2?1bhy}Io02_i zi|5s8(v*#FthHws9bDfx);hBb4zBb6!SzohbXT4(yDQ`-%JPkdx@Ukoh}kHjHM0nIU=?@J_y8cu?mA_yJNC^ zNQen$uWFNlSiWE13wxu-T4@{DHHTcFAh~B8a#u8f)yMOf8}ir;*%l8rkqZ#sJVQCKpH&S>nMV1a^=mn+#jx*eVwpt5r+T_9F?Y3GRpQ^|w+vKw<^gMB{oz{e} zbCPE#XwCU*MSh=6PE#Ocii*-yEK7vZk#<>4PILl@zoz7behJglaV6qt2Gvg}KA3e* z1KIG(XwKIw&fgOu%WEX(DhKDi z4$e2jfb(;AA9Q2b zg+@nxB$JQEkw88M?;?lDH>$ddPC|7ZOV!%3cV*_NmO%BaA2sM1-a0z^tFn@o?^PEM z=q206`VG24?Ow7w`}C6iRO=-jh_(%3U`?p4ce8%H)|7WqEX$h6jbh$Wu_Y?Dwu)_A zq{o(=`nd<6sMyMy!0bL=v5ZkHBNfZ7FJZs(onKq?brA8DZt~TN@ID~K#m}istrg!# ziNk5Lgzr%lyOpR%0LQ`AyPwvHzpE&58O+~SlqYOT8YmzedlFv(#LM(DISC&A{ci5t zTUO47#wkAe~gxg68uEvD-1TVddqR~{BdoPbs#QKJTbrshQ~OR zA8Kq+LPMgJjH4m3_Z8Kz=>#5M(OXVz!*J#+FKI8WD>eoUc!W`o@EL{3%tS zZIhrt`-qG0kp&V(lVO({PgY>o=Sm-h4qD8W-ScCW>&HiE53tvyc*-mYpv>-esJ!Cu zvEUEh3gQ1MwHE?F?M>aHQ<4yX=_5lJl5l4twW1zRcIZ~5LQdVCa9H-@p zfn&89Jl#o-Jp!FXAcu_&2$VZV3@7+xCoOIXv3yAju2oIiJn`lPtqs4=$uJ-v{Eroq zVR;P(HW7>;6oQKWyQApaI%y@F7qiCvs1j7v8A^SGWbng%sQ1KS7rCwX)KgX8ScP~{ z1)HL!oK`Ve9%I1-h{e5Aex;A>O5iaMfcKi)i>s+%T|baH#nu6j26C#ZX?@sV4le4EzuR2=7bX8psn&ou>?`{^rn@Swx`bW zB(_(oIQO9(7PSQ&N^Z^vE75yCf{A00EtL=GCwqG1`^!3qih*~kRzVK{->Ydu)}Jx&hlKf4_qkJRLNb%WM{zwP9}=L+nEgX8s@9KAQfPUcl7 zhkGL|P_H;RzVmX(KG{$9QRp&+LuaEt3XP22n(TK%5m+@mEzdh-$)*S_hWbnpL0h2a zZHmNS_fEgBNeQ*AyCsu zp?GKq7^l%&H5cFPWcX++7}-sdVZ)sapWP3;rq4MU#%$AK*)x*i={p(nAAm*FCr*ZM z9)Q91k!1MbPKIB%gT1`vWGH$N?8o1d;ZK`^7iOudh5a|&=;?=LD&p}2WL;7%748H} z*jgNX7#xum+dPg4QRa!syTH=sILSZR1sf*=C3*Pv+sHq8NSn-OJISx@hc+mY!cd;7)Y)rDmX<1#IoJ^{sGbg zWx~M_e%{I9J$(YR9}0&Jyc%rO3qhe>Re2)re_9jq@*`SbL6!CB|KQPN$49k(V)tIH zhpf*$@z@?MleZb@s8l@D!eYfkdzGya=3}btyq{_l=)9z;wQMiy?k`Wl?hY@5@JUKq zTA^IEfI;vI<6{TPN-5Z{CGxv%%2qI=d8rt@Ub+_wxjWHDSpF2u z=np#>b~+eT<2-gi8^zyra*aF)z5g|viyv2+>HM@dhJWiMz4A0{K7D1AvM;29i!w+5 zRD*2)Y*}ki&R_uy4aA88KKgM5v~KlR-yVn*ATV>@nsucs`9a~5v;vo`wg`78QEU9 zuz^^1R_iXhKCfl*jW((Boz~0Tu5sjcm0(9ao*Kv@&4n13D(VM-QhcL_pU4&m0}K;R z6Oz7HNZ)jEvW^iPK?lLnGsbh-81`4;U+~zzD{l~lOEYa~YzK;K%?bwd^ z+|?r1O6vg+fRAdyxTELI6X>Em9aDK~104@vE8-DgF!4EJa)Ro34MhHnP#N_Hkxw6j z*>U>x*=Dia4k?z~A-xBAmworLMC4T)ARvG=2Fp0A|6?~ji~Aa{FmZE`NdHGS;T>qy z%_d70TJq&P*gMyUn#6ZN_-2*sW?|5Ln}~~VkU18=hZ(_sbbuYJu}rS{=sbIwTwWYg zSswSMHj_Oe<({F8iN536qpA^4|fw zaFdINw(2cmC4T00=$yGHJci(JAV$x+%{%Zcp{18N_h;4;&cz}zkIs?u?meZoVVPc% z^h&KIgIxh2Vd-My+YrFRiZd|EZ@sIHW~P@AWQEd6QK(6xp6sCB$kx>)#HU?swIsaH zL6|2J-q*T=k@b{^#Nu;VwqH{3twH_VS#2QL)*94!P7>A?l!;5VJ7Kv@k2%9~N=n8)PX81N`1@1__! z*JKF&1Q^EO#sFu&L--iQFtR2?)dj6Dzxy_Zq)*|YVYy;hT$7>AXPU_$tHBVdc&^t#<%-sqv|jvMo06&rj-H3`uN3(gARl{Y)feE+ z*Bb1tNZ-pal^NpFCFn;S12vQW3w*dW75yc+Ky7UL^hrfY^LXjk&ekZv&@GYz_t8Dt^sVfWRJ= zJP+ACe8do0(4-;KTy~Wzqkq?$@pHGyc=&fH=lfE|XE1FN=sz4YC0X7ajMcKDx{l*;(tzaaWC zMgMRO`pqZxZtSF&Jlf>3{7psqS`A7ugzLfVCokz!T#w~HDAI3hk{;6Z?mTFiw--__ z2I^p?>xz6Go=E#+pgIv%U%%R$4bL<41Vit@JKn~9+yHKv@{zmk?c90dX&>0LAATE8 zCtu)!b5_WcdnZrxTEMgLHlF|00-kx2r|eFit+n+i{-DhReK%Bu`RSqXgp~A%8axO6 z^iBNOZR8L61Nn=R9FAkvtcX0ZDL~KSmv7@qsslWqOP){fgX%^08oS0{8q5uK;+bw$&`z-5Is~JuPbSSQuGmGTBzQPJ>XS! zHdJrTw^BAq3qBO|i2J0z9?f3zlJ*JHyYLrOiJns>0@^bsA1=m(>nZG#mzI?O84e}* zOfh_7Gf-Z?YoKR>AC=h9QD^HLLN&vC-(k=>1Myk+Et`q#al1UPy(J+=gr3Jbc!gXT z0Ow_oMZhV#1X~E~?}ES#tZR}1jvRS@7aX47_;Q##@x6K2>%ts~L93OEJWUGP^{3{K zM+b3^t=m-Z555%9rB-V4)i!pYL*ok42sSt;N?!(!lub$-!h3B}{Jle!mm5_Ow{+6qZ9f}221rBC(4f#Z=O7x7; zyNPQ)94nI83nV+3Vrp?(HoRCHPRHWQ-f;ebGSM_ZJ>lM_ax6y3)e4^Bt+`qmC|4^3 z(xDFMMoWym5!%{tSj0j#mLeAnKfwEmSLOwJLPg2i%>>CpBR0&qt&q=W3^PSTC zH5A{wC)FeY%$NU2GP1B~l3u9A@>(Nhr5Yn;Pnnvi$MZH`n%o|GxcD_ukLIz8usIOo zh-(Ho4&a~L>$yDJ%aFbirbudlEXC0GHinHILBlLBgKsB2l@}@6>9^6kI_rISm6!JE z&S2*^D%$lnEj104fU1bAjP>oR_vWv7dGr5JZa=>+|_{P8QtWsY!Q}yZsrV<;LC`*1Z^IvQDtk6tPk_TUc6J|- z+4YEgWe{+@>g34G0gjg)952=67@DiM<=;3tKFNhD`O?90$;$x~WS&SL+C02&)xA~A z;kG4tveQol4FOv~#Vj16!%5&Va-8d9Iug39hvC}^Fu%8TFyKLJ*2ZQK zuZ?o#i^>I~mCChrl(hJdR>CZUH{P%*Bxs8zCmA-$7Q-iurHO`h6DQmA!@P2=oKJce z=tZ~zi}|CiB%nj#aGrqUQ@s8M3=!~MRskAqOu^oMY({!UkYarY-#wg ziXT>V&wA;oYJ$q3Yg}{?Q};vfh+j|~=e-;td8Ak~M{mgacxf@AO!7r7dfA%)t5|M& zSxCv%1-c>rn5*~T&F|o&p5AP{td*t^%0j@Ix#42Pd_9u)y@Q2Zq~3}p!^`4PmBFVw zS?HyLX^OhQOHGDr`66h)^-gO0ZGko8MQ(4{fADfpmVRFhSvq(J2koOhsgyk7WuYuh zTnZI-_6`=>NjsxhPI+0V2SSt6;42v?-7n}Zgy*Wh_194tjChw6Z!keN#PMTrVy(VN zELSFg2T!1(D7L)JLlUFF@x$$2yl@1=wkpIcMiB3+!gea`NZZ0qkxgDwf(-IP5+s$^ zkaU#$#eFBpK_2OAz!A2kVfDp5Veq)8t;`DzcgPD3sCqJv2Gsa|uv-n+UlsD1stC#b zVYk|J6k#fy`ooUjcfWs6^=8Lfn^q0`3Y&qgL^y-r1L`XDQ6lrCQCFO=&;$5WPBxg} z1B6dzo%-U#Rj@&@&mmxsQ$QJi&&igu8Vvip4&t}H#MI3A5)=Q;$>AMJa0c7kFzjkg zw#aJ#DD~o1195#N7!|08Akl3dtdHx9=(Qe`9*i)RjkIkzz%01^$Q4 z+sVsIy$kA>-#nN#^Hof%PqslISoF<^kG>L=#`acgpV* zaBJBha72hN=zHjm4=BDjbbmO13SMy~TYPc1aS+MzE1qRH1@EIg> zw?TR8VxV?;{b7>}r;Nw$*SoVWl7Svyc9gV<|3Mr7fIbb3JPF6w^>ML=a)4EIZ^C-R3D6T zLPVp7^^pO8OvLAF`13a?`bm!v+aA^{V%a3P*~V;!FA$D!!OszdzDKeb0m=%IexXBL zpxFP2-hzis!ZXPc;@Ttns@TT=w~)v?g}_}I@p26tk89Y*qWfdI8Qb~)mebrT2iiJM zG~2B=<-I3)Ycfb|+pV|c8I$CslsZXH?2vcq9!!)ivQM@a^~5nlJ%g2`}VTr?F zExb_4nKwx~M=j|5I^R7>R`b@q`Z#V)l7=2=u(f#^gst`c0&ex|4jxuw8#qn-rjqlT zlq0g@;H}=u{rUs^S0yU#NqrQ*q(lK3i8?+>`Xk1xo-E@1fV|;kS>CT+g&`g$&g_E@ z8zN>M(wm9{ud{(6cWJlp6_m(&E}^{w)>B+NsLzAJ8~v27&ftYimK76-aj9a#6zHXR z_aL99bgh~Sy%aV(P#09d*1Vos@JK>QPDg z5C&@a?wBlxZWwRXr1WsvtUfJi{l=LkZplO7ZStVY62C6=dY1zX3 zR1d5JN8R!AFti+h$mi|i*xkCp0imbtuNBCyTsIzEfSfl&nu}?#f*Cx3c~c&LRe|gq z8)X~~n#Ntg1%QhuTk-EzE`ILRc(qKt9MP2*C-qT0$-;}oVQrkJD?ZvlXdlTQ0pesLl zyQ#7X)}Dkn+Tuj|87OV5snWJh6B|F!i+zVq1-qXIPucMd#u%jn9K>GY$8)-i^%g-N zN+z1xS|FM%61Tu^2R)u#K2==0Uzg|H;c*-)Sfmup5=+nPWBBf=@=ca~O7_x^b-1HL ziUm>oY{>=5P}Q>cbYn>+&!hCE8xn zyHm8hLXR%R>pM->VD>cGNdFFk8XW(H9s%tEQkB_lG)?9s9OF_&M4rc!!;7E!Y?Ybc z^2n8=%#bTb5N$u2l2JPW_8Ko@^sXQD)$sJ=;1y4~zf~H(k{aswp^K2@mDN0@Py}UZvI`|4lX^VT6MVeJULq}NT6nin~|tIF$6LLlN+iqI;#HTBD$RaN8~a z3^>QAqJ84f^O4jOgI(vgqBT?93`>pOZMO9PFk0TpI9pi*=n7cZ(9Qc=$z1~ByIO`w zcmUq=`qhy!P(&H~KxV8c1S}lhSHjzwvg7v+g}xRimf!T$dMi^L4Aqv1^@U&;fJOCcU?C;oE#1UweiNuaZTuE`g>Mqh4Vl ziPKa`3si`gM`Fp-6^?f`B91pTV%Su!c#%!sW=XeABDK8Mk#2NsDr@PW%Jag1_0eE- z>^wsbD9`g{o}b?VGc82gYpnl7uQ(?MA5!ig)KzcSFO z!CT)KJx{Rdt?!)avh~4GPvyzeFvc9EZS5eK&q|fHVyO)d zVnx>18u|8>)oZnlZzkIK8DRnSu|_f0+zw~tae8=IX}#)aOyFyjRuDs4XDF?8{s%>b z_wxB0N~yjFiukHh`m!qGM|<=@_a}9XSQc<)I;i*wf37J#zbidyt&F@)sjWmppb^YJ zRr){z>3d1(d*&M0LVV$#N6ZlE*WvJ812HSq=qjQ%z*9|l2^l-u=%00(UXx`Z&1K@< zV52MmQF#ez#td1+zB6RSj^DtO;M0jdBEjFNWu+$8f$uZY>-BI>0HnjQ!Wpt*;RV`I zBUxlt^HO@bp3j^iTQ=^n+I58*fQ})nDLqKrWv5WN~zv9L*%C#W0W%W zVK*4lPD{I8RZWa*Y|O=1maxzuiS)ypN~nKC8n^-YLOQQEQ{<0PZa{!I(+Fs5 z&!nnnvF?6NjlnFa<4lm<8GpLsPxqO!!qaBT3eS!wb(@qrI5JtYeZ_q( zv~adaW&p%eImgH>^lzi;S-#TiRv8%@2NiutX5^qMZJcNsYs}#nW=gy8g;EDSc_Tak zr_uo_34c-wpMFs8HP9{&LfKy~#LQ@LpsHtyxL^MXjDjX&_ywjIriv%*T5&A0MeQLwD;ZCiI2x z%6d*{^P?(jpp3G%OJ!|UE7)^{H+FORKdK5QwT9=+H&ovKka=UH;ZwLq0dH0!M@?)A zw%ly|K&Xg)1%_pa$nOs(ly(<^hgAHkR9sjKULBsLhI0zb(~V5Ae;o|V{>YI5M~@%s zW6WUS4rdwn`;?YIVamjr6llPOC9(nWb#9NL*R2!XLgeedux#{b1R-o7$m%7dXkprH zG$^Hm96P1brlzv?+oj_BNih%6;Ikb@cmAp>*;`60EDy%Rb2D4V{ZhvkhmNkjVER7Y z2~O{)OoFGQSEZshy}@C-B9(k6OV?DqGuRl#Lubj_Ycxxi?Boz*Iy@4+K1|gd`%dck z+SUP2gc6IiB6>an#|sbULiMF>lq+nwd<9rDc(+;7jt99P$}=XisL8XS5~twLH2g8~ zX9oTh;ZMmdX#?h}OuRP2m<)Tg-b|o4Y(7{PQ5@8!kN9b%5l){t$cmxw8)PxM>kfh( z=z|cX$N;}-kX4U9XaJG;H3JCnzSFE=x+OKM7TtLYk$CHAmJfZt05H5M6@n2m=p=)| zG8iU<1?4ityY+yyp9~@}s7D_tfXF<=8q=o<0K=OJAxOeVP9G!yEL8I0<$iz}82Hdf z2mr&Ipdr9}^dOjkfkAip0oDhvxQ8%U#!kl|kgh6%NW7^i%a=Yg09Y1cjIIlU0I#8e z051)K0PpRA%=D5NUiATyMKTyC1H29fBFA80&=&*%gKH1UF&6I(fdIc8kfqaS0{~kr zBV%NM_aZUY>ct~ z^bLTlI`jbmsC;}$1WJ!L|3lH{BgW|U5eSMUhPN34hOb6sb)tLzp(o%8Du^72fj?dE zpA|}X`$Hr?ErT4+ktF!UEUP?#?(>I4e9{IA@#z_0_?!*&;vN2w;Y5ky?fsB8Lk772 z3K;IYf!;|H!`u3S5BH@YtwaWOWiU+!vt)o93|Xw4)-phf`wS4^f)9e$GDwiYL>b_+ z5z=PM0QZOh%a8#sh5*Cm5CrJpLV$i91j}TAUJ+oiGQgP}u0L0=%fQd3_ zF9V!OAQI;X2yl4@0j|0rXexss@%C7wXL&wga4EX{_(pd?3TR+s6pm~f*9A15$5zo7 zOY&({1EN84K8;@_#xX9xR5BbP9No@4jR7s7FOVQ@ZA`>bU0{}D0KyhPkWW`&A_08` z1xLU97zqy90vh5#i32{LMmQii-t%dkBb$yK(L{{Dkd8w?pN2f9cffQs3N+pe@VA@_ zkH&yZK>^hR(k{X%G&SkZybYMK%4ze5t^eGaILgPZ;ASs|JA@r*a@WSfM*FUm+1_Ly#g3DN^wVZ46nM z0*b^$v@rCYkpd!tsB*F_&TAQfq=2dn8Bl7C7tt`W2}DB9(6Z!Hn;@lp>57=Kg&-Zx zN(6CAH6Hg3iazGWD z90=}`0h*P3vN$MfAz<{CkODG0W2?$3DW9wlFrh8Vrw@hH&|E-Y48bV17mWEs+XO7T zVRty6z8(Sy#^sZlLSi&qH8wzz4XqYXzA_CdTVwkJ7E*{9nlR);i$-4{ETCUVucq`- zDjh|roi2b1$jVXX>?=n8`$%S4iL1J z`D7ze4B9%+Mh9}B(ZqP?#stQr6~%Z=_v{*A{4y1HR(|Uw7O(=cx5$3S zLKqX#3S%NNdRD9$k5(Bnd;yls`4kTb#^qD4k>kHtV#r%6>pxb06$OpAsTN3>iZ&hj z<*EkU`~q4-Vbtx*5K8Q;=y6JrUs92414_iX0CLt09PE5*0u)m^fc$OvDWDbsf>(*4 zsiY1ChcTZzKT`jH{mMa;jfk8!zzW}MB{#8>W^5bFQEAjI(8N~K1cL;QD0Ct*3VSnr zydiq35mJux3&!Ex0bkjzf#Hl}r{UCNW9V4g*oYcfry3YaMoOG_DrtJMG4eeT#p$Y& z<|o8(eyAh{4@P~xlBO+BR3*(nHWs1u&}@W5sgkBKB%pzZvsfj~Wf+CiRizn?{lrF- z6gCk;n(!)VZbJf`D=Uf1#$cW!W|@YQ9j0L{4c$tb`fiKD#=$6T%}TR}N54dQjYOOq zZPMj6Fto*XTDKb51cl*Hr+KrIevup%RMM=27$_(QbiSfTeUHdGHr`aBi(6zkLJR35iZuiD+q56i&-XkJB_+no63aZ;L{9 zjKUeXk|t{#!zmjvTmX;}s-y|r5e0U#l2!zcIEUiAE>0?4doDr%#|b-DbTg4q>I=*7}>i@y0`7NsGdp@xkG5nD``D)8&#U3 zszn5;HL!9&g_3QP6k&Hpp@V@^Q52caN^&=Di>jxn+9MU}sU!yksT@(`omAzLtfezf zMqyr%6MJVR`6f2jU#0bhP!ZrF2?-og=*VEyXrw~trjooFjKaZ0#=5+c7ELwcD#^vc zDDp|sy{{xk2cvMPk*i-x-VR2g_d~Y4l6;@rqRMjtZ4BcOLqDvNeh~wHv_G>{BDz(T3%PFuPib;vF3|PA!a2; zF9yh}YK3pNK;yz`#%yyLM8UT)O2y~JMu+Ho2wOqFc-k@BycggKb0z$Of4ZtvbSyDi zh2anfG+zejt^k%JW|tW8ekp{-n!8KI-V&p&KRT4)z*5BJ5~DANg!oxTlR5`L=CsAx zWsnt!8Zpa=3aSwW`|(Z0m{~@nRs-|P3aU(RqIXLKw<_-uiZ+b~+DqSFhh==FMp^j&C-MInzbG+Ne=o~^n-0lC4d;x8{WMn*Bo ziUSlRG?c*vhoCWwjHW1P$s!}Eb6bxftX!y{;GX$&X6Mg{>RDVgyKr_{LD8fIRp#wP zp(6LK2BGzCOAtYejYdOmr>&ozK6FUbkh0Q({F#MCQ=^6yl+G0%?QP7T50iN(gChG++&jObcJ5bP*p$P#!s0%aVu#2AF(t|i7WfAoS? zZEjg=lwnbe!XM@ zs-L*h=o^G)7wC)Z=oeNRBZAP}LUgzt9dn;C#(#{&N$i^Yj5HMc&V9xZ44bWzY9_5R z^8BXQjIXRR1~u7hpmTB8}(=iaqOYEY_7uV=H}SZj3kYi#4m z>x^Xo@eclb)){?}|KvI&55o<|jA+qoz0uCUrGskedZRt2KE2+^_D8SZlWYGCa@363 z0JDuz=A3Qr+hF7)&-aiN=I2Q&pvNd4_9m4^Rtu`Tpk4*D3#S$(MP(G1l@-s7A68Oj z26~vNo;Oq)ZC&0d&mO9Cw^UW_=aoiW@N&u|Ei}B!Ho~KC$WX71o`DG`+2eVAv45k{ z#=p!_s!N-VXr%PnWMl-R7XXz$(2+iBlhFjz7j81*V`bA1E|`*!W(f=zwf)duy{gQP zH45-9NJFj=%jm2MJ$xGU7%1|5ng3l@ylRUv zz<-W|=i(Nlb1OM0hZIjKiyAV$aK?<;U}QXO1@sP?ryWv+ktPR>e+}{yn;acNsPnN7 zC7z6(5yoIFNcL7EqOQ5n!$VyJ;(B5l&@>STw;HVwxvB=xvo&gZM|HzLE< zdIS~F^EOXjJz77%U)tKv+l&%_T>afnaCV!~y9KW5AlofufPN)lcgbKO1(eOy2aL2J z^hqHV*JmILEo|ijMz?ZYnL#wVqY$854gor>5TJVs0j|#=Kvx!mnKEc516+$iBzoEq zpa%>A`o$2;mI1D)0Lzd8t{ebMmsm1-wt(U~0fJ>R2$TW3^bmrBg^ zJ-%Spocyvva5sno9pnn~k1NPOub>Bd6|~`6L67n(XysEu3!@5hVJm27wSu0}SI|Se z3R($OkW*Sg&*v*lbU-U;bx|Rg7ZvpUu7dVME6CNXpyzZIv@Kad9$W>juqwz~s~~5s zg0?OzXdP8S4q64dU=_49tDvpN3Ua$D=owoDZ3|YAlTtxGN`+aDo=64l{8i9qUj;o- ztDtA_6|{({pvk;~=JE=f$}4Dpu7bAWDrmB(4)On|n9!Gw;2bdGn@jkgkLU>4H{}_FF+ZNfo4>Rgezpf^;n`Nav!0bcsDk zSJ;Defjvk&h9I3r3R15gge5Q-UIytbQINXwAe|)&(g~p;b;&_GBNU|L$RM2x3ewr1 zAayxGIw=&SjwDFuc7n8d2kB~hkPb$Jw7mxDx>k_3)*zij36dF>|LE0LFv@r&0TMW`6X^^(WAf1#5(smf6 zvkyVq2(yE<5eDgGLy(TDgR}((X#<1`LJNpAzaVXWLE89&wCx3H(+kp;7o-g@NLN9E zbmA;Xhx);BL#B7gH*U!5Q^5(b#uhjazHn*|rQ^T`QT9M%9KS(~CC}9x#L}K0#^OU8 z#A==!WAS$z#9D=J0YhLB$Plx&loTSmg0dpWJ4OL5jD?FNOnCs}Lk9^+2X~cv9d)h>m|eFz-t*eu%=9PoW2DZ z$Ur%8B4gRUd4uqsEn-EuscY(1u>x+qRZM385B8FAbKuPkd~>VV)Jq1 zg8k~n3-*X>+5a+5+$$br|3}~-_lkWbG7yH>0j2H}+p+(P;0^o4sZwJ?FNI@Y5L-%Q zoEs>Ihrb~9@QURBN}0>b?yrdNz95!G{Rp8M#M=v>#!I}V;6&1kAU7H91zKm~=;j40 z<8v>Hl_g4P3wPg&joJSlaP$3QnwL1+K&MQ&slRLwd~d&4N1~K2xW-H3WcGg#y#FO} z7EAdQoQ&9yqHw2|#rllWClj9y^A*QiUltoMN_r-azu+l{#REEJU?z^Z2|@Ot17ahF zIT&v}AXZ@i2k?gn#377#R3>ivia6Ix27!Uh%w-$jD35QwBF1~kC@_$fiDO+9*!uA&;Auv9FIQ&dXsTtU|%LKR~~j0XB`ov@TeYfMf_}t2xCAT z`5Kf28S({Q%fv9=YblYTUf=}IKOe?^uf8T$@RC7Z;H^vyBfQ2E8QcZl!TaaKG*6?W zVzieG>|n%(`yLfjykxi*_&5{Kcr2_O{^TeWAQ`X)KF`F*JBCff3y+C0UNS@rT*<^Q z9|Jwez$|b*6JI|jRzdX3cSMgeM2|AK?s3R~jLiZ+X5xgwVR1P7IQR@QIt$#%#AW9f ziotIk2NC-c%CDLD&T;WE_T~3XoOD9$z`i`lB%`!e5=jQw<&w&m!S_yx_q}Aq7WgL< zKb~HpA};-g7%x$ZfK%QOdrM^42Cx2o@eOeh`(MVTPC`{CD>g9H!jobv*2Wi4iY2_G zNXn99@wGxiIb8Bhv9g!$J}EyIpM57{3I6O&7y(mC9QfIVZSl@;BH)e3Z-Fjk5EZC4 z7H=p6d*=_nB}Pgqgi;fqeM=nZrT;e^ix<~{cjERvC6;Et!h0J}iLJb3C=+Nu7XMvF z7>`@LEtaB#n?MT5qZl6Dv|uru{Wdrzny&L$oY*G3KK}Y`XyBC6bu8}F4(|Ude_H44 zPB^RJCM^nA!DCLtAb_UpNvMTMi4?{sPeY|5qn|+fSlo14(N4J4J7Oh?Qs8xT?}+2P zEFX(kC&JOy0`H3r zB}!R|3%v#nrvLlk;>idkupaEZ0#5CJ_C8>e;YDEkSo~rmxX-iV2arDrTLOE=;?xhs zI@v#fyaDntWXhbJz&-Nqcl{gbYPJ3rej`03{h%p*jI)jQ^&GI0D^u?p)V@4yV;S+P;~@f> zeTE!6g$M%p8z6KE5yBavTZrIggdQP+oC(DPJWquv5iCg`Lg-G)K9UjALxduXFpv;f z@5~5;385ZgA=AzP8XyF%pQeNngb?bdA;oAQbfBXh=%Z6A3}< ztSQTs5TOe`b55*ChfRTQEOmD1#~zF@Gemfb5oU)7eHdY0h>*?*3qpi}jIcOF7|aMu zLj;({r3TFjQAV*Om=LtioQnNCA!waBC9Dk*CNY)`A;MHf*h~mo$4*(c5rWpSQ^HOl zWV5}Lq-O^c?;%OFUY!zNAOx*br-YXXLF?2h;T1yAI(14oNC>o_CVe`99tjahcMgPO zA;R`d7`6fB^$>-0=RkOq5VTI565b{RGQUeFa3RIJgrIfcG{yUbz&de;ah4FYPMoIr zm=IV;&Qg3z{f*X>(Cn6h+`~m*~;ZH))VggF|CqxjyRF3i?0*NvpMO=u`nGq_72wfQ=K13kl1+XNB2qdxqLQO)5A>(q0Dk!B6r4Yi? zj8LBtw8(;{XhaC1zyd&$2tkV}Xo}_`LN>!_86wPNgvUaJ*+8fOAngc63oR(f7sUF_I)#2+$q>5`f);8}{%(YzMH-aQgAnvUqt0hyB0WO`vwZ2G zEj%W(2Z;vY8yP&qgRNHUd+tpO%(TmgB%~XM2kE@w;b)I0*n{-nKqS33Ji4$)H};_W z7=fC^zP4iz(z^n&HhYjB4Zel5hiP$@PT0Y3h1qYUBZF_G`+`R)QZbHv9$`+pm|3;qWiS&8Tt~Sn&wC0;w{7=?k%U z)lSgnwd;}Uli%q3&$(2DMz2h&hZ|lJ|3PgyfQ?zcrf_6?#+PELBCQNM$Fl!R@iOXT z{DhysEY>j*Qp@>TDZNMvnsbjVTy8n4iJ!b87A@O7M0Q4Baz$K+rgG@X9i>*wVpJJT zBt%W@rB}t~aP!rS)e>B&y#;RX_gxeFqZ~6^`S5N)z%^e$72#b}Gp>t;JxjC5$;JAL zA;n^Nvo>558&)}>!4<3p*I6z6O00zTo8ijg(JvzrU;j#M>e*+**-dd8=t6Dy9bR$$ z+1Fwxbk+eSLFmHddEbWfF5r+Whu?-@mI~229#!)Bk37wBjW0zny6XTc;v3(_xuUqn3a=L@Toq+_!vt7e)3@t)0QwXK6$-!|0b&ErdddWg z^{AY1b80Ev?|YE5#snxct!f&OE58>z!hD$pt186`S+L**PYb*x%jZR%96|2=ASMZq zQxIenXFE!uHywK(n_w~_0LI`ES-vW0j00de9(EHZ^9C|SM_O^o?FeuRkz8RyaOwR= zATT}0SqTKU8uZvrUtzS)F`v|*VCrr)#p5iw(yV>VSg3{hFTtE#zgu9(qmD@Ume>KV zvLljlCQvz15136rOXv7)u_?OZ2$*n3Yz8kIw*X!=15({VTwQltHU03eSQn64z8+7|J5Y1mk?Tbz>YR7bj>pu-&!tvQFTYaE5AUY!8ux}@^A@=1-FVj?t@=p zilwt7WY^!st`G%Su;4hZn~aw)%C%62Bi1+fz)!*9XS2R=O@f9+Z3&Ht+7g;P{SK~# ze&1ns0eAiohoU`>*#z%HHao4^Y-8B~421_S)n62h!Bzf5ORU^tD;CRuyTZw15<_fvBtg5od{bdPA>Y zNK=I+-2xr!1YL+h{{m^LR9Q$W5{AS{rfS%#j1y~7omKrK zztlrOg)K}gR!eeJy^tkJ>B)&b>nGeL(pmJ>gmExdOd;t*0ado-kmw|qb_1aeN+NUg&x*nvZ_Iam-6di`za;!g>mUf~p9D#Jbs52qZe!MOI zt&B7$nq$$cNk>{mIs$GgUKK69f(BYp6b@w)F7%SGq$y_-FgOZb-XwGst{WqrMpHQO z^zl-8T(z9^6`I9SlP}4waj){yCeM^fD`KTeCKi&Jr9`Xh*|?XeWk4;7`60y@Z{Q4MERmd2wK92GQdgCDOV74qav!hNeq zZ9E4j;T=_^A5FZjc1>iG8~{Wpv?zS+JKqxY1&h~?SDt{;vTA`aV2p>=q%aZUldxLS*64hbLoHb6;H%rITGB=2Gt!XAr4?7* z@=eAO-^(Qt2ZLSBQiloo7c)zmI;W2GqbEAXKzEYh+4|BjRM|*ll^{lwfP-c_34q1xHDMxj#8sO~!DudPC$pVv zCLKlDW-<7J>!_KHgK;;TmUF1!#wAPS)_M!Nqur8Cc8kLPme8EHS~x9Dp{344n?j;f zQ_!lCxxPd7zB38e9OG@#^Z{uSf0ByE?y=2l6KTzwNT=4)m*LUpORt<@$h8ipM-}$CDlRAEXbvukh?MD#&~HTsYQ_n28*EzZdyYw zji>dJO4)LH0`KZ2)j-`1HmZYTPTg5fT^^a!!QN7ZNUKi6rr=w>r3Pq3Ub0GKSq*(; zRw>PW(MZk-M1a{~A|(wc^pysqS$WB$2g_r6Zh7=emP;=?kzEEa=_i$rHM%y<=zMW% z?eK$s(rN*1-~^y8Vnu)H657F0X^VJcfRrrdfZJFISHDKa#o#Ifr3BB0Dfr5Ge@PPv zX&R0d>q({sFG(&H>olua@A85`59?Umy%_Q-W}lM=OP(s$6;`pX8Eozqt2fK(%SYzq zT-tx+C67KVk6&}kgOoPBp4wYFX&r%F43<#Sh1f3N&)nlcsdpCiYhX&f|I^9-8J z5on8^k|mWVhTM=P_3})civP)y8k^XNB^`&Y0VdI;sdUD$NS1+YZEwXUO534g9G?gR z>@t#JTE6Ne7*oB(QK?uTPL|@Bqv?yAPL%rMo>QQ}cTL43rbyLHAg=NaWAbgwRlfhN z1!*cf)Q_`MrJ#T=@@hc+a2$q>u$QFXgg(udig+Qc`f-j_T|_r6XpU`YG(-Ci($cVM z(L!mxC;Gm@suu<~YEj!Sf%P{eOfxrlZrE~vDs3c=Ic8dN?6XWt@t`6WFh|z$7S=K= zq?$r>tikFaEFO-fcTl{M#yY@>oyGz)4#quFpJgMNy$yuaU;R|b}kI`f!AuWRhC+|0hX=DZk46`BNMV)3t%yVJm4M8?U z*w&TI895jtO^x3m#e2{iLwYrRlT=+mTMP=OPUq@o2xh<+7T6-~@~oMLk8F{;@O-3N zl`l%fNDq``@mp#3STr7Y-YOM$oOE1hQw=ZPDwX#xBCC(freSrf6jOkJ!k2vcGQn2R znSQ%fI^_XRuy=>_q$m1qLsGqnxaN%GcEgzQLn93>otnm+7hwn3f*|Wcp_%sbI(ED_ zz(KpWnk7tylME+K74}L!h3M~$9G#?^uus~KZX0Q=?e@EAc+v|}Da66JOR&@=L6qu! zQ5q*8FFC)>g)EkKyG&5-ezrJ`yvuDv*}Qp`Ln6y6=f@Y_K}n`peVOHPq5bW3_eTY&H$W!MNLctwn;Z z?@CEw=qU@jqwwo3tWSI(MF`PD4OS=NvpdAJUiPjUx`4p{GZ1v>P^C@N)i-YR0lhukp+JKJd1#m9|JOY4Z0r+4xP9K7b;A$78`A~t?i&DIRKFtfz zJ_huW0krfBsb=lGj8HTgwm~*vmni)AdbvC9a0zU3$C9(91YZnUgRF@-mY`-Zb8$c} z|KAdPiIw1p%hDE6F~#_Ozmpn*zbB|pC_IkDcv zu;_p6DUEnA4S!V8`&FS{Fq^IW00{g7KKxcCuZrXuCP!2mb{@gIg2tmp9%)8yt1pFT zkkyxj@QDD63+xxGR?sZ#v=Z|*E1Z9(v#5g;m-gI_9!%pg8-aO*)T-VF1)xRDZ|JQe zp*m&_oL6qYVG`7UwA5~K&AppN)FLmeKU!EDJ?6bAqRx3?{n^4g`*H6+K}c2Wbo93K zp#ByJZoJ)R25!{XTQa(jkwmWoe8Cn>^{$Sz7VP*L_-Lwk6q;c065qy^?ATmOcIN+5 zvcEG8L0-D7$;s;;lW9DmvbfjP3*)hMW^tY8O75Et3O3QJv|6Z#Hz26K9^UB!+GD|T zbn6ezSn7kG-ZT$7Y+$ijo&|y{*V9_Lo;H#=m1{;{ z?^CvNy*dM5>FceIzA|_%<$5{Sa{bX-u5s=yHpQ=L2m+^`g+Uo7FfCX|v*=7($?DOz zZ>Gt`(1rZMp{0lv6f&lJh@mxKn={aYwPxUFAVl zECM?!TR;;#4iZzBG9%y}C7}9w;Voq5jlu(ld%s7mIaWFqdgu#zDoWv~Fe}l6&4M<- zuYWGX3mis!BR#EW;+vP`Y9{_`BfUFNe=}=qT=KG9luT&c9pz0WY-8rbRs=pS)+DK0X{J$F*$XsF_3aS1cUufr~BocJpNCDIC3~hokho*yj)+ zhQd)21_vkw+JzR5{=MAW2sP&nM#52vM$M)0hP6`RxFq98y~{G9(UgW-jXS==d!97Z zg4Z3DwP3vaYj*wH4$%O-jDZt>Q! zP4aAd2LH0f+XijP3u1c>alIycW~- z3~{+TK3yuC>C)6^j(ZymsG=ngr!id0Q(8_AD2-qDR`H-Z914Ui74Wi?-f5@_M+k-j|S2;3k?D| zTCxBB%sX2^doAdW6?=%4_qWfz)5Gzx6JEJ6Jvm0UvhY@1b_J|>(gMv5ypGJmX;;0| z+!54Yu6hLlozE4b(^uZ!?hyFhue?jqcex_G`n5OP9YO7S-P>0{_j7|#Bff=Lm}0=e zC{oKEEf_FcFiM^Oop*+S3e7gV6^m=g2ywZ)2EAMz8ugbyc)t!qah5zBTj5wOCkK?I zTi&i7RGUK~k-B>Hj@Kuk#vGZ3>P3F`rn6AJ624QjKpEWRu2;r2rpb|>+Ou)|RaD9Z zL$&mQ*{!Vs)HL=##Dis`R(2GG9~0j0AkVD&ztNn<{1wcU5+azV7I(At>Dm%!2eDOpEu8A04zrXe6!dL^ z*=vJW7n*bJ>Vm>Ph&QA;X2-?(_J5%E7xk5T6wZ@HedRo;cy2iAr^S7+0gn^N-NCM~ zD1&iHUrSWO0`F*t)fQGYrIc@<5Z%<^b+7|2QO2jD$BZ=A9=<7#De5czD3pQGzC);o z1*Mg-H-rcQWyAJ{$mYEvj}Y+1vcCN&V1ec$nWp$ijBf$rP~5G%)@&kuDsiR--O_z+ z4sp2;3iV28tJ062t1`1#+G)yGZBVeOg0E{7M1S|{`yPg&%@&Cr2X@;vx!2EO1G{IN z_{!M^cCXICC!6@{po4iq+@&ENn1k=Oms<#P*tqVsBwuM8@cVP{jU-TB*XQ7(&3p~fw|N2HqXB&g z9`d37>9u6v0}t*P>vN7e)lXXa>cfKkTvyjrY%X0Fp%A%6YcFU*hjRXy+qzydUf;zx0<|<)Ex|&wxw!=kDRc9_u9vc36T80J{t4eA58~u?Z`wLj zNZ0mhzHA8%H4E$<)v8uIHROG4!MS*Be_tFroR?fqXt}&<&IR`w;428NZ`1$?KhNa_=yeU~eFG@Z%}+OCsA3!$ z2!$Jc)5zD}2vTvYr+wd`UyL-gTjZjHn^4_Jbnpn6ql0~CkT}n^B?AnZXL9V%PwHi) z`;DeUeZ9k?OBiT&!PD@e;lAOv)*FlKjqoL-ID^&Pdf^JgyZwAM@r(Vuvi(S8^?Cn8 z<2|KGT>`%{()S+Xq;+q*I!~yGejVjI??D~R;ySn8_sv#{Qk!J@QU%o0!fWZ$&xN?$ zN2Gf9Y3`rFgPSAvLDq=<6AjzO$IsG}8`5kMyO~3a1n4Zi)Q4PUk&Y*i_to~yV^j5Q za}DrQmI(S>J-w*yO$diWbM<7r5TF!LN1Ll}o(02zg`C-p!3><+fVuh#LE}fg=5d3W zi)Pvu;ijl}F#Jzd$4(kVNmft_; z+bBdw21D-8o@E-|p5sfkIjqvyzZ_!6XoJ=4uskJ$xrG~*ga6yy#7~;!k$A)k-zSKZ z*xhOAJfT89fPF#OhJ%}~@_mTfnkDCNm}sRAe%@D4K&`kWuEqF^)usj4_%?>4ejG2k z3&61&-Z%3`;R+jlYtcvxtHm?s^ROkCH(5b9bXu6#>$kn(LILa14j!}F_bwi?*>@Gq zv}Ebn1U*{DHc)7Sr?&Xo!}=dCw9PjN^bd86>U zmwbPt7cHz7yZJ&)?t?^KD4U9p9weGstb;_^13H48qIdiJWaY5(USF($&RHaOG?b#r z{l0FfWBYun5PikqwKv*Sb=iv~gYS$)RzGni$c{^KIPOg;zgY&&;14b67K0ZGF}WLD zSI%rbu+{(9;8B{vZy)d-BR3T6JLD@2cWBJd#nYv#SC9C*!mT()BCFA2=Ch#k5jbxj z^(_!kBMS~UB@%=89QOqg2jg!0BAOXX0~~26>@ton7I4R^Q^LyH<#k^N)X%~i=d{jM z%FH@x!%UPx|hLp=T}GI%;0lEPfO&a@uzntut8FLhtxm322)^ zVQ0U#zU%7=TcuW<@eTH@n~#T{@m1s5Xfcs`Zd}Ba5~t^dh4*|7oDLnN=w)cD=4tBS z_k5#7^fo8QwR67p=tGV`*E`OB$=6dr4~(QV z)NpJ}t+k>w;{pmart-IaYe_tL;x2JS%0iR-bM_r=G&mn5CZgaEe)atTo7fNj1~cv` z+5*7^EhTZ|-(fbsB$vWEr@&ja5T z4{C48!*OP#qnl0B)INXvmU^Ol7$|xn8dCwimq+-=p?*dZT6l=NYxtE*{?XtoxfH}y zj-sTxi}H@g|BVMt;82Ls94kpTHx#HO)g(W;kwtCi^*0gFd<&eTKTFf#=0IXvN$3r5 zEAztI)5^NZ?_ZC$<%RVrGiwxHvCfat0Sl|8()127xeqgRb!?U9(ZdWgi*;PrR~u%m zSNydF(~dy=LVo{gye+@~GCFTjz|rFAni}UIF<3kb*4O=K(AO4Li|&I$Ozyhtz-C1t zi~q0ggEifYM*98a7SNa?ez?gkd{G{J&`?e8e2|z_FI6h;?;3_8^TIpK%o~N@D+QG# z#=>eb)W{H%yP4T!<8%>i zMoUvOD*62$w4IZSO1q~ak>Wd&;TNw5giaX7PoEzo3Yc>yEXhBJSf&8q+`!K)4j;l!?pbdVK0?>rhz}v z8(r6cv&S5%YO&^izkrgAL@eqs_VCojlal>^KMH1f3;!Vjb+W*4E2niAvzb9o9QWC& zS(I2 zfnqm#8s6H`Ki)P^vTQL<=;TjD%MD)3WW&KUYK9$ebM7QzmlWreq=GbPLh+F>h9RebS9hb5dZG(0dwxq%J%j2zb>G= zW*wXdNh>rNeuBibT7UHvxafx#R!g;B6=HI));h3F&NMZux4(mcqL!E)pJPd{)^f6= z;4k|4kD_uG5J!`(bpwIEq-a0?Ct$Ig{rp}5)wZBHcHiqYwCa$US}b*zKMN&uth7UX z@u+_?YR6G&hj?PPza;4p?+oxa^&~GL{wE3-9E&9KMVRbQ=1zcZ3}xhQWnCD%eN=If zziv1R@DjL`)pr^zlmoP zUlQ=eQWCpE8o8H*uC+r+yq@VVBt)MvByjObgKV?C=kfF1{V{mXIDY|j!Qi*Jq>q>6 z=7q0;1!1;YcS*@|rCeOnUQN?8OPEXIgm!mHI+IOxXkS@b{?+E;V)_JsBiv(xzcUh^ zHG2TZ=JtXn(chrH(cB7ftVVMy#!>Cft-!NJa}x@znCx%CHMaesY}|`j7saM$ntEii zKT1Fi`25`(+sj%`HWX+mk5Bc_qywjEe%P+i-hi{$m{h!YI(X_XMjC6B)E>8);ZJ%L z%BC6qXVAdhP_k$G8$1f-{7nBcG~R;3g<9>OWhYfQmE1$ES2PPf26#r1FXqsVB45E# z?M1$rFY?8fB0m_)#=XdOQEY{khVRbte~DB+d$$rl>|Wyd@p=CDz`Nd_q!h)~gZ^vi z9Sfpkqj*h2dQrL~7#xC-g z6HvaT<_7NAJD+g3j{3%8h!ns)qgtY(YK3S06=4sLf$7vJhAj0DKqZYdv{7&sF>)!3 z`8gQ(iui^mT7JNzW`6lO{~M?lhfdABX_@~m)QF?fim2xJtFV#!6SzRUzcS9h+}{+g zZcbSa15+NuVT^t%lrgow5ldC zT}|$Ry20qY=6DOMC7S#o#N=MpbYPpZY53uK|4lUCl7(YUJF8`60|C!FWFu5qsA=;z z`CmtCENG6pex#wTWV&kG6?Wx?^%E=WkS+dK(80X0erjfo!q0B?|BX&rSS=R*EX3q) zVO<@YanjVj+xPq=x>BL77w!+)!r?Y ze9nkOJn+R5ZhjTY$i299VH^zo$;UoEq_GAi-SFLm{>Ko9;%@M7HR)0T4h*ifuyGb}$Hw`+mGz0k z{#(({7_3gR_d5cMT?>pf*1qGJ=WvbJ{6i53<1YLSvjkC?4ih(X=tgbX%~9>OWiww} z;EScU{1nQ_y|(CCL!+ z0#4qI zCdA}kuk}K(l_{(}{q7I*py8H09BW2-Ehifa)Qrv#{JV+od+|$D6i5E$KOQ~JfYj@y zv0$ExZ~x`5kLDO@tWIRwGCbpNf1O9ceEhe+AzGO$484$$lg8Z_RnQci1bC#bvYnML zTF@PR^0`$-NHh#h35XM9RB8C?+o`b=*$o?Muo7Y*Sec@UfC|Bh<)XCAEUPw6k7L zZnIdeazbkfeFvkOWt{da*3;xpRO^(MrwWe}^TRT7FPoUXaFb}cDeB`Y=99UKIfRMH zCfiElyANYZ=6V%HNMyXbtX$(!65lT?Pq8goOwYk{W8}_grmM))ausO8ip4eoV#to)pSUNVc`3Qs?%gvT$GhK?LKXyn+O4%+_ceI%LX z9Z$rc?a#qe;^YkUx&w?@`~*;)5b(OgO4GyMh25^*+4z=(!L*U@9XQ18`qS-K|Kr(+WR>!aH)_i%XcU(j-BdrGBhUebw;TLC|4ug5XQlSOek z*w0+yZ^PO~8z%pe*R7|d(t^RWTgrc<{2UC~hw3;O?y6aphsEV~dZO{2SWf}9Vrw~( zOjC7x44MLpH4xSPZDcrd8E;V7d7S#~v0H1$^|xvzf)( zIMPTNKv2-^aru36yBO<4y0{(TK)!X zGH0+1uL9m_L3J$o!5ZpTR`Q-rE9i-|Bzhukp*(K%=s_9j!$%KE&*4v|(cNQ#y|A&Y zLzHb3**XnsHG^vGe7KE+5N!~eX`|E{!(=#@cGl2DYZ;#zlt;D&8Vh-);bNoZ{pda~rJIi!rsczfa6V%A7UzYrIWs z&|o7A`f5(?2F6hwnVLM88yE*;wyw=X5e*%?@=*@efeC~!O@lf$pU>E>PK|K@q4)i$ zwWiBO>`~WR%-)Q;o&&#D3{_Bf%#i!TxloQwm3{IVc>*iRZurINayOhX3vQZRk8$!W zs9-#bYe{BmBCe(-S!AV=MOLUJN$^}s9Wh(3Wf%D!P2@8MBYSn~KXc?$=p&9wB`!Qq zuFbWGBs_l})V(tpZ<;3$LpG2`L3twj&H|$7O#+VQcErg+xg+j9AM^$k`VIje#Z~XI zn%-~cqPN;{fh>|n|HMKWF3?a`8qJ$DdUf$4h#OF0j!bn_mdNR3-`J=n@&G}>A1{$x zn|O&#j-9|bO(x$;{CYj5MPWnlETb$!fo`7Km0r9K?J9MtJW;^%Gcw(A09Dwr9b{=T z*#OK({YG1l`b~1<;{(}IPJygBCq0lQ??94DPXs#z@PHh-f@f)-LetbRJv3cPLeuLI zSB64U5=Ju$cvLMkEwNm_gobb>YJ{c@XlNQY$oSDH74jbqO|!MIXzB{N3ORnVeU+RU zh9((2G~{s%N@i#l8xM&|-=!{EE5mBfyu9$vGxO@#)~~SeT4qe=hq&lOhU3l!T`IHM zAm5_{NHdGkD=&y_0miLjCqv4wVkbj3 zpOd$MT5Ug);WF#yc|qE$AvIx0LV28gNUm8oke4_{mqIfMTou|?YAE18U!`7_hKjAa z!Mj`g^Ma5W%LUz~R;1H7*Ijzr^W-YJ@kwVR9fl<;-maUE$kw2;Q+?D+hcA9ody5Et zanwcm@d~*gXQuT+^NM>e$^+3NPGqBwO=bi3`Noe9b!<1OV`&(FF8_vB8!1_!Kwm7h znWI7{>hNNr)vMTxg?N7YVxfa(R?CZpfNg^ZmBOP>(-I)2betmCs~MD6gj&lpVmXliGEBSs{^k4R* z##lZLSNv8^x2?!Xc;&ZpbL4wIB(PL;X16X-s?Uu6$TPLpU;xX;1$m?_+U$GkooQ zvBLP-U*#lEzvs!$^HMUGnlv!Sl_gaZ-zEx7A`SjcUPR*T-|orx1vHm~BU5^gea|5c z?iol-olE+Cc?nvc7uMIztnk9K2hcljeI8$ZAXi1(c?jZ}pZrrUU{`%Jl-~0~eM_8h zECfyC1jhq>y5u%Pq^VQ>lHB6KgS$SSy5S=0+( zk3o^1xYcZmgGX{L+cWN_c(xom>_Ztw&YCGE85FxIJQ=IicdMaQ0?+8~n?7{U{%RtE zJ2RGZnbFAU$C~I8TFX(XYbstFm1pLFJB#8YWAXapk#YD=RixnOSH;EQL$$#$%U7%K z*GA_A6R4|YK5-YVR6Vr86MfJS!l}D}Gm9l~%X+9KF4#)(+jarGu^M-7h}xhx4HR?F zA)LUk|0%m&toy<0P%qi1wG!vpOJ3A8IJjCp-3V3kAWmXhB#u5>=d!sb@X;fZkRZY4 zD%jrtL-Z{}a=ZSiczi3g8r?I}&_OS^mG{OFxc+}I^cnr-d zlsd`0Vq6fv^%$CiBG;Hb372X9HSBbn({9PHta;FzMdB=Aj^bUnvhHq+_M_T)Vg1(1 zN^?!l3+wk*)`{)W4x3R@ajgz$7wT$3FEq z2{tqQp_$=QL8E#>oz+`=cbA z9h%~z15gvx++elTh9<8B3q@k!jdeuO(7~!Q{jc_7l z1lMRITr*_T_ z^yUo#UtA60*BE-53{eEXH5S=lsk=fm#7aXECquLwhmvjeVdFZyW*lmUHXFPaBdpKW z2z!|k*!JV>IbsETdpz+`TZznS6+c1mH`7SFsrJ_(zZ9fTB6oh(s%w+U+ zHu)XoB0TAVF6>MCH1eez`?8FFAurN~WS_%kp!5KlM}{wCZaF1vNcDcIv?wvU@K*K-Na#3#^xB!#A?-1mDP7RQkBU3e8|t6)OFA zq&{6IA6F;B$0hRdJ()f}L5x0ys7wS8d{3^x`i6Wg8V?^t{s4U?IDHFv1CTaQmweEP zaXJ@%WmPtOzeKR;t*Z1Q)sM*qrSyVU`i>I%T9R4hA9T5xSRp&mkF1~3rDwV#M~o5pk1fC9aytgPJsB6KsWM{Lp~0ZkNxE1BKbH=J|2*dyX2!3sc(_wqapdIK|Xqr zk51%c68RWIK00qFpX(qC%DGf!GVfhYuY& zD5ry8+bdX{@Y1C1p>Sb(ro{SX>065F&<)+8>rv? z1-t{<5FX0y+)~sKcV31hyx~+tMSSO36ysU2epzaEeXdmIu`J8mO~+-#mj$4f!LdQq z-?PPvweeqJ4VaHoJx8rrhyNAUa|=+q=Tj@z$NviJ+(Ixam8;7R|DD3;W*jiz`sjla__|uSZqzK#WRzj&8ss*P*I-4@QO1aUOLw zYD0c4v=T*mj%=W_(2nyW1+`q%4QxPkfTpccJx@DNbmkXX297Ti(9>vYq~QsxP!jrv zmlf9V94!#(WPy16#Pg_6$P8aTk4g*q@C>*@7RRjyD|j|?wgoG|j|Eqv!k&L}F+yQ2 zqX(K1e*a&LpfmrHixKoRAtT&fgKDG7yr^zQC~7mp%C#`W0qLC z4lL1%hbNY3MlB)0zVP*^f#V+Q;#y`&Gzot33qkfY+Q=qLkFQ6SY}xk1G~0eG+ol^J z+d|~MyJuTM%eId>TY80UUdCd&*!3uXwA0QcJxS>-wjT-MlABPS>{)O+DnRC8 zwO*_w36pFs*J)fgu77$!0!A34RAG`{R|6!wTRYvk3cwo8} zxKeo5*nIhL%@~FFmUVrtH_@(-3#M9ZBAY)O=t!Nn2+_FhUesP0#KWEYL5#yE_oAkr{x*cZ zfbfZs?CAx+EEUK_-BhL%`%qJ5t_`I63#hUuTN7uN4Qz%pSj@ceSlsbNR7%-lLwx>4 zK%B`C@pn5>EmDU$4L3PMQcXKA2rr6jtnhl3cWk)VzY^nd!b=b^oU(~|(it=6R9Fly z`!b4CZrb2_To)^QW^0OnZ$tdX8Iel4HaLdW1Euc88;%MB=LK=Io_@ zV&o>gajg^;+nM{>E@m+*($7cGE+IPIp3>M{n2HY{MeUTKTpCQo=8i?CYajUH2MgaqgF7yxnDXB=03@# zq2}iHL>$?SyT60_JqqWOchFkpe6Bd^d+(w>g2D?#^^0|?lBJn`Djd{%5OYf80l?==YNRWvwcuc;AtPACvf6f6d6JI0gj$WZjZ0Nh1z3$ z7UehNZam{li83r5txICv4`C$HgtZlhb}FRl1K6Gu_!B;~9`!c)PCFzsi?wyf&;rG9 zabRIp{s=WEyFxpBj5Z5O>=r=KT?J_%jz%ocGARp*i4k$X^JuG5)5Q8II;u3}Db#w= z7f?B}r!V;eN{t{4y3vZ@bLUaf60>t=?({PLU zGtD{n`y4e_vP>2XImc%;=Qx)886Ye^yc&SP4)QP10%bOrkTyiewx7rpH=_aww0*ex za0b*8a_QIG(U?QivgMmTc-qqVm+w)6vYtz5ZU1-+Zg>UNcmx>u+tRo(bYaT=+_B=X zLgc^;=I#P&Fg2F}ASf559=r-WOO6%P7(?7bUn^~-Npbjg(3*Vrfq><0~4mA*>A95_{BCc3ZGuua$;8 znfdOY5G}aZ@1wRtO&om-4Ky=b%B_K(n|rxw0+|Z|Z2tc(w??eoKE93Wk_(6ZKchHL z^k7aShjM%TSA>;OTpDYHGZ-iR2AhQ*0kaHF4=FROFkHzG-im3F@i^{9)`S^x005HK zw*87n5tLOtJS{RM9ExlsPd2qRT4bwmsq1K%nVA$>q~W`pYPsRN*Aah>fssO!=RYs8 z=B&g{{fS1C6083YY_5*}kWh9Jw!T$4-dz_Wr+9+iS8A&7* zQ#@hOi#UxON-m|OlC3P~(pVeGqHSuWQc8EvqkvYIQCch8tw7uea1l=RD5Vu%9`~~A z$gCIyJW_V7D>}}j8(q=cJlWP2d5&+xWpAMYiiz7&XkGN|+zU;U=sz#CCs?5cVwL0M zg=JN%D9vDG#H&OG3fvBL!`XIcQr~4pf?Ir+z9dvq!{U`zf^A~mr}n6(^bizzyU~zo zQFHV5267LEENy2qQ(@b2@=m3QIyO;>wL_OxcT`sz2uis;LHA_PWen)_A*cx6Qd8Mz z6S^MmUQ2mZX^8wcO}*4ai3^W@j+4UfA&fD?^ISTsmw0ZwdNNr#FXRrEhF@)|46tqK z+qWIZw*v3+BA>y=asDd8U|eWCYUJ6oo!j9_rt3|++z)Rzoh9O~YBef!UuLG~;MLTv zm01d}GIc_Z6Kooj&2Z*1?lbl=?jV+%jgcSY&U6~%nmP3022Rd_d+cD&S8byt2+i^6 z8@`w}xes-#>3j8>lTB&^A)*iM)gyyzMgh-b42MNLsjbpjxyP4*F=4o08x#M+{jAj$ zZfqX_#5A>WJLSG0q~f|Apf~sJfMon2hwBl-)z3O8KL|=VpT>3WY&bKjSpw!fn|4%A zlku~+vvNnNz@yP#qC%=NQmMw1Nn48u&rBaWkepzI`jm_}?kE|JKlrUcEUwW-i4-c} zmR*#AW-ua}^B^lx`lnvxL1+g+I` zw81mFEB(#PmNuWEXGhyScaeut-!+MNW8sa5ef}L5uv(8&>6+3TYoS2Hd3aVlnza`e56&YN!-u&YL!K* z6>iy6`CD1QC8R#cajIn^Gmse-K(sD0tVe1=wMK^0(4)rmR_e>DGDP`_L`)BcDN}vQ z20jm3Zd=AGe)Lt_W^kDJ)dRsZ*2&js?DywOn~z=zz1AD=m~1=Uh6lT-v$k@*K;hwUG-xw^FHDCzl;OhTqXd4Ar(ctRxG{ z2woOapB;^v6EY^;@RD3~6<6|xPr%J;$R*X5tCVJv={0}q(v8XkL7lfzDdFI8njXPBcy_b2+%BJsACV12y`;^5V<+xQ~$GWqIK_4-og^jda6LPsz z(-zmxAS^8uzGz7J)TGn@0%CT{dXNJ}Oeg6lLs^&utU2}oYdzD(j0B8)fHm7Gz%p~_ zd9y`?&o<#}FDuO+v4}uABQ0tgegImtXBX#WjDYD^+OrjoVBmGy)MddExUD<-N)#fRUVp*4oW?GzSzuSHOyXCPBo4yZwTgw`0NQK zD5!H!DC-4fEUz6YIY+Pa0#jo&BnH$dyz&iYgff$7-54+NE156p4DNbsm}VuI-k+XS zhIv-(g5B3Ong!ffG|jA5{a^VHZ1^g*A+Gh7@*Gt4x873DEBkq^T@7}S>AzPunDVwV zOgYZ8S`2nrXK)`9YnW!OLBKTirT3HpVamrmJdwPS>@xf=xZE`*4m7f zyfi%X6D8d?7QVR)|MrQJr2NG3Vs0!f{6N}z$QzhPUD14kreQg&W z@+pjPcp=?~!Wxrf)Zy%b8Ja( zGPH7#7>X_m-~U4Ct<>gONyXrnFW%M|@avb9298rD8l;1o6~9!{eM%c1-L+o4fZgic-;|Dm zne*B`Wr{MLXQGaI@9#FJP^A*jYUwV%*BRXVR}J$&*YXC_@|rKA zKlF*M{1M}nw!EaSed3Qy=2p6r@p8m4r901RQSz3~;I5>G>7?Xf6tTn;*h7MdM*lj9 z_!;g4^A#pLI439(b%e+AGS#$2pK5xHOf}txxGpr+M8bPU0V8Swc~V5gEM+!t1|uLZ zvYBmpoXPzR2$m4|R{%>>+vJbfC8!SyM8J~4GA=zGxjBXc_n3Xn;1nx9GGdvaY~)d> zv%VP>F-qCVld0d`RXCym@o=!*SR3Ce98tuxaSs-YM0{I>hsc+2`I?3>g_6&`$9~`{ z(U77MqrJ+TeAZMVF&ZR#k0%p}3Mpr~NkV$z8(9kVytzj$TQ;J8xEYAJUq=J|GYrBf!pFQjf8S3vfEB|xNh^jW_$7;%t=M->I zet4~j`ZndW_u^M-MbuShaJ(kvr{=2s0z>)NYekf{U%z3LXSimA@w^S-i>nQEh75}h zO4g026h%*FaLps|f@XyMoFWcJ7+)7!j`b>@!+Y`3x)HUN*En925f0{Rgj0qQF4v1F z=U4+oP5b@4_VC43d!1pgq5UK7-7rk8x3%B)&`>VPxOcr&JpiqR~47a+L@ zY0g2KYmnwRFFxjOd z)>hya2C(HMIswiN@5W;hT|9lPcu)OnypnArp73N@@&2!~Yk`X5I>XL_%PunP4Etbt z3A?x~B2Q6X0s%1^-0)BoOElpjsEoMbX%cHuQzNGy2pfz1#$$c8Ng7Q8T9ccY6g4(B zYDKWd(@=wYS~V}s+i0Vv_utu_-8Imj77qXS-TVLdedo^HS?<5h|95^5=d*b-+x_`< zxbnO2;J15w#e?7ULjpYbt+Nlk=Ob!?g2AI}Q=o4bJuGu?E<52TpEw<)SAqQ#C)vT* z?B}_|l9G}=_v{2OQ|J2{`j{tv28H%`!kamSb+vz{INI*Fz}K-r_u9>%zDUNyf(&-* ze>&xDUxV!5FXBx7{vOqYPvVTA|{BA7&|5n+`G zMiF8}NED$;ghxbZ5}{gznIim4X0LXx<0x&W80#a#dJ#AgqD8nXric|o>qO9s&?rKo z2vbFPNQA{AOb|gWLbwP#1!ym1vyCB?+1eFL8ycJ9>#fVXHgyTdXjCUXMN(>4B~c&T z!AS|I=<`sh>g(&PtE=OZ(&CexNsl@$;Nc=RNO?pGT8mhn^0*@y03AhawDLVE*jL2H zs{Z5*Qna-P!;y7dus;_2zC-b&3=GArnel`CV%EsyL0vH$&iF!mF`G!?kHu_=@&ku$ zIb11b1C{5cATy5!2c@849xd^lGf2_au7}Pnqn^bQ|LRo0hIy>P2M;XU+T-BNKecgc z)PLyE;}K?Cy8-Isq6~J$utR}olWpzMaIaAlZC70JP(;9`ZGxTgAA`n`McLcM+XK6fNt z1N%$Zcpseh)EMR!s@3+!eeBeCFJKL-5ogG5riG*$wRR!4@iPyFy1BBkvZ=&klQx|EAzI*KJIVo?;Mn2MqV zMFWaCD6&zMqNqZ#0!0Lh$tappXi!*DJb@w%MGcBT6thr7qDbh;rg8>S9z_(2xhT?5 z1fwWGQI29I6}GB&pX$10wRJU3U4mZ^Jh6~9$mm4ezK|_s3dko5*(xvMl^!sBN4YhA zFGDx%^un^9WTWBgEwv6_ImwzyWQuyra|+=d%=1VOT)d@@P`pb6g~IV3a^uhH>xn+2 z>VQvCtBG-!wqU$uFf^bIcP0MK@3bkgqw9bf)ZUd;idLN~8GMx%pe7HT(;nN;Z(W!n zR$8i_hbc*D)xBVK)&1({?)j*4xNaFa1;;j;Lm@|{^MkWF+;t`$27hia!=+qq7IcK^ zgCKJzH=9i|W)Ex|+%Wj`K;Phc$i3np2fZ(a1jCeP*kJf_Ca3V3N-g#b{t}qqhGhe1 z4OcS`7Sgq5Oca;2fWqQ}vXuW;h z>ANOzh{uhKF1YSvQCQ>_`bFXNS8f@a`y>5nwx7;(jy-&=<~PZf=%C>RtqvYa=XKbB z4?wHJpn-ue3`%lK!=Lkp#1YmTUQg#gC#|8pj*I`_N@?>O(GkCqzzZ?bZ1^Nl@0tyS z)9a5^OS%hd-F0`@>W!`m=BX=qS)b)2rF*W|Egeoib=&D)J^c$Jr+b4xJwLi3`NuOM zkNS_Hvv!57V8_sT?+pn$JciD)By`K-v@wETZU%`OcKZtlOQk6EQ4T+_XqrM6~ zCdGd%qiykyFtT{Z#3N_;lXQQAKT;MjMF@8_0k)h}otJHIgppR=4EW+}l`rhvq6>x_ zubZxsS5K?{kWRF6ZW{+|=_EgLG>{vnuDYH#$zkB4X=3L6wPGAC_p)powdI8^o4V$A zwczPe1q@ysU)J`P5Ki6_A~JTQ#g&U|h*VL>1;AK%N3N8Ok}H|wV|cnu8pT5u2DgRr zVufLKxTGsv@1}zd>kXz~U#91^zKP|Zl2sJo3KR${j~RWTGmgJZol?>jNDHBlkh5jscC=_qdFCg@?A5=p9qrpMYTcVaj zajxD7Imh`xa$p93n`NfKZksv}dRw>&FV;~Qa*s3ui`gr;cpSffbQo_ zg;31!NpSWl-6}Y{M%N9!seCDUp^eX!CAjtcH6M$wCDhSJ-UV^YXq`kG`>FaTsY0CN zRS-LBs_k8dMLMbbZtXKf@XmFI-g(5qgqdaRcA2rxz5tPL%h)Fi?2RX1?qgdg@>`AK zuuAJ1U^dd-2R5c^zLixl(4gV9q%%!(RsomKs3ypglVGTmpA28-YVw(>kTFx!z$C*L z9okF?pRS@kZw;RY7s|aOrKLT28tghu-7c)i)68L}liobd{yb(XS<CHZ|?FoU(%-xSR6ubngZSp zNOZrX=@2R{fzlBAjy4z&vEOh?8jG*?8{95p{VRq`qpOJNRfEiR=Z`<=o@~SQC=IDS zXqc>#5!-GJF>R)g)hQ32U8fvAes9*zhur&igqq^ z-j+8;DH`Z~K|_Ytn)*|v2K5|rE0$b1WYR~Ep$q-UbS#zM`myT1ieJ@4xw=GrtP9sh zO?2J(Hk7*=kd={9s!XW}4;?A{*HWWcTR4QqUoL829_aGNkj6`6F9|tRLBOWTnU!Ad5ow zGh`Pq>*;oeaZe$;hH<#x7YZ>BxA#IkvKh!ykfk8YMm8SV#9s7lTY+>oMg}0ehuN$| zwi@HmrJ1no02S!fOejV6AhKb!vmkp6>kGX+T)PvkZnTNifkvc)yQ5% zhAzv5Ysk=Rnc$DPl%vBnVHhLL7VC!)IFQlL$`YjW>QHwsygvXGf+cKdQ zS%EzTGJG*0yoM|S*-gx)1=$-I7mq9(^TXF-f|bUl*k5!Bg&2wZenE!}Uv~);k>U1U RIDy%Gj|KNr*3wcH|8J2)vmO8d diff --git a/_sources/emacsway/it/sdlc/models/agile/agile.rst.txt b/_sources/emacsway/it/sdlc/models/agile/agile.rst.txt index 2f152ce0..0f204679 100644 --- a/_sources/emacsway/it/sdlc/models/agile/agile.rst.txt +++ b/_sources/emacsway/it/sdlc/models/agile/agile.rst.txt @@ -199,7 +199,7 @@ Agile является естественным следствием эволю -- "Clean Agile: Back to Basics" by Robert C. Martin -Kent Beck выяснил, что напряжение являлось ни чем иным, как упреждающими защитным механизмом, спровоцированным страхами участников процесса разработки. +Kent Beck выяснил, что напряжение являлось ни чем иным, как упреждающими защитным механизмом, спровоцированным страхами обоих сторон процесса разработки. Идея Bill of Rights возникла на основе идеи Declaration of Independence (`перевод `__): @@ -475,6 +475,29 @@ Impossible. Точка. -- "`The New Methodology `__" by Martin Fowler +Пример +------ + +.. + + 💬 I had a chance to witness the pitfalls of this trap firsthand. + Working with Nokia, I noticed that management was measuring the success of its digital transformation by how many people were trained on Agile software development methodologies and were onboarded onto Agile tools. + These activity-based proxy metrics had nothing to do with business outcomes. + As I will summarize in Part I, Nokia’s transformation efforts failed to address the core platform problems that made it so **difficult for the company to adapt to the changing market**. + In spite of what appeared to be a well-planned transformation, management was not able to realize this until too late. + I watched with frustration as Nokia lost the mobile market it had created, in spite of the heroic efforts of my colleagues, who were doing everything they could to save the company. + + ... + + Even if the teams had attained a theoretical ideal of agility, would Nokia have been **able to adapt more quickly** without upstream changes to how the business was measuring delivery? + Or **adapt** downstream changes in how the software was deployed? Or the **architecture changes that were slowing developers down in the first place**? + In my opinion, that narrow-minded and activity-oriented view of Agile was the root cause of Nokia’s failed digital transformation. + The failed transformation made fast iteration and learning from the market impossible, as the lead times for delivering new features, such as an app store and an elegant home screen, were far too slow. + This hindered the business’s ability to learn and adapt, and that inability to adapt was a key factor in Nokia’s downfall. + + -- "Project to Product: How to Survive and Thrive in the Age of Digital Disruption with the Flow Framework" by Mik Kersten + + Cм. также: - "`Writing The Agile Manifesto `__" by Martin Fowler diff --git a/_sources/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.rst.txt b/_sources/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.rst.txt index c452a204..1dfc9f85 100644 --- a/_sources/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.rst.txt +++ b/_sources/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.rst.txt @@ -60,6 +60,12 @@ Product Backlog Item и Requirements Актуальная версия Agile-расширения BABoK (на момент написания статьи) - вторая, хотя актуальная версия самого BABoK - третья. + 💬 "The unit of requirements gathering is the "user story," user-visible functionality that can be developed within one iteration." + + -- "Agile Software Development" by Alistair Cockburn + +.. + 📝 "The **Product Backlog** is a list of **functional and nonfunctional requirements** that, when turned into functionality, will deliver this vision." -- "Agile Project Management with Scrum" by Ken Schwaber diff --git a/_sources/emacsway/it/sdlc/models/iterative.rst.txt b/_sources/emacsway/it/sdlc/models/iterative.rst.txt index 93cf5b6f..613b19e8 100644 --- a/_sources/emacsway/it/sdlc/models/iterative.rst.txt +++ b/_sources/emacsway/it/sdlc/models/iterative.rst.txt @@ -26,7 +26,15 @@ Iterative Development .. - 📝 ""Iteration" here means applying a function to itself." + 💬 If you run into a dead end in one of the areas, **iterate**! + Incremental refinement is a powerful tool for managing complexity. + As Polya recommended in mathematical problem solving, understand the problem, devise a plan, carry out the plan, and then look back to see how you did [Polya 1957]. + + -- "Code Complete" 2nd edition by Steve McConnell + +.. + + 💬 ""Iteration" here means applying a function to itself." -- "Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik diff --git a/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.rst.txt b/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.rst.txt index bf97a6ab..4477f5c9 100644 --- a/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.rst.txt +++ b/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.rst.txt @@ -41,6 +41,8 @@ -- "Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik +Как сказал Томас Эдисон: «Я не терпел поражений. Я просто нашёл 10 000 способов, которые не работают». + Назначение Адаптации ==================== @@ -157,6 +159,43 @@ Prediction при этом не исчезает полностью, а пони Таким образом, использование термина :ref:`requirements `, несмотря на то, что вызывает вопросы относительно семантики, никоим образом не противоречит использованию его в Agile SDLC-моделе, которая, кстати, описана тем же стандартом - ISO/IEC/IEEE 12207:2017, в разделах "5.4.2. Life cycle model for the software system" и "Annex H". +Немножко о продуктовом подходе +============================== + +.. + + 💬 Product-mode: For building, running and **iterating** on the solution or **even pivoting to a different solution** till the underlying problem is **verifiably** solved. + + 💬 **To migrate to product-mode, it is best to adopt an iterative** and fail cheap approach. Start with a pilot or two, **learn and adapt**. + Although it may feel unsound to those who are used to approving big change programs with detailed roadmaps, it is the essence of a Lean-Agile mindset to **avoid overinvesting before validating actual (not projected) benefits**. + + 💬 Product-mode: Product owners prove actual benefits either with data **from A/B testing, analytics, user surveys, etc. or with feedback from business**. This ability is dependent on good engineering **capability to develop and release frequently** in small chunks and good analytics capability to determine delta changes in adoption, conversion etc. + + There is relatively **less emphasis on assessing projected benefits upfront**, especially amongst the best such teams that execute with short cycle times and can therefore try new ideas without incurring a high cost of failure. + The product owner is empowered to approve development of roadmap items as they see fit. By developing in small, end-to-end **iterations**, product owners are able to detect early any efforts that miss the mark and thereby fail-fast (fail-cheap). + + -- "`Products Over Projects `__" by Sriram Narayan + + +Причем здесь refactoring? +========================= + +.. + + 💬 I thought borrowing money was a good idea, I thought that rushing software out the door to **get some experience** with it was a good idea, but that of course, you would eventually go back and **as you learned things about that software** you would repay that loan by refactoring the program **to reflect your experience as you acquired it**. + + -- "`Ward Explains Debt Metaphor `__" by Ward Cunningham + +.. + + 💬 McConnell writes, "In ten years the pendulum has swung from 'design everything' to 'design nothing.' But the alternative to BDUF [Big Design Up Front] isn't no design up front, it's a Little Design Up Front (LDUF) or Enough Design Up Front (ENUF)." + This is a strawman argument. + **The alternative to designing before implementing is designing after implementing.** Some design up-front is necessary, but just enough to get the initial implementation. + Further design takes place once the implementation is in place and the real constraints on the design are obvious. + Far from "design nothing," the XP strategy is "design always." + + -- "Extreme Programming Explained" 2nd edition by Kent Beck + См. также: - "`The New Methodology :: Predictive versus Adaptive `__" by Martin Fowler diff --git a/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.rst.txt b/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.rst.txt index fce3079b..0504cc6b 100644 --- a/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.rst.txt +++ b/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.rst.txt @@ -173,6 +173,12 @@ Martin Fowler о выборе момента реализации проектн -- "`Yagni `__" by Martin Fowler +.. seealso:: + + - "`Определите свои классы обслуживания с помощью Триаж Таблиц `__" Podcast "Kanban talks" Эпизод № 7. Алекс Цыбульник + - "`Classes of Service: The Everyday Concept That Can Turbocharge Your Kanban `__" by Anna Radzikowska + - "Successful Evolutionary Change for Your Technology Business" by David J. Anderson, chapter "Chapter 11: Establishing Service Level Agreements :: Typical Class-of-Service Definitions" + В каких случаях момент реализации не стоит откладывать ====================================================== diff --git a/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.rst.txt b/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.rst.txt index add60b9d..969b3f2a 100644 --- a/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.rst.txt +++ b/_sources/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.rst.txt @@ -73,6 +73,12 @@ Role of Simplicity in Agile -- И.Е. Репин +.. + + 💬 Simplicity is the ultimate sophistication. + + -- Leonardo da Vinci + Единица измерения ================= diff --git a/_sources/emacsway/it/self-education/self-education-for-software-engineer.rst.txt b/_sources/emacsway/it/self-education/self-education-for-software-engineer.rst.txt index b8cb647a..56268ea5 100644 --- a/_sources/emacsway/it/self-education/self-education-for-software-engineer.rst.txt +++ b/_sources/emacsway/it/self-education/self-education-for-software-engineer.rst.txt @@ -891,6 +891,11 @@ Donald E. Knuth: - "`How Do Story Points Relate to Hours? `__" by Mike Cohn +Оценка - это не единичное значение, а вероятностная распределённость: + +- YOW! 2016 Robert C. Martin - "`Effective Estimation (or: How not to Lie) `__" +- "`How to Read Lead Time Distribution `__" by Mauvisoft Team + Функциональное программирование ------------------------------- diff --git a/_sources/emacsway/it/team-topologies/harlan-mills'-proposal.rst.txt b/_sources/emacsway/it/team-topologies/harlan-mills'-proposal.rst.txt index e9d7d409..0c580610 100644 --- a/_sources/emacsway/it/team-topologies/harlan-mills'-proposal.rst.txt +++ b/_sources/emacsway/it/team-topologies/harlan-mills'-proposal.rst.txt @@ -120,7 +120,7 @@ Frederick Brooks формулирует противоречие. С одной Дополнительная нагрузка состоит из двух частей — обучения и обмена данными. Каждого работника нужно обучить технологии, целям проекта, общей стратегии и плану работы. Это обучение нельзя разбить на части, поэтому данная часть затрат изменяется линейно в зависимости от числа занятых. - **С обменом данными дело обстоит хуже. Если все части задания должны быть отдельно скоординированы между собой, то затраты возрастают как n(n-2)/2. Для трех работников требуется втрое больше попарного общения, чем для двух, для четырех — вшестеро. Если помимо этого возникает необходимость в совещаниях трех, четырех и т.д. работников для совместного решения вопросов, положение становится еще хуже. Дополнительные затраты на обмен данными могут полностью обесценить результат дробления исходной задачи и привести к положению, описываемому рисунком 2.4.** + **С обменом данными дело обстоит хуже. Если все части задания должны быть отдельно скоординированы между собой, то затраты возрастают как n(n-1)/2. Для трех работников требуется втрое больше попарного общения, чем для двух, для четырех — вшестеро. Если помимо этого возникает необходимость в совещаниях трех, четырех и т.д. работников для совместного решения вопросов, положение становится еще хуже. Дополнительные затраты на обмен данными могут полностью обесценить результат дробления исходной задачи и привести к положению, описываемому рисунком 2.4.** .. figure:: _media/harlan-mills'-proposal/fig-2.4-task-with-complex-interrelationships.png :alt: Рис. 2.4 Зависимость времени от числа занятых — задача со сложными взаимосвязями. Fig. 2.4 Time versus number of workers—task with complex interrelationships. The image source is "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., "Chapter 2 The Mythical Man-Month", перевод ООО Издательство "Питер". @@ -141,7 +141,7 @@ Frederick Brooks формулирует противоречие. С одной The added burden of communication is made up of two parts, training and intercommunication. Each worker must be trained in the technology, the goals of the effort, the overall strategy, and the plan of work. This training cannot be partitioned, so this part of the added effort varies linearly with the number of workers. - **Intercommunication is worse. If each part of the task must be separately coordinated with each other part/ the effort increases as n(n-I)/2. Three workers require three times as much pairwise intercommunication as two; four require six times as much as two. If, moreover, there need to be conferences among three, four, etc., workers to resolve things jointly, matters get worse yet. The added effort of communicating may fully counteract the division of the original task and bring us to the situation of Fig. 2.4.** + **Intercommunication is worse. If each part of the task must be separately coordinated with each other part/ the effort increases as n(n-1)/2. Three workers require three times as much pairwise intercommunication as two; four require six times as much as two. If, moreover, there need to be conferences among three, four, etc., workers to resolve things jointly, matters get worse yet. The added effort of communicating may fully counteract the division of the original task and bring us to the situation of Fig. 2.4.** Since software construction is inherently a systems effort—an exercise in complex interrelationships—communication effort is great, and it quickly dominates the decrease in individual task time brought about by partitioning. Adding more men then lengthens, not shortens, the schedule." @@ -553,6 +553,18 @@ Scrum of Scrums См. также структуру "Scrum of Scrum Team (SoS) a Core Team" на странице 5 "`The Scrum Software Factory `__" by Amogh Joshi. +Early Scrum +----------- + + The first keynote speaker was Ken Schwaber. Ken and Jeff Sutherland are the authors and founders of the Scrum agile methodology. Ken started by describing his experiences working with Scrum on large projects and several techniques he had successfully used in the early stages of the project life cycle. + + Ken explained on one project how the team was very concerned with getting the overall architecture of the system proven in the early stages of development. Early project iterations (sprints in Scrum terminology) contained stories focused on proving the system architecture peppered with several real business cases. After several iterations, during which the architecture was continuously refined and tested, the team had a good sense of whether the architecture was sufficient for the demands of the business. + + Scaling was then achieved by starting new teams with the founders of the original architecture team. With most of the architectural issues addressed, the new teams could focus on implementing business logic on top of the then stable architecture. + + -- "`Canadian Workshop on Scaling XP/Agile Methods `__" by Jonathan Rasmusson, Jim McDonald + + Другие ------ diff --git a/_sources/emacsway/soft-skills/cognitive-biases.rst.txt b/_sources/emacsway/soft-skills/cognitive-biases.rst.txt index f48e8e3c..ccc5e549 100644 --- a/_sources/emacsway/soft-skills/cognitive-biases.rst.txt +++ b/_sources/emacsway/soft-skills/cognitive-biases.rst.txt @@ -30,6 +30,7 @@ - "`Селективное восприятие `__" - "`Эффект привязки `__" (Эффект якоря) - "`Психологическая защита `__" +- "`Отклонение в сторону статус-кво `__" - "`Реактивное сопротивление `__" - "`Эффект ложной уникальности `__" - "`Эффект неоднозначности `__" (упоминался `здесь `__ и `здесь `__) @@ -56,6 +57,7 @@ - "`Закон тривиальности (эффект велосипедного сарая) `__" - "`Первый закон Паркинсона (Работа заполняет время, отпущенное на неё) `__" - "`Синдром неприятия чужой разработки `__" +- "`Эффект авторитета `__" - "`Групповое мышление `__" - "`Кривая забывания `__" diff --git a/_sources/emacsway/soft-skills/knowledge-vs-opinion.rst.txt b/_sources/emacsway/soft-skills/knowledge-vs-opinion.rst.txt index 5838f75a..cefa6200 100644 --- a/_sources/emacsway/soft-skills/knowledge-vs-opinion.rst.txt +++ b/_sources/emacsway/soft-skills/knowledge-vs-opinion.rst.txt @@ -135,6 +135,7 @@ Сам по себе отсыл к авторитету не является доказательством, однако, авторитеты находятся в более выгодном положении перед практикующими специалистами, поскольку занимаются этим профессионально, в то время как практикующий специалист основную часть ресурсов времени тратит на добывание средств к существованию, и не располагает ресурсами для обеспечения соизмеримой широты дивергентной фазы исследования и глубины конвергентной её проработки. Иными словами, обобщение и систематизация коллективного опыта требует таких ресурсов времени, которыми обычный практик, как правило, не располагает (хотя бывают исключения). + Как гласит народная мудрость, "скажи мне, кто твой друг, и я скажу, кто ты", а "лучший друг - это книга". Тем не менее, авторитеты тоже люди, и тоже могут ошибаться, пусть и реже. Так, например, как показала эволюция архитектурной области знаний, границы микросервисов все-таки не должны соответствовать границам Bounded Context, как считал Sam Newman на заре микросервисной архитектуры. @@ -185,6 +186,12 @@ -- Автор неизвестен +.. + + 💬 "Умный учится на своих ошибках, мудрый учится на чужих, а дурак не учится никогда." + + -- Народная мудрость + Здесь, наверное, было бы уместно сделать небольшое отступление. Распространенным заблуждением начинающих и толковых ребят является вера в то, что практика и опыт могут заменить работу с теорией, в частности - с литературой. @@ -260,6 +267,8 @@ - ":ref:`emacsway-agile-patterns`" - ":ref:`emacsway-brooks's-law`" + - "`Boiled Carrot `__" by Martin Fowler + - "`Мартышка и очки `__" / И.А. Крылов .. todo:: diff --git a/emacsway/it/sdlc/models/agile/agile.html b/emacsway/it/sdlc/models/agile/agile.html index 43a0e75d..a5971143 100644 --- a/emacsway/it/sdlc/models/agile/agile.html +++ b/emacsway/it/sdlc/models/agile/agile.html @@ -62,23 +62,27 @@

-

Что такое Agile Development

+

Что такое Agile Development

Автор раздела: Ivan Zakrevsky

-

Определение

+

Определение

💬 "Agile development - software development approach based on iterative development, frequent inspection and adaptation, and incremental deliveries, in which requirements and solutions evolve through collaboration in cross‐functional teams and through continual stakeholder feedback."

—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"

@@ -111,7 +115,7 @@

Определени

-

История

+

История

В заметке "Что такое Prediction" было сформировано противоречие, которое заключается в том, что для того, чтобы снизить стоимость разработки, нам необходимо повысить точность прогнозирования (повысить полноту требований), но повышение точности прогнозирования, в свою очередь, повышает стоимость разработки (возникает отрицательная обратная связь). Причем, повышает её экспоненциально, в то время как бизнес-выгоды от этой точности возрастают логарифмически. Иными словами, точность прогнозирования всегда имеет предел экономической целесообразности, который определяется пересечением этих двух графиков (за вычетом стоимости реализации, разумеется).

@@ -131,18 +135,18 @@

История

💬 "WaterFall is based on the empirical observation of 30 years ago (ref: BarryBoehm, Software Engineering Economics, Prentice Hall, 1981.) that the cost of change rises exponentially (base 10) by phases. The conclusion is that you should make the big decisions up front, because changing them is so expensive."

—"Water Fall" at c2.com

-
+
Figure 1. The cost of change rising exponentially over time. The image source is "Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change".
-

Figure 1. The cost of change rising exponentially over time. The image source is "Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change".

+

Figure 1. The cost of change rising exponentially over time. The image source is "Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change".

Однако, в конце 1990-х - начале 2000-х, в архитектурном мире произошли существенные изменения - обрели массовую популярность высокоуровневые объектно-ориентированные языки, появились шаблоны и принципы проектирования, методики управления сложностью (ROM, POSA, GOF, OOAD, SOLID, Use Case Driven Approach, Object-Oriented Software Construction etc.), появились TDD, Refactoring и т.п.

Унификация знаний в области архитектуры, переход ментального оперирования на элементы унифицированных шаблонных конструкций более высокого уровня абстракции, позволили сократить когнитивную и коммуникативную нагрузку на разработчика, уменьшить порог вхождения в новый проект, смягчить негативное воздействие Закона Брукса.

-
+
FIGURE 3.8 Historical cost of exploration. The image source is "Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation".
-

FIGURE 3.8 Historical cost of exploration. The image source is "Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation".

+

FIGURE 3.8 Historical cost of exploration. The image source is "Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation".

Рост количественных изменений привел к изменениям качественным ("Второй закон диалектики") - ведущим умам архитектуры своего времени удалось снизить характер роста стоимости адаптации вплоть до пологого графика, максимально приближенного к горизонтальной асимптоте. @@ -154,10 +158,10 @@

История

—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change"

-
+
Figure 3. The cost of change may not rise dramatically over time. The image source is "Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change".
-

Figure 3. The cost of change may not rise dramatically over time. The image source is "Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change".

+

Figure 3. The cost of change may not rise dramatically over time. The image source is "Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change".

Что такое асимтота, можно посмотреть в "§284 Асимтоты" Справочника по высшей математике / М.Я. Выгодский:

@@ -172,7 +176,7 @@

История

-

Суть

+

Суть

Коротко говоря, Agile модель является итеративно-инкрементальной моделью разработки, на которую наложен ряд филосовско-психологических принципов с целью снизить напряжение между техническими специалистами и представителями бизнеса. Морально-психологический климат в ИТ-индустрии того времени был, мягко говоря, напряженным:

@@ -222,7 +226,7 @@

История

—"Clean Agile: Back to Basics" by Robert C. Martin

-

Kent Beck выяснил, что напряжение являлось ни чем иным, как упреждающими защитным механизмом, спровоцированным страхами участников процесса разработки.

+

Kent Beck выяснил, что напряжение являлось ни чем иным, как упреждающими защитным механизмом, спровоцированным страхами обоих сторон процесса разработки.

Идея Bill of Rights возникла на основе идеи Declaration of Independence (перевод):

💬 "Software development is risky. People involved have many fears of what may go wrong.

@@ -360,7 +364,7 @@

История

-

О сложностях

+

О сложностях

Вернемся еще раз к выражению Kent Beck "сделайте изменение легким, а потом делай легко изменение". Оно состоит из двух частей, причем, первая из них предшествует второй. Как раз именно первую часть нередко забывают сделать на современном рынке, а без первой части вторая часть работает не будет, как это нетрудно догадаться. @@ -441,6 +445,23 @@

История

💬 "After all software is supposed to be soft."

—"The New Methodology" by Martin Fowler

+
+

Пример

+
+

💬 I had a chance to witness the pitfalls of this trap firsthand. +Working with Nokia, I noticed that management was measuring the success of its digital transformation by how many people were trained on Agile software development methodologies and were onboarded onto Agile tools. +These activity-based proxy metrics had nothing to do with business outcomes. +As I will summarize in Part I, Nokia’s transformation efforts failed to address the core platform problems that made it so difficult for the company to adapt to the changing market. +In spite of what appeared to be a well-planned transformation, management was not able to realize this until too late. +I watched with frustration as Nokia lost the mobile market it had created, in spite of the heroic efforts of my colleagues, who were doing everything they could to save the company.

+

...

+

Even if the teams had attained a theoretical ideal of agility, would Nokia have been able to adapt more quickly without upstream changes to how the business was measuring delivery? +Or adapt downstream changes in how the software was deployed? Or the architecture changes that were slowing developers down in the first place? +In my opinion, that narrow-minded and activity-oriented view of Agile was the root cause of Nokia’s failed digital transformation. +The failed transformation made fast iteration and learning from the market impossible, as the lead times for delivering new features, such as an app store and an elegant home screen, were far too slow. +This hindered the business’s ability to learn and adapt, and that inability to adapt was a key factor in Nokia’s downfall.

+

—"Project to Product: How to Survive and Thrive in the Age of Digital Disruption with the Flow Framework" by Mik Kersten

+

Cм. также:

+
diff --git a/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.html b/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.html index db0d0c22..b7811198 100644 --- a/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.html +++ b/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.html @@ -109,6 +109,10 @@

Что такое т

Актуальная версия Agile-расширения BABoK (на момент написания статьи) - вторая, хотя актуальная версия самого BABoK - третья.

+

💬 "The unit of requirements gathering is the "user story," user-visible functionality that can be developed within one iteration."

+

—"Agile Software Development" by Alistair Cockburn

+
+

📝 "The Product Backlog is a list of functional and nonfunctional requirements that, when turned into functionality, will deliver this vision."

—"Agile Project Management with Scrum" by Ken Schwaber

diff --git a/emacsway/it/sdlc/models/iterative.html b/emacsway/it/sdlc/models/iterative.html index 0578ac14..2b52f812 100644 --- a/emacsway/it/sdlc/models/iterative.html +++ b/emacsway/it/sdlc/models/iterative.html @@ -76,7 +76,15 @@
-

📝 ""Iteration" here means applying a function to itself."

+

💬 If you run into a dead end in one of the areas, iterate! +Incremental refinement is a powerful tool for managing complexity. +As Polya recommended in mathematical problem solving, understand the problem, devise a plan, carry out the plan, and then look back to see how you did [Polya 1957].

+
+

— "Code Complete" 2nd edition by Steve McConnell

+
+
+
+

💬 ""Iteration" here means applying a function to itself."

—"Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik

В математике итерация - это применение функции самой к себе, и именно этим обеспечивается "Responding", т.к. каждый новый вызов получает на вход результат работы предыдущего вызова.

diff --git a/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.html b/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.html index ca491a8b..2aae9dac 100644 --- a/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.html +++ b/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.html @@ -62,21 +62,23 @@
-

Что такое Adaptation

+

Что такое Adaptation

Автор раздела: Ivan Zakrevsky

-

Суть Адаптации

+

Суть Адаптации

+

Как сказал Томас Эдисон: «Я не терпел поражений. Я просто нашёл 10 000 способов, которые не работают».

-

Назначение Адаптации

+

Назначение Адаптации

Рость неопределенности приводит к росту стоимости Prediction по мере роста его точности. Предел экономической целесообразности Prediction определяется пересечением графика роста стоимости Prediction (в зависимости от его точности) с графиком роста бизнес-выгод от точности Прогнозирования.

Там, где сумма произведений количества Адаптаций Системного Инкремента на стоимость Адаптации системного инкремена для каждой итерации пересечет сумму экономически целесообразной стоимости Prediction на горизонте планирования, возникает предел экономической целесообразности эмпирического способа обработки неопределенности Проекта при допущении, что остаточная стоимость самой реализации (которая не имеет отношения к разрешению неопределенности) остается неизменной в обоих случаях. @@ -110,10 +113,10 @@

Назначение Для наилучшего совокупного экономического эффекта важно правильно находить баланс между Prediction и Adaptation, а также обеспечивать характер роста стоимости Adaptation максимально приближенный к горизонтальной асимптоте, поскольку, чем больше Адаптаций Системного Инкремента возникает на горизонте планирования, тем дороже становится экспериментальный способ разрешения неопределенности по сравнению с логическим.

При этом нужно учитывать, что стоимость Prediction также не константна по отношению к жизненному циклу системы, а имеет тенденцию к понижению. Т.е. чем большая часть системы уже реализована, тем больше баланс экономической целесообразности смещается от Adaptation к Prediction.

-
+
FIGURE 3.6 Make decisions at the last responsible moment. The image source is "Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation".
-

FIGURE 3.6 Make decisions at the last responsible moment. The image source is "Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation".

+

FIGURE 3.6 Make decisions at the last responsible moment. The image source is "Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation".

📝 "Most of us would prefer to wait until we have more information so that we can make a more informed decision. @@ -147,10 +150,10 @@

Назначение

Конечно, сугубо семантически, термин "requirements" немного вводит в заблуждение в Agile, ведь заранее требования к продукту неизвестны полностью, и они изменяются по мере реализации продукта. А в таком случае, как они могут что-то требовать? Вы, наверное, встречали картинку с треугольником "Iron Triangle" (Requirements/Scope, Cost, Time), где в waterfall он обращен вершиной Requirements вниз (константная область), а в Agile - вверх (переменная область). The iron triangle of planning:

-
+
Iron Triangle. Agile fixes the date and resources and varies the scope. The image source is "Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell
-

Iron Triangle. Agile fixes the date and resources and varies the scope. The image source is "Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell

+

Iron Triangle. Agile fixes the date and resources and varies the scope. The image source is "Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell

Итеративная разработка востребована, когда невозможно достигнуть полноты (Complete) требований (set of requirements).

@@ -181,6 +184,33 @@

Назначение

—"IEEE Std 830-1998, IEEE Std 830-1993 IEEE Recommended Practice for Software Requirements Specifications"

Таким образом, использование термина requirements, несмотря на то, что вызывает вопросы относительно семантики, никоим образом не противоречит использованию его в Agile SDLC-моделе, которая, кстати, описана тем же стандартом - ISO/IEC/IEEE 12207:2017, в разделах "5.4.2. Life cycle model for the software system" и "Annex H".

+

+
+

Немножко о продуктовом подходе

+
+

💬 Product-mode: For building, running and iterating on the solution or even pivoting to a different solution till the underlying problem is verifiably solved.

+

💬 To migrate to product-mode, it is best to adopt an iterative and fail cheap approach. Start with a pilot or two, learn and adapt. +Although it may feel unsound to those who are used to approving big change programs with detailed roadmaps, it is the essence of a Lean-Agile mindset to avoid overinvesting before validating actual (not projected) benefits.

+

💬 Product-mode: Product owners prove actual benefits either with data from A/B testing, analytics, user surveys, etc. or with feedback from business. This ability is dependent on good engineering capability to develop and release frequently in small chunks and good analytics capability to determine delta changes in adoption, conversion etc.

+

There is relatively less emphasis on assessing projected benefits upfront, especially amongst the best such teams that execute with short cycle times and can therefore try new ideas without incurring a high cost of failure. +The product owner is empowered to approve development of roadmap items as they see fit. By developing in small, end-to-end iterations, product owners are able to detect early any efforts that miss the mark and thereby fail-fast (fail-cheap).

+

—"Products Over Projects" by Sriram Narayan

+
+
+
+

Причем здесь refactoring?

+
+

💬 I thought borrowing money was a good idea, I thought that rushing software out the door to get some experience with it was a good idea, but that of course, you would eventually go back and as you learned things about that software you would repay that loan by refactoring the program to reflect your experience as you acquired it.

+

—"Ward Explains Debt Metaphor" by Ward Cunningham

+
+
+

💬 McConnell writes, "In ten years the pendulum has swung from 'design everything' to 'design nothing.' But the alternative to BDUF [Big Design Up Front] isn't no design up front, it's a Little Design Up Front (LDUF) or Enough Design Up Front (ENUF)." +This is a strawman argument. +The alternative to designing before implementing is designing after implementing. Some design up-front is necessary, but just enough to get the initial implementation. +Further design takes place once the implementation is in place and the real constraints on the design are obvious. +Far from "design nothing," the XP strategy is "design always."

+

—"Extreme Programming Explained" 2nd edition by Kent Beck

+

См. также:

  • "The New Methodology :: Predictive versus Adaptive" by Martin Fowler

  • diff --git a/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.html b/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.html index 6daf17ac..952ce02b 100644 --- a/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.html +++ b/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.html @@ -210,6 +210,14 @@

    Экономичес

—"Yagni" by Martin Fowler

+
+

См.также

+ +

В каких случаях момент реализации не стоит откладывать

diff --git a/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.html b/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.html index 429a51fb..8b69e7ae 100644 --- a/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.html +++ b/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.html @@ -131,6 +131,10 @@

📝 "Сначала художник рисует плохо и просто. Потом сложно и плохо. Потом сложно и хорошо. И только потом - просто и хорошо."

—И.Е. Репин

+
+

💬 Simplicity is the ultimate sophistication.

+

—Leonardo da Vinci

+

Единица измерения

Посмотрим, к примеру, мотивацию Mediator pattern:

diff --git a/emacsway/it/self-education/self-education-for-software-engineer.html b/emacsway/it/self-education/self-education-for-software-engineer.html index 0859c363..75fe7acd 100644 --- a/emacsway/it/self-education/self-education-for-software-engineer.html +++ b/emacsway/it/self-education/self-education-for-software-engineer.html @@ -959,6 +959,11 @@

Изучаем оц +

Оценка - это не единичное значение, а вероятностная распределённость:

+

Функциональное программирование

diff --git a/emacsway/it/team-topologies/harlan-mills'-proposal.html b/emacsway/it/team-topologies/harlan-mills'-proposal.html index c84077ae..b101b627 100644 --- a/emacsway/it/team-topologies/harlan-mills'-proposal.html +++ b/emacsway/it/team-topologies/harlan-mills'-proposal.html @@ -87,13 +87,14 @@
  • Nexus

  • Extreme Programming

  • Scrum of Scrums

  • -
  • Другие

  • +
  • Early Scrum

  • +
  • Другие

  • -
  • Фрактальная структура

  • -
  • Социальная роль архитектуры

  • -
  • Литература

  • -
  • Ссылки по теме

  • +
  • Фрактальная структура

  • +
  • Социальная роль архитектуры

  • +
  • Литература

  • +
  • Ссылки по теме

  • @@ -174,7 +175,7 @@

    Противореч

    Дополнительная нагрузка состоит из двух частей — обучения и обмена данными. Каждого работника нужно обучить технологии, целям проекта, общей стратегии и плану работы. Это обучение нельзя разбить на части, поэтому данная часть затрат изменяется линейно в зависимости от числа занятых.

    -

    С обменом данными дело обстоит хуже. Если все части задания должны быть отдельно скоординированы между собой, то затраты возрастают как n(n-2)/2. Для трех работников требуется втрое больше попарного общения, чем для двух, для четырех — вшестеро. Если помимо этого возникает необходимость в совещаниях трех, четырех и т.д. работников для совместного решения вопросов, положение становится еще хуже. Дополнительные затраты на обмен данными могут полностью обесценить результат дробления исходной задачи и привести к положению, описываемому рисунком 2.4.

    +

    С обменом данными дело обстоит хуже. Если все части задания должны быть отдельно скоординированы между собой, то затраты возрастают как n(n-1)/2. Для трех работников требуется втрое больше попарного общения, чем для двух, для четырех — вшестеро. Если помимо этого возникает необходимость в совещаниях трех, четырех и т.д. работников для совместного решения вопросов, положение становится еще хуже. Дополнительные затраты на обмен данными могут полностью обесценить результат дробления исходной задачи и привести к положению, описываемому рисунком 2.4.

    Рис. 2.4 Зависимость времени от числа занятых — задача со сложными взаимосвязями. Fig. 2.4 Time versus number of workers—task with complex interrelationships. The image source is "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., "Chapter 2 The Mythical Man-Month", перевод ООО Издательство "Питер".
    @@ -187,7 +188,7 @@

    Противореч

    When a task cannot be partitioned because of sequential constraints, the application of more effort has no effect on the schedule (Fig. 2.2). The bearing of a child takes nine months, no matter how many women are assigned. Many software tasks have this characteristic because of the sequential nature of debugging.

    In tasks that can be partitioned but which require communication among the subtasks, the effort of communication must be added to the amount of work to be done. Therefore the best that can be done is somewhat poorer than an even trade of men for months (Fig. 2.3).

    The added burden of communication is made up of two parts, training and intercommunication. Each worker must be trained in the technology, the goals of the effort, the overall strategy, and the plan of work. This training cannot be partitioned, so this part of the added effort varies linearly with the number of workers.

    -

    Intercommunication is worse. If each part of the task must be separately coordinated with each other part/ the effort increases as n(n-I)/2. Three workers require three times as much pairwise intercommunication as two; four require six times as much as two. If, moreover, there need to be conferences among three, four, etc., workers to resolve things jointly, matters get worse yet. The added effort of communicating may fully counteract the division of the original task and bring us to the situation of Fig. 2.4.

    +

    Intercommunication is worse. If each part of the task must be separately coordinated with each other part/ the effort increases as n(n-1)/2. Three workers require three times as much pairwise intercommunication as two; four require six times as much as two. If, moreover, there need to be conferences among three, four, etc., workers to resolve things jointly, matters get worse yet. The added effort of communicating may fully counteract the division of the original task and bring us to the situation of Fig. 2.4.

    Since software construction is inherently a systems effort—an exercise in complex interrelationships—communication effort is great, and it quickly dominates the decrease in individual task time brought about by partitioning. Adding more men then lengthens, not shortens, the schedule."

    —"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"

    @@ -512,8 +513,17 @@

    Scrum of Scrums<

    См. также структуру "Scrum of Scrum Team (SoS) a Core Team" на странице 5 "The Scrum Software Factory" by Amogh Joshi.

    +
    +

    Early Scrum

    +
    +

    The first keynote speaker was Ken Schwaber. Ken and Jeff Sutherland are the authors and founders of the Scrum agile methodology. Ken started by describing his experiences working with Scrum on large projects and several techniques he had successfully used in the early stages of the project life cycle.

    +

    Ken explained on one project how the team was very concerned with getting the overall architecture of the system proven in the early stages of development. Early project iterations (sprints in Scrum terminology) contained stories focused on proving the system architecture peppered with several real business cases. After several iterations, during which the architecture was continuously refined and tested, the team had a good sense of whether the architecture was sufficient for the demands of the business.

    +

    Scaling was then achieved by starting new teams with the founders of the original architecture team. With most of the architectural issues addressed, the new teams could focus on implementing business logic on top of the then stable architecture.

    +

    —"Canadian Workshop on Scaling XP/Agile Methods" by Jonathan Rasmusson, Jim McDonald

    +
    +
    -

    Другие

    +

    Другие

    Program Management также присутствует в MSF и в FDD. В RAD тоже аналитика является "upstream development activities". RUP реализует спиральную модель.

    @@ -555,7 +565,7 @@

    Другие

    -

    Фрактальная структура

    +

    Фрактальная структура

    Хотя Program Management и выполняет роль опорного хребта коммуникативной нагрузки коллектива, момент его внедрения в процессы разработки должен быть своевременным и оправданным, т.е. издержки на его содержание должны покрываться выгодами от его внедрения. Кроме того, концентрация всех архитектурных задач на уровне Program Management может привести к образованию узкого горлышка. Одним из способов решения этой задачи является децентрализация архитектурных решений об интеграции ограниченных контекстов. @@ -592,14 +602,14 @@

    ДругиеТаким образом, независимо от того, существует ли у команд Program Management, или же команды имеет фрактальную структуру, CDC-Tests позволяют в значительной мере управлять коммуникативной нагрузкой на команды и минизировать Проблему Брукса.

    -

    Социальная роль архитектуры

    +

    Социальная роль архитектуры

    📝 "By keeping things team sized, we help to achieve what MacCormack and colleagues call "an 'architecture for participation' that promotes ease of understanding by limiting module size, and ease of contribution by minimizing the propagation of design changes."[MacCormack et al., "Exploring the Structure of Complex Software Designs."] In other words, we need a team-first software architecture that maximizes people's ability to work with it.

    <...>

    More than ever I believe that someone who claims to be an Architect needs both technical and social skills, they need to understand people and work within the social framework. They also need a remit that is broader than pure technology—they need to have a say in organizational structures and personnel issues, i.e. they need to be a manager too.[Kelly, "Return to Conway's Law."]"

    — "Team Topologies: Organizing Business and Technology Teams for Fast Flow" by Matthew Skelton

    -

    Литература

    +

    Литература

    • "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr.

    • "Team Topologies: Organizing Business and Technology Teams for Fast Flow" by Matthew Skelton

    • @@ -612,7 +622,7 @@

      Социальная

    -

    Ссылки по теме

    +

    Ссылки по теме

    1. "Architecture Ownership Patterns For Team Topologies. Part 1: A Business Architecture Model" by Nick Tune

    2. "Architecture Ownership Patterns for Team Topologies. Part 2: Single Team Patterns" by Nick Tune

    3. diff --git a/emacsway/soft-skills/cognitive-biases.html b/emacsway/soft-skills/cognitive-biases.html index 39efb439..51fbc71b 100644 --- a/emacsway/soft-skills/cognitive-biases.html +++ b/emacsway/soft-skills/cognitive-biases.html @@ -81,6 +81,7 @@
    4. "Селективное восприятие"

    5. "Эффект привязки" (Эффект якоря)

    6. "Психологическая защита"

    7. +
    8. "Отклонение в сторону статус-кво"

    9. "Реактивное сопротивление"

    10. "Эффект ложной уникальности"

    11. "Эффект неоднозначности" (упоминался здесь и здесь)

    12. @@ -107,6 +108,7 @@
    13. "Закон тривиальности (эффект велосипедного сарая)"

    14. "Первый закон Паркинсона (Работа заполняет время, отпущенное на неё)"

    15. "Синдром неприятия чужой разработки"

    16. +
    17. "Эффект авторитета"

    18. "Групповое мышление"

    19. "Кривая забывания"

    20. "Кривая обучаемости"

    21. diff --git a/emacsway/soft-skills/knowledge-vs-opinion.html b/emacsway/soft-skills/knowledge-vs-opinion.html index 432d79ff..31d66d8b 100644 --- a/emacsway/soft-skills/knowledge-vs-opinion.html +++ b/emacsway/soft-skills/knowledge-vs-opinion.html @@ -164,7 +164,8 @@

      РешениеДело может существенно облегчиться, если у коллектива имеются общепризнанные им авторитетные авторы, освещающие решаемый вопрос. Зачастую помогают стандарты и материалы для сертификации уровня знаний.

      Сам по себе отсыл к авторитету не является доказательством, однако, авторитеты находятся в более выгодном положении перед практикующими специалистами, поскольку занимаются этим профессионально, в то время как практикующий специалист основную часть ресурсов времени тратит на добывание средств к существованию, и не располагает ресурсами для обеспечения соизмеримой широты дивергентной фазы исследования и глубины конвергентной её проработки.

      -

      Иными словами, обобщение и систематизация коллективного опыта требует таких ресурсов времени, которыми обычный практик, как правило, не располагает (хотя бывают исключения).

      +

      Иными словами, обобщение и систематизация коллективного опыта требует таких ресурсов времени, которыми обычный практик, как правило, не располагает (хотя бывают исключения). +Как гласит народная мудрость, "скажи мне, кто твой друг, и я скажу, кто ты", а "лучший друг - это книга".

      Тем не менее, авторитеты тоже люди, и тоже могут ошибаться, пусть и реже. Так, например, как показала эволюция архитектурной области знаний, границы микросервисов все-таки не должны соответствовать границам Bounded Context, как считал Sam Newman на заре микросервисной архитектуры. Так что критического мышления никто не отменял.

      @@ -204,6 +205,10 @@

      Решение

      📝 "Знание букв еще не делает человека поэтом."

      —Автор неизвестен

      +
      +

      💬 "Умный учится на своих ошибках, мудрый учится на чужих, а дурак не учится никогда."

      +

      —Народная мудрость

      +

      Здесь, наверное, было бы уместно сделать небольшое отступление. Распространенным заблуждением начинающих и толковых ребят является вера в то, что практика и опыт могут заменить работу с теорией, в частности - с литературой.

      Во-первых, среднестатистический коммерческий проект на рынке не так уж и часто может служить источником качественной практики (если даже не наоборот). @@ -260,6 +265,8 @@

      Рождается
    22. "Психологическое значение планирования"

    23. "Role of Design Patterns in Agile"

    24. "Закон Брукса"

    25. +
    26. "Boiled Carrot" by Martin Fowler

    27. +
    28. "Мартышка и очки" / И.А. Крылов

    diff --git a/rss.xml b/rss.xml index edb04899..7a94e708 100644 --- a/rss.xml +++ b/rss.xml @@ -1,6444 +1,4931 @@ -System Architecturehttps://dckms.github.io/system-architectureru2023, @dckms (<a href="https://dckms.github.io/system-architecture/LICENSE.txt" rel="nofollow">License</a>)Как пользоватьсяhttps://dckms.github.io/system-architecture/README.html - -<p><a class="reference external" href="https://github.com/emacsway/dckms-template">Distributed Collaborative Knowledge Management System</a></p> -<nav class="contents" id="id2"> +System Architecturehttps://dckms.github.io/system-architectureru2023, @dckms (<a href="https://dckms.github.io/system-architecture/LICENSE.txt" rel="nofollow">License</a>)YAGNIhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.html +<span id="emacsway-yagni"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> <p class="topic-title">Содержание</p> <ul class="simple"> -<li><p><a class="reference internal" href="#id1" id="id24">Как пользоваться</a></p> -<ul> -<li><p><a class="reference internal" href="#id3" id="id25">Почему</a></p> +<li><p><a class="reference internal" href="#yagni" id="id6">YAGNI</a></p> <ul> -<li><p><a class="reference internal" href="#id4" id="id26">Коллективность</a></p></li> -<li><p><a class="reference internal" href="#id5" id="id27">Субъектность</a></p></li> -<li><p><a class="reference internal" href="#id6" id="id28">Психология</a></p></li> -<li><p><a class="reference internal" href="#id7" id="id29">Экономия времени</a></p></li> -<li><p><a class="reference internal" href="#id8" id="id30">Навигация</a></p></li> -<li><p><a class="reference internal" href="#id9" id="id31">Интеграция</a></p></li> -<li><p><a class="reference internal" href="#id10" id="id32">Реализация</a></p></li> -<li><p><a class="reference internal" href="#id11" id="id33">Влияние на качество обучения</a></p></li> -<li><p><a class="reference internal" href="#id12" id="id34">Легкость переключения контекста</a></p></li> +<li><p><a class="reference internal" href="#id2" id="id7">Когда реализовывать проектное решение</a></p></li> +<li><p><a class="reference internal" href="#id3" id="id8">Экономический ущерб от преждевременной реализации</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id9">В каких случаях момент реализации не стоит откладывать</a></p></li> +<li><p><a class="reference internal" href="#emacsway-yagni-literature" id="id10">Литература о YAGNI</a></p></li> </ul> </li> -<li><p><a class="reference internal" href="#id13" id="id35">Порядок использования</a></p></li> -<li><p><a class="reference internal" href="#html" id="id36">Как собрать html</a></p></li> -<li><p><a class="reference internal" href="#zettelkasten" id="id37">О Zettelkasten</a></p></li> -<li><p><a class="reference internal" href="#id15" id="id38">Философия</a></p></li> -<li><p><a class="reference internal" href="#id16" id="id39">Близкие по духу системы</a></p> -<ul> -<li><p><a class="reference internal" href="#obsidian" id="id40">Obsidian</a></p></li> -<li><p><a class="reference internal" href="#neuron-zettelkasten" id="id41">Neuron Zettelkasten</a></p></li> -<li><p><a class="reference internal" href="#antora" id="id42">Antora</a></p></li> -<li><p><a class="reference internal" href="#gitjournal" id="id43">GitJournal</a></p></li> -<li><p><a class="reference internal" href="#popular-static-site-generators" id="id44">Статические генераторы сайтов</a></p></li> -<li><p><a class="reference internal" href="#id18" id="id45">Другие интересные проекты</a></p></li> </ul> -</li> -<li><p><a class="reference internal" href="#markdown" id="id46">Markdown</a></p></li> -<li><p><a class="reference internal" href="#using-dckms-on-mobile-devices" id="id47">Как работать на мобильных устройствах</a></p> -<ul> -<li><p><a class="reference internal" href="#android" id="id48">Как работать на Android</a></p></li> -<li><p><a class="reference internal" href="#iphone" id="id49">Как работать на iPhone</a></p></li> +</nav> +<p>Существует очень распространенная проблема, с которой сталкиваются почти все начинающие интеллектуально развитые разработчики. +Называется эта проблема "<a class="reference internal" href="borrowing-trouble.html#emacsway-borrowing-trouble"><span class="std std-ref">Заимствование Проблем</span></a>" ("<a class="reference internal" href="borrowing-trouble.html#emacsway-borrowing-trouble"><span class="std std-ref">Borrowing Trouble</span></a>"). +Я её иногда называю "проблемой умных людей". +Заключается она в непреодолимом желании разработчика осуществить реализацию впрок, исходя из предположения о том, что она может быть востребована в будущем. +К сожалению, чаще всего она так и остается невостребованной. +А если даже когда-нибудь и становится востребованной, то она все-равно причиняет ущерб экономике разработки.</p> +<p>Непонимание того, как этот ущерб образуется, является основной причиной продолжения этой практики и деградации экономики разработки. +Хороший архитектор или тимлид имеет ясное представление о причинах и составляющих этого ущерба, и способен пояснить их каждому разработчику, ведь это влияет непосредственно на темпы разработки. +Образно говоря, вы можете быть насколько угодно великим полководцем, но грош этому цена, если ваши солдаты не умеют метко стрелять.</p> +<p>Когда я узнал о YAGNI, моя персональная эффективность выросла в разы. +Этот подход хорошо сочетается с <a class="reference external" href="https://en.wikipedia.org/wiki/Emergent_Design#Emergent_design_in_agile_software_development">Emergent (Incremental) Design</a>.</p> +<section id="id2"> +<h2><a class="toc-backref" href="#id7" role="doc-backlink">Когда реализовывать проектное решение</a></h2> +<p>Martin Fowler о выборе момента реализации проектного решения:</p> +<blockquote> +<div><p>📝 "До введения рефакторинга в свою работу я всегда искал гибкие решения. +Для каждого технического требования я рассматривал возможности его изменения в течение срока жизни системы. +Поскольку изменения в проекте были дорогостоящими, я старался создать проект, способный выдержать изменения, которые я мог предвидеть. +Недостаток гибких решений в том, что за гибкость приходится платить. +Гибкие решения сложнее обычных. +Создаваемые по ним программы в целом труднее сопровождать, хотя и легче перенацеливать в том направлении, которое предполагалось изначально. +И даже такие решения не избавляют от необходимости разбираться, как модифицировать проект. +Для одной двух функций это сделать не очень трудно, но изменения происходят по всей системе. +Если предусматривать гибкость во всех этих местах, то вся система становится значительно сложнее и дороже в сопровождении. +Весьма разочаровывает, конечно, то, что вся эта гибкость и не нужна. +Потребуется лишь какая то часть ее, но невозможно заранее сказать какая.</p> +<p>Чтобы достичь гибкости, приходится вводить ее гораздо больше, чем требуется в действительности. +Рефакторинг предоставляет другой подход к рискам модификации. +Возможные изменения все равно надо пытаться предвидеть, как и рассматривать гибкие решения. +<strong>Но вместо реализации этих гибких решений следует задаться вопросом: "Насколько сложно будет с помощью рефакторинга преобразовать обычное решение в гибкое?"</strong> +<strong>Если, как чаще всего случается, ответ будет "весьма несложно", то надо просто реализовать обычное решение.</strong></p> +<p>Рефакторинг позволяет создавать более простые проекты, не жертвуя гибкостью, благодаря чему процесс проектирования становится более легким и менее напряженным. +Научившись в целом распознавать то, что легко поддается рефакторингу, о гибкости решений даже перестаешь задумываться. +Появляется уверенность в возможности применения рефакторинга, когда это понадобится. +Создаются самые простые решения, которые могут работать, а гибкие и сложные решения по большей части не потребуются.</p> +<p>Before I used refactoring, I always looked for flexible solutions. +With any requirement I would wonder how that requirement would change during the life of the system. +Because design changes were expensive, I would look to build a design that would stand up to the changes I could foresee. +The problem with building a flexible solution is that flexibility costs. +Flexible solutions are more complex than simple ones. +The resulting software is more difficult to maintain in general, although it is easier to flex in the direction I had in mind. +Even there, however, you have to understand how to flex the design. +For one or two aspects this is no big deal, but changes occur throughout the system. +Building flexibility in all these places makes the overall system a lot more complex and expensive to maintain. +The big frustration, of course, is that all this flexibility is not needed. +Some of it is, but it's impossible to predict which pieces those are. +To gain flexibility, you are forced to put in a lot more flexibility than you actually need.</p> +<p>With refactoring you approach the risks of change differently. +You still think about potential changes, you still consider flexible solutions. +<strong>But instead of implementing these flexible solutions, you ask yourself, "How difficult is it going to be to refactor a simple solution into the flexible solution?"</strong> +<strong>If, as happens most of the time, the answer is "pretty easy," then you just implement the simple solution.</strong></p> +<p>Refactoring can lead to simpler designs without sacrificing flexibility. +This makes the design process easier and less stressful. +Once you have a broad sense of things that refactor easily, you don't even think of the flexible solutions. +You have the confidence to refactor if the time comes. +You build the simplest thing that can possibly work. +As for the flexible, complex design, most of the time you aren't going to need it."</p> +<p class="attribution">—"Refactoring: Improving the Design of Existing Code" 1st edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts, перевод С. Маккавеева</p> +</div></blockquote> +<p>Простое и понятное определение дает Сергей Тепляков:</p> +<blockquote> +<div><p>📝 "Существует простая лакмусовая бумажка принципа YAGNI: <strong>выделение лишних абстракций (и любое другое усложнение) оправдано лишь в том случае, если стоимость их выделения в будущем будет существенно дороже, чем сейчас</strong>."</p> +<p class="attribution">—"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>", Сергей Тепляков</p> +</div></blockquote> +<p>Там же присутствует и другой немаловажный момент:</p> +<blockquote> +<div><p>📝 "Хороший дизайн заключается в простом решении, когда изменения требований ведут к линейным трудозатратам."</p> +<p class="attribution">—"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>", Сергей Тепляков</p> +</div></blockquote> +<p>Решение о выборе момента реализации зависит от условий конкретного проекта и <a class="reference internal" href="../../../models/agile/agile.html#emacsway-agile-development-essence"><span class="std std-ref">характера кривой стоимости изменения его кода</span></a>, который, в свою очередь, зависит от уровня команды, <a class="reference internal" href="../software-design/software-design.html#emacsway-agile-software-design"><span class="std std-ref">качества кода</span></a> и других объективных причин для каждого конкретного случая. +Для принятия решения достаточно просто сравнить затраты на реализацию сейчас и потом.</p> +</section> +<section id="id3"> +<h2><a class="toc-backref" href="#id8" role="doc-backlink">Экономический ущерб от преждевременной реализации</a></h2> +<p>Как оценить финансово стоимость от преждевременного усложения программы (преждевременная реализация, введение излишнего уровня абстракции, косвенности и т.п.)?</p> +<blockquote> +<div><p>📝 "Пример</p> +<p>Представьте, что вы занимаетесь программированием фактически в одиночку. +Вы видите, что добавление в программу некоторой возможности обойдется вам в $10. +Вы ожидаете, что вы сможете заработать на этой возможности приблизительно $15. +Таким образом, чистая текущая ценность (Net Present Value, NPV) добавления в программу данной возможности составит $5.</p> +<p>Представьте, что вы не можете сказать точно, какова будет на самом деле ценность рассматриваемой вами возможности, — вы можете лишь предположить, что заказчик будет готов заплатить за нее $15. +В действительности этот параметр может отличаться от предполагаемого вами значения на 100% в обе стороны. +Теперь предположим, что если вы соберетесь добавлять данную возможность спустя год от текущего момента, то это все равно будет стоить вам те же $10 (см. главу 5).</p> +<p>Какова будет ценность стратегии, в рамках которой вы не будете реализовывать эту возможность прямо сейчас, а подождете в течение года? +В настоящее время средняя процентная ставка составляет около 5% годовых. +С учетом этой процентной ставки искомая ценность составит около $7,87.</p> +<p>Следовательно, стратегия годичного ожидания, прежде чем добавить в программу новую возможность, <em>нам выгоднее</em> [в оригинальном переводе: <em>обойдется нам дороже</em>], чем если бы мы, ничего не ожидая, прямо сейчас инвестировали деньги в разработку данной возможности (напомню, что на текущий момент соответствующая NVP составляет $5). +Почему? В настоящее время мы находимся в неопределенности и не можем точно сказать, будет ли данная возможность действительно полезна для нашего заказчика и сможет ли он прямо сейчас начать зарабатывать на ней деньги. +Если мы реализуем возможность прямо сейчас и возможность окажется действительно полезной, то наш заказчик через год получит за счет этого определенную прибыль. +Однако может оказаться, что для нашего заказчика эта возможность не представляет никакой ценности, и поэтому, отказавшись на текущий момент от ее реализации, мы можем сэкономить собственные ресурсы.</p> +<p>Говоря проще, варианты помогают нам избавиться от нежелательного риска.</p> +<p>Example</p> +<p>Suppose you're programming merrily along and you see that you could add a feature that would cost you $10. +You figure the return on this feature (its net present value) is somewhere around $15. +So the net present value of adding this feature is $5.</p> +<p>Suppose you knew in your heart that it wasn't clear at all how much this new feature would be worth—it was just your guess, not something you really knew was worth $15 to the customer. +In fact, you figure that its value to the customer could vary as much as 100% from your estimate. +Suppose further (see Chapter 5, Cost of Change, page 21) that it would still cost you about $10 to add that feature one year from now.</p> +<p>What would be the value of the strategy of just waiting, of not implementing the feature now? +Well, at the usual interest rates of about 5%, the options theory calculator cranks out a value of $7.87.</p> +<p>The option of waiting is worth more than the value (NPV = $5) of investing now to add the feature. +Why? With that much uncertainy, the feature certainly might be much more valuable to the customer, in which case you're no worse off waiting than you would have been by implementing it now. +Or it could be worth zilch—in which case you've saved the trouble of a worthless exercise.</p> +<p>In the jargon of trading, options "eliminate downside risk."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 3. Economics of Software Development", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Плюс к этому добавляется ущерб от упущенной выгоды:</p> +<blockquote> +<div><p>📝 "By expending our effort on the piracy pricing software we didn't build some other feature. +If we'd instead put our energy into building the sales software for weather risks, we could have put a full storm risks feature into production and be generating revenue two months earlier. +This <strong>cost of delay</strong> due to the presumptive feature is two months revenue from storm insurance."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" by Martin Fowler</p> +</div></blockquote> +<p>И ущерб от роста стоимости сопровождения системы в связи с переусложнением:</p> +<blockquote> +<div><p>📝 "The cost of delay is one cost that a successful presumptive feature imposes, but another is the <strong>cost of carry</strong>. +The code for the presumptive feature adds some complexity to the software, this complexity makes it harder to modify and debug that software, thus increasing the cost of other features."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" by Martin Fowler</p> +</div></blockquote> +<p>Виды стоимостей, образующих экономический ущерб от преждевременной реализации, хорошо разбираются в статье "<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" by Martin Fowler:</p> +<blockquote> +<div><ul class="simple"> +<li><p>cost of build</p></li> +<li><p>cost of delayed value (ущерб упущенной выгоды)</p></li> +<li><p>cost of carry</p></li> +<li><p>cost of other features</p></li> +<li><p>cost of removing</p></li> +<li><p>cost of repair</p></li> +<li><p>on-going costs of working around its difficulties</p></li> </ul> -</li> -<li><p><a class="reference internal" href="#id20" id="id50">Интеграция с другими системами</a></p> -<ul> -<li><p><a class="reference internal" href="#id21" id="id51">Интеграция с Obsidian</a></p></li> -<li><p><a class="reference internal" href="#notion" id="id52">Интеграция с Notion</a></p></li> -<li><p><a class="reference internal" href="#evernote" id="id53">Интеграция с Evernote</a></p></li> -<li><p><a class="reference internal" href="#rss" id="id54">RSS</a></p> -<ul> -<li><p><a class="reference internal" href="#rss-mattermost" id="id55">Интегация RSS с Mattermost</a></p></li> -<li><p><a class="reference internal" href="#rss-telegram" id="id56">Интегация RSS с Telegram</a></p></li> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" by Martin Fowler</p> +</div></blockquote> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://kanbanguide.ru/opredelite-svoi-klassy-obsluzhivaniya-s-pomoshhyu-triazh-tablicz-podcast-kanban-talks-epizod-%E2%84%96-7/">Определите свои классы обслуживания с помощью Триаж Таблиц</a>" Podcast "Kanban talks" Эпизод № 7. Алекс Цыбульник</p></li> +<li><p>"<a class="reference external" href="https://djaa.com/classes-of-service/">Classes of Service: The Everyday Concept That Can Turbocharge Your Kanban</a>" by Anna Radzikowska</p></li> +<li><p>"Successful Evolutionary Change for Your Technology Business" by David J. Anderson, chapter "Chapter 11: Establishing Service Level Agreements :: Typical Class-of-Service Definitions"</p></li> </ul> -</li> -<li><p><a class="reference internal" href="#sitemap" id="id57">Sitemap</a></p></li> +</div> +</section> +<section id="id4"> +<h2><a class="toc-backref" href="#id9" role="doc-backlink">В каких случаях момент реализации не стоит откладывать</a></h2> +<blockquote> +<div><p>📝 "Если стоимость сегодняшнего решения высока, вероятность того, что оно окажется правильным, низка, вероятность того, что завтра вы найдете лучший способ решить проблему, высока, а стоимость внесения изменений в дизайн завтра низка, то мы можем прийти к выводу, что если сегодня мы можем обойтись без решения, значит, мы ни в коем случае не должны принимать это решение сегодня. +Именно такой подход используется в рамках ХР. +"Количество сложностей ровно на один день и не более того".</p> +<p>Однако некоторые факторы могут стереть наши выводы в порошок. +Если затраты, которые возникнут в случае, если мы будем принимать решение завтра, существенно больше сегодняшних, значит, мы должны принять решение сегодня в надежде на то, что завтра мы окажемся правы. +Если инерция дизайна достаточно низка (над проектом работают очень-очень умные люди), значит, у дизайна, формируемого по мере разработки, остается все меньше и меньше преимуществ. +Если вы действительно очень хороший провидец, значит, вы можете спроектировать все без исключения с самого начала, а затем приступать к реализации готового завершенного плана. +Однако для всех остальных обычных людей я не вижу иной альтернативы, кроме той, в рамках которой предлагается проектировать сегодня только то, что требует проектирования именно сегодня, и откладывать на завтра то, что можно спроектировать завтра.</p> +<p>If the cost of today's decision is high, and the probability of its being right is low, and the probability of knowing a better way tomorrow is high, and the cost of putting in the design tomorrow is low, then we can conclude that we should never make a design decision today if we don't need it today. +In fact, that is what XP concludes. +"Sufficient to the day are the troubles thereof."</p> +<p>Now, several factors can make the above evaluation null and void. +If the cost of making the change tomorrow is very much higher, then we should make the decision today on the off chance that we are right. +If the inertia of the design is low enough (for example, you have really, really smart people), then the benefits of just-in-time design are less. +If you are a really, really good guesser, then you could go ahead and design everything today. +For the rest of us, however, I don't see any alternative to the conclusion that today's design should be done today and tomorrow's design should be done tomorrow."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 17. Design Strategy", перевод ООО Издательство "Питер"</p> +</div></blockquote> +</section> +<section id="emacsway-yagni-literature"> +<span id="id5"/><h2><a class="toc-backref" href="#id10" role="doc-backlink">Литература о YAGNI</a></h2> +<ul class="simple"> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>" / Сергей Тепляков</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2012/04/blog-post_19.html">О повторном использовании кода</a>" / Сергей Тепляков</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" (хорошо разъясняет виды экономических ущербов: "cost of build", "cost of delay", "cost of carry", "cost of repair", "cost of removing")</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebt.html">Technical Debt</a>"</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebtQuadrant.html">Technical Debt Quadrant</a>"</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/DesignPayoffLine.html">Design Payoff Line</a>"</p></li> +<li><dl class="simple"> +<dt>"Extreme Programming Explained" 1st edition by Kent Beck</dt><dd><ul> +<li><p>"Chapter 3. Economics of Software Development"</p></li> +<li><p>"Chapter 17. Design Strategy"</p></li> +<li><p>"Chapter 20. Retrofitting XP"</p></li> +<li><p>"Chapter 24. What Makes XP Hard"</p></li> </ul> +</dd> +</dl> </li> -<li><p><a class="reference internal" href="#id22" id="id58">Полезные расширения</a></p></li> -<li><p><a class="reference internal" href="#id23" id="id59">Послесловие</a></p></li> +<li><dl class="simple"> +<dt>"Refactoring: Improving the Design of Existing Code" 1st (and 2nd) edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</dt><dd><ul> +<li><p>"Chapter 2. Principles in Refactoring"</p></li> </ul> +</dd> +</dl> </li> +<li><p>"Working Effectively with Legacy Code" by Michael C. Feathers</p></li> </ul> -</nav> -<section id="id3"> -<h2><a class="toc-backref" href="#id25" role="doc-backlink">Почему</a></h2> -<p>Объем информации в современном мире стал достаточно большим, и возникла потребность этим объемом как-то управлять.</p> -<section id="id4"> -<h3><a class="toc-backref" href="#id26" role="doc-backlink">Коллективность</a></h3> -<p>Опыт показал, что высокое качество объемного материала легче достигают <strong>коллективы авторов</strong>, как, например:</p> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/">.NET Microservices: Architecture for Containerized .NET Applications</a>" (<a class="reference external" href="https://github.com/dotnet/docs">более 4.5 тыс. форков</a>)</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/">Azure Architecture Center</a> (<a class="reference external" href="https://github.com/MicrosoftDocs/architecture-center">более 1.1 тыс. форков</a>)</p></li> -</ul> -<p>Опыт Microsoft продемонстрировал высокую эффективность распределенных коллективных систем управления знаниями с открытым и неограниченным авторским кругом.</p> -<p>Можно заметить, что некоторые пользователи ведут автономные версии форков, периодически вливая в них главный бранч. -Т.е., пользователи стремятся создавать <strong>собственные пространства знаний</strong>, которые <strong>обогащаются</strong> из других источников и <strong>дистиллируются</strong> от всего лишнего.</p> -<p>Это наводит на мысль - а что, если совместить персональную систему управления знаниями с коллективной? -Вы сами решаете, какими именно своими заметками вы хотите поделиться, а какие вы хотите добавить в свою базу от других авторов.</p> -</section> -<section id="id5"> -<h3><a class="toc-backref" href="#id27" role="doc-backlink">Субъектность</a></h3> -<p>У классических коллективных систем управления знаниями на основе wiki-движков, являющихся единственным носителем инфорации, информация может быть представлена только в единственном виде, а значит, она не может удовлетворять различным потребностям разных пользователей. -Возникает противоречие между между потребностью во множестве представлений информации и единственностью возможного представления информации единичного носителя.</p> -<p>Так же у разных пользователей существует различная потребность в объеме и полноте информации. -Что для одного пользователя представляет ценность, для другого - информационная помеха, затрудняющая навигацию по его подмножеству информации.</p> -<p>Попытка разрешить это противоречие порождает ряд вопросов о модерации, редакционной политике, достижении консенсуса и разрешении противоречий, выработке норм поведения, управлении правами, защите от диверсий в виде уничтожения содержимого или постановки информационных помех. -Все это резко ограничивает возможность применения wiki-движков в качестве персональной системы управления знаниями. -Теряется субъектность пользователя. -Также wiki-движки затруднительно использовать в offline-режиме, особенно с мобильного телефона.</p> -<p>Отдельные попытки решить эти проблемы, и совместить персональную и коллективную системы знаний, осуществляет Notion. -Еще интересней выглядит управление знаниями на основе простых текстовых файлов (чаще всего Markdown или reStructuredText) и системы контроля версий (обычно Git).</p> -<p>Такие средства устраняют противоречие, которое заключается в том, что один экземпляр информации не может соответствовать потребностям множества пользователей. -Каждый пользователь сам устраивает свою базу знаний так, как считает нужным, обогащая её информацией от других пользователей посредством системы контроля версий.</p> -<p>Именно на этой идее и построен данный проект, основная суть которого заключается в том, что <strong>субъектом субъектом знаний в такой моделе является именно пользователь</strong>, в то время, как в большинстве других систем управления знаниями на основе wiki-движков, пользователь является, скорее, объектом системы.</p> -<p>Распределенный подход к хранению знаний избавляет от перечисленных выше проблем - вы сами решаете, чем поделиться, и от кого и что добавить в свою базу знаний. -Можете обогащать статьи других авторов своей собственной информацией, удалять нерелевантную для вас информацию, сохраняя сфокусированность своего внимания, и делиться своими знаниями с другими специалистами, публикуя их в публичных бранчах, закрепив, при этом, свое авторство. -Ваша база знаний не обязана следовать чьим-то чужим точкам зрения. -Все как в реальной жизни.</p> -</section> -<section id="id6"> -<h3><a class="toc-backref" href="#id28" role="doc-backlink">Психология</a></h3> -<p>Немаловажным является и психологический фактор. -Одно дело, когда человеку нужно представить на суд пользователей информацию, которая будет оцениваться с позиции стандартов коллектива, а другое дело, когда он просто позволяет другим пользователям использовать его персональные заметки. -Снятие психологического барьера ускоряет обмен информацией.</p> -</section> -<section id="id7"> -<h3><a class="toc-backref" href="#id29" role="doc-backlink">Экономия времени</a></h3> -<p>Еще один фактор, который поспособствовал появлению этого проекта, заключается в том, что сегодня человек живет в условиях стесненного времени. -Каждому из нас есть чем поделиться и обогатить коллективные знания, но не у каждого есть время прорабатывать по этой теме статьи. -Именно поэтому короткие заметки стали сегодня так популярны. -В конечном итоге, люди тратят на Telegram (и другие мессенджеры) намного больше времени, чем требуется на написание статей. -Просто в Telegram они делают это короткими интервалами времени.</p> -<p>В Telegram знания хорошо рождаются, но не кристализируются, из-за чего они часто тонут в безорганизованной свалке информации среди океана информационных помех. -Несмотря на факт своего существования, эта информация быстро становится бесполезной в условиях отсутствия навигации. -Возникает потребность комбинировать Telegram с другими формами управления знаниями, и желательно, чтоб эти формы обеспечивали бы как приватный, так и коллективный способ управления знаниями.</p> -<p>Вы, наверное, замечали, как в профессиональных Telegram-чатах молодые ребята регулярно задают один и тот же вопрос. -И если на первый вопрос кто-то из экспертов ответит, то на следующий вопрос "попугайничать" уже никто из экспертов не хочет. -Тогда пытаются отвечать другие малоопытные ребята, и, зачастую, вреда от таких ответов больше, чем пользы. -Через время, отыскать правильный ответ от эксперта становится практически невозможно, так как его становится сложно выявить среди наплодившейся дезинформации.</p> -</section> -<section id="id8"> -<h3><a class="toc-backref" href="#id30" role="doc-backlink">Навигация</a></h3> -<p>Возникло противоречие: там, где можно структурировать, - там не пишут, а там, где пишут, - структурировать нельзя. -Можно ли это противоречие разрешить?</p> -<p>Цель данного проекта заключается в разрешении этого противоречия, путем обеспечения навигации в распределенной коллективной информации коротких сообщений (заметок). -Навигация позволяет повысить реиспользуемость качественных ответов.</p> -<p>Система управления знаниями - это, своего рода, скелет, на который налипают знания. -Без такого скелета знания просто тонут в бесструктурном и распределенном океане информационных помех. -Вы, наверное, слышали о таком антипаттерне как "коллекционер знаний" - это когда информации накапливается много, но найти что-нибудь в этом мессиве становится нереально.</p> -<p>Навигация обеспечивается комплексом средств:</p> -<ul class="simple"> -<li><p>Полнотекстовый offline поиск с морфологией.</p></li> -<li><p>Древовидная структуризация контента. Причем, деревьев может быть множество, и они могут пересекаться между собой. Деревья навигации не обязаны воспроизводить файловую структуру документов.</p></li> -<li><p>Алфавитный указатель (тегирование/индексирование).</p></li> -<li><p>Перекрестные, и даже кросс-проектные, ссылки.</p></li> -<li><p>Навигация по структурированному содержанию страницы.</p></li> +<li><p>"<a class="reference internal" href="borrowing-trouble.html#emacsway-borrowing-trouble"><span class="std std-ref">Borrowing trouble</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../models/agile/analysis/concerns/technical-concerns/when-to-refactor.html#emacsway-when-to-refactor"><span class="std std-ref">Когда делать refactoring в legacy</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../models/agile/analysis/concerns/technical-concerns/when-to-write-unit-tests.html#emacsway-when-to-write-unit-tests"><span class="std std-ref">Когда писать Unit Tests в legacy</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../software-design/solid.html#emacsway-agile-solid"><span class="std std-ref">Role of SOLID principles in Agile</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../software-design/software-design.html#emacsway-agile-software-design"><span class="std std-ref">Role of Software Design in Agile</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../models/agile/analysis/concerns/balancing-business-technical-concerns.html#emacsway-agile-balancing-business-technical-concerns"><span class="std std-ref">Балансирование Бизнес/Технических интересов</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../crash-course-in-software-development-economics.html#emacsway-software-development-economics-literature"><span class="std std-ref">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">Balancing Prediction/Adaptation</span></a>"</p></li> </ul> -</section> -<section id="id9"> -<h3><a class="toc-backref" href="#id31" role="doc-backlink">Интеграция</a></h3> -<p>Благодаря RSS-каналу, новые сообщения можно легко отражать в Telegram-channel или в другие мессенджеры, например, в Mattermost, посредством ботов и плагинов к мессенджерам. -Таким образом достигается и цель уведомления о новых сообщениях, и сохраняется навигация по сообщениям.</p> -</section> -<section id="id10"> -<h3><a class="toc-backref" href="#id32" role="doc-backlink">Реализация</a></h3> -<p>Система представляет собой минималистичный набор принципов и соглашений, реализованный на Open Source системе документирования <a class="reference external" href="https://www.sphinx-doc.org/">Sphinx-doc</a> и использущий reStructuredText и Markdown форматы разметок. -Sphinx-doc предоставляет и тегирование/индексирование (директива "<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#index-generating-markup">index</a>"), и перекрестные ссылки, и Table of Content (ToC, директива "<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#table-of-contents">toctree</a>"), и неограниченную иерархию файлов, и перекрестные связи между иерархиями файлов и иерархиями ToC, и клиентский полнотекстовый поиск (средствами JS браузера), и <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/extensions/todo.html">TODO</a>-листы, и RSS (в виде стороннего расширения), и подсветку синтаксиса языков программирования, и расширяемость с большим количеством готовых к использованию расширений.</p> -<p>Критически важной является <a class="reference internal" href="#using-dckms-on-mobile-devices"><span class="std std-ref">возможность работать offline на мобильном устройстве</span></a> (используя, при этом, полнотекстовый поиск с морфологией).</p> -</section> -<section id="id11"> -<h3><a class="toc-backref" href="#id33" role="doc-backlink">Влияние на качество обучения</a></h3> -<p>Вот что пишет Евгений Пешков, основатель российского DDD-сообщества, руководитель в ЦИАН:</p> -<blockquote> -<div><p>Летом 2020 я проходил курс по Системному мышлению Левенчука. Анатолий с первых же занятий всячески рекомендует "мышление письмом".</p> -<p>Что это? -Мышление письмом подразумевает создание конспектов занятий, статей, книг. -Но не просто переписывание слов автора, а своё собственное понимание пройденного.</p> -<p>Почему это важно?</p> -<ol class="arabic simple"> -<li><p>Лучше запоминаем. Это происходит из-за того, что мы прогоняем через себя, через внутренний диалог, через механическую память, через визуальный образ собственных слов.</p></li> -<li><p>Лучше понимаем. Когда мы просто мыслим, наши мысли могут быть недостаточно строго сформулированы, могут обрываться, состоять из полуобразов. Но даже с такими несформировавшимися мыслями у нас может быть ложное ощущение понятности. Когда же мы пишем - мы обязаны четко сформулировать тезисы и сложить их в определенном порядке.</p></li> -<li><p>Можно вернуться и доосмыслить. У нас остается артефакт, пригодный для дальнейшей проработки.</p></li> -<li><p>Наше знание становится отчуждаемым. Мы легко можем запостить наши мысли в телеграм или отправить другу.</p></li> -</ol> -<p>Сложно взять и начать записывать, и как одна из рекомендаций в курсе была указана книга "<a class="reference external" href="https://www.goodreads.com/book/show/34507927-how-to-take-smart-notes">How to Take Smart Notes</a>". -И в этой книге есть еще классный поинт: если мы привыкаем делать заметки, то нам становится проще писать в целом. -Тут срабатывает привычка, но кроме этого, как я и указывал ранее, у нас накапливается определенное количество артефактов, которые мы можем легко переиспользовать.</p> -<p>Источник: <a class="reference external" href="https://t.me/dddevotion/176">https://t.me/dddevotion/176</a></p> -</div></blockquote> -<p>На меня, в свое время, произвела сильное впечатление небольшая, и уже не самая молодая, книжечка "Как читать книги" / Поварнин Сергей, которую можно прочесть всего за один день. -Скачать можно <a class="reference external" href="https://royallib.com/book/povarnin_s/kak_chitat_knigi.html">здесь</a> или <a class="reference external" href="https://m.vk.com/wall-56611080_127534">здесь</a>. -Эту книжечку сложно переоценить - она на вес золота.</p> -<p>Также нужно упомянуть про особое значение возможности применять принципы <a class="reference internal" href="#zettelkasten"><span class="std std-ref">Zettelkasten</span></a> для запоминания информации и легкой навигации по ней.</p> -<p>Ну и, раз была затронута тема, не лишне будет упомянуть "A Mind for Numbers: How to Excel at Math and Science" by Barbara Ann Oakley, перевод: "Думай как математик. Как решать любые проблемы быстрее и эффективнее." / Барбара Оакли.</p> -</section> -<section id="id12"> -<h3><a class="toc-backref" href="#id34" role="doc-backlink">Легкость переключения контекста</a></h3> -<p>Специалисты, не работающие с информацией письменно, нередко испытывают затруднения с частым переключением контекста на работе. -Сложность восстанавления в памяти исходного контекста снижает качество решений. -В то же время, у специалистов, работающих с информацией письменно, таких проблем обычно не возникает.</p> -<p>Если выработать привычку записывать все в электронные заметки, прежде чем эта информация отразится в каком-либо еще источнике, то будет единый источник истины, который всегда под рукой, даже offline. -Вначале требуется определенное усилие воли и самодисциплина, чтобы выработать привычку все записывать, но результат проявляется очень быстро, ведь записываем мы один раз, а обращаемся к записанному много раз. -А если к записанному предоставить доступ команде, то это кратно повысит эффективность реиспользования информации и экономию времени.</p> -</section> -</section> -<section id="id13"> -<h2><a class="toc-backref" href="#id35" role="doc-backlink">Порядок использования</a></h2> -<p>Система работает следующим образом:</p> -<ol class="arabic"> -<li><p>Создайте форк <a class="reference external" href="https://github.com/emacsway/dckms-template">репозитария</a>.</p></li> -<li><p>Перейдите в приватный бранч "private".</p></li> -<li><p>Свои приватные заметки ведите в пространстве имен "private" (<code class="docutils literal notranslate"><span class="pre">/private</span></code>, <code class="docutils literal notranslate"><span class="pre">_html_extra/private</span></code>).</p></li> -<li><p>Создайте свой публичный бранч, например, "ivan.ivanov". Приватные директории сразу же внесите в файл ".gitignore" в этом бранче.</p></li> -<li><p>Создайте пространство имен для своих публичных заметок, которыми вы хотите поделиться, например, "ivan.ivanov" (<code class="docutils literal notranslate"><span class="pre">/ivan.ivanov</span></code>, <code class="docutils literal notranslate"><span class="pre">_html_extra/ivan.ivanov</span></code>). Таким образом вы облегчите читателям навигацию по вашим заметкам и сохраните очевидность авторства за собой (можно еще использовать директиву "<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-sectionauthor">sectionauthor</a>"). Создание персонального пространства имен необходимо еще и потому, что древовидное устройство файловой системы сложно унифицировать для всех авторов - у каждого автора есть свое видение на классификацию его материала. Благодаря гибкости директивы "<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#table-of-contents">toctree</a>", вы легко можете включать в дерево своего содержания поддеревья или страницы других авторов.</p></li> -<li><p>Тегируйте свой материал с помощью директивы "<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#index-generating-markup">index</a>"</p></li> -<li><p>С помощью директивы <a class="reference external" href="https://docutils.sourceforge.io/docs/ref/rst/directives.html#include">include</a>, вставляйте одни страницы в другие (полностью или частично, см. options: start-line, start-after, end-line, end-before) для достижения <a class="reference external" href="https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself">DRY</a>. Таким образом вы можете обогащать статьи других авторов, минимзируя исправление оргиниального текста, а также заимствовать текст других авторов в свои статьи.</p></li> -<li><p>Ненужные вам заметки других авторов вы можете удалить в своем приватном бранче. А нужные - добавить, как целиком, так и выборочно, используя <a class="reference external" href="https://git-scm.com/docs/git-cherry-pick">cherry-pick</a>.</p></li> -<li><p>Используя <a class="reference external" href="https://www.uuidgenerator.net/version4">UUID4</a>, создавайте <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#ref-role">перекрестные ссылки</a> между связанными заметками, следуя лучшим практикам <a class="reference internal" href="#zettelkasten"><span class="std std-ref">Zettelkasten</span></a>. Вместо UUID можно использовать префиксирование своих label-names, используя в качестве префикса - пространство имен своих публичных заметок (поскольку заметка может быть перемещена из приватного простанства имен в публичное). Так же можно использовать расширение <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/extensions/autosectionlabel.html">sphinx.ext.autosectionlabel</a> – Allow reference sections using its title (но оно не облегчает изменение локации заметки). И можно даже организовывать ссылки между отдельными проектами, используя директиву <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-seealso">seealso</a> и расширение <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html">sphinx.ext.intersphinx</a>.</p></li> -<li><p>Ведите <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/extensions/todo.html">TODO</a>.</p></li> -<li><p>Создайте Pull Request из своего именного публичного бранча ("ivan.ivanov") в trunk-branch. Может быть множество trunk-бранчей, и, в качестве одного из них, можете использовать <a class="reference external" href="https://github.com/dckms/system-architecture">этот</a>. Trunk-branch можно сравнить с шиной событий в Event Sourcing системе.</p></li> -<li><p>Когда вы делитесь своим контентом в публичном пространстве, важно понимать, что он может оказаться доступным в интернете на других доменах. Чтобы сохранить поисковый траффик за оригинальным адресом предоставляемых страниц, вначале каждой такой страницы используйте <a class="reference external" href="https://www.sphinx-doc.org/en/master/development/theming.html#use-custom-page-metadata-in-html-templates">custom page metadata</a> <code class="docutils literal notranslate"><span class="pre">canonical-url</span></code>:</p> -<blockquote> -<div><div class="highlight-default notranslate"><div class="highlight"><pre><span/><span class="p">:</span><span class="n">canonical</span><span class="o">-</span><span class="n">url</span><span class="p">:</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">my</span><span class="o">-</span><span class="n">domain</span><span class="o">.</span><span class="n">ru</span><span class="o">/</span><span class="n">my</span><span class="o">-</span><span class="n">path</span> -</pre></div> -</div> -<p>или <code class="docutils literal notranslate"><span class="pre">canonical-base-url</span></code> (без закрывающего слэша):</p> -<div class="highlight-default notranslate"><div class="highlight"><pre><span/><span class="p">:</span><span class="n">canonical</span><span class="o">-</span><span class="n">base</span><span class="o">-</span><span class="n">url</span><span class="p">:</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">my</span><span class="o">-</span><span class="n">domain</span><span class="o">.</span><span class="n">ru</span> -</pre></div> </div> -<p>При этом не следует использовать <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_baseurl">html_baseurl</a> или <a class="reference external" href="https://alabaster.readthedocs.io/en/latest/customization.html#theme-options">html_theme_options["canonical_url"]</a>.</p> -</div></blockquote> -</li> -<li><p>Стройте свою распределенную коллективную базу знаний.</p></li> -</ol> -<p>Можно добавить, что GitHub планирует добавить <a class="reference external" href="https://github.com/isaacs/github/issues/629">поддержку cherry-pick в свой web-интерфейс</a>, а в <a class="reference external" href="https://github.blog/2021-03-30-github-desktop-now-supports-cherry-picking/">Desktop-client она уже реализована</a>. -А вот GitLab уже реализовал <a class="reference external" href="https://docs.gitlab.com/ee/user/project/merge_requests/cherry_pick_changes.html">поддержку cherry-pick в web-интерфейсе</a>.</p> -</section> -<section id="html"> -<h2><a class="toc-backref" href="#id36" role="doc-backlink">Как собрать html</a></h2> -<ol class="arabic simple"> -<li><p>Если не установлен Python, то <a class="reference external" href="https://docs.python.org/3/installing/index.html">установите его</a>.</p></li> -<li><p>Установите зависимости. Для этого, из корневой директории проекта выполните команду: <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">-r</span> <span class="pre">requirements.freeze.txt</span></code></p></li> -<li><p>Отредактируйте файл conf.py, подробности смотрите в <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/configuration.html">документации</a>.</p></li> -<li><p>Произведите сборку: <code class="docutils literal notranslate"><span class="pre">make</span> <span class="pre">html</span></code> или <code class="docutils literal notranslate"><span class="pre">sphinx-build</span> <span class="pre">-D</span> <span class="pre">language=ru</span> <span class="pre">-b</span> <span class="pre">html</span> <span class="pre">.</span> <span class="pre">_build</span></code> или <code class="docutils literal notranslate"><span class="pre">docker</span> <span class="pre">build</span> <span class="pre">-t</span> <span class="pre">sphinx_image</span> <span class="pre">.</span> <span class="pre">&amp;&amp;</span> <span class="pre">docker</span> <span class="pre">run</span> <span class="pre">-v</span> <span class="pre">$(pwd):/sphinxtechnicalwriting</span> <span class="pre">sphinx_image</span> <span class="pre">make</span> <span class="pre">html</span></code></p></li> -<li><p>Локальный запуск: <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">http.server</span></code></p></li> -<li><p>Подробнее <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/quickstart.html">здесь</a>.</p></li> -</ol> -<p>Так же существует возможность собрать PDF-файл или электронную книгу EPUB.</p> </section> -<section id="zettelkasten"> -<span id="id14"/><h2><a class="toc-backref" href="#id37" role="doc-backlink">О Zettelkasten</a></h2> +Sat, 21 Oct 2023 00:00:00 Список литературы для самообучения разработчика программного обеспеченияhttps://dckms.github.io/system-architecture/emacsway/it/self-education/self-education-for-software-engineer.html<span class="target" id="index-0"/><section id="emacsway-self-education-literature"> +<span id="id1"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<p>Один из частых вопросов, который я наблюдаю регулярно, - это "посоветуйте список литературы в области разработки программного обеспечения". +В этой статье я изложу свое видение самообучения и приведу список тематической литературы, с учетом моего личного опыта.</p> +<nav class="contents" id="id2"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p><a class="reference external" href="https://zettelkasten.de/posts/overview/">Zettelkasten</a></p></li> -<li><p><a class="reference external" href="https://zettelkasten.de/introduction/">The Introduction to the Zettelkasten Method</a></p></li> -<li><p><a class="reference external" href="https://habr.com/ru/post/509756/">Как я веду Zettelkasten в Notion уже год: стартовый набор и полезные трюки</a></p></li> -<li><p><a class="reference external" href="https://habr.com/ru/post/508672/">Zettelkasten: как один немецкий учёный стал невероятно продуктивным</a></p></li> +<li><p><a class="reference internal" href="#emacsway-self-education-literature" id="id39">Список литературы для самообучения разработчика программного обеспечения</a></p> +<ul> +<li><p><a class="reference internal" href="#id3" id="id40">Предисловие</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id41">Кандидатский минимум</a></p> +<ul> +<li><p><a class="reference internal" href="#id5" id="id42">Учимся обучению</a></p></li> +<li><p><a class="reference internal" href="#id6" id="id43">Изучаем основную используемую технологию</a></p></li> +<li><p><a class="reference internal" href="#id7" id="id44">Азбука программирования</a></p></li> +<li><p><a class="reference internal" href="#id8" id="id45">Учимся быть эффективным</a></p></li> +<li><p><a class="reference internal" href="#id9" id="id46">Учимся делать команду эффективной</a></p></li> +<li><p><a class="reference internal" href="#id10" id="id47">Изучаем операционную систему</a></p></li> +<li><p><a class="reference internal" href="#id11" id="id48">Изучаем основы алгоритмов и структур данных</a></p></li> +<li><p><a class="reference internal" href="#id12" id="id49">Изучаем математику</a></p></li> +<li><p><a class="reference internal" href="#id13" id="id50">Учимся архитектуре</a></p></li> +<li><p><a class="reference internal" href="#id14" id="id51">Изучаем распределенные системы</a></p></li> +<li><p><a class="reference internal" href="#id15" id="id52">Изучаем распределенные системы. Углубляем навыки.</a></p></li> +<li><p><a class="reference internal" href="#ddd" id="id53">Изучаем DDD</a></p> +<ul> +<li><p><a class="reference internal" href="#id16" id="id54">Статьи на частые вопросы по DDD</a></p> +<ul> +<li><p><a class="reference internal" href="#aggregate-domain-modeling" id="id55">Aggregate &amp; Domain Modeling</a></p></li> +<li><p><a class="reference internal" href="#cqrs-event-sourcing" id="id56">CQRS &amp; Event Sourcing</a></p></li> +<li><p><a class="reference internal" href="#bounded-context-and-microservices" id="id57">Bounded Context and Microservices</a></p></li> +<li><p><a class="reference internal" href="#domain-events" id="id58">Domain Events</a></p></li> +<li><p><a class="reference internal" href="#api-design" id="id59">API-Design</a></p></li> +<li><p><a class="reference internal" href="#event-storming" id="id60">Event Storming</a></p></li> +<li><p><a class="reference internal" href="#modelling" id="id61">Modelling</a></p></li> </ul> -<p>То, что Niklas Luhmann <a class="reference external" href="https://vas3k.club/post/3040/">сделал</a> на простых бумажных карточках, можно сделать и на Sphinx-doc.</p> -</section> -<section id="id15"> -<h2><a class="toc-backref" href="#id38" role="doc-backlink">Философия</a></h2> -<p>Основные принципы системы:</p> -<ul class="simple"> -<li><p>минимизация рисков и внешних зависимостей (от конкретного типа текстового редактора, вендора)</p></li> -<li><p>минимализм</p></li> -<li><p>неограниченная расширяемость</p></li> -<li><p>автономность</p></li> -<li><p>субъектность пользователя и полный контроль над информацией</p></li> -<li><p>распределенность и коллективность</p></li> -<li><p>свободное обогащение и дистилляция информации</p></li> +</li> </ul> -</section> -<section id="id16"> -<h2><a class="toc-backref" href="#id39" role="doc-backlink">Близкие по духу системы</a></h2> -<section id="obsidian"> -<h3><a class="toc-backref" href="#id40" role="doc-backlink">Obsidian</a></h3> -<blockquote> -<div><p>In our age when cloud services can shut down, get bought, or change privacy policy any day, the last thing you want is proprietary formats and data lock-in.</p> -<p>With Obsidian, your data sits in a local folder. Never leave your life's work held hostage in the cloud again.</p> -<p>Plain text Markdown also gives you the unparalleled interoperability to use any kind of sync, encryption, or data processing that works with plain text files.</p> -<p class="attribution">—<a class="reference external" href="https://obsidian.md/">https://obsidian.md/</a></p> -</div></blockquote> -</section> -<section id="neuron-zettelkasten"> -<h3><a class="toc-backref" href="#id41" role="doc-backlink">Neuron Zettelkasten</a></h3> -<p><a class="reference external" href="https://github.com/roalyr/zettelkasten">Zettelkasten</a> - a template for a Zettelkasten based on markdown files.</p> -<blockquote> -<div><p>Neuron was designed with these criteria in mind:</p> -<ul class="simple"> -<li><p>Future-proof: store notes locally1 as plain-text (Markdown) files</p></li> -<li><p>Not tied2 to a single text editor</p></li> -<li><p>Statically generated web site, for browsing and publishing on the web</p></li> -<li><p>Remain as simple to use as possible, whilst being feature-rich via Plugins</p></li> +</li> </ul> -<p class="attribution">—<a class="reference external" href="https://neuron.zettel.page/philosophy">https://neuron.zettel.page/philosophy</a></p> -</div></blockquote> -<p>Neuron Zettelkasten может представлять интерес для тех, кто предпочитает минимизацию внешних зависимостей, минимализм и неограниченность:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://neuron.zettel.page/philosophy">https://neuron.zettel.page/philosophy</a></p></li> -<li><p><a class="reference external" href="https://neuron.zettel.page/tutorial">https://neuron.zettel.page/tutorial</a></p></li> -<li><p><a class="reference external" href="https://srid.github.io/neuron-template/README">https://srid.github.io/neuron-template/README</a></p></li> -<li><p><a class="reference external" href="https://github.com/srid/neuron">https://github.com/srid/neuron</a></p></li> -<li><p><a class="reference external" href="https://github.com/srid/neuron-template">https://github.com/srid/neuron-template</a></p></li> +</li> +<li><p><a class="reference internal" href="#id17" id="id62">Дополнительная литература (на выбор)</a></p> +<ul> +<li><p><a class="reference internal" href="#sdlc" id="id63">SDLC</a></p> +<ul> +<li><p><a class="reference internal" href="#single-team-agile" id="id64">Single-Team Agile</a></p></li> +<li><p><a class="reference internal" href="#scaled-agile" id="id65">Scaled Agile</a></p></li> +<li><p><a class="reference internal" href="#id18" id="id66">Стандарты</a></p></li> </ul> -<p><a class="reference external" href="https://lobste.rs/s/kydg6q/neuron_0_4_zettelkasten_note_management#c_me2hhh">Сравнение Neuron Zettelkasten и Sphinx-doc</a>.</p> -</section> -<section id="antora"> -<h3><a class="toc-backref" href="#id42" role="doc-backlink">Antora</a></h3> -<p><a class="reference external" href="https://antora.org/">Antora</a> - the multi-repository documentation site generator for tech writers who writing in <a class="reference external" href="https://asciidoc.org/">AsciiDoc</a>.</p> -</section> -<section id="gitjournal"> -<h3><a class="toc-backref" href="#id43" role="doc-backlink">GitJournal</a></h3> +</li> +<li><p><a class="reference internal" href="#id19" id="id67">Менеджмент</a></p></li> +<li><p><a class="reference internal" href="#id20" id="id68">Развитие личностных профессиональных качеств</a></p></li> +<li><p><a class="reference internal" href="#id21" id="id69">Базы данных</a></p></li> +<li><p><a class="reference internal" href="#id22" id="id70">Изучаем распределенные системы. Третий заход.</a></p></li> +<li><p><a class="reference internal" href="#id23" id="id71">API-Design</a></p></li> +<li><p><a class="reference internal" href="#streaming-processing" id="id72">Streaming Processing</a></p></li> +<li><p><a class="reference internal" href="#id24" id="id73">Углубляем DDD</a></p></li> +<li><p><a class="reference internal" href="#id25" id="id74">Изучаем проектирование</a></p></li> +<li><p><a class="reference internal" href="#posa" id="id75">POSA</a></p></li> +<li><p><a class="reference internal" href="#id26" id="id76">Алгоритмы. Второй заход.</a></p></li> +<li><p><a class="reference internal" href="#id27" id="id77">Тестирование</a></p></li> +<li><p><a class="reference internal" href="#id28" id="id78">Компиляторы</a></p></li> +<li><p><a class="reference internal" href="#id29" id="id79">Архитектура</a></p></li> +<li><p><a class="reference internal" href="#id30" id="id80">Аналитика</a></p></li> +<li><p><a class="reference internal" href="#id31" id="id81">Изучаем оценивание задач</a></p></li> +<li><p><a class="reference internal" href="#id32" id="id82">Функциональное программирование</a></p></li> +<li><p><a class="reference internal" href="#id33" id="id83">Справочники</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#id34" id="id84">Справочная информация</a></p> +<ul> +<li><p><a class="reference internal" href="#body-of-knowledge" id="id85">Body of Knowledge</a></p></li> +<li><p><a class="reference internal" href="#id35" id="id86">ГОСТы</a></p></li> +<li><p><a class="reference internal" href="#online" id="id87">Online-каталоги</a></p></li> +<li><p><a class="reference internal" href="#code-smell-catalogs" id="id88">Code Smell catalogs</a></p></li> +<li><p><a class="reference internal" href="#id36" id="id89">Другие подборки литературы</a></p></li> +<li><p><a class="reference internal" href="#id37" id="id90">Почтовые рассылки и сообщества</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#emacsway-reference-applications" id="id91">Эталонные демонстрационные приложения</a></p></li> +</ul> +</li> +</ul> +</nav> +<section id="id3"> +<h2><a class="toc-backref" href="#id40" role="doc-backlink">Предисловие</a></h2> +<p>Классическая ошибка новичков - жажда к знаниям, нетерпеливость. +Обычно это приводит к тому, что, в погоне за количеством, они <a class="reference internal" href="../../soft-skills/planning-in-psychology.html"><span class="doc">надрываются</span></a> (объем знаний, который предстоит освоить, действительно, огромный), осознают невыполнимость желаемого, впадают в депрессию, а затем и в состояние <a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">психологической защиты</a> (мол, "академичность" неуместна на практике), и прекращают развиваться. +Решается эта проблема очень просто - жажда должна быть не к знаниям, а к дисциплине. +А уж дисциплина обязательно приведет к обретению знаний. +Дисциплина - это, своего рода, производная знаний. +Она поддерживает постоянную скорость на пути освоения знаний. +Сперва нужно выработать привычку, а затем привычка будет работать на вас. +Как говорится, сохраняйте порядок, и порядок сохранит вас.</p> <blockquote> -<div><p>Compatible with your favorite Desktop Apps. GitJournal aims to be extremely configurable and work with your favorite apps. The idea is to not build another silo and instead integrate into your existing workflow.</p> -<p>No two people are the same...</p> -<p>Multiple Editors. All your notes are stored in Markdown. However you can edit the notes in many different ways depending on the task.</p> -<p>100% Open Source. GitJournal will always be completely Open Source. Join the community and help us build your ideal note taking app.</p> -<p class="attribution">—<a class="reference external" href="https://gitjournal.io/">https://gitjournal.io/</a></p> +<div><p>📝 "I'm not a great programmer; I'm just a good programmer with great habits."</p> +<p class="attribution">—Kent Beck at "Refactoring: Improving the Design of Existing Code" 1st edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p> </div></blockquote> +<p>Достаточно читать по 5 страниц в день. +Тут главное - стабильность. +Пусть будет по чуть-чуть, но постоянно. +Дисциплина - мать победы, говорил А.В. Суворов. +Гнаться за количеством не нужно.</p> <blockquote> -<div><p>Why create another Note Taking App? There are many Note taking apps on the desktop, but the mobile space is lacking good note taking apps which give you control over your data and operate with open protocols.</p> -<p class="attribution">—<a class="reference external" href="https://gitjournal.io/support/">https://gitjournal.io/support/</a></p> +<div><p>📝 "A little reading goes a long way toward professional advancement. If you read even one +good programming book every two months, roughly 35 pages a week, you'll soon have +a firm grasp on the industry and distinguish yourself from nearly everyone around you."</p> +<p class="attribution">—"Code Complete" by Steve McConnell</p> </div></blockquote> -</section> -<section id="popular-static-site-generators"> -<span id="id17"/><h3><a class="toc-backref" href="#id44" role="doc-backlink">Статические генераторы сайтов</a></h3> -<p>Существует целый класс инструментов, предназначенных для генерации сайта -(блога, документации или информационной страницы) из исходных материалов -в текстовых файлах в markdown, reStructuredText и других аналогичных -форматах. Часто генераторы сайтов поддерживают дополнительную разметку -(shortcodes), которая упрощает вставку диаграмм, формул, сносок, ссылок -на твиты, видео и других элементов.</p> -<p>Наиболее известные из cтатических генераторов сайтов - <a class="reference external" href="https://gohugo.io">Hugo</a> (написан -на Go, распространяется как бинарный исполняемый файл, поддерживает -<a class="reference external" href="https://gohugo.io/content-management/formats/">множество форматов</a> разметки) и <a class="reference external" href="https://github.com/jekyll/jekyll">Jekyll</a> -(требует установки Ruby). Так, например, страницы для представления -markdown файлов на Github Pаges обрабатываются Jekyll.</p> -<p>Есть группа генераторов на JavaScript, как связанная с конкретными -фреймворками (Gastby, Next, Nuxt, VuePress), так и самостоятельных -(Hexo, Eleventy и другие). На Python написаны sphinx, mkdocs, pelican и -другие. -На Ruby можно добавить еще Middleman.</p> -<p>У многих генераторов есть темы оформления, связанные с документацией, -например, очень красивый дизайн у <a class="reference external" href="https://squidfunk.github.io/mkdocs-material/">mkdocs-material</a>, <a class="reference external" href="https://getdoks.org/">doks</a>, <a class="reference external" href="https://github.com/google/docsy">Docsy</a> -для Hugo, а также у <a class="reference external" href="https://github.com/pmarsceill/just-the-docs">just-the-docs</a> и <a class="reference external" href="https://github.com/google/docsy">Docsy Jekyll Theme</a> для Jekyll.</p> -<p>Ряд статических генераторов нацелены преимущественно на "книжный" формат -представления документов c оглавлением слева:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://rust-lang.github.io/mdBook/">mdbook</a> - очень лаконичный и быстрый в развертывании генератор, -используется для документации языка Rust, поставляется бинарным -файлом</p></li> -<li><p><a class="reference external" href="https://jupyterbook.org/intro.html">jupyterbook</a> (Python)</p></li> -<li><p><a class="reference external" href="https://www.bookdown.org/">bookdown</a> (R)</p></li> -</ul> -<p>Список статических генераторов сайтов по полуярности на Github можно -посмотреть <a class="reference external" href="https://share.streamlit.io/epogrebnyak/ssg-dataset/main">здесь</a> -или <a class="reference external" href="https://jamstack.org/generators/">здесь</a>.</p> -</section> -<section id="id18"> -<h3><a class="toc-backref" href="#id45" role="doc-backlink">Другие интересные проекты</a></h3> -<ul> -<li><p>"<a class="reference external" href="https://github.com/imdone/imdone-core">imdone-core</a>" - Text based kanban processor (<a class="reference external" href="https://github.com/imdone/imdone-core#resources">Why?</a>).</p></li> -<li><p>"<a class="reference external" href="https://github.com/coddx-hq/coddx-alpha">coddx-alpha</a>" - Todo Kanban Board manages tasks and save them as TODO.md - a simple plain text file.</p></li> -<li><p>"<a class="reference external" href="http://www.orgzly.com/">Orgzly</a>" - Outliner for notes and tasks. Notebooks in plain text (<a class="reference external" href="https://github.com/orgzly">Source Code</a>).</p></li> -<li><p>"<a class="reference external" href="https://joplinapp.org/">Joplin</a>" - an open source note taking and to-do application with synchronization capabilities for Windows, macOS, Linux, Android and iOS (<a class="reference external" href="https://github.com/laurent22/joplin/">Source Code</a>).</p></li> -<li><p>"<a class="reference external" href="https://taskjuggler.org/">TaskJuggler</a>" is a modern and powerful, Free and Open Source Software project management tool. Its new approach to project planning and tracking is more flexible and superior to the commonly used Gantt chart editing tools.</p> -<blockquote> -<div><ul> -<li><p><a class="reference external" href="https://github.com/taskjuggler/TaskJuggler">source code</a></p></li> -<li><p><a class="reference external" href="https://github.com/melexis/jira-juggler">импортер из Jira</a></p></li> -<li><p>документация:</p> <blockquote> -<div><ul class="simple"> -<li><p><a class="reference external" href="https://taskjuggler.org/download/TaskJuggler-Workshop.pdf">https://taskjuggler.org/download/TaskJuggler-Workshop.pdf</a></p></li> -<li><p><a class="reference external" href="https://taskjuggler.org/tj3/manual/index.html">https://taskjuggler.org/tj3/manual/index.html</a></p></li> -</ul> +<div><p>📝 "We become authorities and experts in the practical and scientific spheres +by so many separate acts and hours of work. +If a person keeps faithfully busy each hour of the working day, +he can count on waking up some morning to find himself one of the competent +ones of his generation."</p> +<p class="attribution">—William James, cited by Steve McConnell in "Code Complete"</p> </div></blockquote> -</li> -<li><p><a class="reference external" href="https://github.com/taskjuggler/TaskJuggler/tree/master/examples">примеры</a></p></li> -</ul> +<p>И, желательно, чтобы читаемая книга совпадала с тематикой текущего проекта, чтобы через практику хорошо легла в память. +Я по этой причине часто изменял свой график чтения. +Обычно я читал в параллели 2-3 книги. Одну - планово, другие - по потребностям проекта.</p> +<p>Еще одной ошибкой является неудачный выбор литературы. +Сегодня штампуется много литературы, но далеко не каждая книга достойна внимания. +<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D0%9F%D0%B0%D1%80%D0%B5%D1%82%D0%BE">Закон Парето</a> работает и здесь.</p> +<p>Хорошей вещью для систематизации собственных знаний является написание статей и участие в профессиональных дискуссиях. +Ничто так не систематизирует собственные знания, как попытка объяснить что-то другому человеку. +Вы, конечно, будете периодически ошибаться, но для кристализации знаний это лучше, чем ничего не делать. +К тому же, это хорошо развивает сдержанность в аргументации, что немаловажно.</p> +<p>На первых порах критически важно участвовать в Open Source проектах. +Можно завести свои собственные Open Source проекты. +Можно принимать участие в каких-то существующих проектах с авторитетными комьюнити, которые будут помогать избавляться от ошибок. +В любом случае, не надейтесь на то, что профессиональные проекты предоставят вам достаточную практику для закрепления знаний. +А Open Source проекты - очень даже предоставят. +Я даже считаю, что практика должна предшествовать теории, потому что трудно запомнить какое-то решение, если вам на практике не знакома решаемая проблема.</p> +<blockquote> +<div><p>📝 "Если лечиться по справочнику, то рискуешь умереть от опечатки."</p> +<p class="attribution">—Марк Твен</p> </div></blockquote> -</li> +<p>Потребность в теории должна назреть. +Когда я приступал к теории, то у меня был накоплен уже солидный багаж проблем, решение которых я искал. +Когда я впервые прочитал о мотивации паттерна Bridge, у меня в голове промелькнуло: "так вот, оказывается, как решается та самая проблема". +Когда я читал каталог Code Smells, я частенько вспоминал свой код. +В результате, решения навечно запечатлелись в памяти.</p> +<p>Очень правильно <a class="reference external" href="https://sergeyteplyakov.blogspot.com/2017/02/reading-books-considered-harmful.html">сказал</a> Сергей Тепляков: "Полноценное обучение – это не теория vs. практика. Это комбинация этих вещей, при этом процент одного и другого зависит от человека и изучаемой темы."</p> +<p>Ну и, главное, не впадать в фанатизм. +Засасывает. +Нужно себя уравновешивать другими интересами, семья, спорт, физкультура, шашлыки, друзья, путешествия... +Непредвзятый и свободный взгляд намного важнее изобилия знаний. +Путешествие должно быть на легке, как говорил Кент Бек. +По сути, знания нужны только для того, чтобы избавиться от всего лишнего. +Архитектура - это, на самом деле, наука об ограничениях (т.е. о том, как не надо делать).</p> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference internal" href="../../soft-skills/knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">Разрешение конфликтов на почве недостатка знаний</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../soft-skills/planning-in-psychology.html#emacsway-planning-in-psychology"><span class="std std-ref">Психологическое значение планирования</span></a>"</p></li> </ul> +</div> </section> +<section id="id4"> +<h2><a class="toc-backref" href="#id41" role="doc-backlink">Кандидатский минимум</a></h2> +<section id="id5"> +<h3><a class="toc-backref" href="#id42" role="doc-backlink">Учимся обучению</a></h3> +<p>Это может показаться немного удивительным, но первая книга будет посвящена не техническим знаниям, а вопросам самоорганизации, управления временем, психологии, методикам работы под стрессом, оцеванию задач по разработке программного обеспечения, вопросам коммуникации и поведению в конфликтных ситуациях, и, самое главное, - науке быть правдивым. +Именно правдивость является важнейшим отличительным признаком настоящего профессионала. +И это не так просто, как может показаться на первый взгляд. +Есть разница между кодером и профессионалом. +И эта книга о том, как стать профессионалом. +Без знаний, изложенных в этой книге, вы просто не сможете изыскать время на самообучение, и список остальных книг вам может просто не понадобиться:</p> +<ul class="simple"> +<li><p>"The Clean Coder" by Robert C. Martin</p></li> +</ul> </section> -<section id="markdown"> -<h2><a class="toc-backref" href="#id46" role="doc-backlink">Markdown</a></h2> -<p>Markdown - популярный язык разметки. -Приводимые в начале этой страницы архитектурные руководства Microsoft написаны на Markdown.</p> -<p>Вы легко можете использовать Markdown, благодаря расширению <a class="reference external" href="https://myst-parser.readthedocs.io/en/latest/">MyST-Parser</a> (<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/markdown.html">порядок установки</a>). -Расширение позволяет использовать в Markdown все директивы и роли Sphinx-doc, и является мостом Docutils к <a class="reference external" href="https://github.com/executablebooks/markdown-it-py">markdown-it-py</a>, который поддерживает синтаксис <a class="reference external" href="https://commonmark.org/">CommonMark</a>.</p> -<p>Как вариант, возможна и обычная статическая конвертация Markdown в reStructuredText:</p> +<section id="id6"> +<h3><a class="toc-backref" href="#id43" role="doc-backlink">Изучаем основную используемую технологию</a></h3> +<p>Следующая книга должна быть посвящена основной используемой технологии, т.е. синтаксическим возможностям языка программирования. +Для Python-разработчиков хорошим выбором была бы книга:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://github.com/miyakogi/m2r">m2r</a> - Markdown to reStructuredText converter</p></li> -<li><p><a class="reference external" href="https://github.com/kata198/mdToRst">mdToRst</a> - tool and library to convert markdown [md] to restructed text [rst] (md to rst).</p></li> +<li><p>"Learning Python" 5th edition by Mark Lutz</p></li> </ul> -<p>И reStructuredText в Markdown:</p> +<p>Для Golang интересно выглядят книги:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://rst-to-myst.readthedocs.io/en/latest/">RST-to-MyST</a></p></li> +<li><p>"Hands-On Software Architecture with Golang. Design and architect highly scalable and robust applications using Go" by Jyotiswarup Raiturkar</p></li> +<li><p>"The Go Programming Language" by Alan A.A. Donovan Google Inc., Brian W. Kernighan Princeton University</p></li> </ul> -</section> -<section id="using-dckms-on-mobile-devices"> -<span id="id19"/><h2><a class="toc-backref" href="#id47" role="doc-backlink">Как работать на мобильных устройствах</a></h2> -<section id="android"> -<h3><a class="toc-backref" href="#id48" role="doc-backlink">Как работать на Android</a></h3> +<p>Для Erlang:</p> <ul class="simple"> -<li><p>Markor - популярный Markdown-редактор на Android: <a class="reference external" href="https://github.com/gsantner/markor">GitHub</a>, <a class="reference external" href="https://f-droid.org/packages/net.gsantner.markor">F-Droid</a>, <a class="reference external" href="https://play.google.com/store/apps/details?id=net.gsantner.markor">Google Play</a>.</p></li> -<li><p><a class="reference external" href="https://termux.com/">Termux</a> - a unix-like environment for Android, for git and python3.</p></li> -<li><p><a class="reference external" href="https://gitjournal.io/">GitJournal</a> - mobile first Markdown Notes integrated with Git: <a class="reference external" href="https://github.com/GitJournal/GitJournal">GitHub</a>, <a class="reference external" href="https://play.google.com/store/apps/details?id=io.gitjournal.gitjournal&amp;pcampaignid=website">Google Play</a>.</p></li> -<li><p><a class="reference external" href="https://manichord.com/projects/mgit.html">MGit</a> is a Git client Android App: <a class="reference external" href="https://github.com/maks/MGit">GitHub</a>, <a class="reference external" href="https://play.google.com/store/apps/details?id=com.manichord.mgit">Google Play</a>, <a class="reference external" href="https://f-droid.org/packages/com.manichord.mgit">F-Droid</a>.</p></li> +<li><p>"Programming Erlang: Software for a Concurrent World (Pragmatic Programmers)" 2nd edition by Joe Armstrong</p></li> </ul> -</section> -<section id="iphone"> -<h3><a class="toc-backref" href="#id49" role="doc-backlink">Как работать на iPhone</a></h3> +<p>Для frontend-разработчиков, работающих с Angular, имеет смысл обратить внимание на книгу:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://gitjournal.io/">GitJournal</a> - mobile first Markdown Notes integrated with Git: <a class="reference external" href="https://github.com/GitJournal/GitJournal">GitHub</a>, <a class="reference external" href="https://apps.apple.com/app/gitjournal/id1466519634">App Store</a>.</p></li> -<li><p><a class="reference external" href="https://apps.apple.com/ca/app/working-copy-git-client/id896694807">Working Copy</a> - a Git client.</p></li> -<li><p><a class="reference external" href="https://1writerapp.com/">1Writer</a> - powerful, beautiful Markdown editor for iOS.</p></li> -<li><p><a class="reference external" href="https://ia.net/writer">iA Writer</a> - the simple, award-winning design of iA Writer delivers the essential writing experience.</p></li> -<li><p><a class="reference external" href="https://www.omz-software.com/editorial/">Editorial</a> is a plain text editor for iOS with great Markdown support and powerful automation tools.</p></li> -<li><p><a class="reference external" href="https://tekacs.github.io/editorial-obsidian/">Editorial-obsidian</a> - Editorial scripts for Obsidian (unofficial): <a class="reference external" href="https://github.com/tekacs/editorial-obsidian">GitHub</a>.</p></li> -<li><p><a class="reference external" href="https://brettterpstra.com/ios-text-editors/">iTextEditors</a> - the iOS Text Editor roundup.</p></li> +<li><p>"ng-book2. The Complete Book on Angular 6" by Nate Murray, Felipe Coury, Ari Lerner, and Carlos Taborda</p></li> </ul> </section> -</section> -<section id="id20"> -<h2><a class="toc-backref" href="#id50" role="doc-backlink">Интеграция с другими системами</a></h2> -<p>Интеграция с другими системами, сервисами и приложениями возможна в пределах пересекающегося подмножества поддерживаемого Markdown-синтаксиса.</p> -<section id="id21"> -<h3><a class="toc-backref" href="#id51" role="doc-backlink">Интеграция с Obsidian</a></h3> -<p>Идея Obsidian так же построена на локальных Markown-файлах, но с GUI-клиентом (недавно появился и <a class="reference external" href="https://help.obsidian.md/Obsidian/Mobile+app+beta">мобильный клиент</a>). -Теоретически это означает, что вы можете шарить файлы между двумя системами. -На практике я не пробовал это сделать (если попробуете - расскажите, пожалуйста, как получилось).</p> -<p>Зато сообщество Obsidian <a class="reference external" href="https://forum.obsidian.md/t/how-do-i-work-with-obsidian-on-mobile/471">дает много дельных советов</a>, как работать с Markdown-файлами на мобильных устройствах.</p> -<p>А также сообщество Obsidian предоставляет <a class="reference external" href="https://forum.obsidian.md/t/static-site-generators-any-guides/8915">варианты статической генерации</a> помимо помимо <a class="reference external" href="https://obsidian.md/publish">Obsidian Publish</a>.</p> -</section> -<section id="notion"> -<h3><a class="toc-backref" href="#id52" role="doc-backlink">Интеграция с Notion</a></h3> -<p>Notion позволяет экспортировать содержимое в Markdown-файлы. -Теоретически это означает, что вы можете шарить файлы между двумя системами. -На практике я не пробовал это сделать (если попробуете - расскажите, пожалуйста, как получилось). -Массового импорта в Notion я не встречал, но есть варианты, например <a class="reference external" href="https://github.com/Cobertos/md2notion/">Notion.so Markdown Importer</a>.</p> -</section> -<section id="evernote"> -<h3><a class="toc-backref" href="#id53" role="doc-backlink">Интеграция с Evernote</a></h3> -<p>Существуют решения для экспорта заметок из Evernote:</p> +<section id="id7"> +<h3><a class="toc-backref" href="#id44" role="doc-backlink">Азбука программирования</a></h3> +<p>Подразумевается что вы уже хорошо знаете синтаксис основного языка программирования. +Но, знание букв еще не делает вас поэтом. +Следующие книги являются азбукой программирования. +Я привожу их в таком порядке, в каком я рекомендую их прочтение:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://github.com/wormi4ok/evernote2md">evernote2md</a> - convert Evernote .enex files to Markdown.</p></li> -<li><p><a class="reference external" href="https://github.com/claytron/ever2simple">ever2simple</a> - migrate from evernote to simplenote with markdown formatting.</p></li> -<li><p><a class="reference external" href="https://github.com/nicholaskuechler/ever2text">ever2text</a> - convert Evernote exports to text files.</p></li> +<li><p>"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides</p></li> +<li><p>"Patterns of Enterprise Application Architecture" by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford</p></li> +<li><p>"Refactoring: Improving the Design of Existing Code" 1st edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p></li> +<li><p>"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p></li> +<li><p>"Code Complete" 2nd edition by Steve McConnell</p></li> +<li><p>"UML Distilled. A Brief Guide to the Standard Object Modeling Language" 3d edition by Martin Fowler</p></li> +<li><p>"<a class="reference external" href="https://people.apache.org/~fhanik/kiss.html">KISS Principles</a>"</p></li> </ul> </section> -<section id="rss"> -<h3><a class="toc-backref" href="#id54" role="doc-backlink">RSS</a></h3> -<p>Существует несколько коробочных решений RSS-feed для Sphinx:</p> +<section id="id8"> +<h3><a class="toc-backref" href="#id45" role="doc-backlink">Учимся быть эффективным</a></h3> +<p>Знаний предыдущих пяти книг достаточно для того, чтобы вы стали работать в разы эффективней. +Но нужно не только знать, а еще и <a class="reference internal" href="../tdd/tdd.html"><span class="doc">уметь быть эффективным на практике</span></a>. +Никто не раскрывает этот вопрос лучше, чем Kent Beck:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://github.com/sphinx-contrib/yasfb">https://github.com/sphinx-contrib/yasfb</a></p></li> -<li><p><a class="reference external" href="https://github.com/sphinx-contrib/feed">https://github.com/sphinx-contrib/feed</a></p></li> -<li><p><a class="reference external" href="https://github.com/lsaffre/sphinxfeed">https://github.com/lsaffre/sphinxfeed</a></p></li> -<li><p><a class="reference external" href="https://github.com/prometheusresearch/sphinxcontrib-newsfeed">https://github.com/prometheusresearch/sphinxcontrib-newsfeed</a></p></li> +<li><p>"Test-Driven Development By Example" by Kent Beck</p></li> </ul> -<p>Смотрите так же <a class="reference external" href="https://github.com/sphinx-doc/sphinx/issues/2">https://github.com/sphinx-doc/sphinx/issues/2</a></p> -<section id="rss-mattermost"> -<h4><a class="toc-backref" href="#id55" role="doc-backlink">Интегация RSS с Mattermost</a></h4> +</section> +<section id="id9"> +<h3><a class="toc-backref" href="#id46" role="doc-backlink">Учимся делать команду эффективной</a></h3> +<p>Следующий барьер - умение сделать команду эффективной. +Вы не сможете быть эффективным в изоляции, поскольку ваша эффективность определяется качеством кодовой базы, а она разрабатывается всей командой. +Или вы сделаете команду эффективной, или ваша эффективность так и останется мечтательством. +Опять же, лучший наставник в этих вопросах - Kent Beck:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://integrations.mattermost.com/rssfeed-plugin/">https://integrations.mattermost.com/rssfeed-plugin/</a></p></li> -<li><p><a class="reference external" href="https://github.com/wbernest/mattermost-plugin-rssfeed">https://github.com/wbernest/mattermost-plugin-rssfeed</a></p></li> +<li><p>"Extreme Programming Explained" 1st edition by Kent Beck</p></li> </ul> +<p>На данном этапе, этой книги достаточно. +Обратите внимание, я советую именно первое издание, так как оно лучше раскрывает смысл и назначение <a class="reference internal" href="../sdlc/models/agile/agile.html#emacsway-agile-development-essence"><span class="std std-ref">Agile разработки</span></a>.</p> </section> -<section id="rss-telegram"> -<h4><a class="toc-backref" href="#id56" role="doc-backlink">Интегация RSS с Telegram</a></h4> +<section id="id10"> +<h3><a class="toc-backref" href="#id47" role="doc-backlink">Изучаем операционную систему</a></h3> +<p>Вот по операционным системам я мало что могу посоветовать, так как низкоуровневым программированием я практически не занимался. +Но вам обязательно нужно получить представление о том, как работают регистры процессора, память, и как управлять операционной системой.</p> +<p>Я в свое время читал эти книги (к сожалению, сегодня они устарели):</p> <ul class="simple"> -<li><p><a class="reference external" href="https://github.com/BoKKeR/RSS-to-Telegram-Bot">https://github.com/BoKKeR/RSS-to-Telegram-Bot</a></p></li> -<li><p><a class="reference external" href="https://thefeedreaderbot.com/">https://thefeedreaderbot.com/</a> ( <a class="reference external" href="https://telegram.me/TheFeedReaderBot">https://telegram.me/TheFeedReaderBot</a> )</p></li> -<li><p><a class="reference external" href="https://www.integromat.com/en/integrations/rss/telegram">https://www.integromat.com/en/integrations/rss/telegram</a></p></li> -<li><p><a class="reference external" href="https://core.telegram.org/bots/faq">https://core.telegram.org/bots/faq</a></p></li> +<li><p>"The Linux® Kernel Primer: A Top-Down Approach for x86 and PowerPC Architectures" by Claudia Salzberg Rodriguez, Gordon Fischer, Steven Smolski</p></li> +<li><p>"Digital computers and microprocessors" by Aliyev / "Цифровая вычислительная техника и микропроцессоры" М.М.Алиев</p></li> +</ul> +<p>А вот этот справочник у меня всегда под рукой:</p> +<ul class="simple"> +<li><p>"Unix and Linux System Administration Handbook" 5th edition by Evi Nemeth, Garth Snyder, Trent R. Hein, Ben Whaley, Dan Mackin</p></li> </ul> </section> -</section> -<section id="sitemap"> -<h3><a class="toc-backref" href="#id57" role="doc-backlink">Sitemap</a></h3> +<section id="id11"> +<h3><a class="toc-backref" href="#id48" role="doc-backlink">Изучаем основы алгоритмов и структур данных</a></h3> +<p>Алгоритмы хоть и используются редко в прикладной разработке (если вы только не пишете поисковые системы, системные утилиты, языки программирования и операционные системы, системы маршрутизации, биржевые анализаторы и т.п.), но знать хотя бы базовые основы необходимо. +Существует книга, которая за двести с небольшим страниц может дать эти базовые основы в легкой и популярной форме:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://github.com/jdillard/sphinx-sitemap">https://github.com/jdillard/sphinx-sitemap</a></p></li> +<li><p>"Algorithms Unlocked" 3d edition by Thomas H. Cormen</p></li> +</ul> +<p>Данная книга не акцентируется на математике, что, с одной стороны, облегчает освоение материала, но, с другой стороны, оставляет невосполненным важный аспект профессиональных знаний. +К счастью, существует книга, которая обеспечивает легкий вход в алгоритмы, включая их математический анализ:</p> +<ul class="simple"> +<li><p>"Introduction to the Design and Analysis of Algorithms" 3d edition by A.Levitin</p></li> +</ul> +<p>При чтении этой книги могут возникать вопросы справочного характера по математике, ответы на которые можно найти в приложении этой книги (Appendix A: Useful Formulas for the Analysis of Algorithms, Appendix B: Short Tutorial on Recurrence Relations), в математических справочниках (например, М.Я. Выгодского, А.А. Гусака) или в справочном разделе по математике "VIII Appendix: Mathematical Background" книги "Introduction to Algorithms" 3d edition by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein.</p> +<p>В качестве минималистичного ликбеза по теоретическим основам может неплохо подойти книга:</p> +<ul class="simple"> +<li><p>"Computer Science Distilled" by Wladston Ferreira Filho</p></li> </ul> +<p>Она содержит минималистичные основы математики (логика, комбинаторика, вероятность), алгоритмы и структуры данных, основы Баз Данных (RDBMS, NoSQL), описание Парадигм Программирования и основы архитектуры железа.</p> </section> +<section id="id12"> +<h3><a class="toc-backref" href="#id49" role="doc-backlink">Изучаем математику</a></h3> +<p>Существует монументальная книга, которую стоит упомянуть отдельно (обратите внимание на фамилии авторов, которые в представлении не нуждаются). +Чтобы не тормозить общий процесс обучения, ее лучше читать в параллельно-фоновом режиме. +К тому же математические знания следует всегда поддерживать в актуальном состоянии, и регулярно освежать их в голове в фоновом режиме.</p> +<ul class="simple"> +<li><p>"Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik</p></li> +</ul> +<p>Эта книга дает прекрасную математическую базу для функционального программирования. +И хорошо заходит в сочетании с "The Art Of Computer Programming" Volume 1 3d edition by Donald Knuth, поскольку у них многие темы пересекаются и раскрываются с разных точек зрения, что дает полноту понимания. +Справочник математических нотаций в конце книги нередко оказывается полезным.</p> +<p>Книги по математике и алгоритмам - сложные книги, и я хотел бы поделиться одним советом, который я услышал еще в студенчестве. +Если что-то непонятно - прочитай три раза:</p> +<ol class="arabic simple"> +<li><p>Первый раз просто прочитай, оставив попытки что-то понять, - нужно просто получить обзорность материала.</p></li> +<li><p>Второй раз прочитай уже пытаясь слегка вникать.</p></li> +<li><p>И третий раз прочитай уже вникая полностью.</p></li> +</ol> </section> -<section id="id22"> -<h2><a class="toc-backref" href="#id58" role="doc-backlink">Полезные расширения</a></h2> +<section id="id13"> +<h3><a class="toc-backref" href="#id50" role="doc-backlink">Учимся архитектуре</a></h3> +<p>Теперь можно приступить и к архитектуре:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://sphinxcontrib-needs.readthedocs.io/en/latest/">Sphinx-Needs</a> (<a class="reference external" href="https://github.com/useblocks/sphinxcontrib-needs">source code</a>) - Sphinx-Needs allows the definition, linking and filtering of need-objects, which are by default: requirements, specifications, implementations, test cases.</p></li> -<li><p><a class="reference external" href="https://0x6d64.github.io/sphinx-traceability-example/">Sphinx Traceability plugin</a> (<a class="reference external" href="https://github.com/melexis/sphinx-traceability-extension">source code</a>) - traceability extension for Sphinx documentation generator. Sphinx plugin that allows defining documentation items and relations between those items. Can be used as a requirements management tool for e.g. ISO26262 projects.</p></li> -<li><p><a class="reference external" href="https://github.com/sphinx-contrib/kroki">sphinxcontrib-kroki</a> - Embed PlantUML, DOT, etc. diagrams in your documentation using <a class="reference external" href="https://kroki.io/">Kroki</a>.</p></li> +<li><p>"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p></li> </ul> </section> -<section id="id23"> -<h2><a class="toc-backref" href="#id59" role="doc-backlink">Послесловие</a></h2> -<p>Проект в состоянии развития. Стабильность пока не гарантируется.</p> -<p>Технически, в отдаленной перспективе можно было бы приспособить под принципы и соглашения системы одно из Open Source приложений для заметок, но у меня такая цель на данный момент не стоит. В таком приложении можно было бы выбирать источники подписок, автоматизировать и облегчить просмотр и принятие коммитов в свою базу знаний, например, если коммит содержит новую заметку, связанную с одной из уже принятых ранее заметок, или является её обновлением, тогда принимать коммит автоматически.</p> -<p>P.S.: Контент проекта представляет собой личную записную книжку и доступен только для учебных и исследовательских целей.</p> +<section id="id14"> +<h3><a class="toc-backref" href="#id51" role="doc-backlink">Изучаем распределенные системы</a></h3> +<ul class="simple"> +<li><p>"NoSQL Distilled. A Brief Guide to the Emerging World of Polyglot Persistence." by Pramod J. Sadalage, Martin Fowler</p></li> +<li><p>"Building Microservices. Designing Fine-Grained Systems" 2nd edition by Sam Newman</p></li> +<li><p>"<a class="reference external" href="http://ksat.me/a-plain-english-introduction-to-cap-theorem">A plain english introduction to CAP Theorem</a>" (<a class="reference external" href="https://habr.com/ru/post/130577/">Russian</a>) by Kaushik Sathupadi</p></li> +<li><p>"<a class="reference external" href="http://ksat.me/map-reduce-a-really-simple-introduction-kloudo">Map Reduce: A really simple introduction</a>" by Kaushik Sathupadi</p></li> +<li><p>"<a class="reference external" href="https://www.allthingsdistributed.com/2008/12/eventually_consistent.html">Eventually Consistent - Revisited</a>" by Werner Vogels</p></li> +<li><p>"<a class="reference external" href="http://book.mixu.net/distsys/">Distributed systems: for fun and profit</a>" (2013). An introduction to distributed systems. (<a class="reference external" href="https://github.com/mixu/distsysbook">source code</a>)</p></li> +<li><p>"<a class="reference external" href="https://martin.kleppmann.com/2020/11/18/distributed-systems-and-elliptic-curves.html">Lecture notes (PDF) (including exercises)</a>" by Martin Kleppmann (<a class="reference external" href="https://www.cl.cam.ac.uk/teaching/2021/ConcDisSys/dist-sys-notes.pdf">download</a>, <a class="reference external" href="https://github.com/ept/dist-sys">source code</a>, <a class="reference external" href="https://www.youtube.com/playlist?list=PLeKd45zvjcDFUEv_ohr_HdUFe97RItdiB">video</a>)</p></li> +<li><p>"<a class="reference external" href="https://github.com/ept/ddia-references">Literature references for "Designing Data-Intensive Applications"</a>" by Martin Kleppmann</p></li> +<li><p>"<a class="reference external" href="https://crdt.tech/">Resources and community around CRDT technology - papers, blog posts, code and more.</a>" by Martin Kleppmann (<a class="reference external" href="https://github.com/ept/crdt-website">source code</a>)</p></li> +</ul> </section> -Wed, 11 Oct 2023 00:00:00 Domain Model Definitionhttps://dckms.github.io/system-architecture/stanislav.bolsun/it/ddd/domain-model/domain-model-definition.html -<span id="stanislav3316-domain-model-definition"/> -<p><em>Автор раздела: Stanislav Bolsun</em></p> -<p>Как показывает моя практика, понимание таких фундаментальных основ как доменная модель, границы доменной модели (ограниченный контекст), могут заметно повысить эффективность (скорость) команды разработки.</p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> +<section id="id15"> +<h3><a class="toc-backref" href="#id52" role="doc-backlink">Изучаем распределенные системы. Углубляем навыки.</a></h3> +<p>Книг по этой теме предстоит прочитать слишком много. +Вряд-ли ваша работа будет ждать, пока вы прочитаете их все. +К счастью, сообщество .NET разработчиков подготовило краткий справочник, который заменит вам прочтение десятка книг:</p> <ul class="simple"> -<li><p><a class="reference internal" href="#domain-model-definition" id="id10">Domain Model Definition</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id11">Доменная модель</a></p> -<ul> -<li><p><a class="reference internal" href="#id3" id="id12">А что если попытаться реализовать единственную всеобъемливающую модель предметной области?</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id13">Важное дополнение: модель по Тарасенко</a></p></li> -<li><p><a class="reference internal" href="#id5" id="id14">Доменная модель, ограниченный контекст и единый язык</a></p></li> -<li><p><a class="reference internal" href="#id7" id="id15">Ограниченный контекст и команды разработки</a></p></li> -<li><p><a class="reference internal" href="#id8" id="id16">Классическая ошибка моделирования ограниченного контекста</a></p></li> -<li><p><a class="reference internal" href="#id9" id="id17">Источники информации</a></p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/index">.NET Microservices: Architecture for Containerized .NET Applications</a>" edition v2.2.1 (<a class="reference external" href="https://aka.ms/microservicesebook">mirror</a>) by Cesar de la Torre, Bill Wagner, Mike Rousos</p></li> </ul> -</li> +<p>К этой книге существует эталонное приложение, которое наглядно демонстрирует практическое применение изложенной в книге информации:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers">https://github.com/dotnet-architecture/eShopOnContainers</a> (CQRS, DDD, Microservices)</p></li> </ul> -</li> +<p>Еще одно хорошее краткое руководство от Microsoft:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/">Building microservices on Azure</a>"</p></li> </ul> -</nav> -<section id="id2"> -<h2><a class="toc-backref" href="#id11" role="doc-backlink">Доменная модель</a></h2> -<p>Начнем с канонического определения модели по Эвансу:</p> -<blockquote> -<div><p>💬 "every model represents some aspect of reality or an idea that is of interest. -A model is a simplification. It is an interpretation of reality that abstracts the aspects relevant to solving the problem at hand and ignores extraneous detail..."</p> -<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p> -</div></blockquote> -<blockquote> -<div><p>💬 "Модель - это упрощение; это такая интерпретация реальности, при которой из явления извлекаются существенные для решения задачи аспекты, а лишние детали игнорируются."</p> -<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> -</div></blockquote> -<p>Каждая модель имеет свой контекст применимости, без контекста применимости мы не сможем создать модель, так как не знаем какую проблему решаем (то есть какие свойства и поведение нужны для решения конкретной проблемы).</p> -<figure class="align-center"> -<a class="reference internal image-reference" href="../../../../_images/model_of_earth_processes.png"><img alt="Model of Earth processes" src="../../../../_images/model_of_earth_processes.png" style="width: 100%;"/></a> -</figure> -<p>На изображении выше, мы видим модель процессов Земли, служащую для решения определенных задач.</p> -<p>Ограниченный контекст, являясь границей модели, определяет контекст применимости этой модели. -На это и делают акцент Эванс (см. выше), Вернон и Зимарев в определениях модели:</p> -<blockquote> -<div><p>💬 "So, models represent some artifact of the real world, but with a narrow purpose. -How much space the building will occupy and how high the whole complex will be, for example, -are often just enough for a rough model, during the first review stage of the building project. -Models do not intend to replicate real life. Instead, they represent some particular aspects of real life at a certain level of detail, -depending on the purpose of the model...</p> -<p>Going back to Chapter 1, Why Domain-Driven Design?, if the business domain and the particular problems we have to -solve are in our problem space, the domain model is purely in our solution space. -We will be modeling our solution, and those models will be our domain models."</p> -<p class="attribution">—"Hands-On Domain-Driven Design with .NET Core: Tackling complexity in the heart of software by putting DDD principles into practice" by Alexey Zimarev</p> -</div></blockquote> -<blockquote> -<div><p>💬 "What’s a Domain Model? -It’s a software model of the very specific business domain you are working in. Often it’s implemented as an object model, -where those objects have both data and behavior with literal and accurate business meaning. -Creating a unique, carefully crafted domain model at the heart of a core, strategic application or subsystem is essential to -practicing DDD. With DDD your domain models will tend to be smallish, very focused. -Using DDD, you never try to model the whole business enterprise with a single, large domain model. Phew, that’s good!""</p> -<p class="attribution">—"Implementing Domain-Driven Design" by Vaughn Vernon</p> -</div></blockquote> -<figure class="align-center"> -<a class="reference internal image-reference" href="../../../../_images/real-model-impl.jpg"><img alt="Real object, model and implementation" src="../../../../_images/real-model-impl.jpg" style="width: 100%;"/></a> -</figure> -<p>Важное уточнение: Модель - это абстракция, которая формирует реализацию, но не является реализацией, хотя реализация и может осуществлять (реализовывать) эту модель. -Модель это часть solution space.</p> -<blockquote> -<div><p>💬 "A domain model is not a particular diagram; it is the idea that the diagram is intended to convey. -It is not just the knowledge in a domain expert's head; -it is a rigorously organized and selective abstraction of that knowledge. -A diagram can represent and communicate a model, as can carefully written code, as can an English sentence...</p> -<p>The model and the heart of the design shape each other. -It is the intimate link between the model and the implementation that makes the model relevant and ensures that the analysis that went into it applies to the final product, a running program. -This binding of model and implementation also helps during maintenance and continuing development, because the code can be interpreted based on understanding the model. (See Chapter 3.)"</p> -<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p> -</div></blockquote> -<section id="id3"> -<h3><a class="toc-backref" href="#id12" role="doc-backlink">А что если попытаться реализовать единственную всеобъемливающую модель предметной области?</a></h3> -<p>Если решаемой проблемы не существует или она неизвестена, то у нас есть два возможных пути:</p> -<ol class="arabic"> -<li><p>модель не создавать вообще</p></li> -<li><p>создать модель на все случаи жизни, но тогда придется полностью воспроизвести объект моделирования, что не позволит эффективно решать задачи (например, осуществление навигации судна по точной копии Земли).</p> -<blockquote> -<div><p>💬 "Because the term domain model includes the word domain, we might get the idea that we should create a single, cohesive, all-inclusive model of an organization’s entire business domain—you know, like an enterprise model. -However, when using DDD, that is not our goal. DDD places emphasis on just the opposite. The whole Domain of the organization is composed of Subdomains. -Using DDD, models are developed in Bounded Contexts. In fact, developing a Domain Model is actually one way that we focus on only one specific area of the whole business domain. -Any attempt to define the business of even a moderately complex organization in a single, all-encompassing model will be at best extremely difficult and will usually fail. -As is made clear in this chapter, vigorously separating distinct areas of the whole business domain will help us succeed.</p> -<p>So, if a domain model shouldn’t be all-inclusive of what the organization does and how it does it, what should it be, exactly?</p> -<p>Almost every software Domain has multiple Subdomains. It really doesn’t matter whether the organization is huge and extremely complex or consists of just a few people and the software they use. -There are different functions that make any business successful, so it’s advantageous to think about each of those business functions separately."</p> -<p class="attribution">—"Implementing Domain-Driven Design" by Vaughn Vernon</p> -</div></blockquote> -</li> -</ol> -<p>В качестве иллюстрации того, что модель создается для решения конкретных задач (имеет определенный контекст применимости), рассмотрим примеры из доклада Эрика Эванса (Eric Evans — Tackling Complexity in the Heart of Software, Domain-Driven Design Europe 2016 - Brussels, January 26-29, 2016).</p> -<ol class="arabic simple"> -<li><p>Карта морского ориентирования (цилиндрическая проекция Меркатора)</p></li> -</ol> -<figure class="align-center"> -<a class="reference internal image-reference" href="../../../../_images/mercator_projection.png"><img alt="Mercator projection" src="../../../../_images/mercator_projection.png" style="width: 100%;"/></a> -</figure> -<p>Такие карты используют относительное искажение размеров объектов относительно друг друга, но помогают направлять компас в сторону нужной конечной точки (направление на карте полностью совпадет со стрелкой компаса). -На этой карте Африка и Гренландия выглядят равными по площади, но в действительности, Африка в 14 раз больше Гренландии, то есть у карты есть четкое предназначение, задача для которой она нужна, и только для нее - навигация судов.</p> -<ol class="arabic simple" start="2"> -<li><p>Картографическая проекция земного шара на поверхность многогранника (проекция Димаксион (Фуллера))</p></li> -</ol> -<figure class="align-center"> -<a class="reference internal image-reference" href="../../../../_images/fuller_projection.png"><img alt="Fuller projection" src="../../../../_images/fuller_projection.png" style="width: 100%;"/></a> -</figure> -<p>Данная проекция имеет меньшие искажения относительных размеров объектов, особенно в сравнении с проекцией Меркатора, то есть, она может служить более точным инструментом определения относительных размеров объектов земли.</p> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> -<blockquote> -<div><p>💬 "We're making an effort with DDD to recognize that there is no practical way to have a canonical, enterprise data model where every single element in the model is representative of how every team in the enterprise would want to use it. -It just doesn't happen. There's always some difference, and many times there are many differences that make it very painful for one team to try to use the model that another team has created. -That's why we're focused on the bounded context with a ubiquitous language."</p> -</div></blockquote> -<p><a class="reference external" href="https://www.infoq.com/articles/modeling-uncertainty-reactive-ddd/">Vaughn Vernon объясняет, почему построение канонической всеобъемлющей модели предприятия и единой предметной области на основе единой модели деятельности - миф</a></p> -</div> +<p>И можно сюда включить еще и книгу:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-US/previous-versions/msp-n-p/jj554200(v=pandp.10)">CQRS Journey</a>" by Dominic Betts, Julián Domínguez, Grigori Melnik, Fernando Simonazzi, Mani Subramanian</p></li> +</ul> +<p>К ней также существует демонстрационное приложение:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/microsoftarchive/cqrs-journey">https://github.com/microsoftarchive/cqrs-journey</a> (Event Sourcing, SAGA transactions)</p></li> +</ul> +<p>Оригинальная статья "<a class="reference external" href="https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf">SAGAS</a>" by Garcia-Molina, Kenneth Salem (<a class="reference external" href="https://dl.acm.org/doi/10.1145/38713.38742">копия</a>).</p> </section> -<section id="id4"> -<h3><a class="toc-backref" href="#id13" role="doc-backlink">Важное дополнение: модель по Тарасенко</a></h3> -<blockquote> -<div><p>💬 "Мы уже сформулировали два определения модели. Первое: модель есть средство осуществления любой деятельности субъекта. Второе: модель есть форма существования знаний. -Можно несколько дополнить каждое из этих определений указанием на то, что модель — тоже система, со всеми описанными в главе 2 общесистемными свойствами. -Отличительная особенность моделей от других систем состоит (в дополнение к тому, что говорят два определения) в их предназначенности отображать моделируемый оригинал, заменять его в определенном отношении, т.е. содержать и представлять информацию об оригинале. -Выразим эту мысль в виде еще одного общего определения: модель есть системное отображение оригинала. -Все три определения носят очень общий, можно сказать, философский характер. Для дальнейшего нам понадобится конкретизация типов моделей и их характерных свойств. -Как мы уже знаем, уточнение описания модели можно сделать с помощью анализа и синтеза."</p> -<p class="attribution">—"Прикладной системный анализ" Ф.П. Тарасенко</p> -</div></blockquote> -<figure class="align-center"> -<a class="reference internal image-reference" href="../../../../_images/tarasenko_model.png"><img alt="Tarasenko model" src="../../../../_images/tarasenko_model.png" style="width: 100%;"/></a> -</figure> -<p>и следует за этим:</p> -<blockquote> -<div><p>💬 "Продолжая рассмотрение отношений между моделью и оригиналом, остановимся на содержании информации в модели. Оригинал и модель — разные вещи. -В оригинале есть много такого, чего нет в модели, по двум причинам: во-первых, не все из того, что известно об оригинале, понадобится включить в модель, предназначенную для достижения конкретной цели (зона А на рис. 3.13 изображает известное, но ненужное, в том числе ошибочно сочтенное ненужным и невключенное в модель); -во-вторых, в оригинале есть всегда нечто непознанное, поэтому не могущее быть включенным в модель (зона В на рис. 3.13).</p> -<p>Зона 2 на рисунке изображает информацию об оригинале, включенную в модель. Это истинная информация, то общее, что имеется у модели и оригинала, благодаря чему модель может служить его (частным, специальным) заменителем, представителем. -Обратим внимание на зону 3. Она отображает тот факт, что у модели всегда есть собственные свойства, не имеющие никакого отношения к оригиналу, т.е. ложное содержание. -Важно подчеркнуть, что это относится к любой модели, как бы ни старался создатель модели включать в нее только истину."</p> -<p class="attribution">—"Прикладной системный анализ" Ф.П. Тарасенко</p> -</div></blockquote> -</section> -<section id="id5"> -<h3><a class="toc-backref" href="#id14" role="doc-backlink">Доменная модель, ограниченный контекст и единый язык</a></h3> -<p>Ограниченный контекст - это рассмотрение объекта моделирования с определенной точки зрения, с определенного ракурса решаемой проблемы (см. пример с огурцом далее). -Основным назначением ограниченного контекста является поиск баланса между простой модели и ее достаточностью для решения проблемы.</p> -<p>Количество слов используемых человеком в лексиконе ограничено, это около 6000 слов (в зависимости от языка), а количство явлений окружающего мира - безгранично. -Это и есть та самая причина того, что если один термин обозначает несколько явлений окружающего мира, либо наоборот, одно явление мы называем различными терминами, - это обозначает лингвистический конфликт.</p> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> -<p><a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%A1%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D0%BD%D1%8B%D0%B9_%D0%B7%D0%B0%D0%BF%D0%B0%D1%81/">Википедия: Словарный запас</a></p> -</div> -<p>И при поиске ограниченных контекстов мы можем ориентироваться на эти лингвистические конфликты в процессе коммуникации (эти конфликты и являются первыми маркерами/границами ограниченнных контекстов).</p> -<blockquote> -<div><p>💬 "The Language of a team in an explicit Bounded Context expressed as a domain model adds true business value -and gives us certainty that we are implementing the correct software."</p> -<p class="attribution">—"Implementing Domain-Driven Design" by Vaughn Vernon</p> -</div></blockquote> -<p>Если внутри своего ограниченно контекста мы встречаем языковой конфликт, то это может являться симптомом того, что мы решаем сразу несколько задач одновременно. -То есть, если мы называем одно явление разными терминами, то скорее всего это явление используется в разных контекстах, и наш контекст служит нескольким целям. -Это сигнал о том, что наша модель переусложнена и при решении одной задачи мы вынуждены работать с теми деталями модели, которые нерелевантны для нас в момент рассмотрения. Это все отбирает ресурс внимания у команды и может удорожать процесс разработки для бизнеса.</p> -<p>Поэтому, внутри каждого ограниченного контекста существует строгий единый (согласованный) язык. -Единый (согласованный) язык не просто словарь внутри компании, это подразумевает, в первую очередь, согласованный язык внутри границ применимости модели. -Мы, в рамках модели, ограничены ограниченным контекстом, где каждый термин обозначает строго одно явление.</p> -<blockquote> -<div><p>💬 "The model is a set of concepts built up in the heads of people on the project, with terms and relationships that reflect domain insight. -These terms and interrelationships provide the semantics of a language that is tailored to the domain while being precise enough for technical development. -This is a crucial cord that weaves the model into development activity and binds it with the code."</p> -<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p> -</div></blockquote> -<p>В качестве примера можно привести модель обыкновенного огурца, где термин "огурец" в каждом ограниченном контексте имеет строгое и однозначное толкование (но разное): плод, ингредиент, груз ...</p> -<figure class="align-center"> -<a class="reference internal image-reference" href="../../../../_images/cucumber_BC.jpg"><img alt="cucumber in diffent Bounded Contexts" src="../../../../_images/cucumber_BC.jpg" style="width: 100%;"/></a> -</figure> -<p>[Дополнение] Про профессиональные языки от Тарасенко:</p> -<blockquote> -<div><p>💬 "Главная для нас особенность — то, что язык является универсальным средством моделирования: говорить можно о чем угодно. Из многих свойств языка, обеспечивающих ему это свойство, обратим внимание на расплывчатость смысла слов.</p> -<p>Приведем пример словесной модели некоторой ситуации. «В комнату вошел высокий красивый молодой человек, неся тяжелый сверток». Так и видится реальная картина. Но «высокий» — какого именно роста? «Молодой» — а сколько ему лет? -Не говоря уж о том, что такое «красивый». «Тяжелый» — какого веса? Практически ни одно слово естественного языка не имеет точного смысла. Можно привести аналогию: «смысл» конкретной ситуации — точка, «смысл» слова — облако. -Описывая конкретную ситуацию, мы как бы обволакиваем точку облаками, понимая, что истина гдето в середине этого скопления. В большинстве случаев, особенно в быту, такого приблизительного, расплывчатого описания бывает достаточно для действий, часто успешных. -В некоторых видах деятельности такая расплывчатость сознательно используется как важный позитивный фактор: поэзия, юмор, политика, дипломатия, мошенничество…</p> -<p>Однако в случаях, когда необходимо произвести конкретный продукт, достичь конкретного результата, этой конкретности начинает мешать расплывчатость бытового языка. -И тогда те, кто занимается конкретной деятельностью, изживают мешающую неопределенность, вводя в язык более точные термины. -У всякой группы с ее общими целями вырабатывается свой, специфический язык, обеспечивающий нужной точностью эту деятельность. -У скотоводческого африканского племени масаев есть сотни терминов для характеристики коров; у северных народов — множество терминов, определяющих состояние снега; -на своих языках разговаривают физики, медики, юристы; уголовники «ботают по фене»; молодежь говорит на слэнге, не понятном для взрослых; лондонские «низы» разговаривают на «кокни». -Общий вывод: всякая групповая деятельность требует выработки специального, более точного, чем разговорный, языка; условно назовем его профессиональным.</p> -<p>Профессиональные языки более точны, чем разговорный, за счет большей определенности их терминов. Важно осознать, что снятие неопределенности может быть осуществлено только за счет новой, дополнительной информации.</p> -<p>Таким образом, увеличение точности смысла языковых моделей идет за счет добывания и включения в язык все новой и новой информации о предмете интереса.</p> -<p>Есть ли предел этому процессу уточнения? Есть, и это язык математики, в котором термины максимально точны, однозначны. Правда, полностью изжить неопределенность невозможно, иначе было бы невозможно о бесконечности мира говорить конечными фразами. -Есть несколько (и не только вспомогательных, но и базовых) понятий в математике, имеющих расплывчатый смысл: «приблизительно равно», «значительно больше (меньше)», «бесконечно мало (велико)», «неопределенно» и т.д. -И все же математический язык является крайним, самым точным справа в спектре языков описания реальности (рис. 3.7)."</p> -<p class="attribution">—"Прикладной системный анализ" Ф.П. Тарасенко</p> -</div></blockquote> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +<section id="ddd"> +<h3><a class="toc-backref" href="#id53" role="doc-backlink">Изучаем DDD</a></h3> +<p>Начинать я рекомендовал бы с прекрасного краткого руководства:</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="language-context.html#stanislav3316-language-context"><span class="std std-ref">Language Context Definition</span></a>"</p></li> +<li><p>"<a class="reference external" href="https://www.oreilly.com/library/view/what-is-domain-driven/9781492057802/">What Is Domain-Driven Design?</a>" by Vladik Khononov</p></li> </ul> -</div> -</section> -<section id="id7"> -<h3><a class="toc-backref" href="#id15" role="doc-backlink">Ограниченный контекст и команды разработки</a></h3> -<p>Для того чтобы реализовать модель, команда должна ее понимать, соответственно, набольшей эффективностью команда будет обладать тогда, когда граница ответственности команды совпадает с границей модели. -Это и можно назвать границей автономности рабочей команды, что позволяет команде фокусироваться на решении конкретной задачи. -В ограниченном контексте команды модель обладает наибольшей внутренней связанностью (cohesion) и наименьшим сопряжением (coupling) с другими ограниченными контекстами.</p> -<p>В таком случае решается проблема Брукса, а именно, достижение автономности команды, - рост коммуникационных связей внутри команды и уменьшение коммуникационных связей между командами.</p> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +<p>Или с более новой книги этого же автора:</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="../../../../emacsway/it/team-topologies/harlan-mills%27-proposal.html#emacsway-team-topologies-at-scale"><span class="std std-ref">Роль архитектуры в масштабировании команд, DDD и микросервисах</span></a>"</p></li> +<li><p>"Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy" 1st Edition by Vlad Khononov</p></li> </ul> -</div> -<p>Если же модель поделить неправильно, допустим, разрезать полноценную модель на две разные части, то резко возрастет количество коммуникационных путей между командами (для сохранения и поддержки инвариантов модели), и этим мы ухудшаем параллелизм задач. -Аналогично, если свалим в один ограниченный контекст две модели которые служат двум разным целям, то мы увеличим когнитивную нагрузку команды (путем введения информации нерелеватной в момент рассмотрения, тем самым отнимая когнитивные ресурсы у человека). -И чтобы достичь наибольшего уровня автономности команд, обеспечить их независимость друг от друга нужно правильно определить ограниченные контексты.</p> -<p>Таким образом, можно прийти к выводу, что ограниченный контекст помогает решить две проблемы:</p> -<ol class="arabic simple"> -<li><p>Снижение когнитивной нагрузки на команду (путем исключения из рассмотрения нерелевантных деталей)</p></li> -<li><p>Снижение коммуникативной нагрузки между командами (путем концентрации релевантных деталей)</p></li> -</ol> -</section> -<section id="id8"> -<h3><a class="toc-backref" href="#id16" role="doc-backlink">Классическая ошибка моделирования ограниченного контекста</a></h3> -<p>Классическая ошибка при моделировании ограниченного контекста заключается в том, что при неправильном понимании модели возникает желание "запихнуть" модель объекта моделирования в какой-то один ограниченный контекст. -Существует два самых неправильных вопроса - в какой ограниченный контекст поместить сущность и как мне получить из другого ограниченного контекста нужную сущность.</p> -<p>Моделирование ограниченного контекста - это не кройка. Плод, груз, ингредиент, блюдо - это все модели одного и того же объекта моделирования - огурца, только в разных ограниченных контекстах. -Можно рассмотреть ограниченный контекст как одну из плоскостей додека‌эдра (когда один и тот же элемент виден под разными ракурсами), а не как фрагмент пазла (когда один элемент может принадлежать только одному фрагменту полотна).</p> -<p>Задача не в том, в какой ограниченный контекст "запихнуть", и не в том, как разрезать, а в том, какие именно аспекты поведения объекта моделирования релевантны в контексте решаемой проблемы текущего ограниченного контекста. -Посетитель, пользователь, клиент, покупатель, плательщик, получатель, адресат - это все тоже модели одного и того же объекта моделирования.</p> -<figure class="align-center"> -<a class="reference internal image-reference" href="../../../../_images/bc_perspective.png"><img alt="Different pespectives are matter" src="../../../../_images/bc_perspective.png" style="width: 60%;"/></a> -</figure> -<p>Владик отлично выводит противоречие, как опытный диалектик:</p> -<blockquote> -<div><p>💬 "However, it is more difficult to represent such a divergent model of the business domain in software. Source code doesn’t cope well with ambiguity. If we were to bring the sales department’s complicated model into marketing, -it would introduce complexity where it’s not needed— far more detail and behavior than marketing people need for optimizing advertising campaigns. But if we were to try to simplify the sales model according to the marketing world view, -it wouldn’t fit the sales subdomain’s needs, because it’s too simplistic for managing and optimizing the sales process. -We’d have an overengineered solution in the first case and an under-engineered one in the second."</p> -</div></blockquote> -</section> -<section id="id9"> -<h3><a class="toc-backref" href="#id17" role="doc-backlink">Источники информации</a></h3> -<ol class="arabic simple"> -<li><p>Ivan Zakrevskii</p></li> -<li><p>Группа тг-канала объединения ИТ-архитекторов (@ru_arc)</p></li> -<li><p>DDDevotion chat (tg <a class="reference external" href="https://t.me/iDDDqd">https://t.me/iDDDqd</a>)</p></li> -<li><p>Группа тг-канала (@emacsway_log) о Software Design/Architecture, DDD, Microservice Architecture, Distributed Systems, SDLC, Agile, Team Topology etc.</p></li> -<li><p>рефлексия собственного опыта</p></li> -</ol> -</section> -</section> -Wed, 11 Oct 2023 00:00:00 Language Context Definitionhttps://dckms.github.io/system-architecture/stanislav.bolsun/it/ddd/domain-model/language-context.html -<span id="stanislav3316-language-context"/> -<p><em>Автор раздела: Stanislav Bolsun</em></p> -<section id="id1"> -<h2>Определение языкового контекста</h2> -<blockquote> -<div><p>💬 ЯЗЫКОВОЙ КОНТЕКСТ. — -1. Фрагмент текста или речи, содержащий избранное для анализа языковое выражение или единицу языка; -2. Ситуация употребления анализируемого выражения.</p> -<p>Языковой контекст во многом определяют семантические характеристики выражений языка. Прежде всего, это состоит в том, что контекст уменьшает или вовсе элиминирует многозначность выражения. Благодаря наличию контекста, оно часто интерпретируется как однозначное. Предельным случаем такого уточнения смысла при помощи контекста можно считать контекстуальные определения, т.е. такие определения, одна из частей которых является контекстом, включающим определяемый термин.</p> -<p>Контексты часто влияют на семантические отношения. Напр., одни и те же выражения могут в разных контекстах выступать и как синонимы, и как антонимы. С отношением к синонимии, кроме того, связано различение двух типов контекстов: экстенсиональных и интенсиональных. Это различение определяется возможностью замены в данном контексте одного выражения на синонимичное (по экстенсионалу) без изменения семантических характеристик контекста в целом. Напр., высказывание «Диагонали ромба перпендикулярны друг другу» представляет собой экстенсиональный контекст для выражения «ромб». При замене его на синонимичное по экстенсионалу выражение «параллелограмм, две смежные стороны которого равны между собой» мы получим семантически эквивалентное высказывание. Важнейшей семантической характеристикой, которая сохраняется при указанной замене, является истинность. Интенсиональный контекст не допускает такой замены. Примером интенсионального контекста является высказывание: «Требуется доказать, что параллелограмм, две смежные стороны которого равны между собой, является ромбом». Если приведенное высказывание истинно, то после замены оно может оказаться ложным. Различение двух типов контекстов имеет важный эпистемологический смысл, поскольку в них по-разному отражено состояние знания о предмете. Экстенсиональный контекст предполагает указание на предмет в целом. Его использование подразумевает, что классы объектов, описываемых двумя взаимозаменимыми выражениями, являются полностью обозримыми и что эта обозримость позволяет обнаружить совпадение классов. Поэтому заменимость выражений в экстенсиональном контексте вытекает из тождества обозначаемых ими объектов. Интенсиональный контекст указывает не на предмет, а лишь на определенное свойство (в приведенном примере — на свойство какого-то предмета быть ромбом). Знание о предмете предполагается еще не полным, а совпадение экстенсионалов двух выражений — не установленным. Можно указать на связь между понятиями интенсионального контекста и интенциональности. Использование интенсионального контекста подразумевает описание не самого предмета, а его ноэматического образа, т.е. смысла, установленного в сознании, или интенционального объекта. Поэтому интенсиональные контексты нельзя сводить (как это делал Г. Фреге) к пропозициональным установкам, т.е. к высказываниям типа: «N знает, что...», или «N думает, что...». Они возникают при упоминании любого интенционального акта, т.е. акта сознания, направленного на предмет (см. также Семантика, Синонимия).</p> -<p>Значительная часть описаний, фигурирующих как в науке, так и в обыденной речи носят интенсиональный и, соответственно, интенциональный характер. Они не могут претендовать на полноту понятия о предмете, но, скорее, выражают лишь некоторый спектр его характеристик. Поэтому для более точного определения некоторых понятий часто требуются более широкие контексты или даже совокупность контекстов, содержащих обозначающий это понятие термин. В естествознании или математике этого удается избежать с помощью формализации языков описания. В рамках формальной теории, как правило, возможно обойтись без интенсиональных контекстов, хотя применимость таких теорий всегда ограничена областью идеальных объектов. В гуманитарной сфере, где едва ли осуществима формализация, полнота знания так или иначе связана с широтой контекстов. Такая ситуация, напр., весьма характерна при определении важнейших философских категорий, а также вообще при рассмотрении ключевых или предельных понятий той или иной дисциплины. Напр., смысл понятия «материя» в философии Аристотеля невозможно передать при помощи краткого определения. Его понимание требует привлечения весьма широкого контекста, включающего сопоставление этого понятия с рядом др. (напр., возможность, лишенность), противопоставление его понятию «форма» (и действительность), а кроме того — множество примеров, аналогий, рассуждений, использующих это понятие и т.д.</p> -<p>Контекстуальный характер понимания находит отражение в идее сократического диалога (см. Диалог). Согласно этой идее, определить (и, соответственно, понять) нечто невозможно с помощью какой-либо краткой словесной формулировки. Полное определение требует включения исследуемого понятия во множество контекстов, приведения различных примеров его употребления, сопоставления разных определений и т.д. Сам диалог оказывается при этом попыткой раскрытия (или создания) полного контекста существования исследуемого понятия. При этом, говоря о контексте, уже невозможно ограничиться представлением о нем, как о явно присутствующем фрагменте текста (пусть даже достаточно длинном). Он подразумевает также совокупность коммуникативных ситуаций употребления выражения.</p> -<p>Для характеристики роли Я. к. в коммуникации важны используемые в лингвистике понятия об экстралингвистическом и имплицитном контексте. Первый (противопоставляемый собственно лингвистическому контексту) представляет собой неязыковой фон коммуникации. Он включает время и место общения, обстановку, в которой оно происходит, психическое и физическое состояние участников коммуникации, их социальный статус, их отношение друг к другу и т.д. Имплицитный контекст (противопоставляемый эксплицитному — т.е. непосредственно наблюдаемому -лингвистическому и экстралингвистическому контексту) составляет совокупность фоновых знаний участников коммуникации. Он включает, напр., все лингвистические пресуппозиции, существенные для данной коммуникативной ситуации (см. Пресуппозиция в лингвистике). Кроме того, он включает знания участников коммуникации друг о друге, память о прошлых коммуникациях, представление о настоящей ситуации и т.д. Очевидно, что все указанные обстоятельства влияют на характер понимания используемых языковых выражений и на правила их употребления. См. также Дискурс.</p> -<p>Г.Б. Гутнер</p> -<p class="attribution">—"Энциклопедия эпистемологии и философии науки. М.: «Канон+», РООИ «Реабилитация». И.Т. Касавин. 2009"</p> -</div></blockquote> -</section> -Wed, 11 Oct 2023 00:00:00 Specification in Golanghttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/specification.html -<span id="emacsway-specification-in-golang"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<p>Затем приступить к классике:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/specification-pattern-c-implementation/">Specification pattern: C# implementation</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/specification-pattern-always-valid-domain-model/">Specification Pattern vs Always-Valid Domain Model</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://khorikov.org/posts/2021-08-02-purity-specification-pattern/">Specification Pattern in DDD trilemma</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://github.com/vkhorikov/SpecificationPattern">Implementation of the Specification Pattern in C#</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://github.com/vkhorikov/SpecPattern">Implementation of the Specification Pattern in C#</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/apsupp/spec.pdf">Specification</a>" by Martin Fowler</p></li> +<li><p>"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p></li> +<li><p>"<a class="reference external" href="https://kalele.io/books/">Implementing Domain-Driven Design</a>" by Vaughn Vernon</p></li> </ul> -Wed, 23 Aug 2023 00:00:00 Technical Debt и сложный процентhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/compound-interest.html -<span id="emacsway-compound-interest"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> +<p>Существуют краткие изложения этих двух книг по DDD.</p> +<p>Краткие изложения "Domain-Driven Design" by Eric Evans:</p> <ul class="simple"> -<li><p><a class="reference internal" href="#technical-debt" id="id2">Technical Debt и сложный процент</a></p></li> +<li><p>"<a class="reference external" href="https://domainlanguage.com/ddd/reference/">Domain-Driven Design Reference</a>" by Eric Evans</p></li> +<li><p>"<a class="reference external" href="https://www.infoq.com/books/domain-driven-design-quickly/">Domain-Driven Design Quickly</a>"</p></li> </ul> -</nav> -<p>"<a class="reference internal" href="common-planning-errors.html#emacsway-planning-error-false-commutativity"><span class="std std-ref">Ложная Коммутативность</span></a>" в управленческих решениях - это когда совокупная стоимость реализации нескольких задач зависит от последовательности их выполнения. -Особенно это касается платформенных (технических) задач, которые иногда нужно уметь "продать" бизнесу, если только у вас нет выделенной <a class="reference external" href="https://www.scaledagileframework.com/agile-teams/">платформенной команды</a>.</p> -<p>И, зачастую, представителям бизнеса, находящимся в контексте бизнес-проблем, а не технических проблем, сложно понять, почему первой должна выполняться задача "А", если задача "Б" более востребована бизнесом. -Это называется <a class="reference internal" href="../balancing-business-technical-concerns.html#emacsway-agile-balancing-business-technical-concerns"><span class="std std-ref">поиском баланса между бизнес-интересами и техническими интересами</span></a>. -Острота этого вопроса в Agile даже привела к тому, что Quality, изначально бывшее 4-ой переменной управления разработкой (наряду с Cost, Time, Scope), очень быстро было <a class="reference internal" href="../balancing-business-technical-concerns.html#emacsway-xp2-balancing-business-technical-concerns"><span class="std std-ref">преобразовано в константу</span></a>.</p> -<p>Выявлением причинно-следственных циклов занимается "Системное Мышление", и вам сильно повезло, если ваши представители бизнеса знакомы с этой наукой. -В противном случае, как пишет Craig Larman, проблемы могут возникать даже в таких компаниях, как Microsoft, являющихся "колыбелью архитектуры" (откуда вышли такие авторы, как Steve McConnell), см. "<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems Thinking</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">на русском</a>).</p> -<p>Наверное, наилучшим образом помочь донести представителям бизнеса проблему "Ложной Коммутативности" может "<a class="reference external" href="https://quote.rbc.ru/news/training/5e280d059a7947eb63f54970">Сложный Процент</a>".</p> -<p>Основная проблема термина "Technical Debt" в русском менталитете заключается в том, что зачастую его влияние на стоимость разработки воспринимается представителями бизнеса как константная величина - сколько сегодня позаимствовали, столько завтра и вернем.</p> -<p>На самом же деле, основная суть термина "<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebt.html">Technical Debt</a>", вложенная в этот термин by Ward Cunningham, заключается в "interest on the debt":</p> -<blockquote> -<div><p>📝 "Thinking of this as paying interest versus paying of principal can help decide which cruft to tackle."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebt.html">Technical Debt</a>" by Martin Fowler</p> -</div></blockquote> -<blockquote> -<div><p>📝 "...that would slow us down which is like paying interest on a loan."</p> -<p class="attribution">—"<a class="reference external" href="https://youtu.be/pqeJFYwnkjE?t=90">Debt Metaphor</a>" by Ward Cunningham</p> -</div></blockquote> -<blockquote> -<div><p>💬 Burden</p> -<p>I think that there were plenty of cases where people would rush software out the door and learn things but never put that learning back into the program, and that by analogy was borrowing money thinking that you never had to pay it back.</p> -<p>Of course, if you do that, you know, say with your credit card, <strong>eventually all your income goes to interest and your purchasing power goes to zero</strong>.</p> -<p>By the same token, if you develop a program for a long period of time by only adding features and never reorganizing it to reflect your understanding of those features, then eventually that program simply does not contain any understanding and all efforts to work on it take longer and longer. In other words, the interest is total — you'll make zero progress.</p> -<p class="attribution">—"<a class="reference external" href="http://wiki.c2.com/?WardExplainsDebtMetaphor">Ward Explains Debt Metaphor</a>" by Ward Cunningham</p> -</div></blockquote> -<blockquote> -<div><p>💬 Debt</p> -<p>I coined the debt metaphor to explain the refactoring that we were doing on the WyCash product. This was an early product done in Digitalk Smalltalk, and it was important to me that we accumulate the learnings we did about the application over time by modifying the program to look as if we had known what we were doing all along and to look as if it had been easy to do in Smalltalk.</p> -<p>The explanation I gave to my boss, and this was financial software, was a financial analogy I called "the debt metaphor". And that said that if we failed to make our program align with what we then understood to be the proper way to think about our financial objects, then we were gonna continually stumble over that disagreement and that would slow us down which was like paying interest on a loan.</p> -<p class="attribution">—"<a class="reference external" href="http://wiki.c2.com/?WardExplainsDebtMetaphor">Ward Explains Debt Metaphor</a>" by Ward Cunningham</p> -</div></blockquote> -<p>А он рассчитывается по правилу "сложного процента". -Вся суть в том, чтобы перенести внимание бизнеса с тела долга на геометрическую прогрессию роста его процента:</p> -<blockquote> -<div><div class="highlight-default notranslate"><div class="highlight"><pre><span/><span class="n">S</span> <span class="o">=</span> <span class="n">P</span><span class="o">*</span><span class="p">(</span><span class="mi">1</span><span class="o">+</span> <span class="n">i</span><span class="p">)</span><span class="o">^</span><span class="n">n</span> <span class="p">(</span><span class="n">в</span> <span class="n">степени</span> <span class="n">n</span><span class="p">),</span> -</pre></div> -</div> -<p>где S – получаемая сумма, P – цена облигации при покупке, i – процент в сотых долях, а n – число выплат.</p> -<p class="attribution">—"<a class="reference external" href="https://bankiros.ru/wiki/term/kak-rasscitat-dohodnost-obligacij">Как рассчитать доходность облигаций</a>" / Редакция Bankiros.ru</p> -</div></blockquote> -<p>По утверждению ряда авторитетных авторов (Kent Beck, Martin Fowler, Robert C. Martin и др.), рост стоимости разработки при накоплении техдолга может обретать характер, близкий именно к геометрической прогрессии (или к экспоненте). -Статистику конкретного проекта смотрите в "Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin.</p> -<p>Термин "TechnicalDebt" у нас воспринимается несколько по-иному, безобиднее, еще и потому, что он ассоциируется в нашем менталитете с "академической задолженностью" в ВУЗе, где в центре внимания лежит тело долга (paying of principal), а не геометрический характер роста процентов (paying interest). -А так же находит отражение традиция безпроцентного долга в виде взаимовыручки "до зарплаты", который является распространенным явлением в дружеской среде. -Поэтому, термин "TechnicalDebt" не несет своего изначального смысла в нашем менталитете, и не выполняет своей функции, как метафоры, надлежащим образом, что приводит к росту напряженности и недопонимания между представителями бизнеса и техническими специалистами. -Для разработчика техдолг означает экспоненциальный рост стоимости изменения кода, в то время, как для представителя бизнеса, - это просто отложенное выполнение задачи.</p> -<blockquote> -<div><p>📝 "Asking "is something technical debt" is usually uninteresting. The metaphor's value is comparing paying interest vs principal. We judge debt of $1K differently if we are paying $1/month to service it vs $100/month"</p> -<p class="attribution">—<a class="reference external" href="https://twitter.com/martinfowler/status/1517152168775614473?t=BMpST8vXSLBnY36k9o-lUg&amp;s=19">Martin Fowler</a></p> -</div></blockquote> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +<p>Краткое изложение "Implementing Domain-Driven Design" by Vaughn Vernon:</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="architecture-options.html#emacsway-architecture-options"><span class="std std-ref">Architecture: Selling Options</span></a>"</p></li> +<li><p>"<a class="reference external" href="https://kalele.io/books/">Domain-Driven Design Distilled</a>" by V.Vernon</p></li> </ul> -</div> -Wed, 23 Aug 2023 00:00:00 Repository in Golanghttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/infrastructure/repository.html -<span id="emacsway-repository-in-golang"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -Sat, 19 Aug 2023 00:00:00 Balancing Prediction/Adaptationhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/balancing-prediction-adaptation.html -<span id="emacsway-balancing-prediction-adaptation"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> +<section id="id16"> +<h4><a class="toc-backref" href="#id54" role="doc-backlink">Статьи на частые вопросы по DDD</a></h4> <ul class="simple"> -<li><p><a class="reference internal" href="#balancing-prediction-adaptation" id="id4">Balancing Prediction/Adaptation</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id5">Стоимость гибкости</a></p></li> -<li><p><a class="reference internal" href="#open-agile-architecture-standard-by-the-open-group" id="id6">Open Agile Architecture™ Standard by The Open Group</a></p></li> -<li><p><a class="reference internal" href="#prediction-adaptation" id="id7">Эволюционный маятник баланса Prediction/Adaptation</a></p> -<ul> -<li><p><a class="reference internal" href="#prediction-adaptation-adaptation" id="id8">Занос маятника Prediction/Adaptation в сторону Adaptation</a></p></li> -<li><p><a class="reference internal" href="#prediction-adaptation-prediction" id="id9">Отскок маятника Prediction/Adaptation назад к Prediction</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#alberto-brandolini-about-prediction-adaptation" id="id10">Alberto Brandolini about Prediction/Adaptation</a></p></li> -</ul> -</li> +<li><p><a class="reference external" href="https://martinfowler.com/tags/domain%20driven%20design.html">Patterns related to Domain Driven Design</a> by Martin Fowler</p></li> +</ul> +<section id="aggregate-domain-modeling"> +<h5><a class="toc-backref" href="#id55" role="doc-backlink">Aggregate &amp; Domain Modeling</a></h5> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/what-is-domain-logic/">What is domain logic?</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-vs-application-services/">Domain services vs Application services</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-model-isolation/">Domain model isolation</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/email-uniqueness-as-aggregate-invariant/">Email uniqueness as an aggregate invariant</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/how-to-know-if-your-domain-model-is-properly-isolated/">How to know if your Domain model is properly isolated?</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-model-purity-completeness/">Domain model purity vs. domain model completeness</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-model-purity-lazy-loading/">Domain model purity and lazy loading</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-model-purity-current-time/">Domain model purity and the current time</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/immutable-architecture/">Immutable architecture</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/link-to-an-aggregate-reference-or-id/">Link to an aggregate: reference or Id?</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://udidahan.com/2008/02/29/how-to-create-fully-encapsulated-domain-models/">How to create fully encapsulated Domain Models</a>" by Udi Dahan</p></li> +<li><p>"<a class="reference external" href="https://dddcommunity.org/library/vernon_2011/">Effective Aggregate Design</a>" by Vaughn Vernon</p></li> +<li><p>"<a class="reference external" href="https://github.com/ardalis/DDD-NoDuplicates">Designing a Domain Model to enforce No Duplicate Names</a> by Steve Smith</p></li> </ul> -</nav> -<blockquote> -<div><p>💬 "Scrum projects do not have an up-front analysis or design phase; all work occurs within the repeated cycle of sprints. -This does not mean, however, that design on a Scrum project is not intentional. -An intentional design process is one in which the design is guided through deliberate, conscious decision making. -The difference on a Scrum project is not that intentional design is thrown out, but that it is done (like everything else on a Scrum project) incrementally. -Scrum teams acknowledge that as nice as it might be to make all design decisions up front, doing so is impossible. -This means that on a Scrum project, design is both intentional and emergent.</p> -<p>A big part of an organization's becoming agile is finding the appropriate balance between anticipation and adaptation (Highsmith 2002). -Figure 9.2 shows this balance along with activities and artifacts that influence the balance. -When doing up-front analysis or design, we are attempting to anticipate users' needs. -Because we cannot perfectly anticipate these, we will make some mistakes; some work will need to be redone. -When we forgo analysis and design and jump immediately into coding and testing with no forethought at all, we are trying to adapt to users' needs. -All projects of interest will be positioned somewhere between anticipation and adaptation based on their own unique characteristics; no application will be all the way to either extreme. -A life-critical, medical safety application may be far to the anticipation side. -A three-person startup company building a website of information on kayak racing may be far toward the side of adaptation.</p> -<p>Foretelling the agile preference for simplicity, in 1990, was speaker and author Do-While Jones.</p> -<blockquote> -<div><p>I'm not against planning for the future. -Some thought should be given to future expansion of capability. -But when the entire design process gets bogged down in an attempt to satisfy future requirements that may never materialize, then it is time to stop and see if there isn't a simpler way to solve the immediate problem.</p> -<p class="attribution">—Jones' 1990 article, "The Breakfast Food Cooker," remains a classic parable of what can go wrong when software developers over-design a solution. I highly recommended reading it at <a class="reference external" href="http://www.ridgecrest.ca.us/~do_while/toaster.htm">http://www.ridgecrest.ca.us/~do_while/toaster.htm</a></p> -</div></blockquote> -<p>Scrum teams avoid this "bogging down" by realizing that not all future needs are worth worrying about today. Many future needs may be best handled by planning to adapt as they arise."</p> -<p class="attribution">—"Succeeding with Agile: Software Development Using Scrum" by Mike Cohn</p> -</div></blockquote> -<figure class="align-left" id="id3"> -<a class="reference internal image-reference" href="../../../../_images/fig-9.2-balancing-anticipation-adaptation.png"><img alt="FIGURE 9.2 Achieving a balance between anticipation and adaptation involves balancing the influence of the activities and artifacts on each side. The image source is &quot;Succeeding with Agile: Software Development Using Scrum&quot; by Mike Cohn" src="../../../../_images/fig-9.2-balancing-anticipation-adaptation.png" style="width: 90%;"/></a> -<figcaption> -<p><span class="caption-text">FIGURE 9.2 Achieving a balance between anticipation and adaptation involves balancing the influence of the activities and artifacts on each side. The image source is "Succeeding with Agile: Software Development Using Scrum" by Mike Cohn</span></p> -</figcaption> -</figure> -<blockquote> -<div><p>💬 McConnell writes, "In ten years the pendulum has swung from 'design everything' to 'design nothing.' -But the alternative to BDUF [Big Design Up Front] isn't no design up front, it's a Little Design Up Front (LDUF) or Enough Design Up Front (ENUF)." -This is a strawman argument. -The alternative to designing before implementing is designing after implementing. -Some design up-front is necessary, but just enough to get the initial implementation. -Further design takes place once the implementation is in place and the real constraints on the design are obvious. -Far from "design nothing," the XP strategy is "design always."</p> -<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck</p> -</div></blockquote> -<blockquote> -<div><p>💬 "From the very earliest days of agile methods, people have asked what role there is for architectural or design thinking. -A common misconception is that since agile methods drop the notion of a detailed up-front design artifact, that there is no room for architecture in an agile project. -In my keynote at the first-ever agile conference, I pointed out that design was every bit as important for agile projects, but it manifests itself differently, becoming an evolutionary approach."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/agile.html">Agile Software Development</a>" by Martin Fowler</p> -</div></blockquote> -<blockquote> -<div><p>💬 "Though BDUF is an Agile anti-pattern, does it mean architecture should solely be a product from emergence? As James Coplien argues [Coplien 2010], some intentional architecture saves waste and accelerates the decision process.</p> -<p>Agile Architecture shall seek a balance between intentional and emerging. Intentional architecture provides value if it is done differently. Intentional architecture represents a set of assumptions that must be verified. It should not slow down the integration of new requirements.</p> -<p>[Coplien 2010] Lean Architecture, by James Coplien and Gertrud Bjørnvig, July 2010, published by Wiley"</p> -<p class="attribution">—"Open Agile Architecture™" by The Open Group, Chapter "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard-single/#_axiom_14_bias_for_change">9.14. Axiom 14. Bias for Change</a>"</p> -</div></blockquote> -<blockquote> -<div><p>💬 "The incremental and iterative nature of Agile development can facilitate efficient technical and management processes and practices to reduce the cost associated with change. -In comparison, projects managed at the waterfall end of the continuum seek to reduce total rework cost by minimizing the number of changes, limiting the number of control points, and baselining detailed specifications which are reviewed and traced throughout the project."</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> -</div></blockquote> -<blockquote> -<div><p>💬 "Agile" methods actually can be applied within a variety of models. -While Agile methods are common in executing an evolutionary lifecycle model, they can be used in other lifecycle models at various stages. -What the methods have in common is an emphasis on continuous inspection and collaboration in the rapid production of working software in an environment where changes, including changes to requirements, are expected.</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> -</div></blockquote> -<blockquote> -<div><p>💬 Waterfalls and iterations may nest inside each other. -A six year project might consist of two 3 year projects, where each of the two projects are structured in a waterfall style, but the second project adds additional features. -You can think of this as a two-iteration project at the top level with each iteration as a waterfall. Due to the large size and small number of iterations, I'd regard that as primarily a waterfall projecta -In contrast you might see a project with 16 iterations of one month each, where each iteration is planned in a waterfall style. -That I'd see as primarily iterative. -While in theory there's potential for a middle ground projects that are hard to classify, in practice it's usually easy to tell that one style predominates.</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/WaterfallProcess.html">Waterfall Process</a>" by Martin Fowler</p> -</div></blockquote> -<section id="id2"> -<h2><a class="toc-backref" href="#id5" role="doc-backlink">Стоимость гибкости</a></h2> -<p>Изменяемость тоже имеет свою стоимость. Нельзя создавать бесконечно гибкое решение. Важен баланс.</p> -<blockquote> -<div><p>💬 "One trade-off that's often overlooked is between the number of options you have and the resulting complexity. More options are desirable, but wanting to have all options all the time will result in unnecessary complexity, as is often the case with overly elaborate abstraction layers or massive configuration frameworks. I captured this effect into Gregor's Law:</p> -<blockquote> -<div><p>Excessive complexity is nature's punishment for organizations that are unable to make decisions."</p> -</div></blockquote> -<p class="attribution">—"<a class="reference external" href="https://architectelevator.com/gregors-law/">Gregor's Law. Excessive complexity is nature's punishment for organizations that are unable to make decisions</a>" by Gregor Hohpe</p> -</div></blockquote> -<blockquote> -<div><p>💬 "If you pick any one aspect of software then you can make it easy to change, but we don't know how to make everything easy to change. Making something easy to change makes the overall system a little more complex, and making everything easy to change makes the entire system very complex. Complexity is what makes software hard to change. That, and duplication."</p> -<p class="attribution">—Ralf Johnson at "<a class="reference external" href="https://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf">Who Needs an Architect?</a>" by Martin Fowler</p> -</div></blockquote> </section> -<section id="open-agile-architecture-standard-by-the-open-group"> -<h2><a class="toc-backref" href="#id6" role="doc-backlink">Open Agile Architecture™ Standard by The Open Group</a></h2> -<p>Глава "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/architecture-development.html#_architecture_development_styles">4.5. Architecture Development Styles</a>" стандарта посвящена поиску баланса между "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/architecture-development.html#_intentional_architecture_2">4.5.2. Intentional Architecture</a>" и "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/architecture-development.html#emergence">4.5.1. Emergence Architecture</a>".</p> +<section id="cqrs-event-sourcing"> +<h5><a class="toc-backref" href="#id56" role="doc-backlink">CQRS &amp; Event Sourcing</a></h5> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/myth-busting/2020-07-09-overselling-event-sourcing/">Overselling Event Sourcing</a>" by Alexey Zimarev</p></li> +<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/microservices/">Event Sourcing and Microservices</a>" by Alexey Zimarev</p></li> +<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/projections/">Projections in Event Sourcing</a>" by Alexey Zimarev</p></li> +<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/cqrs/">Event Sourcing and CQRS</a>" by Alexey Zimarev</p></li> +<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/entities-as-streams/">Entities as event streams</a>" by Alexey Zimarev</p></li> +<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/introduction/">Event Sourcing basics</a>" by Alexey Zimarev</p></li> +<li><p>"<a class="reference external" href="https://eventstore.com/blog/what-is-event-sourcing/">What is Event Sourcing?</a>" by Alexey Zimarev</p></li> +<li><p>"<a class="reference external" href="https://eventstore.com/blog/event-sourcing-and-cqrs/">Event Sourcing and CQRS</a>" by Alexey Zimarev</p></li> +<li><p>"<a class="reference external" href="https://www.eventstore.com/blog/event-immutability-and-dealing-with-change">Event immutability and dealing with change</a>" by Savvas Kleanthous</p></li> +<li><p>"<a class="reference external" href="https://www.eventstore.com/blog/10-problems-that-event-sourcing-can-help-solve-for-you">10 problems that Event Sourcing can help solve for you</a>" by Dennis Doomen</p></li> +<li><p>"<a class="reference external" href="http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/">CQRS, Task Based UIs, Event Sourcing agh!</a>" by Greg Young</p></li> +<li><p>"<a class="reference external" href="https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf">CQRS Documents</a>" by Greg Young</p></li> +<li><p>"<a class="reference external" href="https://leanpub.com/esversioning">Versioning in an Event Sourced System</a>" by Greg Young ("<a class="reference external" href="https://leanpub.com/esversioning/read">читать online</a>", "<a class="reference external" href="https://github.com/luque/Notes--Versioning-Event-Sourced-System">конспект книги</a>")</p></li> +<li><p>"<a class="reference external" href="https://www.researchgate.net/publication/315637858_The_dark_side_of_event_sourcing_Managing_data_conversion">The Dark Side of Event Sourcing: Managing Data Conversion</a>" by Michiel Overeem, Marten Spoor, Slinger Jansen</p></li> +<li><p>"<a class="reference external" href="http://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" by Udi Dahan</p></li> +<li><p>"<a class="reference external" href="https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/">Busting some CQRS myths</a>" by Jimmy Bogard</p></li> +</ul> </section> -<section id="prediction-adaptation"> -<span id="emacsway-balancing-prediction-adaptation-pendulum-swinging"/><h2><a class="toc-backref" href="#id7" role="doc-backlink">Эволюционный маятник баланса Prediction/Adaptation</a></h2> -<p>В 2021 году большую популярность обрела статья, освещавшая назревшие в индустрии вопросы относительно поиска баланса Prediction/Adaptation:</p> +<section id="bounded-context-and-microservices"> +<h5><a class="toc-backref" href="#id57" role="doc-backlink">Bounded Context and Microservices</a></h5> <ul class="simple"> -<li><p>"<a class="reference external" href="https://threedots.tech/post/software-dark-ages/">Software Dark Ages</a>" by Robert Laszczak</p></li> -<li><p>"<a class="reference external" href="https://habr.com/ru/company/cian/blog/569940/">Темные века разработки программного обеспечения</a>" by Robert Laszczak, перевод Евгения Пешкова</p></li> +<li><p>"<a class="reference external" href="https://vladikk.com/2018/01/21/bounded-contexts-vs-microservices/">Bounded Contexts are NOT Microservices</a>" by Vladik Khononov</p></li> +<li><p>"<a class="reference external" href="https://vladikk.com/2018/02/28/microservices/">Tackling Complexity in Microservices</a>" by Vladik Khononov</p></li> +<li><p>"<a class="reference external" href="https://youtu.be/Z0RgR9xIQE4">DDDDD: Bounded Contexts, Microservices, and Everything In Between</a>" by Vladik Khononov</p></li> +<li><p>"<a class="reference external" href="https://kalele.io/reactive-microservices/">Reactive Microservices</a>" by Vaughn Vernon</p></li> +<li><p>"<a class="reference external" href="https://kalele.io/microservices-and-microservices/">Microservices and [Micro]services</a>" by Vaughn Vernon</p></li> +<li><p>"<a class="reference external" href="https://blog.avanscoperta.it/2020/06/11/about-bounded-contexts-and-microservices/">About Bounded Contexts and Microservices</a>" by Alberto Brandolini</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/model/domain-analysis">Using domain analysis to model microservices</a>"</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/model/microservice-boundaries">Identifying microservice boundaries</a>"</p></li> +<li><p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/domains-subdomain-problem-solution-space-in-ddd-clearly-defined-e0b49c7b586c">Domain, Subdomain, Bounded Context, Problem/Solution Space in DDD: Clearly Defined</a>" by Nick Tune</p></li> +<li><p>"<a class="reference external" href="https://medium.com/@kentbeck_7670/monolith-services-theory-practice-617e4546a879">Monolith -&gt; Services: Theory &amp; Practice</a>" by Kent Beck</p></li> +<li><p>"<a class="reference external" href="https://tidyfirst.substack.com/p/tldr-coupling-and-later-cohesion">tl;dr Coupling (&amp; later Cohesion)</a>" by Kent Beck</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/articles/break-monolith-into-microservices.html#GoMacroFirstThenMicro">How to break a Monolith into Microservices :: Go Macro First, then Micro</a>" by Zhamak Dehghani</p></li> +</ul> +<p>Tools:</p> +<ul class="simple"> +<li><p>См. Context Map средствами Archi на диаграмме "Views : Tactical Architecture : Program Level : Context Map" of <a class="reference external" href="https://community.opengroup.org/archimate-user-community/home/-/issues/8">Model</a> used for presentation "Enterprise Architecture Modelling with ArchiMate in an Agile at Scale Programme"</p></li> +<li><p>"<a class="reference external" href="https://github.com/ddd-crew/context-mapping">Context Mapping</a>" by Nick Tune and DDD-Crew</p></li> +<li><p>"<a class="reference external" href="https://github.com/ddd-crew/ddd-starter-modelling-process#organise">Context Map Cheat Sheet</a>" by Nick Tune and DDD-Crew</p></li> +<li><p>"<a class="reference external" href="https://miro.com/app/board/o9J_kqrI8ck=/">Context Map Cheat Sheet (Miro template)</a>" by Nick Tune and DDD-Crew</p></li> +<li><p>"<a class="reference external" href="https://github.com/ddd-crew/context-mapping-quiz">Context Mapping Quiz</a>" by Nick Tune and DDD-Crew</p></li> +<li><p>"<a class="reference external" href="https://miro.com/app/board/o9J_lzWf14U=/">Context Mapping Quiz (Miro template)</a>" by Nick Tune and DDD-Crew</p></li> +<li><p>"<a class="reference external" href="https://contextmapper.org/">ContextMapper - a Modeling Framework for Strategic Domain-driven Design</a>"</p></li> +<li><p>"<a class="reference external" href="https://github.com/ContextMapper">Context Mapper - a Modeling Framework for Strategic Domain-driven Design (DDD) and Service Decomposition (at Github)</a>"</p></li> +<li><p>"<a class="reference external" href="https://github.com/ServiceCutter/ServiceCutter">ServiceCutter - a Structured Way to Service Decomposition</a>"</p></li> +<li><p>"<a class="reference external" href="https://domorobo.to/">DomoRoboto - strategic, rapid, learning for teams using Domain-Driven Design and Architecture modeling</a>" (EventStorming, Bounded Contexts, Context Mapping, Topo Architecture) by Vaughn Vernon</p></li> +<li><p>"<a class="reference external" href="https://speakerdeck.com/mploed/visualizing-sociotechnical-architectures-with-context-maps?slide=56">Visualizing sociotechnical architectures with Context Maps</a>"</p></li> </ul> -<p>Simon Brown тоже обратил внимание на тот факт, что на современном рынке маятник Prediction/Adaptation качнулся в сторону Prediction (анализ и проектирование) от Adaptation (преобладающий принцип Single-Team Agile):</p> -<blockquote> -<div><p>💬 "Even just a few years ago, "software architecture" was not a topic that people were interested in ... "because agile". Times are changing?"</p> -<p class="attribution">—2021-12-23, <a class="reference external" href="https://t.co/ipu5HpS1C4">https://t.co/ipu5HpS1C4</a></p> -</div></blockquote> -<p>В 2000-м Tom DeMarco и Camden, Maine писали:</p> -<blockquote> -<div><p>💬 "In On War, Carl von Clausewitz tells us that military history is a pendulum swinging back and forth between the relative advantages of armor and of mobility. -The knights in shining armor were able to dominate any knight without, but they were no match for the quick, nearly naked pony warriors that swept across the plains with Genghis Kahn and his Mongols. -Light cavalry itself was doomed as soon as there were tanks, and tanks were no match for fleet-footed Palestinian teenagers with Sagger missiles. -With the Maginot Line, the French were gambling that the pendulum had swung again toward armor, but it hadn't, and the Germans simply went around it.</p> -<p>In the field of IT, we are just emerging from a time in which armor (process) has been king. -And now we are moving into a time when only mobility matters. -Building a product the right way still sounds like a laudable goal, but—let's face it—what really matters today is building it fast. -Because we are process-obsessed in our field, we have tended to react to this new imperative as we reacted to the imperatives thrust upon us in the 1980s and 1990s. -We have asked, "What shall we add to our process to deal with this new situation?"</p> -<p class="attribution">—Foreword of "Planning Extreme Programming" by Kent Beck, Martin Fowler</p> -</div></blockquote> -<section id="prediction-adaptation-adaptation"> -<h3><a class="toc-backref" href="#id8" role="doc-backlink">Занос маятника Prediction/Adaptation в сторону Adaptation</a></h3> -<p>Можно заметить, что на рубеже 2000 года, <a class="reference internal" href="../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">маятник Prediction/Adaptation максимально отклонился в сторону Adaptation</span></a>, зачастую минимизируя долю Prediction до минималистичного набора практик - PBR, Spike, Planning. -Этому способствовало радикальное снижение стоимости Adaptation в те годы, благодаря росту популярности OOP, <a class="reference internal" href="adaptation/software-design/patterns.html#emacsway-agile-patterns"><span class="std std-ref">шаблонов</span></a> проектирования и принципов проектирования, методик управления сложностью (ROM, POSA, GOF, OOAD, <a class="reference internal" href="adaptation/software-design/solid.html#emacsway-agile-solid"><span class="std std-ref">SOLID</span></a>, Use Case Driven Approach, Object-Oriented Software Construction etc.), <a class="reference internal" href="../../tdd/tdd.html#emacsway-tdd"><span class="std std-ref">TDD</span></a>, Refactoring и т.д.</p> -<p>В конце 90-х — в начале 2000-х, когда ведущим умам архитектуры своего времени удалось достигнуть <a class="reference internal" href="../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">пологого графика роста стоимости изменения (адаптации) кода, максимально приближенного к горизонтальной асимтоте</span></a>, что открыло широкие возможности по удешевлению разработки путем <a class="reference internal" href="adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">эмпирического (т.е. опытным путем) разрешения неопределенности</span></a> (т.е. итеративно). -Это означало, что стоимость реализации решения больше не зависело от момента его принятия, что позволило отказаться от заблаговременного проектирования и откладывать принятие решения до момента наибольшей полноты информированности, даже после частичной реализации продукта.</p> -<p>Основной фокус архитектуры сместился с</p> -<blockquote> -<div><p>💬 "Architecture is the decisions that you wish you could get right early in a project, but that you are not necessarily more likely to get them right than any other." — Ralph Johnson</p> -</div></blockquote> -<p>на</p> -<blockquote> -<div><p>💬 "A good architect pretends that the decision has not been made, and shapes the system such that those decisions can still be deferred or changed for as long as possible.</p> -<p>A good architect maximizes the number of decisions not made."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> -</div></blockquote> -<blockquote> -<div><p>💬️ "Ah, interesting! -Both architecture and agile methods thrive under high levels of uncertainty! -And isn't that exactly the environment we mostly face today with rapid changes in technology and short-lived business models? -So, agile and architecture are addressing the same problem from different angles: <strong>architecture gives you the options to sustain velocity when the unexpected happens</strong>. -And agile gives you the attitude to always be learning and to quickly adapt to changing circumstances."</p> -<p class="attribution">—"<a class="reference external" href="https://architectelevator.com/transformation/agile_architecture/">Agile and Architecture: Friend, not Foe</a>" by Gregor Hohpe</p> -</div></blockquote> -<blockquote> -<div><p>💬️ "Grady Booch has also provided a set of guidelines for an agile architecture (which in turn imply some duties for the agile architect). -Booch claims that all good software-intensive architectures are agile. -What does he mean by this? He means that a successful architecture is resilient and loosely coupled. -It is composed of a core set of well-reasoned design decisions but still contains some "wiggle room" that allows modifications to be made and refactorings to be done, without ruining the original structure.</p> -<p>Booch also notes that an effective agile process will allow the architecture to grow incrementally as the system is developed and matures. -The key to success is to have decomposability, separation of concerns, and near-independence of the parts. -(Sound familiar? These are all modifiability tactics.)</p> -<p>Finally, Booch notes that to be agile, the architecture should be visible and self-evident in the code; this means making the design patterns, cross-cutting concerns, and other important decisions obvious, well communicated, and defended. -This may, in turn, require documentation. -But whatever architectural decisions are made, the architect must make an effort to "socialize" the architecture."</p> -<p class="attribution">—"Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman</p> -</div></blockquote> -<blockquote> -<div><p>💬 Agile methodologies are based on the notion of embracing change over following detailed plans; to quote the Agile Manifesto: working software over comprehensive documentation. -The future is uncertain. -Customer needs change and so do external conditions; -any plans you draw up will need to be <strong>altered</strong> anyway. -This means that the <strong>role of architecture in an Agile context is different from the “waterfall” approach</strong>, where you first draw up plans and then execute them. -In an Agile context the plans themselves, and hence <strong>the architecture, are constantly being adapted</strong> to match changing circumstances and requirements. -This does not mean that architecture is no longer relevant in Agile. -On the contrary, architecture captures the shared vision needed by Agile teams.</p> -<p class="attribution">—"<a class="reference external" href="https://pubs.opengroup.org/architecture/guides/agile-modeling/">The Open Group Guide: Agile Architecture Modeling Using the ArchiMate® Language :: Chapter 2.1 Agile and Architecture in General</a>"</p> -</div></blockquote> -<p>Маятник отклонился от Prediction к Adaptation с большим заносом. -Хотя в то время уже были модели разработки того, что мы сегодня называем моделями масштабируемого Agile (RUP, MSF, RAD, FDD, Crystal Clear etc.), но они не занимали значительной части рынка.</p> -<p>Так же, как во времена роста популярности OOP, "Switch-Case Statement" считался Code Smell, дабы стимулировать продвижение OOP в массы (об этом признается M.Fowler во втором издании книги Refactoring), в начале 2000-х значение заблаговременного анализа и проектирования (Prediction) нередко принебрегалось, дабы подчеркнуть превосходство эмпирического способа разрешения неопределенности (Adaptation) и стимулировать продвижение этой идеи в массы.</p> -<blockquote> -<div><p>💬️ "We decided to call it a manifesto since it was a call to arms and a statement of our beliefs."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/agileStory.html">Writing The Agile Manifesto</a>" by Martin Fowler</p> -</div></blockquote> -<blockquote> -<div><p>💬️ "The Agile movement is not anti-methodology, in fact, many of us want to restore credibility to the word methodology. -We want to restore a balance. We embrace modeling, but not in order to file some diagram in a dusty corporate repository. -We embrace documentation, but not hundreds of pages of never-maintained and rarely-used tomes. -We plan, but recognize the limits of planning in a turbulent environment. -Those who would brand proponents of XP or SCRUM or any of the other Agile Methodologies as "hackers" are ignorant of both the methodologies and the original definition of the term hacker."</p> -<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/history.html">History: The Agile Manifesto</a>"</p> -</div></blockquote> </section> -<section id="prediction-adaptation-prediction"> -<h3><a class="toc-backref" href="#id9" role="doc-backlink">Отскок маятника Prediction/Adaptation назад к Prediction</a></h3> -<p>Однако, в статье мы наблюдаем, что маятник пошел в обратном направлении:</p> -<blockquote> -<div><p>💬 "пять дней кодинга может сэкономить день планирования</p> -<p>With 5 days of coding, you can save 1 day of planning"</p> -<p class="attribution">—"<a class="reference external" href="https://threedots.tech/post/software-dark-ages/">Software Dark Ages</a>" by Robert Laszczak, перевод Евгения Пешкова</p> -</div></blockquote> -<p>При этом, в статье очень вяло и вскользь говорится о снижении стоимости Adaptation:</p> -<blockquote> -<div><p>💬 "Если вам нужно реализовать что-то "на будущее", потому что позже будет сложнее добавить это, – это очень плохой знак. -Вам следует подумать о том, как упростить позднее добавление.</p> -<p>If you need to implement something "for the future" because it will be harder to add it later – that's a very bad sign. -You should think about how to make it easy to add it later."</p> -<p class="attribution">—"<a class="reference external" href="https://threedots.tech/post/software-dark-ages/">Software Dark Ages</a>" by Robert Laszczak, перевод Евгения Пешкова</p> -</div></blockquote> -<p>Что это? Бунт против Agile? Против заветов Eric Evans?</p> -<p>Причин здесь две.</p> -<ol class="arabic"> -<li><p>Проекты стали сложнее, а команды стали больше, нежели они были 20 лет назад. -Cредний проект стал слишком большим для Single-Team Agile, а стоимость Adaptation нарастает со значительным опережением роста численности коллектива.</p> -<p>Это вынуждает <a class="reference internal" href="../../team-topologies/harlan-mills%27-proposal.html#emacsway-harlan-mills-proposal"><span class="std std-ref">сместить баланс Prediction/Adaptation назад, в сторону Prediction</span></a>. -Интерес к Prediction-методам обработки неопределенности начал возвращаться. -На первое место вышли вопросы достижения автономности команд и интеграции производимых ими системных инкрементов. -Архитектура стала обретать социальное значение.</p> -<p>И здесь мы наблюдаем воскрешение старых принципов, которые были хорошо известны в RUP, MSF, RAD, FDD, Crystal Clear etc. -На базе старых моделей масштабируемой итеративной разработки появились новые (SAFe, DAD, LESS etc.). -Дело в том, что в старые времена Scaled Agile хоть и был не таким частым явлением, как сегодня, да и не назывался вовсе Agile, но он все-таки существовал в немногочисленных крупных корпорациях, т.к. они уже тогда столкнулись с теми проблемами, которые обрели массовость примерно к 2010 году. -Например, многие идеи популярной книги "Team Topologies", которые сегодня создают "вау-эффект", были описаны, еще в RAD.</p> -<p>Обратите внимание на тот факт, что это совпало хронологически со взрывным ростом интереса к микросервисной архитектурой и DDD, поскольку они также отвечали на главный вызов своего времени - стремительной рост размера среднего проекта и среднего коллектива.</p> -</li> -<li><p>Начали появляться новые, более легковесные и экономичные методики анализа и проектирования (Event Storming/Modeling, Domain Storytelling, Impact Mapping, Example Mapping, Design Thinking etc.). -Prediction стал дешевле, что позволило увеличить его долю, оставаясь в прежних пределах его экономической целесообразности.</p></li> -</ol> -<p>Изменился контекст разработки, и сегодня в индустрии принципы Single-Team Agile зачастую стали не ускорять, а замедлять разработку. -Это качнуло маятник назад, в сторону Prediction.</p> -<p>Многие старые идеи Scaled Agile реинкарнировали в современные итеративные модели разработки, такие как DAD и SAFe.</p> -<p>Начали появляться способы интеграции <a class="reference internal" href="../../team-topologies/harlan-mills%27-proposal.html#emacsway-program-management"><span class="std std-ref">Program Management</span></a> (т.е. организации процессов Prediction) в даже самые легковесные Scaled Agile Frameworks, такие как Nexus by Ken Schwaber.</p> -<p>А в основе лежит все та же идея "<a class="reference internal" href="../../team-topologies/harlan-mills%27-proposal.html#emacsway-harlan-mills-proposal"><span class="std std-ref">Метода Хирурга</span></a>" Харлана Миллза, который младше Закона Конвея всего на три года.</p> -<p>Разные реализации разных SDLC-моделей отличаются прежде всего различным горизонтом видения Prediction и его долей в балансе Prediction/Adaptation, например, в SAFe доля Prediction больше, чем в Nexus, а в RUP - еще больше. Важно уметь грамотно выбирать модель под потребности конкретного проекта. -Grady Booch даже назвал <a class="reference internal" href="../sdlc-reference.html#emacsway-sdlc-literature"><span class="std std-ref">качество управления моделью жизненного цикла разработки критическим условием успешности проекта</span></a>. -А поскольку модель SDLC призвана решать проблему управления неопределенностью требований, то <a class="reference external" href="https://itabok.iasaglobal.org/itabok3_0/architecture-methodologies-and-frameworks/">выбор модели становится архитектурной задачей</a>.</p> -<p>Здесь Prediction сфокусирован, главным образом, на разрешении неопределенности в problem-space (т.е. требований), что влияет на выбор SDLC-модели. -За разрешение неопределенности в solution-space на уровне Implementation и Software Design отвечает принцип <a class="reference internal" href="adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>, целью которого является само снижение стоимости Adaptation.</p> -<p>О том, как интегрировать активности по анализу и проектированию в Agile-модель разработки, см. также в разделе <a class="reference internal" href="../../team-topologies/harlan-mills%27-proposal.html#emacsway-program-management"><span class="std std-ref">Program Management</span></a>.</p> -<p>Новый исторический контекст выдвинул новые проблемы и новые способы их решения. -Agile модель разработки изменилась.</p> -<blockquote> -<div><p>💬 "Despite discussions over whether the Manifesto itself should be amended, many of the original signers see the document as a historical—not a living—document. -"It's like a Declaration of Independence in U.S. history," says Cockburn. -"You don't go back and rewrite that.""</p> -<p class="attribution">—"<a class="reference external" href="https://www.theatlantic.com/technology/archive/2017/12/agile-manifesto-a-history/547715/">The Winter Getaway That Turned the Software World Upside Down</a>" by Caroline Mimbs Nyce</p> -</div></blockquote> -<p>В своем докладе "<a class="reference external" href="https://youtu.be/d4qldY0g_dI?t=16m57s">Kent Beck talks beyond Agile Programming @ Startup Lessons Learned Conference 2010</a>" Kent Beck говорит, что по прошествии 10 лет принципа "Individuals and interactions over processes and tools" of "Agile Manifesto" уже недостаточно, и он добавил бы к нему еще и "Team vision and discipline".</p> -<p>Ценность "Individuals and interactions over processes and tools" of "Agile Manifesto" нередко воспринимается в отрасли как противопоставление проектным практикам и всей Prediction-активности.</p> -<blockquote> -<div><p>💬 "I see some teams that use the word "agile" when they really mean "chaotic""</p> -<p class="attribution">—"<a class="reference external" href="https://pragdave.me/blog/2007/02/24/some-agile-history.html">Some Agile History</a>" by Dave Thomas</p> -</div></blockquote> -<p>На самом деле, у этого пункта были конкретные причины, и они не ставили цели "исключить" Prediction-активности из процессов разработки.</p> -<blockquote> -<div><p>💬 "For example, I think that ultimately, Extreme Programming has mushroomed in use and interest, not because of pair-programming or refactoring, but because, taken as a whole, the practices define a developer community freed from the baggage of Dilbertesque corporations. -Kent Beck tells the story of an early job in which he estimated a programming effort of six weeks for two people. -After his manager reassigned the other programmer at the beginning of the project, he completed the project in twelve weeks—and felt terrible about himself! -The boss—of course—harangued Kent about how slow he was throughout the second six weeks. -<strong>Kent, somewhat despondent because he was such a "failure" as a programmer, finally realized that his original estimate of 6 weeks was extremely accurate—for 2 people—and that his "failure" was really the manager's failure, indeed, the failure of the standard "fixed" process mindset that so frequently plagues our industry.</strong></p> -<p><strong>This type of situation goes on every day—marketing, or management, or external customers, internal customers, and, yes, even developers — don't want to make hard trade-off decisions, so they impose irrational demands through the imposition of corporate power structures.</strong> -This isn't merely a software development problem, it runs throughout Dilbertesque organizations.</p> -<p><strong>In order to succeed in the new economy, to move aggressively into the era of e-business, e-commerce, and the web, companies have to rid themselves of their Dilbert manifestations of make-work and arcane policies.</strong> -This freedom from the inanities of corporate life attracts proponents of Agile Methodologies, and scares the begeebers (you can't use the word 'shit' in a professional paper) out of traditionalists. -Quite frankly, the Agile approaches scare corporate bureaucrats — at least those that are happy pushing process for process' sake versus trying to do the best for the "customer" and deliver something timely and tangible and "as promised" — because they run out of places to hide.</p> -<p><strong>The Agile movement is not anti-methodology, in fact, many of us want to restore credibility to the word methodology.</strong> -<strong>We want to restore a balance.</strong> -<strong>We embrace modeling, but not in order to file some diagram in a dusty corporate repository.</strong> -<strong>We embrace documentation, but not hundreds of pages of never-maintained and rarely-used tomes.</strong> -<strong>We plan, but recognize the limits of planning in a turbulent environment.</strong> -Those who would brand proponents of XP or SCRUM or any of the other Agile Methodologies as "hackers" are ignorant of both the methodologies and the original definition of the term hacker."</p> -<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/history.html">History: The Agile Manifesto</a>"</p> -</div></blockquote> -<blockquote> -<div><p>💬 ...people and how they work together is the primary factor in software development, and that processes are a secondary factor. -This is reflected in the first value of the agile manifesto "Individuals and interactions over processes and tools"...</p> -<p>&lt;...&gt;</p> -<p>An important consequence of these values and principles is that a team should choose its own process - one that suits the people and context in which they work. -<strong>Imposing an agile process from the outside strips the team of the self-determination which is at the heart of agile thinking.</strong></p> -<p>&lt;...&gt;</p> -<p>This notion of a process made to fit the team (and not the other way around) is a necessary condition for agile methods, but clearly isn't sufficient. -A team may choose a totally waterfall, un-agile process. -In that case, clearly the process is no more agile than apples taste of strawberries. -But <strong>agile methods aren't the best for all situations</strong>, and personally I'd rather have a team work in a non-agile manner they chose themselves than have my favorite agile practices imposed upon them.</p> -<p>&lt;...&gt;</p> -<p>imposition isn't as clear cut as it can sound, but the fundamental point remains - <strong>imposing agile methods introduces a conflict with the values and principles that underlie agile methods</strong>.</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/AgileImposition.html">Agile Imposition</a>" by Martin Fowler</p> -</div></blockquote> +<section id="domain-events"> +<h5><a class="toc-backref" href="#id58" role="doc-backlink">Domain Events</a></h5> +<ul class="simple"> +<li><p>"<a class="reference internal" href="../ddd/tactical-design/domain-model/domain-events/domain-events-in-ddd.html"><span class="doc">Domain Events in DDD</span></a>"</p></li> +</ul> </section> +<section id="api-design"> +<h5><a class="toc-backref" href="#id59" role="doc-backlink">API-Design</a></h5> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/design/api-design">Designing APIs for microservices</a>"</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design">Web API design</a>"</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-implementation">Web API implementation</a>"</p></li> +<li><p>"<a class="reference external" href="https://github.com/Microsoft/api-guidelines">Microsoft REST API Guidelines</a>"</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/graph/query-parameters#filter-parameter">Microsoft Graph API</a>"</p></li> +<li><p>"<a class="reference external" href="https://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part2-url-conventions/odata-v4.0-errata03-os-part2-url-conventions-complete.html#_Toc453752358">OData protocol</a>"</p></li> +<li><p>"<a class="reference external" href="https://google.aip.dev/general">Google REST API Guidelines</a>"</p></li> +<li><p>"<a class="reference external" href="https://cloud.google.com/files/apigee/apigee-web-api-design-the-missing-link-ebook.pdf">Apigee. Web API Design: The Missing Link. Best Practices for Crafting Interfaces that Developers Love.</a>" by Google Cloud</p></li> +<li><p>"<a class="reference external" href="https://microservice-api-patterns.org/">Microservice API Patterns</a>"</p></li> +<li><p>"<a class="reference external" href="https://w3ctag.github.io/capability-urls/">Good Practices for Capability URLs</a>", W3C Draft</p></li> +<li><p>"<a class="reference external" href="https://pages.apigee.com/rs/apigee/images/api-design-ebook-2012-03.pdf">Web API Design - Crafting Interfaces that Developers Love</a>"</p></li> +<li><p>"<a class="reference external" href="https://goodapi.co/blog/rest-vs-graphql">REST vs. GraphQL: A Critical Review</a>"</p></li> +<li><p>"<a class="reference external" href="https://blog.logrocket.com/5-reasons-you-shouldnt-be-using-graphql-61c7846e7ed3/?gi=f67074d77004">5 reasons you shouldn't be using GraphQL</a>" (<a class="reference external" href="https://medium.com/devschacht/esteban-herrera-5-reasons-you-shouldnt-use-graphql-bae94ab105bc">перевод на Русский</a>)</p></li> +<li><p>"<a class="reference external" href="https://www.openapis.org/">OpenAPIs</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.asyncapi.com/">AsyncAPI</a>"</p></li> +<li><p>"<a class="reference external" href="http://www.persvr.org/rql/">Resource Query Language (RQL)</a>"</p></li> +<li><p>"<a class="reference external" href="https://jsonapi.org/">JSON:API</a>"</p></li> +<li><p>"<a class="reference external" href="https://goessner.net/articles/JsonPath/">JSONPath specification - XPath for JSON</a>", "<a class="reference external" href="https://www.baeldung.com/guide-to-jayway-jsonpath">Introduction to JsonPath</a>"</p></li> +<li><p>"<a class="reference external" href="https://netflix.github.io/falcor/starter/what-is-falcor.html">Falcor</a>"</p></li> +<li><p>"<a class="reference external" href="https://microservice-api-patterns.org/cheatsheet">Cheat Sheet a.k.a. API Design Heuristics</a>" - шпаргалка по "Microservices API Patterns"</p></li> +<li><p>"<a class="reference external" href="https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling">REST API Design - Resource Modeling</a>" by Prakash Subramaniam, WhoughtWorks</p></li> +<li><p>"<a class="reference external" href="https://lostechies.com/jimmybogard/2016/06/01/cqrs-and-rest-the-perfect-match/">CQRS and REST: the perfect match</a>" by Jimmy Bogard</p></li> +<li><p>"<a class="reference external" href="https://lostechies.com/jimmybogard/2016/05/12/entities-arent-resources-resources-arent-representations/">Entities aren't resources, resources aren't representations</a>" by Jimmy Bogard</p></li> +<li><p>"<a class="reference external" href="https://blogs.msdn.microsoft.com/maarten_mullender/2004/07/23/crud-only-when-you-can-afford-it-revisited/">CRUD, only when you can afford it (Revisited)</a>" by Maarten Mullender</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/eshoponcontainers-cqrs-ddd-microservice#cqrs-and-ddd-patterns-are-not-top-level-architectures">CQRS and DDD patterns are not top-level architectures</a>"</p></li> +<li><p>"<a class="reference external" href="https://twirl.github.io/The-API-Book/index.ru.html">The API</a>" by Sergey Konstantinov (<a class="reference external" href="https://github.com/twirl/The-API-Book">Source Code</a>, <a class="reference external" href="https://twirl.github.io/The-API-Book/index.html">English</a>)</p></li> +</ul> </section> -<section id="alberto-brandolini-about-prediction-adaptation"> -<h2><a class="toc-backref" href="#id10" role="doc-backlink">Alberto Brandolini about Prediction/Adaptation</a></h2> -<p><em>Автор раздела: Андрей Ганичев</em></p> -<p>Андрей Ганичев, contributor of "<a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd">Full Modular Monolith application with Domain-Driven Design approach</a>", на тему поиска баланса Prediction/Adaptation:</p> -<p>Когда читал книгу Брандолини про "<a class="reference external" href="https://leanpub.com/introducing_eventstorming">Introducing EventStorming: An act of Deliberate Collective Learning</a>" by Alberto Brandolini (та которая недописанная), обратил внимание что и он вскользь проходит по этой теме.</p> -<p>Глава Pretending to solve the problem writing software, раздел Embrace Change:</p> -<blockquote> -<div><p>💬 "...iterative development is expensive. It is the best approach for developing software in very complex, and lean-demanding domains. However, the initial starting point matters, a lot. A big refactoring will cost a lot more than iterative fine tuning (think splitting a database, vs renaming a variable). So I'll do everything possible to start iterating from the most reasonable starting point."</p> -<p class="attribution">—"<a class="reference external" href="https://leanpub.com/introducing_eventstorming">Introducing EventStorming: An act of Deliberate Collective Learning</a>" by Alberto Brandolini</p> -</div></blockquote> -<blockquote> -<div><p>💬 "Upfront is a terrible word in the agile jargon. It recalls memories the old times analysis phase in the worst corporate waterfall. Given this infamous legacy, the word has been banned from agile environments like blasphemy. But unfortunately ...there's always something upfront. Even the worst developer thinks before typing the firs line of code."</p> -<p class="attribution">—"<a class="reference external" href="https://leanpub.com/introducing_eventstorming">Introducing EventStorming: An act of Deliberate Collective Learning</a>" by Alberto Brandolini</p> -</div></blockquote> -<p>Cм. также:</p> +<section id="event-storming"> +<h5><a class="toc-backref" href="#id60" role="doc-backlink">Event Storming</a></h5> +<p>By Alberto Brandolini (<a class="reference external" href="https://twitter.com/ziobrando">twitter</a>):</p> <ul class="simple"> -<li><p>"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin</p> -<ul> -<li><p>"Chapter 3 Agile Principles :: Prediction and Adaptation"</p></li> -<li><p>"Chapter 3 Agile Principles :: Balance Predictive Up-Front Work with Adaptive Just-in-Time Work"</p></li> +<li><p>"Domain-Driven Design: The First 15 Years", chapter "Discovering Bounded Contexts with EventStorming" by Alberto Brandolini</p></li> +<li><p>"<a class="reference external" href="http://ziobrando.blogspot.com/2013/11/introducing-event-storming.html">Introducing Event Storming</a>" by Alberto Brandolini</p></li> +<li><p>"<a class="reference external" href="https://blog.avanscoperta.it/2020/03/26/remote-eventstorming/">Remote EventStorming</a>" by Alberto Brandolini</p></li> +<li><p>"<a class="reference external" href="https://blog.avanscoperta.it/2020/03/26/eventstorming-in-covid-19-times/">EventStorming in COVID-19 times</a>" by Alberto Brandolini</p></li> +<li><p>"<a class="reference external" href="https://leanpub.com/introducing_eventstorming">Leanpub: Introducing EventStorming</a>" by Alberto Brandolini</p></li> +<li><p><a class="reference external" href="https://www.eventstorming.com/">EventStorming.com</a></p></li> </ul> -</li> -<li><p>"Succeeding with Agile: Software Development Using Scrum" by Mike Cohn, "Chapter 9 Technical Practices :: Design: intentional yet Emergent"</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/architecture/">Software Architecture Guide</a>" by Martin Fowler</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/agile.html">Agile Software Guide</a>" by Martin Fowler</p></li> -<li><p>"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html#PredictiveVersusAdaptive">The New Methodology :: Predictive versus Adaptive</a>" by Martin Fowler</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/WaterfallProcess.html">Waterfall Process</a>" by Martin Fowler</p></li> +<p>Others:</p> +<ul class="simple"> +<li><p>"Domain-Driven Design Distilled" by Vaughn Vernon, chapter "Chapter 7 Acceleration and Management Tools :: Event Storming"</p></li> +<li><p>"<a class="reference external" href="https://www.oreilly.com/library/view/what-is-domain-driven/9781492057802/">What is Domain-Driven Design?</a>" by Vladik Khononov, chapter "Chapter 8: Event Storming"</p></li> +<li><p>"<a class="reference external" href="https://ddd-crew.github.io/eventstorming-glossary-cheat-sheet/">EventStorming Glossary &amp; Cheat sheet</a>" by Nick Tune</p></li> +<li><p>"Open Agile Architecture", chapter "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/">19. Event Storming</a>"</p></li> +<li><p>"<a class="reference external" href="http://agilemindset.ru/event-storming-%D0%BD%D0%B0-%D0%BF%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85-%D0%BA%D0%B5%D0%B9%D1%81%D0%B0%D1%85/">Event Storming на практических кейсах</a>", Сергей Баранов (<a class="reference external" href="https://www.youtube.com/watch?v=kJjuTuviZ-E">видео</a>)</p></li> +<li><p>"<a class="reference external" href="https://www.ibm.com/cloud/architecture/architecture/practices/event-storming-methodology-architecture/">Event storming. The workshop focuses on domain events that are generated in the context of a business process or a business application.</a>" by IBM</p></li> +<li><p>"<a class="reference external" href="https://developer.ibm.com/tutorials/reactive-in-practice-1/">Reactive in practice, Unit 1: Event storming the stock trader domain</a>" by Kevin Webber, Dana Harrington</p></li> +<li><p>"<a class="reference external" href="https://www.ibm.com/cloud/architecture/architecture/practices/event-storming-methodology-architecture/">Event storming at ibm.com</a>"</p></li> +<li><p>"<a class="reference external" href="https://developer.ibm.com/tutorials/reactive-in-practice-1/">Event storming &amp; domain-driven design: Reactive in practice — Event storming the stock trader domain — IBM Developer</a>" by Kevin Webber, Dana Harrington</p></li> +<li><p>"<a class="reference external" href="https://ibm-cloud-architecture.github.io/refarch-eda/methodology/event-storming/">Event driven solution implementation methodology</a>"</p></li> +<li><p>"<a class="reference external" href="https://ibm-cloud-architecture.github.io/refarch-kc/implementation/event-storming-analysis/">Container Shipment Analysis</a>" by IBM</p></li> +<li><p>"<a class="reference external" href="https://github.com/ibm-cloud-architecture/refarch-kc">refarch-kc - Implementation solution for container shipment using Event-Driven Architecture</a>" by IBM</p></li> +<li><p>"<a class="reference external" href="https://github.com/mariuszgil/awesome-eventstorming">Awesome EventStorming</a>"</p></li> </ul> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +<p>Tools:</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> -<li><p>"<a class="reference internal" href="prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Что такое Prediction</span></a>"</p></li> -<li><p>"<a class="reference internal" href="adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>"</p></li> -<li><p>"<a class="reference internal" href="adaptation/software-construction/borrowing-trouble.html#emacsway-borrowing-trouble"><span class="std std-ref">Borrowing trouble</span></a>"</p></li> +<li><p>"<a class="reference external" href="https://domorobo.to/">DomoRoboto - strategic, rapid, learning for teams using Domain-Driven Design and Architecture modeling</a>" (EventStorming, Bounded Contexts, Context Mapping, Topo Architecture) by Vaughn Vernon</p></li> +<li><p><a class="reference external" href="https://github.com/tmorin/plantuml-libs/blob/master/dist/eventstorming/README.md">EventStorming для PlantUML</a></p></li> +<li><p><a class="reference external" href="https://miro.com/">miro.com</a>, см. <a class="reference external" href="https://miro.com/miroverse/category/ideation-and-brainstorming/event-storming">Event Storming template</a></p></li> +<li><dl class="simple"> +<dt>EventStorming для ArchiMate:</dt><dd><ul> +<li><p>C4-Model &amp; Event Storming with ArchiMate, см. "Figure 13: Event Storming Model" of "Agile Architecture Modeling Using the ArchiMate® Language" (см. <a class="reference external" href="https://publications.opengroup.org/g20e">здесь</a>, <a class="reference external" href="https://nicea.nic.in/sites/default/files/Agile_Architecture_Modelling_Using_Archimate.pdf">здесь</a> или <a class="reference external" href="https://nicea.nic.in/download-files.php?nid=247">здесь</a>)</p></li> +<li><p><a class="reference external" href="https://community.opengroup.org/archimate-user-community/home/-/issues/8">Model used by Jean-Baptiste Sarrodie for presentation "Enterprise Architecture Modelling with ArchiMate in an Agile at Scale Programme"</a></p></li> +</ul> +</dd> +</dl> +</li> </ul> -</div> </section> -Sat, 19 Aug 2023 00:00:00 Как осуществлять изменения в коллективеhttps://dckms.github.io/system-architecture/emacsway/soft-skills/change-making.html<span class="target" id="index-0"/><section id="emacsway-change-making-in-psychology"> -<span id="id1"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id2"> -<p class="topic-title">Содержание</p> +<section id="modelling"> +<h5><a class="toc-backref" href="#id61" role="doc-backlink">Modelling</a></h5> <ul class="simple"> -<li><p><a class="reference internal" href="#emacsway-change-making-in-psychology" id="id5">Как осуществлять изменения в коллективе</a></p> -<ul> -<li><p><a class="reference internal" href="#id3" id="id6">Один из реальных примеров</a></p></li> -<li><p><a class="reference internal" href="#emacsway-change-making-literature" id="id7">Литература по теме осуществления изменений</a></p></li> +<li><p>"<a class="reference external" href="https://github.com/ddd-crew/welcome-to-ddd">Getting started with DDD. Definitions of DDD and fundamental concepts to reduce the learning curve and confusion.</a>" by Nick Tune &amp; DDD-Crew</p></li> +<li><p>"<a class="reference external" href="https://github.com/ddd-crew/ddd-starter-modelling-process">Domain-Driven Design Starter Modelling Process. If you're new to DDD and not sure where to start, this process will guide you step-by-step.</a>" by Nick Tune &amp; DDD-Crew</p></li> +<li><p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/legacy-architecture-modernisation-with-strategic-domain-driven-design-3e7c05bb383f">Legacy Architecture Modernisation With Strategic Domain-Driven Design</a>" by Nick Tune</p></li> </ul> -</li> +<p>Собственно, этих знаний достаточно для того, чтобы стать зрелым специалистом. +Своего рода - кандидатский минимум. +Далее - порядок чтения может быть произвольным. +Читать весь список необязательно.</p> +</section> +</section> +</section> +</section> +<section id="id17"> +<h2><a class="toc-backref" href="#id62" role="doc-backlink">Дополнительная литература (на выбор)</a></h2> +<section id="sdlc"> +<h3><a class="toc-backref" href="#id63" role="doc-backlink">SDLC</a></h3> +<section id="single-team-agile"> +<h4><a class="toc-backref" href="#id64" role="doc-backlink">Single-Team Agile</a></h4> +<ul class="simple"> +<li><p>"Extreme Programming Explained" 2nd edition by Kent Beck</p></li> +<li><p>"Planning Extreme Programming" by Kent Beck, Martin Fowler</p></li> +<li><p>"More Effective Agile: A Roadmap for Software Leaders" by Steve McConnell</p></li> +<li><p>"Clean Agile: Back to Basics" by Robert C. Martin</p></li> +<li><p>"Agile! The Good, the Hype and the Ugly" by Bertrand Meyer</p></li> +<li><p>"Scrum and XP from the Trenches: How We Do Scrum" 2nd edition by Henrik Kniberg</p></li> +<li><p>"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin</p></li> +<li><p>"Succeeding with Agile: Software Development Using Scrum" by Mike Cohn</p></li> +<li><p>"User Stories Applied: For Agile Software Development" by Mike Cohn</p></li> +<li><p>"Jeff Sutherland's Scrum Handbook" by Jeff Sutherland</p></li> </ul> -</nav> -<p>На протяжении своей практики я регулярно наблюдал одну и ту же картину: кто-то из сотрудников узнал что-то новое, или же был принят на работу сотрудник с новыми знаниями (например, DDD, архитектурные, методологические, процессные подходы и т.п.), но, странное дело, новая идея получает не поддержку, а сопротивление коллектива, хотя и могла бы облегчить жизнь многим.</p> -<p>Далее одно из двух - либо напряженность нарастает, и наступает разрыв отношений, либо человек смиряется, проявив "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%BD%D0%BE%D1%81%D1%82%D1%8C">Внешний конформизм</a>".</p> -<p>Последний вариант опасен тем, что для человека намного проще согласиться с существующим положением дел, и, чтобы подавить "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%B3%D0%BD%D0%B8%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9_%D0%B4%D0%B8%D1%81%D1%81%D0%BE%D0%BD%D0%B0%D0%BD%D1%81">Когнитивный диссонанс</a>", человек старается всеми силами преувеличить существенность принятого им решения, одновременно приуменьшая важность отвергнутого. -Вследствие этого альтернатива теряет всякую привлекательность в его глазах.</p> -<p>Далее наступает "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%98%D1%81%D0%BA%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_%D0%B2%D0%BE%D1%81%D0%BF%D1%80%D0%B8%D1%8F%D1%82%D0%B8%D0%B8_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B2%D1%8B%D0%B1%D0%BE%D1%80%D0%B0">Искажение в восприятии сделанного выбора</a>" и "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%98%D1%80%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%83%D1%81%D0%B8%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5">Закон иррационального усиления</a>", и, из сторонника изменений, человек превращается в реакциониста, находя в этом "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологическую защиту</a>".</p> -<p>Наверняка вы слышали в своей практике такие фразы, как "я тоже был таким когда-то...", "юношеский максимализм" и т.п.</p> -<p>Но бывает и третий вариант - человеку удается изменить среду. -В конце концов, существующая среда была кем-то создана. -Почему одним это удается, а другим нет?</p> -<blockquote> -<div><p>📝 "Исторический фатализм существует для трусов. -Смелость и счастливый случай не раз меняли ход событий. -Этому учит нас история. -Бывают моменты, когда воля нескольких человек сокрушает все препятствия и открывает новые дороги".</p> -<p class="attribution">—<a class="reference external" href="https://topwar.ru/28631-general-sharl-de-goll.html">Шарль де Голль</a></p> -</div></blockquote> -<p>По моим наблюдениям, условием снижения напряженности является <a class="reference internal" href="knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">выравнивание уровня знаний</span></a>. -Вероятность разрыва отношений выше в ригидных коллективах с низкой обучаемостью. -Поэтому, первая задача, которую предстоит решить, - это изменить систему ценностей коллектива, и возвести знания в элемент престижа.</p> -<p>Никогда не предлагайте внедрения какого-либо нового подхода, например, DDD. -Для коллектива это - еще одна неопределенность, которая может превратиться в еще одну проблему на их шее. -В силу "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%BE%D0%B4%D0%BD%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Эффекта неоднозначности</a>" предлагаемые изменения будут отвергнуты.</p> -<p>Не пытайтесь доказать собеседнику его неправоту, потому что:</p> +</section> +<section id="scaled-agile"> +<h4><a class="toc-backref" href="#id65" role="doc-backlink">Scaled Agile</a></h4> <ul class="simple"> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%BE%D0%B5_%D0%B2%D0%BE%D1%81%D0%BF%D1%80%D0%B8%D1%8F%D1%82%D0%B8%D0%B5">Селективное восприятие</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%BB%D0%BE%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%BA_%D0%BF%D0%BE%D0%B4%D1%82%D0%B2%D0%B5%D1%80%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D1%8E_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D0%B7%D1%80%D0%B5%D0%BD%D0%B8%D1%8F">Склонность к подтверждению своей точки зрения</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%94%D0%B0%D0%BD%D0%BD%D0%B8%D0%BD%D0%B3%D0%B0_%E2%80%94_%D0%9A%D1%80%D1%8E%D0%B3%D0%B5%D1%80%D0%B0">Эффект Даннинга — Крюгера</a>"</p></li> -<li><p><a class="reference external" href="https://architectelevator.com/strategy/always-be-right/">Вы и сами можете ошибаться.</a></p></li> +<li><p>"Scaling Software Agility: Best Practices for Large Enterprises" by Dean Leffingwell</p></li> +<li><p>"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</p></li> +<li><p>"SAFe® 5.0: The World's Leading Framework for Business Agility" by Richard Knaster, Dean Leffingwell</p></li> +<li><p>"Large-Scale Scrum: More with LeSS" by Craig Larman</p></li> +<li><p>"<a class="reference external" href="https://less.works/less/framework/introduction">LeSS</a>" (<a class="reference external" href="https://less.works/ru/less/framework/introduction">перевод на Русский</a>)</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile">Disciplined Agile®</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/">SAFe - Scaled Agile Framework</a>"</p></li> </ul> -<p>Мне известен только один действенный способ провести изменения, это - <a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">идентифицировать проблемы</a>, и в ответ на <strong>конкретные проблемы</strong> предлагать <strong>конкретные решения</strong>. -Например, если проблему решает один из тактических паттернов DDD, то не нужно настаивать на переходе на DDD полностью. -Если проблему решает "<a class="reference external" href="https://www.pmi.org/disciplined-agile/lifecycle/program">Program Management</a>", то <a class="reference external" href="https://www.scrum.org/resources/blog/scaling-scrum-nexus-and-kanban">не нужно настаивать на переходе на SAFe или DAD полностью</a>.</p> -<p>Также учтите, что <a class="reference external" href="https://www.hindawi.com/journals/np/2009/482696/">мозгу нужно время</a>, чтобы осознать решение и рассеять неопределенность. -Поэтому, не спешите. -Вернитесь к вопросу несколько раз через время. -<a class="reference internal" href="icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Вода камень точит</span></a>. -Видели как море режет скалы? -Обязательно посмотрите - вдохновляет. -Стекающие капельки воды прорезают в камне бороздки и углубляют их до тех пор, пока глыба не обрушится. -Капля против скалы! -А вы - больше, чем капля. -Терпенье и труд, как говорится...</p> -<p>Этот пример учит еще одному - <a class="reference internal" href="icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">чем меньше гранулярность изменений, тем выше вероятность их принятия</span></a>. -Это важно, ибо силовое превосходство не на вашей стороне. -Чтобы повысить удельное давление, нужно уменьшить площадь воздействия. -Побеждает не тот, кто сильнее, а тот, кто способен создать силовое превосходство в нужное время в нужном месте.</p> -<p>В крайнем случае, сработает "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BD%D0%BE%D0%B9_%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D0%B8">Каскад доступной информации</a>".</p> -<p>Как говорил Генри Форд, <em>"качество — это делать что-либо правильно, даже когда никто не смотрит"</em>. -Единственный способ этого достигнуть - это единое понимание и полнота информированности коллектива. -Достигается это проливанием света на недостающие связи между причиной и следствием. -Изменения должны происходить снизу, от самоорганизующегося коллектива, а не спускаться директивно сверху. -Важно уметь не внедрить изменения, а инициировать и подпитывать их. -Больше слушать, спрашивать, меньше говорить. -Mike Cohn в статье "<a class="reference external" href="https://www.mountaingoatsoftware.com/blog/my-favorite-hard-questions-to-ask-when-making-a-decision">My Favorite Hard Questions to Ask When Making a Decision</a>" разделяет эту тактику, и даже конкретизирует список вопросов, которые нужно задавать для осуществления влияния.</p> -<section id="id3"> -<h2><a class="toc-backref" href="#id6" role="doc-backlink">Один из реальных примеров</a></h2> -<p>Nick Tune поделился <a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/carefully-forming-teams-to-begin-technology-modernization-f4aa3e776e1f">историей конфликта с одним из ведущих разработчиков</a>. -Его статья напомнила мне <a class="reference external" href="https://ain.ua/ru/2017/10/17/we-fired-our-rick/">другую нашумевшую статью</a>.</p> -<p>Подобных историй я уже слышал предостаточно. -Коротко описать ситуацию можно так: в старом коллективе есть некий синьор, на котором много лет держалась кодовая база. -Пришел новый специалист с новыми процессами и с новой архитектурой. -Старый специалист начинает саботировать изменения вплоть до раскола коллектива.</p> -<p>По всей видимости, старый специалист рассчитывал на признание со стороны руководства за многолетний вклад, а вместо этого получил демонстрацию недоверия в виде делегации полномочий нанятому со стороны специалисту, способного (в отличии от него) решить проблему, и которому он теперь должен подчиняться. -<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологическая защита</a> была вполне ожидаемой.</p> -<p>Катализатором конфликта выступил <a class="reference internal" href="knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">разный уровень знаний</span></a>:</p> -<blockquote> -<div><p>"People in the first modernization teams must be especially open to learning"</p> -<p class="attribution">—"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/carefully-forming-teams-to-begin-technology-modernization-f4aa3e776e1f">Carefully Forming Teams to Begin Technology Modernization</a>" by Nick Tune.</p> -</div></blockquote> -<p>Так как стороной конфликта выступил Nick Tune, известный автор в области архитектуры ПО, то можно предположить, что синьор заметно уступал ему. -<a class="reference internal" href="knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">Выравнивание уровня знаний</span></a> - основной способ устранения причин сопротивления.</p> -<p>Но сама по себе <strong>разница в уровне знаний</strong> была не причиной конфликта, а только его почвой. -Причиной стало <a class="reference internal" href="knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">принуждение коллектива к изменениям в условиях недостаточной информированности</span></a>.</p> -<p>Сила внешнего принуждения в данном случае оказалась сильней сил консолидации коллектива - коллектив распался.</p> -<p>Как можно было предотвратить эту ситуацию?</p> -<p>Один из вариантов - просто не принуждать коллектив к изменениям в условиях недостаточной информированности. -Тем более, что еще Kent Beck писал ряд предостережений по поводу деликатности внедрения парного программирования. -Это предотвратило бы раскол, но не устранило бы сопротивления.</p> -<p>У сопротивления было две причины:</p> -<ol class="arabic simple"> -<li><p>Недооцененность давнего сотрудника.</p></li> -<li><p>Чувство ущербности старого сотрудника на фоне знаний нового сотрудника.</p></li> -</ol> -<p>Первая причина решается очень легко - на недооценненного сотрудника возлагается самая ответственная задача по внедрению изменений (или любая другая ответственная задача). -Это позволило бы ему сохранить свои позиции в коллективе и почувствовать оказание ему доверия, что выбило бы почву для психологической защиты.</p> -<p>Вторая причина решается возведением знаний в элемент престижа коллектива и постоянным выравниванием уровня знаний. -Вот тут уже все зависит от обучаемости конкретного специалиста, и гарантий никто дать не может. -Однако, из статьи следует, что он - парень, в общем-то, способный, и его ценили, несмотря на его замкнутость.</p> -<p>Но был в этой ситуации и политический момент. -На самом деле, Nick Tune уволил его не из-за того, что тот саботировал изменения, а из-за того, что он подрывал авторитет Ника в коллективе, и, обладая сильной позицией в коллективе, настраивал коллектив против изменений. -Т.е. он выступал в роли очага консолидации сил сопротивления всего коллектива. -В этом заключается главная причина. -Шла борьба за влияние на коллектив.</p> -<p>Проблема этой ситуации в том, что Nick Tune выбрал слишком широкий фронт изменений, на котором не смог <a class="reference internal" href="icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">обеспечить превосходство сил изменения над силами сопротивления</span></a>. -В конечном итоге он это осознал, и повысил удельную силу изменений путем сокращения численности коллектива, чем ослабил силу сопротивления. -Правда, для этого ему пришлось уволить из компании основные очаги сопротивления.</p> -<p>Этот шаг был вынужденным, так как оставшаяся часть коллектива не оказывала достаточной поддержки изменениям, но и не выражала сильного сопротивления:</p> -<blockquote> -<div><p>"afraid to speak in meetings"</p> -<p class="attribution">—"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/carefully-forming-teams-to-begin-technology-modernization-f4aa3e776e1f">Carefully Forming Teams to Begin Technology Modernization</a>" by Nick Tune.</p> -</div></blockquote> -<p>Можно было бы попытаться сохранить коллектив, если внедрять изменения инкрементально. -Это позволило бы Нику сформировать плацдарм (в виде обученной части коллектива), который оказал бы ему поддержку в дальнейшем распространении изменений. -И тогда расстановка сил в коллективе была бы уже совсем иной. -Из риска остаться изгоем, такой синьор уже воздержался бы от попыток саботажа.</p> -<p>А вот выносить конфликт в публичную плоскость было, пожалуй, опрометчиво - люди объединяются по принципу отождествления общих угроз, что может уменьшить базу его поддержки.</p> </section> -<section id="emacsway-change-making-literature"> -<span id="id4"/><h2><a class="toc-backref" href="#id7" role="doc-backlink">Литература по теме осуществления изменений</a></h2> +<section id="id18"> +<h4><a class="toc-backref" href="#id66" role="doc-backlink">Стандарты</a></h4> <ul class="simple"> -<li><p>"<a class="reference external" href="https://architectelevator.com/transformation/reversing-disablement-cycle/">Reversing the disablement cycle: Everyone does the right thing, yet nothing much gets done. How to break self-reinforcing bad habits.</a>" by Gregor Hohpe</p></li> -<li><p>"<a class="reference external" href="https://craiglarman.com/wiki/index.php?title=Larman%27s_Laws_of_Organizational_Behavior">Larman's Laws of Organizational Behavior</a>" by Craig Larman (<a class="reference external" href="https://habr.com/ru/companies/scrumtrek/articles/320832/">на русском</a>)</p></li> -<li><p>"<a class="reference external" href="https://less.works/less/structure">Structure</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/structure">на русском</a>)</p></li> -<li><p>"Social psychology" 13th edition by David G. Myers. Перевод: "Социальная психология" / Майерс Д. Пер. с англ. З. Замчук; Зав. ред. кол. Л. Винокуров. — 7-е изд. — СПб.: Питер, 2006.</p></li> -<li><p>"Leading Change, With a New Preface by the Author" by John P. Kotter, November 6, 2012</p></li> -<li><p>"The Dance of Change: The challenges to sustaining momentum in a learning organization" by Peter M. Senge, George Roth, March 16, 1999</p></li> -<li><p>"Lean Change Management: Innovative practices for managing organizational change" by Jason Little</p></li> +<li><p>"ISO/IEC/IEEE 12207:2017 Systems and software engineering — Software life cycle processes"</p></li> +<li><p>"ISO/IEC/IEEE 15288:2015 Systems and software engineering — System life cycle processes"</p></li> +<li><p>"ISO/IEC/IEEE 29148:2018 Systems and software engineering — Life cycle processes — Requirements engineering"</p></li> +<li><p>"ISO/IEC/IEEE 15289:2019 Systems and software engineering — Content of life-cycle information items (documentation)"</p></li> +<li><p>"ISO/IEC/IEEE 24765:2017 Systems and software engineering — Vocabulary"</p></li> +<li><p>"ISO 9000:2005 Quality management systems — Fundamentals and vocabulary"</p></li> +<li><p>"ISO/IEC 33001:2015 Information technology — Process assessment — Concepts and terminology"</p></li> +<li><p>"ГОСТ Р ИСО/МЭК 12207-2010 Информационная технология. Системная и программная инженерия. Процессы жизненного цикла программных средств."</p></li> +<li><p>"ГОСТ Р 57193-2016 Системная и программная инженерия. Процессы жизненного цикла систем."</p></li> +</ul> +</section> +</section> +<section id="id19"> +<h3><a class="toc-backref" href="#id67" role="doc-backlink">Менеджмент</a></h3> +<ul class="simple"> +<li><p>"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr.</p></li> +<li><p>"<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems Thinking</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">перевод на Русский</a>)</p></li> +<li><p>"Art of Project Management" by Scott Berkun</p></li> +<li><p>"Менеджмент: Учебник для вузов." 3-е изд. Глухов В. В.</p></li> +<li><p>"Оргуправленческое мышление. Идеология, методология, технология" / Щедровицкий Георгий Петрович</p></li> <li><p>"The Leadership Experience" 7th edition by Richard L. Daft</p></li> <li><p>"Management" 013 edition by Richard L. Daft</p></li> -<li><p>"Вызов лидеров" / Карлоф Б., Седерберг С.</p></li> -<li><p>"Organizational development and change." by Huse E., L., 1975.</p></li> -<li><p>"The change masters." by Kanter R., N.Y., 1985.</p></li> -<li><p>"Choosing strategies for change" by Kotter J., Schlesinger L. //Harvard business review. March. 1979.</p></li> -<li><p>"Transformational leadership and organizational change during agile and devops initiatives." by Mayner, Stephen, ProQuest, 2017.</p></li> -<li><p>"The effects of transformational and change leadership on employees' commitment to change: a multi-level study." by Herold, David M., Donald B. Fedor, Steven Caldwell, and Yi Liu, Journal of Applied Psychology, Volume 93, 2008.</p></li> -<li><p>"Leading Change, With a New Preface by the Author." by Kotter, John P, Harvard Business Review Press, 2012.</p></li> -<li><p>"Switch: How to Change Things When Change Is Hard." by Heath, Chip, and Dan Heath, The Crown Publishing Group, 2010.</p></li> -<li><p>"A More Beautiful Question: The Power of Inquiry to Spark Breakthrough Ideas" by Warren Berger</p></li> -<li><p>"Just Listen: Discover the Secret to Getting Through to Absolutely Anyone" by Mark Goulston</p></li> -<li><p>Бражников М.А. Управление изменениями: базовый курс: учеб. пособие / М.А. Бражников, И.В. Хорина. – Самара: Самар. гос. техн. ун-т, 2015. – 238 с.</p></li> -<li><p>Данилюк. УПРАВЛЕНИЕ ИЗМЕНЕНИЯМИ: учебное пособие. Тюмень: Издательство Тюменского государственного университета, 2014. 288 с.</p></li> -<li><p>Иванова Е.А. Управление изменениями: Учебное пособие. - М: МГУПС (МИИТ), 2014. – 167 с..</p></li> -<li><p>Кужева С.Н. Управление изменениями: учебное пособие/ С.Н. Кужева.– Омск: Изд-во Ом. гос. ун-та, 2011. – 140 с.</p></li> -<li><p>Медведева Н.В. Управление изменениями в организации: Учебное пособие. – Саратов: СГУ, 2016. – 119 с.</p></li> -<li><p>Колеман Д., Фармер А. Управление изменениями. Жуковский, 1992.</p></li> -<li><p>Тичи Н., Деванна М. Лидеры реорганизаций. М., 1990.</p></li> -<li><p>"<a class="reference external" href="http://ibcm.biz/%d1%87%d1%82%d0%be-%d1%82%d0%b0%d0%ba%d0%be%d0%b5-%d1%81%d0%be%d0%bf%d1%80%d0%be%d1%82%d0%b8%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b8%d0%b7%d0%bc%d0%b5%d0%bd%d0%b5%d0%bd%d0%b8%d1%8f%d0%bc-%d0%b8/">Что такое сопротивление изменениям и как с ним работать?</a>"</p></li> -<li><p>"<a class="reference external" href="http://ibcm.biz/wp-content/uploads/2016/06/%D0%A2%D0%B5%D0%BA%D1%81%D1%82-%D0%9E%D1%81%D0%BE%D0%B1%D0%B5%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8-%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8-%D0%B2-%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D0%B8.pdf">Особенности управления изменениями в России</a>" / Демьяненко Василий и др.</p></li> -<li><p>"<a class="reference external" href="https://membership.neuroleadership.com/material/scarf-a-brain-based-model-for-collaborating-with-and-influencing-others-vol-1/">SCARF®: A Brain-Based Model for Collaborating with and Influencing Others (Vol. 1)</a>" by David Rock</p></li> -<li><p>"<a class="reference external" href="http://ibcm.biz/%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C-%D1%81%D0%BE%D1%86%D0%B8%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE-%D0%BF%D0%BE%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D1%8F-scarf-%D0%B4%D1%8D%D0%B2%D0%B8%D0%B4/">Как управлять поведением сотрудников с помощью модели социального поведения SCARF (Дэвид Рок)</a>"</p></li> -<li><p>"<a class="reference external" href="https://theoryandpractice.ru/posts/20482-chto-takoe-model-scarf-ili-kak-nash-mozg-ispolzuet-knut-i-pryanik">Что такое модель SCARF, или Как наш мозг использует кнут и пряник</a>" / Александра Смаракова</p></li> +<li><p>"<a class="reference external" href="https://publications.opengroup.org/g183">Managing Digital Concepts and Practices</a>"</p></li> </ul> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +</section> +<section id="id20"> +<h3><a class="toc-backref" href="#id68" role="doc-backlink">Развитие личностных профессиональных качеств</a></h3> <ul class="simple"> -<li><p>"<a class="reference internal" href="icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Принцип ледокола</span></a>"</p></li> -<li><p>"<a class="reference internal" href="knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">Разрешение конфликтов на почве недостатка знаний</span></a>"</p></li> +<li><p>"The Pragmatic Programmer: From Journeyman to Master" 1st edition by David Thomas, Andrew Hunt</p></li> +<li><p>"The Pragmatic Programmer: your journey to mastery, 20th Anniversary Edition" 2nd edition by David Thomas, Andrew Hunt</p></li> +<li><p>"A Mind for Numbers: How to Excel at Math and Science" by Barbara Ann Oakley</p></li> +<li><p>"Systems Thinking. Quality Software Management. New York: Dorset House." by Gerald M. Weinberg, 1992, ISBN: 0932633226</p></li> +<li><p>"An Introduction to General Systems Thinking" by Gerald M. Weinberg</p></li> +<li><p>"Becoming a Technical Leader" by Gerald M. Weinberg</p></li> +<li><p>"Harvard Business Review on Decision Making" by Harvard Business School Press</p></li> +<li><p>"The Software Architect Elevator: Redefining the Architect's Role in the Digital Enterprise 1st Edition" by Gregor Hohpe</p></li> +<li><p>"Fundamentals of Software Architecture: An Engineering Approach" 1st edition by Mark Richards, Neal Ford</p></li> +<li><p>"Software Architecture: The Hard Parts: Modern Trade-Off Analyses for Distributed Architectures" 1st Edition by Neal Ford, Mark Richards, Pramod Sadalage, Zhamak Dehghani</p></li> +<li><p>"The Book: 37 Things One Architect Knows About IT Transformation" by Gregor Hohpe</p></li> +<li><p>"Eat or Be Eaten!: Jungle Warfare for the Corporate Master Politician" by Phil Porter</p></li> +<li><p>"Presentation patterns: techniques for crafting better presentations" by Neal Ford, Matthew McCullough, Nathaniel Schutta</p></li> +<li><p>"Technology Strategy Patterns: Architecture as Strategy" 1st edition by Eben Hewitt</p></li> +<li><p>"Thinking in Systems: A Primer" by Donella H. Meadows, Diana Wright</p></li> +<li><p>"Social psychology" 13th edition by David G. Myers. Перевод: "Социальная психология" / Майерс Д. Пер. с англ. З. Замчук; Зав. ред. кол. Л. Винокуров. — 7-е изд. — СПб.: Питер, 2006.</p></li> +<li><p>"Never split the difference: negotiating as if life depended on it" by Chris Voss. Перевод: "Договориться не проблема. Как добиваться своего без конфликтов и ненужных уступок." / Крис Восс</p></li> +<li><p>"Искусство спора. О теории и практике спора." / Поварнин С.И.</p></li> +<li><p>"Эристика, или Искусство побеждать в спорах" / Шопенгауэр Артур. English: "The Art of Being Right: 38 Ways to Win an Argument" by Arthur Schopenhauer</p></li> +<li><p>"Как читать книги" / Поварнин С.И.</p></li> +<li><p>"<a class="reference external" href="https://ruxpert.ru/%D0%98%D1%81%D0%BA%D1%83%D1%81%D1%81%D1%82%D0%B2%D0%BE_%D1%81%D0%BF%D0%BE%D1%80%D0%B0_(%D0%BE%D0%B1%D1%83%D1%87%D0%B0%D1%8E%D1%89%D0%B8%D0%B5_%D0%BC%D0%B0%D1%82%D0%B5%D1%80%D0%B8%D0%B0%D0%BB%D1%8B)">Искусство спора (обучающие материалы)</a>"</p></li> +<li><p>"<a class="reference external" href="https://m.vk.com/wall-56611080_127534">Книги по риторике</a>"</p></li> +</ul> +<p>Простой и доходчивый видеокурс по SoftSkills:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://youtube.com/channel/UCSN7G8syJUaRiXrw1l0qk_g">Soft Skills Pro</a>"</p></li> </ul> -</div> -</section> </section> -Tue, 08 Aug 2023 00:00:00 Что такое Agile Developmenthttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/agile/agile.html -<span id="emacsway-agile-development"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> +<section id="id21"> +<h3><a class="toc-backref" href="#id69" role="doc-backlink">Базы данных</a></h3> <ul class="simple"> -<li><p><a class="reference internal" href="#agile-development" id="id9">Что такое Agile Development</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id10">Определение</a></p></li> -<li><p><a class="reference internal" href="#id3" id="id11">История</a></p></li> -<li><p><a class="reference internal" href="#emacsway-agile-development-essence" id="id12">Суть</a></p></li> -<li><p><a class="reference internal" href="#emacsway-agile-development-difficulties" id="id13">О сложностях</a></p></li> +<li><p>"Mastering PostgreSQL In Application Development" by Dimitri Fontaine</p></li> +<li><p>"The Art of PostgreSQL" 2nd edition by Dimitri Fontaine - is the new title of "Mastering PostgreSQL in Application Development"</p></li> +<li><p>"SQL Antipatterns. Avoiding the Pitfalls of Database Programming." by Bill Karwin</p></li> +<li><p>"Refactoring Databases. Evolutionary Database Design" by Scott J Ambler and Pramod J. Sadalage</p></li> +<li><p>"An Introduction to Database Systems" by C.J. Date</p></li> +<li><p>"PostgreSQL 10 High Performance" by Ibrar Ahmed, Gregory Smith, Enrico Pirozzi</p></li> </ul> -</li> +<p>PostgresPro представил <a class="reference external" href="https://postgrespro.ru/education/books">четыре книги</a> для разных уровней подготовленности читателей, от совершенно неосведомленного человека до разработчика баз данных. +Книги дают комплексные знания в лаконичной форме. +Все книги доступны для скачивания в свободном доступе:</p> +<ol class="arabic simple"> +<li><p>"<a class="reference external" href="https://postgrespro.ru/education/books/introbook">Postgres: первое знакомство</a>" / П.В. Лузанов, Е.В. Рогов, И.В. Лёвшин</p></li> +<li><p>"<a class="reference external" href="https://postgrespro.ru/education/books/internals">PostgreSQL изнутри</a>" / Е.В. Рогов — М.: ДМК Пресс, 2022. — 660 с.</p></li> +<li><p>"<a class="reference external" href="https://postgrespro.ru/education/books/sqlprimer">PostgreSQL. Основы языка SQL: учеб. пособие</a>" / Е.П. Моргунов; под ред. Е.В. Рогова, П.В. Лузанова.</p></li> +<li><p>"<a class="reference external" href="https://postgrespro.ru/education/books/dbtech">Основы технологий баз данных: учеб. пособие</a>" / Б.А. Новиков, Е.А. Горшкова, Н.Г. Графеева; под ред. Е.В. Рогова.</p></li> +</ol> +<p>Так же доступны <a class="reference external" href="https://postgrespro.ru/education/courses">учебные материалы курсов</a>: слайды, видео, руководства. Скачать можно все материалы каждого курса одним архивом.</p> +<p><a class="reference external" href="https://postgrespro.ru/education/where">Видеозаписи курсов</a>.</p> +<p>Превосходная подборка статей с фундаментальной информацией простым языком о внутреннем устройстве PostgreSQL, от разработчиков PostgresPro:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://m.habr.com/ru/company/postgrespro/blog/442804/">MVCC-1. Изоляция</a></p></li> +<li><p><a class="reference external" href="https://m.habr.com/ru/company/postgrespro/blog/458186/">WAL в PostgreSQL: 1. Буферный кеш</a></p></li> +</ul> +<p>Шпаргалка по выбору типа хранилища данных:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/guide/technology-choices/data-store-comparison">Understand data store models</a>"</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/guide/technology-choices/data-store-decision-tree">Select an Azure data store for your application</a>"</p></li> +</ul> +<p>Jepsen's analysis over two dozen databases, coordination services, and queues—and we've found replica divergence, data loss, stale reads, read skew, lock conflicts, and much more:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://jepsen.io/analyses">Analyses</a>"</p></li> +<li><p>"<a class="reference external" href="https://aphyr.com/tags/jepsen">Everything Tagged "Jepsen"</a>"</p></li> +</ul> +<p>Рейтинг хранилищ данных:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://db-engines.com/en/ranking">DB-Engines Ranking</a>"</p></li> </ul> -</nav> -<section id="id2"> -<h2><a class="toc-backref" href="#id10" role="doc-backlink">Определение</a></h2> -<blockquote> -<div><p>💬 "Agile development - software development approach based on <a class="reference internal" href="../iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a> development, frequent inspection and <a class="reference internal" href="../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">adaptation</span></a>, and <a class="reference internal" href="../incremental.html#emacsway-incremental-development"><span class="std std-ref">incremental</span></a> deliveries, in which requirements and solutions evolve through collaboration in cross‐functional teams and through continual stakeholder feedback."</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> -</div></blockquote> -<blockquote> -<div><p>💬 "Scrum is, as the reader supposedly knows, an agile method. -The agile family of development methods evolved from the old and well-known <a class="reference internal" href="../iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a> and <a class="reference internal" href="../incremental.html#emacsway-incremental-development"><span class="std std-ref">incremental</span></a> life-cycle approaches. -They were born out of a belief that an approach more grounded in human reality – and the product development reality of learning, innovation, and change – would yield better results."</p> -<p class="attribution">—"Jeff Sutherland's Scrum Handbook" by Jeff Sutherland</p> -</div></blockquote> -<blockquote> -<div><p>💬 ""Agile" methods actually can be applied within a variety of models. -While Agile methods are common in executing an evolutionary lifecycle model, they can be used in other lifecycle models at various stages. -What the methods have in common is an emphasis on continuous inspection and collaboration in the rapid production of working software in an environment where changes, including changes to requirements, are expected."</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> -</div></blockquote> -<blockquote> -<div><p>💬 "As discussed in 5.4.2, the life cycle models used in agile projects are often highly <a class="reference internal" href="../incremental.html#emacsway-incremental-development"><span class="std std-ref">incremental</span></a> and <a class="reference internal" href="../evolutionary.html#emacsway-evolutionary-development"><span class="std std-ref">evolutionary</span></a>."</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> -</div></blockquote> -<blockquote> -<div><p>💬 "Unlike Waterfall, Agile emphasizes <strong>iterative</strong> development, or building software <strong>in pieces</strong> <em>[i.e. incremental]</em>. -Agile teams typically work in short cycles—which are called "sprints" in Scrum, today one of the most widely used forms of Agile—that usually last two weeks each."</p> -<p class="attribution">—"<a class="reference external" href="https://www.theatlantic.com/technology/archive/2017/12/agile-manifesto-a-history/547715/">The Winter Getaway That Turned the Software World Upside Down</a>" by Caroline Mimbs Nyce</p> -</div></blockquote> -<blockquote> -<div><p>💬 In the software world, “waterfall” is commonly used to describe a style of software process, one that contrasts with the ideas of iterative, or agile styles.</p> -<p>💬 "Certainly agile processes require an iterative approach and cannot work in a waterfall style."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/WaterfallProcess.html">Waterfall Process</a>" by Martin Fowler</p> -</div></blockquote> </section> -<section id="id3"> -<h2><a class="toc-backref" href="#id11" role="doc-backlink">История</a></h2> -<p>В заметке "<a class="reference internal" href="../../uncertainty-management/prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Что такое Prediction</span></a>" было сформировано противоречие, которое заключается в том, что для того, чтобы снизить стоимость разработки, нам необходимо повысить точность прогнозирования (повысить полноту требований), но повышение точности прогнозирования, в свою очередь, повышает стоимость разработки (возникает отрицательная обратная связь). -Причем, повышает её экспоненциально, в то время как бизнес-выгоды от этой точности возрастают логарифмически. -Иными словами, точность прогнозирования всегда имеет предел экономической целесообразности, который определяется пересечением этих двух графиков (за вычетом стоимости реализации, разумеется).</p> -<p>Мы не можем повышать точность прогнозирования, т.к. она превысит предел экономической целесообразности, но мы вынуждены её повысить для того, чтобы принимать решения в момент наименьшей стоимости их реализации.</p> -<p>Как можно разрешить этот "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A3%D0%BB%D0%BE%D0%B2%D0%BA%D0%B0-22">Catch-22</a>"? -Согласно "Первому закону диалектики", противоречие должно привести к синтезу, т.е. к качественному изменению.</p> -<p>И решение этого противоречия схоже с решением противоречия "<a class="reference internal" href="../../../team-topologies/harlan-mills%27-proposal.html#emacsway-brooks-s-law"><span class="std std-ref">Закона Брукса</span></a>", в виде автономных команд. -Или же с решением в виде Bounded Context, которое разрешает противоречие, заключающееся в том, что при стремлении выровнять язык по всей модели, он стремится к противоречивости (и неоднозначности). -Т.е. стремление следовать предметной области вынуждает отступать от неё. -В нашем случае решение так же заключается в разбиении целого (процесса разработки) на части (итерации), только вместо согласованности единого языка здесь критерием разделения выступает достаточность полноты требований.</p> -<p>Agile является естественным следствием эволюции итеративной разработки, краткий обзор которой можно посмотреть в превосходной статье Craig Larman "<a class="reference external" href="https://www.craiglarman.com/wiki/downloads/misc/history-of-iterative-larman-and-basili-ieee-computer.pdf">Iterative and Incremental Development: A Brief History</a>". -В ней говорится о том, что цикл PDSA известен еще с 1930 года, в 1957 году впервые была применена <a class="reference internal" href="../incremental.html#emacsway-incremental-development"><span class="std std-ref">инкрементальная</span></a> модель разработки, а в 1968 году - <a class="reference internal" href="../iterative.html#emacsway-iterative-development"><span class="std std-ref">итеративная</span></a>.</p> -<p>Как уже говорилось ранее, итеративная модель разработки открывает широкие возможности для <a class="reference internal" href="../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">удешевления обработки неопределенности</span></a>. -Однако долгое время эти возможности оставались экономически нецелесообразными по причине быстрорастущего характера роста стоимости <a class="reference internal" href="../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Adaptation</span></a>, приближющегося к экспоненциальному. -При таком характере роста возникает экономическая целесообразность принимать решения в момент наименьшей стоимости их реализации, вплоть до заблаговременного проектирования (BDUF).</p> -<blockquote> -<div><p>💬 "WaterFall is based on the empirical observation of 30 years ago (ref: BarryBoehm, Software Engineering Economics, Prentice Hall, 1981.) that the cost of change rises exponentially (base 10) by phases. The conclusion is that you should make the big decisions up front, because changing them is so expensive."</p> -<p class="attribution">—"<a class="reference external" href="https://wiki.c2.com/?WaterFall">Water Fall</a>" at c2.com</p> -</div></blockquote> -<figure class="align-left" id="id6"> -<a class="reference internal image-reference" href="../../../../../_images/exponential-cost-of-change.png"><img alt="Figure 1. The cost of change rising exponentially over time. The image source is &quot;Extreme Programming Explained&quot; 1st edition by Kent Beck, &quot;Chapter 5. Cost of Change&quot;." src="../../../../../_images/exponential-cost-of-change.png" style="width: 90%;"/></a> -<figcaption> -<p><span class="caption-text">Figure 1. The cost of change rising exponentially over time. The image source is "Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change".</span></p> -</figcaption> -</figure> -<p>Однако, в конце 1990-х - начале 2000-х, в архитектурном мире произошли существенные изменения - обрели массовую популярность высокоуровневые объектно-ориентированные языки, появились <a class="reference internal" href="../../uncertainty-management/adaptation/software-design/patterns.html#emacsway-agile-patterns"><span class="std std-ref">шаблоны</span></a> и принципы проектирования, методики управления сложностью (ROM, POSA, GOF, OOAD, <a class="reference internal" href="../../uncertainty-management/adaptation/software-design/solid.html#emacsway-agile-solid"><span class="std std-ref">SOLID</span></a>, Use Case Driven Approach, Object-Oriented Software Construction etc.), появились <a class="reference internal" href="../../../tdd/tdd.html#emacsway-tdd"><span class="std std-ref">TDD</span></a>, Refactoring и т.п.</p> -<p>Унификация знаний в области архитектуры, переход ментального оперирования на элементы унифицированных шаблонных конструкций более высокого уровня абстракции, позволили сократить когнитивную и коммуникативную нагрузку на разработчика, уменьшить порог вхождения в новый проект, смягчить негативное воздействие <a class="reference internal" href="../../../team-topologies/harlan-mills%27-proposal.html#emacsway-brooks-s-law"><span class="std std-ref">Закона Брукса</span></a>.</p> -<figure class="align-left" id="id7"> -<a class="reference internal image-reference" href="../../../../../_images/historical-cost-of-exploration.png"><img alt="FIGURE 3.8 Historical cost of exploration. The image source is &quot;Essential Scrum: A Practical Guide to the Most Popular Agile Process&quot; by Kenneth Rubin, &quot;Chapter 3 Agile Principles :: Prediction and Adaptation&quot;." src="../../../../../_images/historical-cost-of-exploration.png" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">FIGURE 3.8 Historical cost of exploration. The image source is "Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation".</span></p> -</figcaption> -</figure> -<p>Рост количественных изменений привел к изменениям качественным ("Второй закон диалектики") - ведущим умам архитектуры своего времени удалось снизить характер роста стоимости адаптации вплоть до пологого графика, максимально приближенного к горизонтальной асимптоте. -Это означало, что стоимость реализации решения больше не зависело от момента его принятия, что позволило отказаться от заблаговременного проектирования и откладывать принятие решения до момента наибольшей полноты информированности, даже после частичной реализации продукта.</p> -<blockquote> -<div><p>💬 "What would we do if all that investment paid off? -What if all that work on languages and databases and whatnot actually got somewhere? -What if the cost of change didn't rise exponentially overtime, but rose much more slowly, <strong>eventually reaching an asymptote</strong>? -What if tomorrow's software engineering professor draws Figure 3 on the board?"</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change"</p> -</div></blockquote> -<figure class="align-left" id="id8"> -<a class="reference internal image-reference" href="../../../../../_images/flatten-cost-of-change.png"><img alt="Figure 3. The cost of change may not rise dramatically over time. The image source is &quot;Extreme Programming Explained&quot; 1st edition by Kent Beck, &quot;Chapter 5. Cost of Change&quot;." src="../../../../../_images/flatten-cost-of-change.png" style="width: 90%;"/></a> -<figcaption> -<p><span class="caption-text">Figure 3. The cost of change may not rise dramatically over time. The image source is "Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change".</span></p> -</figcaption> -</figure> -<p>Что такое асимтота, можно посмотреть в "§284 Асимтоты" Справочника по высшей математике / М.Я. Выгодский:</p> -<blockquote> -<div><p>💬 "Прямая АВ называется асимптотой линии L, если расстояние МК (черт. 297) от точки М линии L до прямой АВ стремится к нулю при удалении точки М в бесконечность."</p> -<p class="attribution">—"Справочник по высшей математике" / М.Я. Выгодский</p> -</div></blockquote> -<p>В нашем случае, нас интересует Асимптоты, параллельная оси абсцисс (там же):</p> -<blockquote> -<div><p>💬 "Для разыскания горизонтальных асимптот линии y = f(х) ищем пределы f(х) при х -&gt; +∞ и при х -&gt; -∞. Если lim х-&gt;∞ f(x) = b, то прямая у = b - асимптота (при бесконечном удалении вправо; черт. 299)."</p> -<p class="attribution">—"Справочник по высшей математике" / М.Я. Выгодский</p> -</div></blockquote> +<section id="id22"> +<h3><a class="toc-backref" href="#id70" role="doc-backlink">Изучаем распределенные системы. Третий заход.</a></h3> +<ul class="simple"> +<li><p>"Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions" by Gregor Hohpe, Bobby Woolf</p></li> +<li><p>"Service Design Patterns: Fundamental Design Solutions for SOAP/WSDL and RESTful Web Services" by Robert Daigneau</p></li> +<li><p>"Microsoft .NET: Architecting Applications for the Enterprise" 2nd edition by Dino Esposito, Andrea Saltarello</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/">Cloud Design Patterns</a>"</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn568099(v=pandp.10)">Cloud Design Patterns. Prescriptive architecture guidance for cloud applications</a>" by Alex Homer, John Sharp, Larry Brader, Masashi Narumoto, Trent Swanson. (<a class="reference external" href="http://aka.ms/cloud-design-patterns-sample">Code Samples</a>)</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices">Build Microservices on Azure</a>" by Microsoft Corporation and community</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/best-practices/">Cloud Best Practices</a>" by Microsoft Corporation and community</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/antipatterns">Performance Antipatterns</a>" by Microsoft Corporation and community</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/guide/">Azure Application Architecture Guide</a>" by Microsoft Corporation and community</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/data-guide/">Azure Data Architecture Guide</a>" by Microsoft Corporation and community</p></li> +<li><p>"Release It! Design and Deploy Production-Ready Software" 2nd edition by Michael Nygard</p></li> +<li><p>"<a class="reference external" href="https://www.manning.com/books/microservice-patterns">Microservices Patterns: With examples in Java</a>" 1st edition by Chris Richardson (<a class="reference external" href="https://microservices.io/book">more info</a>)</p></li> +<li><p>"Monolith to Microservices Evolutionary Patterns to Transform Your Monolith" by Sam Newman</p></li> +<li><p>"Microservices AntiPatterns and Pitfalls" by Mark Richards</p></li> +<li><p>"Microservices vs. Service-Oriented Architecture" by Mark Richards</p></li> +<li><p>"<a class="reference external" href="https://landing.google.com/sre/books/">Site Reliability Engineering: How Google runs production systems</a>" edited by Betsy Beyer, Chris Jones, Jennifer Petoff &amp; Niall Richard Murphy</p></li> +<li><p>"<a class="reference external" href="https://landing.google.com/sre/books/">The Site Reliability Workbook: Practical Ways to Implement SRE.</a>" by Betsy Beyer, Niall Richard Murphy, David K. Rensin, Kent Kawahara &amp; Stephen Thorne</p></li> +<li><p>"<a class="reference external" href="https://landing.google.com/sre/books/">Building Secure &amp; Reliable Systems: Best Practices for Designing, Implementing and Maintaining Systems.</a>" by Heather Adkins, Betsy Beyer, Paul Blankinship, Ana Oprea, Piotr Lewandowski, Adam Stubblefield</p></li> +<li><p>"Database Reliability Engineering. Designing and Operating Resilient Database Systems." by Laine Campbell and Charity Majors</p></li> +<li><p>"Designing Data-Intensive Applications. The Big Ideas Behind Reliable, Scalable, and Maintainable Systems" by Martin Kleppmann</p></li> +<li><p>"Database Internals: A Deep Dive into How Distributed Data Systems Work" by Alex Petrov</p></li> +<li><p>"<a class="reference external" href="https://www.distributed-systems.net/index.php/books/ds3/">Distributed systems: principles and paradigms</a>" 3d edition by Andrew S. Tanenbaum, Maarten Van Steen</p></li> +<li><p>"<a class="reference external" href="http://books.ifmo.ru/file/pdf/1551.pdf">Введение в распределенные вычисления</a>" / Косяков М. С. — СПб: НИУ ИТМО, 2014. — С. 75-82. — 155 с.</p></li> +<li><p>"Service-Oriented Architecture Analysis and Design for Services and Microservices" by Thomas Erl</p></li> +<li><p>"Workflow patterns: the definitive guide" by Aalst, Wil van der, Russell, Nick, Ter Hofstede, Arthur</p></li> +<li><p>"Real-Life BPMN (4th edition): Includes an introduction to DMN" by Jakob Freund, Bernd Rücker</p></li> +<li><p>"Practical Process Automation" by Bernd Ruecker</p></li> +</ul> </section> -<section id="emacsway-agile-development-essence"> -<span id="id4"/><h2><a class="toc-backref" href="#id12" role="doc-backlink">Суть</a></h2> -<p>Коротко говоря, Agile модель является итеративно-инкрементальной моделью разработки, на которую наложен ряд филосовско-психологических принципов с целью снизить напряжение между техническими специалистами и представителями бизнеса. -Морально-психологический климат в ИТ-индустрии того времени был, мягко говоря, напряженным:</p> -<blockquote> -<div><p>💬 "For example, I think that ultimately, Extreme Programming has mushroomed in use and interest, not because of pair-programming or refactoring, but because, taken as a whole, the practices define a developer community freed from the baggage of Dilbertesque corporations. -Kent Beck tells the story of an early job in which he estimated a programming effort of six weeks for two people. -After his manager reassigned the other programmer at the beginning of the project, he completed the project in twelve weeks—and felt terrible about himself! -The boss—of course—harangued Kent about how slow he was throughout the second six weeks. -Kent, somewhat despondent because he was such a "failure" as a programmer, finally realized that his original estimate of 6 weeks was extremely accurate—for 2 people—and that his "failure" was really the manager's failure, indeed, the failure of the standard "fixed" process mindset that so frequently plagues our industry.</p> -<p>This type of situation goes on every day—marketing, or management, or external customers, internal customers, and, yes, even developers — don't want to make hard trade-off decisions, so they impose irrational demands through the imposition of corporate power structures. -This isn't merely a software development problem, it runs throughout Dilbertesque organizations.</p> -<p>In order to succeed in the new economy, to move aggressively into the era of e-business, e-commerce, and the web, companies have to rid themselves of their Dilbert manifestations of make-work and arcane policies. -This freedom from the inanities of corporate life attracts proponents of Agile Methodologies, and scares the begeebers (you can't use the word 'shit' in a professional paper) out of traditionalists. -Quite frankly, the Agile approaches scare corporate bureaucrats — at least those that are happy pushing process for process' sake versus trying to do the best for the "customer" and deliver something timely and tangible and "as promised" — because they run out of places to hide.</p> -<p>The Agile movement is not anti-methodology, in fact, many of us want to restore credibility to the word methodology. -We want to restore a balance. We embrace modeling, but not in order to file some diagram in a dusty corporate repository. -We embrace documentation, but not hundreds of pages of never-maintained and rarely-used tomes. We plan, but recognize the limits of planning in a turbulent environment. -Those who would brand proponents of XP or SCRUM or any of the other Agile Methodologies as "hackers" are ignorant of both the methodologies and the original definition of the term hacker."</p> -<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/history.html">History: The Agile Manifesto</a>"</p> -</div></blockquote> -<blockquote> -<div><p>💬 "I think the Agile Manifesto has helped teams around the world rethink their priorities, and in the process has helped re-humanize software development."</p> -<p class="attribution">—"<a class="reference external" href="https://pragdave.me/blog/2007/02/24/some-agile-history.html">Some Agile History</a>" by Dave Thomas</p> -</div></blockquote> -<p>Основой этой филосовско-психологической прослойки <a class="reference external" href="https://www.informit.com/articles/article.aspx?p=2990402&amp;seqNum=3">стал</a> документ "<a class="reference external" href="http://www.agilenutshell.com/bill_of_rights">Bill of Rights</a>", который является результатом глубокого аналитического труда Kent Beck в области психологии. -Дело в том, что Kent Beck имел превосходную эрудированность в области психологии, философии и менеджмента.</p> -<blockquote> -<div><p>💬 "<strong>Customer Bill of Rights</strong></p> +<section id="id23"> +<h3><a class="toc-backref" href="#id71" role="doc-backlink">API-Design</a></h3> <ul class="simple"> -<li><p>You have the right to an overall plan, to know what can be accomplished when and at what cost.</p></li> -<li><p>You have the right to get the most possible value out of every programming week.</p></li> -<li><p>You have the right to see progress in a running system, proven to work by passing repeatable tests that you specify.</p></li> -<li><p>You have the right to change your mind, to substitute functionality, and to change priorities without paying exorbitant costs.</p></li> -<li><p>You have the right to be informed of schedule changes, in time to choose how to reduce the scope to restore the original date. You can cancel at any time and be left with a useful working system reflecting investment to date.</p></li> +<li><p>"REST in Practice: Hypermedia and Systems Architecture" by Savas Parastatidis, Jim Webber, Ian Robinson</p></li> +<li><p>"RESTful Web APIs: Services for a Changing World" by Leonard Richardson, Sam Ruby, Mike Amundsen</p></li> +<li><p>"Web API Design Crafting Interfaces that Developers Love" by Brian Mulloy</p></li> +<li><p>"REST API Design Rulebook" by Mark Massé</p></li> +<li><p>"Principles of Web API Design: Delivering Value with APIs and Microservices" by James Higginbotham</p></li> +<li><p>"Continuous API Management" 2nd edition by Mehdi Medjaoui, Erik Wilde, Ronnie Mitra, Mike Amundsen</p></li> </ul> -<p><strong>Programmer Bill of Rights</strong></p> +</section> +<section id="streaming-processing"> +<h3><a class="toc-backref" href="#id72" role="doc-backlink">Streaming Processing</a></h3> <ul class="simple"> -<li><p>You have the right to know what is needed, with clear declarations of priority.</p></li> -<li><p>You have the right to produce quality work at all times.</p></li> -<li><p>You have the right to ask for and receive help from peers, managers, and customers.</p></li> -<li><p>You have the right to make and update your own estimates.</p></li> -<li><p>You have the right to accept your responsibilities instead of having them assigned to you."</p></li> +<li><p>"Streaming Data: Understanding the real-time pipeline" 1st edition by Andrew Psaltis</p></li> +<li><p>"Big Data: Principles and best practices of scalable realtime data systems" 1st edition by Nathan Marz, James Warren</p></li> +<li><p>"Kafka Streams in Action: Real-time apps and microservices with the Kafka Streams API" 1st edition by Bill Bejeck</p></li> +<li><p>"The Enterprise Big Data Lake: Delivering the Promise of Big Data and Data Science" 1st edition by Alex Gorelik</p></li> </ul> -<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler</p> -</div></blockquote> -<blockquote> -<div><p>💬 "During the <a class="reference external" href="https://martinfowler.com/articles/agileStory.html">Snowbird meeting</a>, Kent Beck said that the goal of Agile was to heal the divide between business and development. -To that end, the following "bill of rights" was developed by Kent, Ward Cunningham, and Ron Jeffries, among others."</p> -<p class="attribution">—"Clean Agile: Back to Basics" by Robert C. Martin</p> -</div></blockquote> -<p>Kent Beck выяснил, что напряжение являлось ни чем иным, как упреждающими защитным механизмом, спровоцированным страхами участников процесса разработки.</p> -<p>Идея Bill of Rights возникла на основе идеи Declaration of Independence (<a class="reference external" href="http://www.hist.msu.ru/ER/Etext/indpndnc.htm">перевод</a>):</p> -<blockquote> -<div><p>💬 "Software development is risky. People involved have many fears of what may go wrong.</p> -<p>To develop effectively we must acknowledge these fears. Why do we need a software process? For the same reason that we need laws, governments, and taxes: fear.</p> -<p>The Declaration of Independence says:</p> -<blockquote> -<div><p>That among these [rights] are life, liberty, and the pursuit of happiness. That to secure these rights, governments are instituted among men, deriving their just powers from the consent of the governed.</p> -</div></blockquote> -<p>Though the profundity of these words may distract us, consider the word secure. We institute governments because we are afraid of losing our rights. By the same token, we institute software processes because we are afraid.</p> -<p><strong>Customers are afraid that</strong></p> +</section> +<section id="id24"> +<h3><a class="toc-backref" href="#id73" role="doc-backlink">Углубляем DDD</a></h3> <ul class="simple"> -<li><p>They won't get what they asked for.</p></li> -<li><p>They'll ask for the wrong thing.</p></li> -<li><p>They'll pay too much for too little.</p></li> -<li><p>They must surrender control of their career to techies who don't care.</p></li> -<li><p>They won't ever see a meaningful plan.</p></li> -<li><p>The plans they do see will be fairy tales.</p></li> -<li><p>They won't know what's going on.</p></li> -<li><p>They'll be held to their first decisions and won't be able to react to changes in the business.</p></li> -<li><p>No one will tell them the truth.</p></li> +<li><p>"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon</p></li> +<li><p>"Patterns, Principles, and Practices of Domain-Driven Design" by Scott Millett, Nick Tune</p></li> +<li><p>"Hands-On Domain-Driven Design with .NET Core: Tackling complexity in the heart of software by putting DDD principles into practice" by Alexey Zimarev</p></li> +<li><p>"Balancing Coupling in Software Design: Successful Software Architecture in General and Distributed Systems" by Vladislav Khononov</p></li> +<li><p>"<a class="reference external" href="https://www.informit.com/imprint/series_detail.aspx?ser=7937178">The Addison-Wesley Signature Series: Vaughn Vernon</a>"</p></li> +<li><p>"<a class="reference external" href="https://leanpub.com/dddwithpython">Event Sourced Building Blocks for Domain-Driven Design with Python</a>" by John Bywater</p></li> </ul> -<p><strong>Developers are afraid, too. They fear that</strong></p> +</section> +<section id="id25"> +<h3><a class="toc-backref" href="#id74" role="doc-backlink">Изучаем проектирование</a></h3> <ul class="simple"> -<li><p>They will be told to do more than they know how to do.</p></li> -<li><p>They will be told to do things that don't make sense.</p></li> -<li><p>They are too stupid.</p></li> -<li><p>They are falling behind technically.</p></li> -<li><p>They will be given responsibility without authority.</p></li> -<li><p>They won't be given clear definitions of what needs to be done.</p></li> -<li><p>They'll have to sacrifice quality for deadlines.</p></li> -<li><p>They'll have to solve hard problems without help.</p></li> -<li><p>They won't have enough time to succeed."</p></li> +<li><p>"Agile Software Development. Principles, Patterns, and Practices." by Robert C. Martin, James W. Newkirk, Robert S. Koss</p></li> +<li><p>"Analysis Patterns. Reusable Object Models" by Martin Fowler</p></li> +<li><p>"Implementation Patterns" by Kent Beck</p></li> +<li><p>"Smalltalk Best Practice Patterns" by Kent Beck</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/eaaDev/">Development of Further Patterns of Enterprise Application Architecture</a>" by Martin Fowler</p></li> +<li><p>"Domain Specific Languages" by Martin Fowler (with Rebecca Parsons)</p></li> +<li><p>"Pattern Hatching: Design Patterns Applied" by John Vlissides</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ff650706(v=pandp.10)?redirectedfrom=MSDN">Microsoft Application Architecture Guide</a>" 2nd edition (Patterns &amp; Practices) by Microsoft Corporation (J.D. Meier, David Hill, Alex Homer, Jason Taylor, Prashant Bansode, Lonnie Wall, Rob Boucher Jr., Akshay Bogawat)</p></li> +<li><p>"Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development" by Craig Larman</p></li> +<li><p>"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer</p></li> +<li><p>"Working Effectively with Legacy Code" by Michael C. Feathers</p></li> +<li><p>"Refactoring To Patterns" by Joshua Kerievsky</p></li> +<li><p>"Structure and Interpretation of Computer Programs" (aka SICP) 2nd edition (MIT Electrical Engineering and Computer Science) by Harold Abelson, Gerald Jay Sussman, Julie Sussman</p></li> +<li><p>"How to Design Programs, second edition: An Introduction to Programming and Computing" 2d edition by Matthias Felleisen, Robert Bruce Findler, Matthew Flatt, Shriram Krishnamurthi</p></li> +<li><p>"Object Oriented Software Engineering: A Use Case Driven Approach" by Ivar Jacobson</p></li> +<li><p>"Object-Oriented Analysis and Design with Applications" 3rd edition by Grady Booch, Robert A. Maksimchuk, Michael W. Engle, Bobbi J. Young Ph.D., Jim Conallen, Kelli A. Houston</p></li> </ul> -<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler</p> -</div></blockquote> -<blockquote> -<div><p>💬 "But it was here, nestled in the white-capped mountains at a ski resort, that a group of software rebels gathered in 2001 to frame and sign one of the most important documents in its industry's history, a sort of Declaration of Independence for the coding set."</p> -<p class="attribution">—"<a class="reference external" href="https://www.theatlantic.com/technology/archive/2017/12/agile-manifesto-a-history/547715/">The Winter Getaway That Turned the Software World Upside Down</a>" by Caroline Mimbs Nyce</p> -</div></blockquote> -<p>Вся суть Agile (итеративной) модели разработки была лаконично и метко выражена Кент Беком всего одним предложением:</p> -<blockquote> -<div><p>💬 "Сделайте изменение легким, а потом делай легко изменение.</p> -<p><strong>Make the change easy then make the easy change.</strong>"</p> -<p class="attribution">—Kent Beck, "<a class="reference external" href="https://youtu.be/3gib0hKYjB0?t=2662">Continued Learning: The Beauty of Maintenance - Kent Beck - DDD Europe 2020</a>"</p> -</div></blockquote> -<blockquote> -<div><p>Thanks to Vladik Khononov for <a class="reference external" href="https://youtu.be/ybYtgII151g?t=9808">https://youtu.be/ybYtgII151g?t=9808</a></p> -</div></blockquote> -<p>Невероятный талант Kent Beck объяснять сложные вещи простым языком. -Именно об этом я говорил в статье "<a class="reference internal" href="../../../../soft-skills/learning.html#emacsway-learning-in-psychology"><span class="std std-ref">Кристаллизация знаний. Как читать и не превратиться в коллекционера информации.</span></a>". -И это при необычайной эрудированности Kent Beck. Cписок использованной литературы в его книгах просто ошеломляет.</p> -<p>Более развернутый вариант его фразы:</p> -<blockquote> -<div><p>💬 "At the core of understanding this argument is the software change curve. -The change curve says that as the project runs, it becomes exponentially more expensive to make changes. -The change curve is usually expressed in terms of phases "a change made in analysis for $1 would cost thousands to fix in production". -This is ironic as most projects still work in an ad-hoc process that doesn't have an analysis phase, but the exponentiation is still there. -<strong>The exponential change curve means that evolutionary design cannot possibly work.</strong> -It also conveys why planned design must be done carefully because any mistakes in planned design face the same exponentiation.</p> -<p><strong>The fundamental assumption underlying XP is that it is possible to flatten the change curve enough to make evolutionary design work.</strong> -This flattening is both enabled by XP and exploited by XP. -This is part of the coupling of the XP practices: specifically <strong>you can't do those parts of XP that exploit the flattened curve without doing those things that enable the flattening.</strong> -This is a common source of the controversy over XP. -Many people criticize the exploitation without understanding the enabling. -Often the criticisms stem from critics' own experience where they didn't do the enabling practices that allow the exploiting practices to work. -As a result they got burned and when they see XP they remember the fire."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by M.Fowler</p> -</div></blockquote> -<blockquote> -<div><p>💬 "<strong>Именно это является одной из предпосылок ХР</strong>. -<strong>Это техническая предпосылка ХР.</strong> -[в оригинальном переводе: <em>Именно это является одним из основных предположений ХР. Это техническое предположение ХР.</em>] -Если стоимость внесения в систему изменений со временем растет достаточно медленно, стратегия разработки программы должна быть совершенно другой, отличной от той, которая используется в случае, если стоимость внесения в систему изменений со временем растет экспоненциально. -В подобной ситуации вы можете откладывать решение важных задач на более поздние сроки. -Вы получаете возможность принимать важные решения настолько поздно, насколько это возможно. -Это делается для того, чтобы осуществлять связанные с этим затраты как можно позже. -Кроме того, если вы откладываете решение важных вопросов на более поздний срок, тем самым вы повышаете вероятность того, что выбранное вами решение окажется правильным. -Другими словами, сегодня вы должны реализовать только то, без чего сегодня не обойтись, при этом вы можете рассчитывать на то, что проблемы, решение которых вы отложили до завтра, развеются сами собой, то есть перестанут быть актуальными. -Вы можете добавлять в дизайн новые элементы только в случае, если эти новые элементы упрощают код или делают написание следующего фрагмента кода более простым.</p> -<p><strong>Если пологая кривая роста затрат делает ХР возможным, то экспоненциальная кривая роста затрат делает ХР невозможным.</strong> -Если изменение обойдется вам в кругленькую сумму, вы сойдете с ума, пытаясь предугадать, каким образом это изменение повлияет на работу системы. -Если же изменение обходится вам дешево, вы всегда можете рискнуть и проверить, что будет, если вы тем или иным образом измените код, — позже вы всегда можете изменить систему так, как это будет лучше.</p> -<p><strong>This is one of the premises of XP. It is the technical premise of XP.</strong> -If the cost of change rose slowly over time, you would act completely differently from how you do under the assumption that costs rise exponentially. -You would make big decisions as late in the process as possible, to defer the cost of making the decisions and to have the greatest possible chance that they would be right. -You would only implement what you had to, in hopes that the needs you anticipate for tomorrow wouldn't come true. -You would introduce elements to the design only as they simplified existing code or made writing the next bit of code simpler.</p> -<p><strong>If a flattened change cost curve makes XP possible, a steep change cost curve makes XP impossible.</strong> -If change is ruinously expensive, you would be crazy to charge ahead without careful forethought. -But if change stays cheap, the additional value and reduced risk of early concrete feedback outweighs the additional cost of early change."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change", перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>Поскольку это было произнесено еще до встречи 2001 года и принятия Agile Manifesto, то под XP следует понимать Agile (или даже любую итератиную модель разработки) в принципе, поскольку XP - это частный случай Agile.</p> -<p>Иными словами, внутреннее качество программы является первичным условием в Agile, как и в любой другой итеративной разработке.</p> -<blockquote> -<div><p>💬 "Engineers who don't understand exponential growth and the cost curve as economies of scale kick in come to wildly incorrect conclusions."</p> -<p class="attribution">—<a class="reference external" href="https://twitter.com/KentBeck/status/1402276528910704655?s=19">Kent Beck</a></p> -</div></blockquote> -<blockquote> -<div><p>💬 "Continuous attention to technical excellence and good design enhances agility."</p> -<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/principles.html">Principles behind the Agile Manifesto</a>"</p> -</div></blockquote> -<blockquote> -<div><p>💬 "The incremental and iterative nature of Agile development can facilitate <strong>efficient technical and management processes and practices to reduce the cost associated with change</strong>. -In comparison, projects managed at the waterfall end of the continuum seek to reduce total rework cost by minimizing the number of changes, limiting the number of control points, and baselining detailed specifications which are reviewed and traced throughout the project."</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> -</div></blockquote> -<p>При соблюдении этого условия, использование <a class="reference internal" href="../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Adaptation</span></a> обретает экономическую целесообразность:</p> -<blockquote> -<div><p>💬 "Responding to change over following a plan"</p> -<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/">Manifesto for Agile Software Development</a>"</p> -</div></blockquote> -<blockquote> -<div><p>💬 "Welcome changing requirements, even late in development. Agile processes harness change for the customer's competitive advantage."</p> -<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/principles.html">Principles behind the Agile Manifesto</a>"</p> -</div></blockquote> -<blockquote> -<div><p>💬️ "We considered a bunch of names, and agreed eventually on <strong>"agile"</strong> as we felt that captured the <strong>adaptiveness</strong> and <strong>response to change</strong> which we felt was so important to our approach."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/agileStory.html">Writing The Agile Manifesto</a>" by Martin Fowler</p> -</div></blockquote> -<blockquote> -<div><p>💬 "‘<strong>Agile!</strong> Oh great, let’s go,’” Cockburn tells me. “It was really a lot of work.” The other finalist, he says, was <strong>“Adaptive.”</strong>"</p> -<p class="attribution">—"<a class="reference external" href="https://www.theatlantic.com/technology/archive/2017/12/agile-manifesto-a-history/547715/">The Winter Getaway That Turned the Software World Upside Down</a>" by Caroline Mimbs Nyce</p> -</div></blockquote> -<blockquote> -<div><p>💬 "<strong>Agile</strong> methods are <strong>adaptive</strong> rather than predictive."</p> -<p class="attribution">—"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html">The New Methodology</a>" by Martin Fowler</p> -</div></blockquote> -<p>О том, почему я обратился к высказываю Kent Beck в этом вопросе, неплохо поясняет Martin Fowler:</p> -<blockquote> -<div><p>💬 "Extreme Programming (XP) is a software development methodology developed primarily by Kent Beck. -XP was one of the first agile methods, indeed XP was the dominant agile method in the late 90s and early 00s before Scrum became dominant as the noughties passed. -Many people (including myself) consider XP to be the primary catalyst that got attention to agile methods, and superior to Scrum as a base for starting out in agile development."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/ExtremeProgramming.html">Extreme Programming</a>" by Martin Fowler</p> -</div></blockquote> </section> -<section id="emacsway-agile-development-difficulties"> -<span id="id5"/><h2><a class="toc-backref" href="#id13" role="doc-backlink">О сложностях</a></h2> -<p>Вернемся еще раз к выражению Kent Beck "<em>сделайте изменение легким, а потом делай легко изменение</em>". -Оно состоит из двух частей, причем, первая из них предшествует второй. -Как раз именно первую часть нередко забывают сделать на современном рынке, а без первой части вторая часть работает не будет, как это нетрудно догадаться. -Так недалеко и до полного Уроборос.</p> -<blockquote> -<div><p>💬 "Scrum is ok if you do it right."</p> -<p class="attribution">—<a class="reference external" href="https://youtu.be/0oGpWmS0aYQ?t=921">OOP 2015 Keynote - Robert C. Martin ("Uncle Bob"): Agility and Architecture at 15:21</a></p> -</div></blockquote> -<blockquote> -<div><p>💬 "One pattern I see time and time again on software teams is that they adopt Scrum, pay little attention to technical practices, and they're able to consistently increase their velocity for the first few years. -But after about three or four years the technical debt they've accumulated in their code is so great that their velocity starts to grind to a halt and they find it difficult to even get simple features implemented. -This is a place you do not want to get to, though I see it far too often in the software community—teams stuck there without a clue how to get out."</p> -<p class="attribution">—"<a class="reference external" href="https://www.agilealliance.org/how-to-increase-velocity/">How to Increase Velocity</a>" by David Bernstein</p> -</div></blockquote> -<p>Происходит это во многом потому, что:</p> -<blockquote> -<div><p>💬 "Я узнал от Jeff Sutherland, что первый Scrum на самом деле использовал все XP практики. -Но Ken Schwaber убедил его оставить инженерные практики за рамками Scrum, чтобы упростить модель и позволить командам брать на себя ответственность за выбор тех или иных практик. -Возможно, это ускорило распространение Scrum, но с другой стороны многие команды страдают из-за отсутствия технических практик, позволяющих поддерживать постоянный темп гибкой разработки.</p> -<p>I learned from Jeff Sutherland that the first Scrum actually did all the XP practices. -But Ken Schwaber convinced him to leave the engineering practices out of Scrum, to keep the model simple and let the teams take responsibility for the tech practices themselves. -Perhaps this helped spread Scrum faster, but the downside is that a lot of teams suffer because they lack the technical practices that enable sustainable agile development."</p> -<p class="attribution">—"Scrum and XP from the Trenches: How We Do Scrum" 2nd edition by Henrik Kniberg, перевод под редакцией Алексея Кривицкого</p> -</div></blockquote> -<p>Последнее предложение приведенной выше цитаты выражает то же самое, но другими словами. -А ведь еще в 2004 г., в книге "Agile Project Management with Scrum" by Ken Schwaber, Scrum назывался методологий.</p> -<p>Позвольте еще раз повторить слова Kent Beck:</p> -<blockquote> -<div><p>💬 "If a flattened change cost curve makes XP possible, a steep change cost curve makes XP impossible."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck</p> -</div></blockquote> -<p>Impossible. Точка.</p> -<p>Если говорить более развернуто, то, конечно же, это не совсем "Impossible", просто это становится экономически нецелесообразным, поскольку при быстрорастущем графике изменения кода возникает экономическая целесообразность принимать решения в момент наименьшей стоимости их реализации, вплоть до заблаговременного проектирования.</p> -<blockquote> -<div><p>💬 "To make agile work, you need solid technical practices. -A lot of agile education under-emphasizes these, but if you skimp on this you won't gain the productivity and responsiveness benefits that agile development can give you (stranding you at level 1 of the agile fluency model.) -This is one of the reasons that I still think that Extreme Programming is the most valuable of the named agile methods as a core and starting point."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/agile.html">Agile Software Development</a>" by Martin Fowler</p> -</div></blockquote> -<blockquote> -<div><p>💬 "We need to stress that you shouldn't worry too much about the issue of reworking. -<strong>XP's practices are all about reducing the cost of reworking to manageable levels.</strong> -If you find yourself in a situation <strong>where the cost of reworking is prohibitive, then you should either not use XP or you should use an environment that makes rework easier</strong>."</p> -<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler</p> -</div></blockquote> -<p>Этому вопросу посвящена статья "<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler.</p> -<blockquote> -<div><p>💬 "In its common usage, evolutionary design is a disaster. -The design ends up being the aggregation of a bunch of ad-hoc tactical decisions, each of which makes the code harder to alter. -In many ways you might argue this is no design, certainly it usually leads to a poor design. -As Kent puts it, <strong>design is there to enable you to keep changing the software easily in the long term.</strong> -<strong>As design deteriorates, so does your ability to make changes effectively.</strong> -You have the state of software entropy, over time the design gets worse and worse. -Not only does this make the software harder to change, it also makes bugs both easier to breed and harder to find and safely kill. -This is the "code and fix" nightmare, where the bugs become exponentially more expensive to fix as the project goes on."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler</p> -</div></blockquote> -<blockquote> -<div><p>💬 "If you're a manager or customer how can you tell if the software is well designed? -It matters to you because poorly designed software will be more expensive to modify in the future."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler</p> -</div></blockquote> -<p>И очень удачно по этому вопросу высказался Grady Booch:</p> -<blockquote> -<div><p>💬 "Grady Booch has also provided a set of guidelines for an agile architecture (which in turn imply some duties for the agile architect). -Booch claims that all good software-intensive architectures are agile. -What does he mean by this? He means that a successful architecture is resilient and loosely coupled. -It is composed of a core set of well-reasoned design decisions but still contains some "wiggle room" that allows modifications to be made and refactorings to be done, without ruining the original structure.</p> -<p>Booch also notes that an effective agile process will allow the architecture to grow incrementally as the system is developed and matures. -The key to success is to have decomposability, separation of concerns, and near-independence of the parts. -(Sound familiar? These are all modifiability tactics.)</p> -<p>Finally, Booch notes that to be agile, the architecture should be visible and self-evident in the code; this means making the design patterns, cross-cutting concerns, and other important decisions obvious, well communicated, and defended. -This may, in turn, require documentation. -But whatever architectural decisions are made, the architect must make an effort to "socialize" the architecture."</p> -<p class="attribution">—"Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman</p> -</div></blockquote> -<blockquote> -<div><p>💬 "After all software is supposed to be soft."</p> -<p class="attribution">—"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html">The New Methodology</a>" by Martin Fowler</p> -</div></blockquote> -<p>Cм. также:</p> -<blockquote> -<div><ul class="simple"> -<li><p>"<a class="reference external" href="https://martinfowler.com/articles/agileStory.html">Writing The Agile Manifesto</a>" by Martin Fowler</p></li> -<li><p>"<a class="reference external" href="https://www.informit.com/articles/article.aspx?p=2990402">The Reasons for Agile</a>" by Robert C. Martin</p></li> -<li><p>"<a class="reference external" href="https://www.theatlantic.com/technology/archive/2017/12/agile-manifesto-a-history/547715/">The Winter Getaway That Turned the Software World Upside Down</a>" by Caroline Mimbs Nyce</p></li> -<li><p>"<a class="reference external" href="https://pragdave.me/blog/2007/02/24/some-agile-history.html">Some Agile History</a>" by Dave Thomas</p></li> -<li><p>"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html">The New Methodology</a>" by Martin Fowler</p></li> -<li><p>"<a class="reference external" href="http://agilemanifesto.org/history.html">History: The Agile Manifesto</a>"</p></li> -</ul> -</div></blockquote> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +<section id="posa"> +<h3><a class="toc-backref" href="#id75" role="doc-backlink">POSA</a></h3> <ul class="simple"> -<li><p>"<a class="reference internal" href="../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../uncertainty-management/prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Что такое Prediction</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../uncertainty-management/balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">Balancing Prediction/Adaptation</span></a>"</p></li> -<li><p>"<a class="reference internal" href="analysis/concerns/balancing-business-technical-concerns.html#emacsway-agile-business-concerns-predominance"><span class="std std-ref">Преобладание бизнес-интересов</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../uncertainty-management/adaptation/software-design/software-design.html"><span class="doc">Role of Software Design in Agile</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../uncertainty-management/adaptation/crash-course-in-software-development-economics.html"><span class="doc">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> +<li><p>"Pattern-Oriented Software Architecture: A System of Patterns, Volume 1" by Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, Michael Stal</p></li> +<li><p>"Pattern-Oriented Software Architecture: Patterns for Concurrent and Networked Objects, Volume 2" by Douglas C. Schmidt, Michael Stal, Hans Rohnert, Frank Buschmann</p></li> +<li><p>"Pattern-Oriented Software Architecture: Patterns for Resource Management, Volume 3" by Michael Kircher, Prashant Jain</p></li> +<li><p>"Pattern-Oriented Software Architecture: A Pattern Language for Distributed Computing, Volume 4" by Frank Buschmann, Kevin Henney, Douglas C. Schmidt</p></li> +<li><p>"Pattern-Oriented Software Architecture: On Patterns and Pattern Languages, Volume 5" by Frank Buschmann, Kevin Henney, Douglas C. Schmidt</p></li> </ul> -</div> </section> -Sun, 06 Aug 2023 00:00:00 Iterative Developmenthttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/iterative.html -<span id="emacsway-iterative-development"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<blockquote> -<div><p>📝 "The "iterative development" model performs initial planning and then consists of a cyclic process of prototyping, testing, analyzing and refining the requirements and the solution. -"Iterative" models repeatedly perform the life cycle processes to deliver prioritized system functions sooner, with refined or more complex elements of the system coming in later iterations."</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> -</div></blockquote> -<figure class="align-left" id="id1"> -<a class="reference internal image-reference" href="../../../../_images/iterating.jpg"><img alt="Iterative Development. The image source is &quot;Don't Know What I Want, But I Know How to Get It&quot; by Jeff Patton &amp; Associates https://www.jpattonassociates.com/dont_know_what_i_want/" src="../../../../_images/iterating.jpg" style="width: 90%;"/></a> -<figcaption> -<p><span class="caption-text">Iterative Development. The image source is "<a class="reference external" href="https://www.jpattonassociates.com/dont_know_what_i_want/">Don't Know What I Want, But I Know How to Get It</a>" by Jeff Patton &amp; Associates</span></p> -</figcaption> -</figure> -<blockquote> -<div><p>📝 ""Iteration" here means applying a function to itself."</p> -<p class="attribution">—"Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik</p> -</div></blockquote> -<p>В математике итерация - это применение функции самой к себе, и именно этим обеспечивается "Responding", т.к. каждый новый вызов получает на вход результат работы предыдущего вызова.</p> -<blockquote> -<div><p>💬 The key to iterative development is to frequently produce working versions of the final system that have a subset of the required features.</p> -<p>💬 Iterative development makes sense in predictable processes as well. -But it is essential in adaptive processes because an adaptive process needs to be able to deal with changes in required features. -This leads to a style of planning where long term plans are very fluid, and the only stable plans are short term plans that are made for a single iteration. -Iterative development gives you a firm foundation in each iteration that you can base your later plans around.</p> -<p class="attribution">—"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html">The New Methodology</a>" by Martin Fowler</p> -</div></blockquote> -<blockquote> -<div><p>💬 In this thinking waterfall means "do one activity at a time for all the features" while iterative means "do all activities for one feature at a time".</p> -<p>💬 Indeed we've found that delivering a subset of features does more than anything to help clarify what needs to be done next, so an iterative approach allows us to shift to an adaptive planning approach where we update our plans as we learn what the real software needs are.</p> -<p>💬 But it is easy to follow an iterative approach (i.e. non-waterfall) but not be agile. -I might do this by taking 100 features and dividing them up into ten iterations over the next year, and then expecting that each iteration should complete on time with its planned set of features. -If I do this, my initial plan is a predictive plan, if all goes well I should expect the work to closely follow the plan. -But adaptive planning is an essential element of agile thinking. -I expect features to move between iterations, new features to appear, and many features to be discarded as no longer valuable enough.</p> -<p>My rule of thumb is that anyone who says "we were successful because we were on-time and on-budget" is thinking in terms of predictive planning, even if they are following an iterative process, and thus is not thinking with an agile mindset. -In the agile world, success is all about business value - regardless of what was written in a plan months ago. -Plans are made, but updated regularly. -They guide decisions on what to do next, but are not used as a success measure.</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/WaterfallProcess.html">Waterfall Process</a>" by Martin Fowler</p> -</div></blockquote> -<p>Итерация может дать Responding, а может и не дать. -Важны не итерации сами по себе, а именно Responding. -Поэтому в Agile Manifesto пишут про Responding, а не про итерации.</p> -<p>Ключевым элементом итеративной разработки является <a class="reference internal" href="../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Adaptation</span></a>.</p> -<p>См. также:</p> +<section id="id26"> +<h3><a class="toc-backref" href="#id76" role="doc-backlink">Алгоритмы. Второй заход.</a></h3> <ul class="simple"> -<li><p>"<a class="reference external" href="https://www.agilealliance.org/glossary/iteration">Iteration</a>" at Glossary of agilealliance.org</p></li> +<li><p>"Introduction to Algorithms" 3d edition by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein</p></li> +<li><p>"Algorithms and Data Structures" (Oberon version: August 2004) by N.Wirth</p></li> </ul> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +<p>Donald E. Knuth:</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> -<li><p>"<a class="reference internal" href="agile/agile.html#emacsway-agile-development"><span class="std std-ref">Что такое Agile Development</span></a>"</p></li> +<li><p>"The Art of Computer Programming, Volume 1: Fundamental Algorithms" 3d edition by Donald Knuth</p></li> +<li><p>"The Art of Computer Programming, Volume 1, Fascicle 1: MMIX; A RISC Computer for the New Millennium" 1st edition by Donald Knuth</p></li> +<li><p>"The Art of Computer Programming, Volume 2, Seminumerical Algorithms" 3rd edition by Donald E. Knuth</p></li> +<li><p>"The Art of Computer Programming, Volume 3, Sorting and Searching" 2nd edition by Donald E. Knuth</p></li> +<li><p>"The Art of Computer Programming, Volume 4, Fascicle 0: Introduction to Combinatorial Algorithms and Boolean Functions" 1st edition by Donald E. Knuth</p></li> +<li><p>"The Art of Computer Programming, Volume 4, Fascicle 1: Bitwise Tricks &amp; Techniques; Binary Decision Diagrams" 1st edition by Donald E. Knuth</p></li> +<li><p>"The Art of Computer Programming, Volume 4, Fascicle 2: Generating All Tuples and Permutations" 1st edition by Donald E. Knuth</p></li> +<li><p>"The Art of Computer Programming, Volume 4, Fascicle 3: Generating All Combinations and Partitions Paperback" 1st edition by Donald E. Knuth</p></li> +<li><p>"Art of Computer Programming, Volume 4, Fascicle 4: Generating All Trees; History of Combinatorial Generation 1st edition by Donald E. Knuth</p></li> +<li><p>"The Art of Computer Programming" Volume 4, Fascicle 5: Mathematical Preliminaries Redux; Introduction to Backtracking; Dancing Links" 1st edition by Donald E. Knuth</p></li> +<li><p>"The Art of Computer Programming, Volume 4, Fascicle 6: Satisfiability" 1st edition by Donald E. Knuth</p></li> +<li><p>"The Art of Computer Programming, Volume 4A, Combinatorial Algorithms, Part 1" 1st edition by Donald E. Knuth</p></li> </ul> -</div> -Sun, 06 Aug 2023 00:00:00 Как сохранить Агрегат в БД не разрушая инкапсуляции?https://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/aggregate-encapsulation.html -<span id="id1"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<p>Инварианты лишены смысла своего существования в условиях дырявой, как решето, инкапсуляции. -Вопрос в том, как сохранить инкапсуляцию Агрегатов в Golang, когда нам требуется его внутреннее состояние для формирования SQL-запроса, или, наоборот, требуется установить состояние Агрегата в результате выполнения SQL-запроса.</p> -<nav class="contents" id="id2"> -<p class="topic-title">Содержание</p> +<p>Хорошая подборка книг по алгоритмам: <a class="reference external" href="http://e-maxx.ru/bookz/">http://e-maxx.ru/bookz/</a></p> +</section> +<section id="id27"> +<h3><a class="toc-backref" href="#id77" role="doc-backlink">Тестирование</a></h3> <ul class="simple"> -<li><p><a class="reference internal" href="#emacsway-golang-encapsulation" id="id4">Как сохранить Агрегат в БД не разрушая инкапсуляции?</a></p> -<ul> -<li><p><a class="reference internal" href="#memento-pattern" id="id5">Memento pattern</a></p></li> -<li><p><a class="reference internal" href="#walker" id="id6">Walker</a></p></li> -<li><p><a class="reference internal" href="#valuer-scanner" id="id7">Valuer &amp; Scanner</a></p></li> -<li><p><a class="reference internal" href="#reflection" id="id8">Reflection</a></p></li> -<li><p><a class="reference internal" href="#exporter" id="id9">Exporter</a></p> -<ul> -<li><p><a class="reference internal" href="#accepting-interface-mediator" id="id10">1. Accepting interface (Mediator)</a></p></li> -<li><p><a class="reference internal" href="#returning-structure" id="id11">2. Returning structure</a></p></li> -</ul> -</li> +<li><p>"xUnit Test Patterns. Refactoring Test Code." by Gerard Meszaros</p></li> +<li><p>"Unit Testing Principles, Practices, and Patterns: Effective testing styles, patterns, and reliable automation for unit testing, mocking, and integration testing with examples in C#" 1st Edition by Vladimir Khorikov</p></li> +<li><p>"Growing Object-Oriented Software, Guided by Tests" by Steve Freeman, Nat Pryce</p></li> +<li><p>"Agile Testing: A Practical Guide for Testers and Agile Teams" by Lisa Crispin, Janet Gregory</p></li> +<li><p>"More Agile Testing: Learning Journeys for the Whole Team" by Lisa Crispin, Janet Gregory</p></li> +<li><p>"ATDD by Example: A Practical Guide to Acceptance Test-Driven Development" by Markus Gärtner</p></li> +<li><p>"Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation" by Jez Humble, David Farley</p></li> +<li><p>"Continuous Integration: Improving Software Quality and Reducing Risk" by Paul M. Duvall, Steve Matyas, Andrew Glover</p></li> +<li><p>"<a class="reference external" href="https://www.istqb.org/references/books/istqb-related-books.html">ISTQB® Related Books</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.istqb.org/references/books/referenced-books-in-istqb-syllabi.html">Referenced Books in ISTQB® Syllabi</a>"</p></li> </ul> -</li> +</section> +<section id="id28"> +<h3><a class="toc-backref" href="#id78" role="doc-backlink">Компиляторы</a></h3> +<ul class="simple"> +<li><p>"<cite>Crafting Interpreters &lt;https://craftinginterpreters.com/&gt;</cite>" by Robert Nystrom</p></li> +<li><p>"Compiler Construction" by N.Wirth</p></li> +<li><p>"Compilers: Principles, Techniques, and Tools" 2nd edition by Alfred V. Aho, Monica S. Lam, Ravi Sethi, Jeffrey D. Ullman</p></li> </ul> -</nav> -<section id="memento-pattern"> -<h2><a class="toc-backref" href="#id5" role="doc-backlink">Memento pattern</a></h2> -<p>Memento оказался близко, но не по назначению. Суть Memento в том, что он не должен раскрывать свое состояние никому, кроме своего создателя:</p> -<blockquote> -<div><ol class="arabic simple"> -<li><p>Preserving encapsulation boundaries. Memento avoids exposing information that only an originator should manage but that must be stored nevertheless outside the originator. -The pattern shields other objects from potentially complex Originator internals, thereby preserving encapsulation boundaries.</p></li> -</ol> -<p class="attribution">—"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides</p> -</div></blockquote> -<p>Тем не менее, этот подход используется некоторыми авторитетными источниками, см. <a class="reference external" href="https://github.com/microsoftarchive/cqrs-journey/blob/6ffd9a8c8e865a9f8209552c52fa793fbd496d1f/source/Conference/Registration/SeatsAvailability.cs#L237">здесь</a> и <a class="reference external" href="https://github.com/microsoftarchive/cqrs-journey/blob/6ffd9a8c8e865a9f8209552c52fa793fbd496d1f/source/Infrastructure/Azure/Infrastructure.Azure/EventSourcing/AzureEventSourcedRepository.cs#L31">здесь</a>.</p> -<blockquote> -<div><p>💬 The event is stored using some form of serialization, for the rest of this discussion the mechanism will assumed to be built in serialization although the use of the memento pattern can be highly advantageous.</p> -<p>&lt;...&gt;</p> -<p>Many use the default serialization package available with their platform with good results though the Memento pattern is quite useful when dealing with snapshots. The Memento pattern (or custom serialization) better insulates the domain over time as the structure of the domain objects change. The default serializer has versioning problems when the new structure is released (the existing snapshots must either deleted and recreated or updated to match the new schema). The use of the Memento pattern allows the separated versioning of the snapshot schema from the domain object itself.</p> -<p class="attribution">—"<a class="reference external" href="https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf">CQRS Documents by Greg Young</a>"</p> -</div></blockquote> -</section> -<section id="walker"> -<h2><a class="toc-backref" href="#id6" role="doc-backlink">Walker</a></h2> -<p>Walker представляет собою модификацию паттерна Visitor с целью сохранить инкапсуляцию Агрегатов. К числу недостатков паттерна паттерна Visitor относится:</p> -<blockquote> -<div><p>6. Breaking encapsulation. Visitor's approach assumes that the ConcreteElement interface is powerful enough to let visitors do their job. -As a result, the pattern often forces you to provide public operations that access an element's internal state, which may compromise its encapsulation.</p> -<p class="attribution">—"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides</p> -</div></blockquote> -<p>Что будет создавать Walker в случае обхода иерархической структуры Агрегата с несколькими вложенными Сущностями? -Вероятно, это будет будет несколько SQL-запросов с параметрами, т.е. некий композитный объект, выраженный некой структурой данных. -Это лишает смысла использование Visitor, если можно сразу возвратить структуру данных, причем, абстрагированную от SQL.</p> -<p>Технически, можно сделать так:</p> -<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kd">type</span><span class="w"> </span><span class="nx">Walkable</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">Accept</span><span class="p">(</span><span class="nx">Walker</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Walker</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">SetField</span><span class="p">(</span><span class="kt">string</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">WalkWalkable</span><span class="p">(</span><span class="nx">Walkable</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">WalkUint8</span><span class="p">(</span><span class="kt">uint8</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">WalkUint64</span><span class="p">(</span><span class="kt">uint64</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">WalkUint</span><span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">WalkTime</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> -</pre></div> -</div> -<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">)</span><span class="w"> </span><span class="nx">Accept</span><span class="p">(</span><span class="nx">walker</span><span class="w"> </span><span class="nx">interfaces</span><span class="p">.</span><span class="nx">Walker</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">walker</span><span class="p">.</span><span class="nx">SetField</span><span class="p">(</span><span class="s">"endorserId"</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">walker</span><span class="p">.</span><span class="nx">WalkWalkable</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">endorserId</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">walker</span><span class="p">.</span><span class="nx">SetField</span><span class="p">(</span><span class="s">"endorserGrade"</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">walker</span><span class="p">.</span><span class="nx">WalkWalkable</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">endorserGrade</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="c1">// ...</span><span class="w"/> -<span class="p">}</span><span class="w"/> -</pre></div> -</div> -<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">id</span><span class="w"> </span><span class="nx">EndorserId</span><span class="p">)</span><span class="w"> </span><span class="nx">Accept</span><span class="p">(</span><span class="nx">walker</span><span class="w"> </span><span class="nx">interfaces</span><span class="p">.</span><span class="nx">Walker</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">walker</span><span class="p">.</span><span class="nx">WalkUint64</span><span class="p">(</span><span class="nx">id</span><span class="p">.</span><span class="nx">Value</span><span class="p">())</span><span class="w"/> -<span class="p">}</span><span class="w"/> -</pre></div> -</div> -<p>Проблема в том, что на этапе создания SQL-запроса нам пока еще могут быть неизвестны первичные ключи Агрегатов, чтобы их можно было бы проставить в SQL-запросы их Сущностей.</p> -<p>Кроме того, осведомленность о способах образования SQL-запросов размазывается между Walkers и Repositories, что вызывает "Разлет Дроби" (Code Smell) в случае изменения существующего способа построения SQL (например, в случае изменения диалекта БД или в случае внедрения какого-либо QueryBuilder). -Walker начинает быть слишком осведомленным о деталях реализации Repository.</p> -<p>В целях достижения DRY возникает целесообразность возложить на Walker генерирование только части SQL, и освободить его от осведомленности знания таблиц в БД, что будет разрывать обязанность за построение SQL на несколько объектов и подрывать Cohesion.</p> </section> -<section id="valuer-scanner"> -<h2><a class="toc-backref" href="#id7" role="doc-backlink">Valuer &amp; Scanner</a></h2> +<section id="id29"> +<h3><a class="toc-backref" href="#id79" role="doc-backlink">Архитектура</a></h3> <ul class="simple"> -<li><p><a class="reference external" href="https://pkg.go.dev/database/sql/driver#Valuer">Valuer</a></p></li> -<li><p><a class="reference external" href="https://pkg.go.dev/database/sql#Scanner">Scanner</a></p></li> +<li><p>"Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman</p></li> +<li><p>"Documenting Software Architectures: Views and Beyond" 2nd edition by Paul Clements, Felix Bachmann, Len Bass, David Garlan, James Ivers, Reed Little, Paulo Merson, Robert Nord, Judith Stafford</p></li> +<li><p>"Software Systems Architecture: Working With Stakeholders Using Viewpoints and Perspectives" 2nd edition by Nick Rozanski, Eóin Woods</p></li> +<li><p>"Designing Software Architectures: A Practical Approach (SEI Series in Software Engineering)" 1st edition by Humberto Cervantes, Rick Kazman</p></li> +<li><p>"Fundamentals of Software Architecture: An Engineering Approach" 1st edition by Mark Richards, Neal Ford</p></li> +<li><p>"Introduction to Solution Architecture Paperback" by Alan McSweeney</p></li> +<li><p>"Systems Analysis and Design" 7th edition by Alan Dennis, Barbara Haley Wixom, Roberta M. Roth</p></li> +<li><p>"The Design of Design: Essays from a Computer Scientist" by Frederick P. Brooks</p></li> +<li><p>"Living Documentation: Continuous Knowledge Sharing by Design" by Cyrille Martraire</p></li> +<li><p>"Just Enough Software Architecture: A Risk-Driven Approach" by George H. Fairbanks</p></li> +<li><p>"The Book: 37 Things One Architect Knows About IT Transformation" by Gregor Hohpe</p></li> +<li><p>"The Software Architect Elevator: Redefining the Architect's Role in the Digital Enterprise 1st Edition" by Gregor Hohpe</p></li> +<li><p>"Cloud Strategy: A Decision-based Approach to Successful Cloud Migration" by Gregor Hohpe, Michele Danieli, Jean-Francois Landreau, Tahir Hashmi</p></li> +<li><p>"Architecting for Scale" 2nd Edition by Lee Atchison</p></li> +<li><p>"Software Engineering: A Practitioner's Approach" 9th edition by Roger S. Pressman, Bruce Maxim</p></li> +<li><p>"Presentation patterns: techniques for crafting better presentations" by Neal Ford, Matthew McCullough, Nathaniel Schutta</p></li> +<li><p>"Team Topologies: Organizing Business and Technology Teams for Fast Flow" by Matthew Skelton, Manuel Pais</p></li> +<li><p>"Technology Strategy Patterns: Architecture as Strategy" 1st edition by Eben Hewitt</p></li> </ul> -<p>Интерфейс Scanner открывает дверь к изменяемости ValueObject, что противоречит основной его сути. -А так же открывает брешь в инкапсуляции Агрегата. -Справедливости ради, стоит отметить, что можно его реализовать таким образом, чтобы он был только однократно мутируемым, предварительно проверяя, не установлено ли уже значение.</p> -<p>Но есть еще один момент - метод <code class="docutils literal notranslate"><span class="pre">Scan(src</span> <span class="pre">any)</span> <span class="pre">error</span></code> вызывается у конкретного типа, что препятствует использованию паттерна, известного как <a class="reference external" href="https://martinfowler.com/eaaCatalog/specialCase.html">Special Case</a> или <a class="reference external" href="https://refactoring.com/catalog/introduceSpecialCase.html">Null Object</a>. -Кроме того, в некоторых случаях может потребоваться преобразовать неизменяемые исторические данные для новой версии модели. -Вопрос затрагивался в разделе "4. Validating historical data" статьи "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/always-valid-domain-model/">Always-Valid Domain Model</a>" by Vladimir Khorikov и в разделе "6. The use of ORMs within and outside of the always-valid boundary" статьи "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/database-always-valid-domain-model/">Database and Always-Valid Domain Model</a>" by Vladimir Khorikov.</p> -<p>С другой стороны, Valuer может возвращать только примитивные типы, а значит, он не пригоден для экспорта иерархической структуры состояния Агрегата:</p> -<blockquote> -<div><p>It is either nil, a type handled by a database driver's NamedValueChecker interface, or an instance of one of these types:</p> +<p>Архитектура в Agile:</p> <ul class="simple"> -<li><p>int64</p></li> -<li><p>float64</p></li> -<li><p>bool</p></li> -<li><p>[]byte</p></li> -<li><p>string</p></li> -<li><p>time.Time</p></li> +<li><p>"Building Evolutionary Architectures: Support Constant Change" 1st Edition by Neal Ford, Rebecca Parsons, Patrick Kua</p></li> +<li><p>"Agile Software Architecture: Aligning Agile Processes and Software Architectures" by Muhammad Ali Babar, Alan W. Brown, Kai Koskimies, Ivan Mistrík</p></li> +<li><p>"Continuous Architecture: Sustainable Architecture in an Agile and Cloud-Centric World" by Murat Erder, Pierre Pureur</p></li> +<li><p>"<a class="reference external" href="https://www.amazon.com/Balancing-Agility-Discipline-Guide-Perplexed/dp/0321186125">Balancing Agility and Discipline: A Guide for the Perplexed</a>" by Barry Boehm, Richard Turner</p></li> +<li><p>"<a class="reference external" href="https://www.researchgate.net/publication/228701141_Architected_Agile_Solutions_for_Software-Reliant_Systems">Architected Agile Solutions for Software-Reliant Systems</a>" by Barry Boehm, Jo Ann Lane, Richard Turner</p></li> +<li><p>"<a class="reference external" href="https://www.researchgate.net/publication/224579114_The_ROI_of_Systems_Engineering_Some_Quantitative_Results">The ROI of Systems Engineering: Some Quantitative Results</a>" by Barry Boehm, Ricardo Valerdi</p></li> +<li><p>"Lean Architecture: for Agile Software Development" 1st edition by James O. Coplien, Gertrud Bjørnvig</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute (PMI), 2017</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile/process/enterprise-architecture">Enterprise Architecture in Disciplined Agile</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/enterprise-architect/">Enterprise Architect in SAFe</a>"</p></li> </ul> -<p class="attribution">—<a class="reference external" href="https://pkg.go.dev/database/sql/driver#Value">Источник</a></p> -</div></blockquote> +<p>Стандарты:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/">Open Agile Architecture: A Standard of The Open Group</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.iso.org/standard/50508.html">ISO/IEC/IEEE 42010:2011(en) Systems and software engineering — Architecture description</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.iso.org/standard/68982.html">ISO/IEC/IEEE 42020:2019 Software, systems and enterprise — Architecture processes</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.iso.org/standard/73436.html">ISO/IEC/IEEE 42030:2019 Software, systems and enterprise — Architecture evaluation framework</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.iso.org/standard/35733.html">ISO/IEC 25010:2011 Systems and software engineering — Systems and software Quality Requirements and Evaluation (SQuaRE) — System and software quality models</a>"</p></li> +<li><p><a class="reference external" href="https://allgosts.ru/35/080/gost_r_57100-2016">ГОСТ Р 57100-2016 Системная и программная инженерия. Описание архитектуры</a></p></li> +</ul> +<p>Рейтинг инструментов для упраления требованиями/архитектурой/SDLC/etc. от Gartner по категориям: "<a class="reference external" href="https://www.gartner.com/reviews/markets">Reviews Organized by Markets</a>".</p> </section> -<section id="reflection"> -<h2><a class="toc-backref" href="#id8" role="doc-backlink">Reflection</a></h2> -<p>В документации <a class="reference external" href="https://pkg.go.dev/reflect#Value.FieldByName">отсутствуют</a> какие-либо упоминания об ограничении доступа к защищенным атрибутам структуры данных посредством рефлекции.</p> -<p>Может быть через рефлексию и заработало бы - я не пробовал. -Но использовать рефлексию в production для таких целей как-то не сильно хочется, в т.ч. и по соображениям производительности. -К тому же этот метод является, по сути, еще одним способом пробить брешь в инкапсуляции.</p> -<p>Похожий трюк используется <a class="reference external" href="https://stackoverflow.com/a/25405485">здесь</a>:</p> -<div class="literal-block-wrapper docutils container" id="id3"> -<div class="code-block-caption"><span class="caption-text"><a class="reference external" href="https://stackoverflow.com/a/25405485">How to marshal struct when some members are protected/inner/hidden</a></span></div> -<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"/> - -<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"fmt"</span><span class="w"/> -<span class="w"> </span><span class="s">"reflect"</span><span class="w"/> - -<span class="w"> </span><span class="s">"github.com/bitly/go-simplejson"</span><span class="w"/> -<span class="p">)</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">A</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:"name"`</span><span class="w"/> -<span class="w"> </span><span class="nx">code</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:"code"`</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="nx">marshal</span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="nx">A</span><span class="p">)</span><span class="w"> </span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">simplejson</span><span class="p">.</span><span class="nx">New</span><span class="p">()</span><span class="w"/> -<span class="w"> </span><span class="nx">va</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">a</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">vt</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">va</span><span class="p">.</span><span class="nx">Elem</span><span class="p">()</span><span class="w"/> -<span class="w"> </span><span class="nx">types</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">vt</span><span class="p">.</span><span class="nx">NumField</span><span class="p">();</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">j</span><span class="p">.</span><span class="nx">Set</span><span class="p">(</span><span class="nx">types</span><span class="p">.</span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">Tag</span><span class="p">.</span><span class="nx">Get</span><span class="p">(</span><span class="s">"json"</span><span class="p">),</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Sprintf</span><span class="p">(</span><span class="s">"%v"</span><span class="p">,</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">Indirect</span><span class="p">(</span><span class="nx">va</span><span class="p">).</span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="p">)))</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">j</span><span class="p">.</span><span class="nx">MarshalJSON</span><span class="p">()</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">A</span><span class="p">{</span><span class="nx">name</span><span class="p">:</span><span class="w"> </span><span class="s">"jessonchan"</span><span class="p">,</span><span class="w"> </span><span class="nx">code</span><span class="p">:</span><span class="w"> </span><span class="s">"abc"</span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="nx">b</span><span class="p">,</span><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">marshal</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nb">string</span><span class="p">(</span><span class="nx">b</span><span class="p">))</span><span class="w"/> -<span class="p">}</span><span class="w"/> -</pre></div> -</div> -</div> +<section id="id30"> +<h3><a class="toc-backref" href="#id80" role="doc-backlink">Аналитика</a></h3> +<ul class="simple"> +<li><p>"Software Requirements (Developer Best Practices)" 3rd Edition by Karl Wiegers</p></li> +<li><p>"<a class="reference external" href="https://bertrandmeyer.com/2022/10/28/new-book-requirements-handbook/">Handbook of Requirements and Business Analysis</a>" by Bertrand Meyer</p></li> +<li><p>"INCOSE Guide for Writing Requirements" by INCOSE</p></li> +<li><p>"<a class="reference external" href="https://www.incose.org/products-and-publications/se-handbook">Systems engineering handbook. A guide for System Life Cycle Processes and activities.</a>" by INCOSE</p></li> +<li><p>"Managing Software Requirements: A Unified Approach" 1st edition by Dean Leffingwell, Don Widrig</p></li> +<li><p>"Managing Software Requirements (paperback): A Use Case Approach" 2d Edition by Dean Leffingwell, Don Widrig</p></li> +<li><p>"Requirements Engineering Fundamentals: A Study Guide for the Certified Professional for Requirements Engineering Exam - Foundation Level - IREB compliant" 2nd Edition by Klaus Pohl, Chris Rupp</p></li> +<li><p>"Прикладной системный анализ" / Ф.П. Тарасенко</p></li> +<li><p>"<a class="reference external" href="https://www.iiba.org/career-resources/a-business-analysis-professionals-foundation-for-success/babok/">A Guide to the Business Analysis Body of Knowledge (BABOK®)</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.sebokwiki.org/wiki/Download_SEBoK_PDF">Guide to the Systems Engineering Body of Knowledge (SEBoK)</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/en/downloads/tag:handbook">Library of IREB artifacts</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/5-cpre-foundation-level-handbook/cpre_foundationlevel_handbook_en_v1.0.pdf">Handbook for the CPRE Foundation Level according to the IREB Standard Education and Training for Certified Professional for Requirements Engineering (CPRE) Foundation Level</a>" Version 1.0.0</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/13-cpre-advanced-level-elicitation-handbook/advanced_level_elicitation_handbook_en.pdf">Handbook of Advanced Level Elicitation according to the IREB Standard Education and Training for IREB Certified Professional for Requirements Engineering Advanced Level Advanced Level Elicitation</a>" Version 1.0.3</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/16-cpre-advanced-level-requirements-management-handbook/ireb-cpre-handbook-for-requirements-management-advanced-level-en-v1.1.pdf">Requirements Management according to the IREB Standard Education and Training for the IREB Certified Professional for Requirements Engineering Qualification Advanced Level Requirements Management</a>" Version 1.1.0</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/19-handbook-cpre-advanced-level-requirements-modeling/ireb_cpre_handbook_requirements-modeling_advanced-level-v1.3.pdf">Handbook of Requirements Modeling According to the IREB Standard Education and Training for IREB Certified Professional for Requirements Engineering Advanced Level Requirements Modeling</a>" Version 1.3</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/1-cpre-glossary/ireb_cpre_glossary_17.pdf">A Glossary of Requirements Engineering Terminology</a>" Version 1.7</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/2-cpre-glossary-2-0/ireb_cpre_glossary_en_2.0.pdf">A Glossary of Requirements Engineering Terminology Caution: This glossary is aligned to the CPRE Foundation Level syllabus 3.0 only!</a>" Version 2.0.0</p></li> +</ul> +<p>Аналитика в Agile:</p> +<ul class="simple"> +<li><p>"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</p></li> +<li><p>Whitepaper "<a class="reference external" href="https://scalingsoftwareagility.files.wordpress.com/2007/03/a-lean-and-scalable-requirements-information-model-for-agile-enterprises-pdf.pdf">A Lean and Scalable Requirements Information Model for the Agile Enterprise</a>" by Dean Leffingwell with Juha‐Markus Aalto</p></li> +<li><p>"<a class="reference external" href="https://scalingsoftwareagility.wordpress.com/2010/03/05/an-agile-architectural-epic-kanban-system-part-2-%E2%80%93-the-model/">An Agile Architectural Epic Kanban System: Part 2 – The Model</a>" by Dean Leffingwell</p></li> +<li><p>"<a class="reference external" href="https://www.iiba.org/career-resources/business-analysis-resources/iiba-bookstore/">Agile Extension to the BABOK® Guide</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/23-cpre-advanced-level-re-agile-handbook/handbook_cpre_al_re%40agile_en_v2.0.pdf">Handbook of RE@Agile According to the IREB Standard Education and Training for IREB Certified Professional for Requirements Engineering Advanced Level RE@Agile</a>" Version 2.0</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/36-re-agile-glossary/ireb_cpre_re%40agile_glossary_v1.0.5.pdf">IREB Certified Professional for Requirements Engineering RE@Agile Glossary</a>"</p></li> +</ul> +<p>Другие подборки литературы по аналитике:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://systems.education/books">Литература по аналитике на сайте Systems.Education</a></p></li> +<li><p><a class="reference external" href="https://www.volere.org/resources/books/">Литература по аналитике на сайте Volere Requirements Resources</a>.</p></li> +</ul> +<p>Смотрите также список инструментов для управления требованиями:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.volere.org/tools/">Tools</a> on Volere Requirements Resources</p></li> +<li><p><a class="reference external" href="https://www.volere.org/requirements-tools/">Requirements Tools</a> on Volere Requirements Resources</p></li> +</ul> </section> -<section id="exporter"> -<h2><a class="toc-backref" href="#id9" role="doc-backlink">Exporter</a></h2> -<section id="accepting-interface-mediator"> -<h3><a class="toc-backref" href="#id10" role="doc-backlink">1. Accepting interface (Mediator)</a></h3> -<p>Такой вариант рассматривается в книге "<a class="reference external" href="https://kalele.io/books/">Implementing Domain-Driven Design</a>" by Vaughn Vernon:</p> -<blockquote> -<div><p>Use a Mediator to Publish Aggregate Internal State</p> -<p>To work around the problem of tight coupling between the model and its clients, you may choose to design Mediator -[Gamma et al.] (aka Double-Dispatch and Callback) interfaces to which the Aggregate publishes its internal state. -Clients would implement the Mediator interface, passing the implementer’s object reference to the Aggregate as a method argument. -The Aggregate would then double-dispatch to that Mediator to publish the requested state, all without revealing its shape or structure. -The trick is to not wed the Mediator’s interface to any sort of view specification, but to keep it focused on rendering -Aggregate states of interest:</p> -<div class="highlight-java notranslate"><div class="highlight"><pre><span/><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">BacklogItem</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="p">...</span><span class="w"/> -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">provideBacklogItemInterest</span><span class="p">(</span><span class="n">BacklogItemInterest</span><span class="w"> </span><span class="n">anInterest</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informTenantId</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">tenantId</span><span class="p">().</span><span class="na">id</span><span class="p">());</span><span class="w"/> -<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informProductId</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">productId</span><span class="p">().</span><span class="na">id</span><span class="p">());</span><span class="w"/> -<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informBacklogItemId</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">backlogItemId</span><span class="p">().</span><span class="na">id</span><span class="p">());</span><span class="w"/> -<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informStory</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">story</span><span class="p">());</span><span class="w"/> -<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informSummary</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">summary</span><span class="p">());</span><span class="w"/> -<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informType</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">type</span><span class="p">().</span><span class="na">toString</span><span class="p">());</span><span class="w"/> -<span class="w"> </span><span class="p">...</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">provideTasksInterest</span><span class="p">(</span><span class="n">TasksInterest</span><span class="w"> </span><span class="n">anInterest</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="n">Set</span><span class="o">&lt;</span><span class="n">Task</span><span class="o">&gt;</span><span class="w"> </span><span class="n">tasks</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">allTasks</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informTaskCount</span><span class="p">(</span><span class="n">tasks</span><span class="p">.</span><span class="na">size</span><span class="p">());</span><span class="w"/> -<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">Task</span><span class="w"> </span><span class="n">task</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">tasks</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="p">...</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="p">...</span><span class="w"/> -<span class="p">}</span><span class="w"/> -</pre></div> -</div> -<p>The various interest providers may be implemented by other classes, much the same way that Entities (5) describe the way -validation is delegated to separate validator classes.</p> -<p>Be aware that some will consider this approach completely outside the responsibility of an Aggregate. Others will consider -it a completely natural extension of a well-designed domain model. -As always, such trade-offs must be discussed by your technical team members.</p> -</div></blockquote> -<p>Ссылки по теме:</p> +<section id="id31"> +<h3><a class="toc-backref" href="#id81" role="doc-backlink">Изучаем оценивание задач</a></h3> <ul class="simple"> -<li><p>"<a class="reference external" href="https://www.infoworld.com/article/2072302/more-on-getters-and-setters.html">More on getters and setters</a>" by Allen Holub</p></li> -<li><p>"<a class="reference external" href="https://stackoverflow.com/questions/24921227/save-and-load-objects-without-breaking-encapsulation">Save and load objects without breaking encapsulation</a>" at Stackoverflow</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/framework/practice-standard-scheduling-3rdedition">Practice Standard for Scheduling</a>" 3d edition by Project Management Institute</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/framework/practice-standard-for-estimating">Practice Standard for Project Estimating</a>" 2d edition Project Management Institute</p></li> +<li><p>"Software Estimation: Demystifying the Black Art (Developer Best Practices)" by Steve McConnell (я встречал в интернете <a class="reference external" href="http://igorshevchenko.ru/blog/entries/software-estimation">краткий конспект</a>)</p></li> +<li><p>"Agile Estimating and Planning" by Mike Cohn</p></li> </ul> -<p>Идею также можно посмотреть на примере:</p> -<div class="literal-block-wrapper docutils container" id="emacsway-code-exporter-example-1"> -<div class="code-block-caption"><span class="caption-text"><a class="reference external" href="https://www.infoworld.com/article/2072302/more-on-getters-and-setters.html">Example by Allen Holub</a></span></div> -<div class="highlight-java notranslate"><div class="highlight"><pre><span/><span class="w"> </span><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.Locale</span><span class="p">;</span><span class="w"/> - -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">Employee</span><span class="w"/> -<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">Name</span><span class="w"> </span><span class="n">name</span><span class="p">;</span><span class="w"/> -<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">EmployeeId</span><span class="w"> </span><span class="n">id</span><span class="p">;</span><span class="w"/> -<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">Money</span><span class="w"> </span><span class="n">salary</span><span class="p">;</span><span class="w"/> - -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">interface</span> <span class="nc">Exporter</span><span class="w"/> -<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">addName</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">addID</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">addSalary</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">salary</span><span class="w"> </span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">interface</span> <span class="nc">Importer</span><span class="w"/> -<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">provideName</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">provideID</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">provideSalary</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">open</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">close</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="nf">Employee</span><span class="p">(</span><span class="w"> </span><span class="n">Importer</span><span class="w"> </span><span class="n">builder</span><span class="w"> </span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">open</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Name</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">provideName</span><span class="p">()</span><span class="w"> </span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">EmployeeId</span><span class="p">(</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">provideID</span><span class="p">()</span><span class="w"> </span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">salary</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Money</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">provideSalary</span><span class="p">(),</span><span class="w"/> -<span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Locale</span><span class="p">(</span><span class="s">"en"</span><span class="p">,</span><span class="w"> </span><span class="s">"US"</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">close</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">export</span><span class="p">(</span><span class="w"> </span><span class="n">Exporter</span><span class="w"> </span><span class="n">builder</span><span class="w"> </span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">addName</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">name</span><span class="p">.</span><span class="na">toString</span><span class="p">()</span><span class="w"> </span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">addID</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">id</span><span class="p">.</span><span class="na">toString</span><span class="p">()</span><span class="w"> </span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">addSalary</span><span class="p">(</span><span class="w"> </span><span class="n">salary</span><span class="p">.</span><span class="na">toString</span><span class="p">()</span><span class="w"> </span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="c1">//...</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -</pre></div> -</div> -</div> -<p>Пример реализации:</p> -<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kn">package</span><span class="w"> </span><span class="nx">grade_1</span><span class="w"/> - -<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"time"</span><span class="w"/> -<span class="p">)</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Exporter</span><span class="p">[</span><span class="nx">T</span><span class="w"> </span><span class="kt">any</span><span class="p">]</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">SetState</span><span class="p">(</span><span class="nx">T</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Exportable</span><span class="p">[</span><span class="nx">T</span><span class="w"> </span><span class="kt">any</span><span class="p">]</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">ExportTo</span><span class="p">(</span><span class="nx">Exporter</span><span class="p">[</span><span class="nx">T</span><span class="p">])</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="p">)</span><span class="w"> </span><span class="nx">Export</span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="nx">Exporter</span><span class="p">[</span><span class="kt">uint</span><span class="p">])</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetState</span><span class="p">(</span><span class="nb">uint</span><span class="p">(</span><span class="nx">e</span><span class="p">))</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">EndorserExporterSetter</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">SetId</span><span class="p">(</span><span class="nx">MemberId</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">SetGrade</span><span class="p">(</span><span class="nx">Grade</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">SetAvailableEndorsementCount</span><span class="p">(</span><span class="nx">EndorsementCount</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">SetPendingEndorsementCount</span><span class="p">(</span><span class="nx">EndorsementCount</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">SetVersion</span><span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">SetCreatedAt</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">UintExporter</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">UintExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetState</span><span class="p">(</span><span class="nx">value</span><span class="w"> </span><span class="kt">uint</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="o">*</span><span class="nx">e</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">UintExporter</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Endorser</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">grade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"/> -<span class="w"> </span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"/> -<span class="w"> </span><span class="nx">version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">Export</span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="nx">EndorserExporterSetter</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetId</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetGrade</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">grade</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetAvailableEndorsementCount</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetPendingEndorsementCount</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetVersion</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetCreatedAt</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">createdAt</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">EndorserExporter</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">Id</span><span class="w"> </span><span class="nx">UintExporter</span><span class="w"/> -<span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="nx">UintExporter</span><span class="w"/> -<span class="w"> </span><span class="nx">AvailableEndorsementCount</span><span class="w"> </span><span class="nx">UintExporter</span><span class="w"/> -<span class="w"> </span><span class="nx">PendingEndorsementCount</span><span class="w"> </span><span class="nx">UintExporter</span><span class="w"/> -<span class="w"> </span><span class="nx">Version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">CreatedAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetId</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="nx">MemberId</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">val</span><span class="p">.</span><span class="nx">Export</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ex</span><span class="p">.</span><span class="nx">Id</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetGrade</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="nx">Grade</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">val</span><span class="p">.</span><span class="nx">Export</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ex</span><span class="p">.</span><span class="nx">Grade</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetAvailableEndorsementCount</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">val</span><span class="p">.</span><span class="nx">Export</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ex</span><span class="p">.</span><span class="nx">AvailableEndorsementCount</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetPendingEndorsementCount</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">val</span><span class="p">.</span><span class="nx">Export</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ex</span><span class="p">.</span><span class="nx">PendingEndorsementCount</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetVersion</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="kt">uint</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">Version</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">val</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetCreatedAt</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">CreatedAt</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">val</span><span class="w"/> -<span class="p">}</span><span class="w"/> -</pre></div> -</div> -<p>Или на более лаконичном примере:</p> -<div class="literal-block-wrapper docutils container" id="emacsway-code-exporter-example-2"> -<div class="code-block-caption"><span class="caption-text"><a class="reference external" href="https://stackoverflow.com/questions/24921227/save-and-load-objects-without-breaking-encapsulation">Example from Stackoverflow</a></span></div> -<div class="highlight-java notranslate"><div class="highlight"><pre><span/><span class="w"> </span><span class="kd">interface</span> <span class="nc">PersonImporter</span><span class="w"> </span><span class="p">{</span><span class="w"/> - -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="nf">getAge</span><span class="p">();</span><span class="w"/> - -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">getId</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="kd">interface</span> <span class="nc">PersonExporter</span><span class="w"> </span><span class="p">{</span><span class="w"/> - -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">setDetails</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">age</span><span class="p">);</span><span class="w"/> - -<span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="kd">class</span> <span class="nc">Person</span><span class="w"> </span><span class="p">{</span><span class="w"/> - -<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">age</span><span class="p">;</span><span class="w"/> -<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">id</span><span class="p">;</span><span class="w"/> - -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="nf">Person</span><span class="p">(</span><span class="n">PersonImporter</span><span class="w"> </span><span class="n">importer</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="n">age</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">importer</span><span class="p">.</span><span class="na">getAge</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">importer</span><span class="p">.</span><span class="na">getId</span><span class="p">();</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">export</span><span class="p">(</span><span class="n">PersonExporter</span><span class="w"> </span><span class="n">exporter</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="n">exporter</span><span class="p">.</span><span class="na">setDetails</span><span class="p">(</span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">age</span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="p">}</span><span class="w"/> -</pre></div> -</div> -</div> -<p>Замечательный вариант, но проблема в том, что он использует интерефейсы, и это получается слишком многословно - требуется декларировать сам тип (структуру), интерфейс, сеттеры. -Вряд ли кто-то будет этим заниматься, когда можно просто обязать Агрегат вернуть простую структуру.</p> -<blockquote> -<div><p>💬️ "Цель архитектуры программного обеспечения — уменьшить человеческие трудозатраты на создание и сопровождение системы.</p> -<p>The goal of software architecture is to minimize the human resources required to build and maintain the required system."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin, перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p><a class="reference internal" href="#emacsway-code-exporter-example-2"><span class="std std-ref">Второй</span></a> из приведенных примеров содержит пакетированный сеттер, что делает его несколько менее многословным. -Этот вариант уступает первому варианту тем, что в случае одноименного метода <code class="docutils literal notranslate"><span class="pre">setDetails</span></code> нельзя обойти одним экспортером сразу несколько вложенных объектов, например, агрегат и его композитный первичный ключ, что может быть удобным для составления списка параметров SQL-запроса. -В таком случае придется жертвовать консистентностью именования, что лишает второй вариант превосходств перед первым вариантом. -Также второй вариант обладает несколько большей хрупкостью при добавлении новых полей, либо их удалении.</p> -<p>Немного смущает смешивание парадигм FP и OOP для ValueObject. -Хотя ValueObject и остается неизменяемым, но сам факт того, что функционально чистый объект вызывает мутирующие методы другого объекта, вызывает небольшое смущение. -Возникает вопрос - почему функционально чистый объект не может просто взять и вернуть другой функционально чистый объект? -Если бы Golang поддерживать Generics для методов, тогда могло бы получиться что-то похожее на <code class="docutils literal notranslate"><span class="pre">Endorser.Export[T](exporterFactory</span> <span class="pre">function(attr1,</span> <span class="pre">attr2,</span> <span class="pre">attr3)</span> <span class="pre">T)</span> <span class="pre">T</span></code>. -Однако, если продолжить развивать эту мысль, то мы обнаружим, что таким образом пытаемся решить проблему обхода инкапсуляции, которая вызвана именно применением OOP.</p> -<p>Как говорил Michael Feathers:</p> -<blockquote> -<div><p>💬️ "OO makes code understandable by encapsulating moving parts. -FP makes code understandable by minimizing moving parts." -— <a class="reference external" href="https://twitter.com/mfeathers/status/29581296216">Michael Feathers</a></p> -</div></blockquote> -<p>Использование такого подхода в тестовых кейсах делает их несколько более многословными.</p> -<p>Можно было бы сказать, что тестировать нужно по принципам <a class="reference internal" href="../../../tdd/tdd.html#emacsway-tdd-black-box"><span class="std std-ref">черного ящика</span></a>, т.е. только внешнее поведение. -Совершенно верно, но только нам требуется не только внешнее поведение, но и достоверность сохранения введенной в конструктор Агрегата информации в БД.</p> -<blockquote> -<div><p>💬️ "Давно известно, что простота тестирования является характерным признаком хорошей архитектуры. -Шаблон «Скромный объект» — хороший пример, потому что раздел между легко и тяжело тестируемыми частями часто совпадает с архитектурными границами. -Раздел между Презентаторами и Представлениями — одна из таких границ, но существует много других.</p> -<p>It has long been known that testability is an attribute of good architectures. -The Humble Object pattern is a good example, because the separation of the behaviors into testable and non-testable parts often defines an architectural boundary. -The Presenter/View boundary is one of these boundaries, but there are many others."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin, перевод ООО Издательство "Питер"</p> -</div></blockquote> -</section> -<section id="returning-structure"> -<h3><a class="toc-backref" href="#id11" role="doc-backlink">2. Returning structure</a></h3> -<p>Возникает целесообразность облегчить метод экспортирования, придав ему сигнатуру <code class="docutils literal notranslate"><span class="pre">Endorser.Export()</span> <span class="pre">EndorserState</span></code> вместо <code class="docutils literal notranslate"><span class="pre">Endorser.ExportTo(ex</span> <span class="pre">EndorserExporter)</span></code>. -Получится что-то типа DTO с тем лишь отличием, что он пересекает не сетевые границы, а границы инкапсуляции Агрегата. -В Golang этот вариант выглядит чуть более привлекательным, хотя и менее OOP, но зато не контрастирует с FP принципами Value Object.</p> -<p>О таком же принципе этом писал Robert C. Martin:</p> -<blockquote> -<div><p>💬️ "Презентаторы являются разновидностью шаблона проектирования «Скромный объект» (Humble Object), помогающего выявлять и защищать архитектурные границы.</p> -<p>Presenters are a form of the Humble Object pattern, which helps us identify and protect architectural boundaries."</p> -<p>💬️ "Обычно через границы данные передаются в виде простых структур. -При желании можно использовать простейшие структуры или объекты передачи данных (Data Transfer Objects; DTO). -Данные можно также передавать в вызовы функций через аргументы. -Или упаковывать их в ассоциативные массивы или объекты. -Важно, чтобы через границы передавались простые, изолированные структуры данных. -Не нужно хитрить и передавать объекты сущностей или записи из базы данных. -Структуры данных не должны нарушать правило зависимостей.</p> -<p>Например, многие фреймворки для работы с базами данных возвращают ответы на запросы в удобном формате. -Их можно назвать «представлением записей». -Такие представления записей не должны передаваться через границы внутрь. -Это нарушает правило зависимостей, потому что заставляет внутренний круг знать что-то о внешнем круге. -Итак, при передаче через границу данные всегда должны принимать форму, наиболее удобную для внутреннего круга.</p> -<p>Typically the data that crosses the boundaries consists of <strong>simple data structures</strong>. -You can use <strong>basic structs or simple data transfer objects</strong> if you like. -Or the data can simply be arguments in function calls. -Or you can pack it into a hashmap, or construct it into an object. -The important thing is that isolated, <strong>simple data structures</strong> are passed across the boundaries. -We don't want to cheat and pass Entity objects or database rows. -We don't want the data structures to have any kind of dependency that violates the Dependency Rule.</p> -<p>For example, many database frameworks return a convenient data format in response to a query. -We might call this a "row structure." -We don't want to pass that row structure inward across a boundary. -Doing so would violate the Dependency Rule because it would force an inner circle to know something about an outer circle.</p> -<p>Thus, when we pass data across a boundary, it is always in the form that is most convenient for the inner circle."</p> -<p>💬️ "Он также переносит данные из базы данных Database в память сущностей Entities через интерфейс DataAccessInterface. -По завершении UseCaseInteractor забирает данные из сущностей Entities и конструирует из них другой простой Java-объект OutputData. -Затем объект OutputData передается через интерфейс OutputBoundary презентатору Presenter.</p> -<p>It also uses the DataAccessInterface to bring the data used by those Entities into memory from the Database. -Upon completion, the UseCaseInteractor gathers data from the Entities and constructs the OutputData as another <strong>plain old Java object</strong>. -The OutputData is then passed through the OutputBoundary interface to the Presenter."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin, перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>Этот подход демонстрируется в <a class="reference external" href="https://github.com/EventStore/training-advanced-go/blob/9cc2b5a4f3484dc643757c88480c4b6e371149fd/domain/doctorday/day.go#L225">Golang DDD ES/CQRS Reference Application</a> от контрибьюторов EventStore.</p> -<p>И такой же подход демонстрирует Nick Tune в <a class="reference external" href="https://github.com/elbandit/PPPDDD/blob/4d9d864fa6d9dfc0bad323ae21e949be1808b460/21%20-%20Repositories/DDDPPP.Chap21.EFExample/DDDPPP.Chap21.EFExample.Application/Model/Auction/Auction.cs#L48">демонстрационном коде</a> к своей книге. -Причем, применяет он его даже <a class="reference external" href="https://github.com/elbandit/PPPDDD/blob/4d9d864fa6d9dfc0bad323ae21e949be1808b460/21%20-%20Repositories/DDDPPP.Chap21.EFExample/DDDPPP.Chap21.EFExample.Application/Model/Auction/Money.cs#L58">для Value Object</a>.</p> -<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kn">package</span><span class="w"> </span><span class="nx">grade_2</span><span class="w"/> - -<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"time"</span><span class="w"/> -<span class="p">)</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Exportable</span><span class="p">[</span><span class="nx">T</span><span class="w"> </span><span class="kt">any</span><span class="p">]</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">Export</span><span class="p">()</span><span class="w"> </span><span class="nx">T</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="p">)</span><span class="w"> </span><span class="nx">Export</span><span class="p">()</span><span class="w"> </span><span class="kt">uint</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">uint</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">EndorserState</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">Id</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">AvailableEndorsementCount</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">PendingEndorsementCount</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">Version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">CreatedAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Endorser</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">grade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"/> -<span class="w"> </span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"/> -<span class="w"> </span><span class="nx">version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">Export</span><span class="p">()</span><span class="w"> </span><span class="nx">EndorserState</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">EndorserState</span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">id</span><span class="p">.</span><span class="nx">Export</span><span class="p">(),</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">grade</span><span class="p">.</span><span class="nx">Export</span><span class="p">(),</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="p">.</span><span class="nx">Export</span><span class="p">(),</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="p">.</span><span class="nx">Export</span><span class="p">(),</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="p">,</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">createdAt</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="p">}</span><span class="w"/> -</pre></div> -</div> -<p>Недостатком такого решения, который я успел обнаружить, является то, что клиент не имеет возможности контролировать структуру экспортируемого объекта, в отличии от варианта с интерфейсом. -Это затрудняет создание обобщенных классов, например, <a class="reference external" href="https://martinfowler.com/eaaCatalog/identityField.html">обобщенного композитного первичного ключа</a>. -В результате плодятся промежуточные структуры, которые затем нужно преобразовывать к нужному виду.</p> -<p>Знание о возвращаемом типе подталкивает к применению generics там, где этого несложно избежать.</p> -<p>Возвращаемая структура и ее типизация является избыточным знанием, которое может препятствовать обобщению (абстрагированию) клиента этого метода, например, препятствовать выделению абстрактного класса паттерна Repository. -Гораздо удобней в таком случае был бы массив/срез объектов с типом <a class="reference external" href="https://pkg.go.dev/database/sql/driver#Value">driver.Value</a>. -Это еще один аргумент в пользу первого варианта с отдельными сеттерами для каждого атрибута Агрегата.</p> -<p>Попробовав оба варианта, я остановился, все-таки, на первом, каноническом, даже несмотря на его многословность.</p> -</section> -</section> -Sun, 30 Jul 2023 00:00:00 Event Storming with Archihttps://dckms.github.io/system-architecture/emacsway/it/ddd/ddd-in-practice/event-storming/archi.html -<span id="emacsway-event-storming-archi"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> -<ul class="simple"> -<li><p><a class="reference internal" href="#event-storming-with-archi" id="id11">Event Storming with Archi</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id12">Обзор инструментов</a></p></li> -<li><p><a class="reference internal" href="#archi" id="id13">Archi</a></p></li> -<li><p><a class="reference internal" href="#archi-event-storming" id="id14">Достоинства Archi для Event Storming</a></p></li> -<li><p><a class="reference internal" href="#id3" id="id15">Недостатки</a></p> -<ul> -<li><p><a class="reference internal" href="#git" id="id16">Средствами Git</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id17">Штатный механизм слияния модели</a></p></li> -<li><p><a class="reference internal" href="#id5" id="id18">Избегание конфликтов</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#id6" id="id19">Установка</a></p></li> -<li><p><a class="reference internal" href="#id7" id="id20">Определение границ микросервисов</a></p></li> -<li><p><a class="reference internal" href="#id8" id="id21">Интеграция</a></p> -<ul> -<li><p><a class="reference internal" href="#id9" id="id22">Генерация документации</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#id10" id="id23">Стикеры</a></p></li> -<li><p><a class="reference internal" href="#c4-model" id="id24">C4 Model</a></p></li> -<li><p><a class="reference internal" href="#archimatetool-troubleshooting" id="id25">Archimatetool troubleshooting</a></p></li> -</ul> -</li> -</ul> -</nav> -<section id="id2"> -<h2><a class="toc-backref" href="#id12" role="doc-backlink">Обзор инструментов</a></h2> -<p><a class="reference external" href="https://github.com/tmorin/plantuml-libs/blob/master/distribution/eventstorming/README.md">PlantUML</a> достаточно быстро исчерпал свои возможности и диаграммы стали нечитаемыми и неуправляемым. -Попытки выровнять диаграмму штатными средствами оказались безуспешниыми. -На разных серверах диаграмма отображалась по-разному.</p> -<p>Сервис Miro вынуждает архитектурно-значимую информацию покидать периметр безопасности, образует лицензионную зависимость и находится под давлением геополитических факторов. -Как и PlantUML, не позволяет находить границы микросервисов ввиду <a class="reference external" href="https://c4model.com/#Modelling">отсутствия в нем модели</a>.</p> -<p>Неплохие надежды подает <a class="reference external" href="https://domorobo.to/">domorobo.to</a>, но он пока еще сыроват.</p> -</section> -<section id="archi"> -<h2><a class="toc-backref" href="#id13" role="doc-backlink">Archi</a></h2> -<p>В процессе поиска внимание привлекла внимание диаграмма на "Figure 13: Event Storming Model" of "Agile Architecture Modeling Using the ArchiMate® Language" (см. <a class="reference external" href="https://publications.opengroup.org/g20e">здесь</a>, <a class="reference external" href="https://nicea.nic.in/sites/default/files/Agile_Architecture_Modelling_Using_Archimate.pdf">здесь</a> или <a class="reference external" href="https://nicea.nic.in/download-files.php?nid=247">здесь</a>).</p> -<p><a class="reference external" href="https://community.opengroup.org/archimate-user-community/home/-/issues/8">Model used by Jean-Baptiste Sarrodie for presentation "Enterprise Architecture Modelling with ArchiMate in an Agile at Scale Programme"</a></p> -<p>Попробовал сделать Event Storming в Archi, и обнаружил, что он делается с такой же легкостью, как и в Miro. -Разве что для публикации своих изменений другим участникам нужно сделать 5 кликов мышкой. -Технически, это можно автоматизировать по регулярному расписанию, используя <a class="reference external" href="https://www.archimatetool.com/plugins/">jArchi</a>. -А вот изменения других участников уже и так подтягиваются по настраиваемому регулярному расписанию фоновым процессом.</p> -<p>Нотации (т.е. цвета) Event Storming практически идентичны нотациям "<a class="reference external" href="https://pubs.opengroup.org/architecture/archimate31-doc/apdxc.html#_Toc10045506">C.1.10 Business Process Cooperation Viewpoint</a>".</p> -</section> -<section id="archi-event-storming"> -<h2><a class="toc-backref" href="#id14" role="doc-backlink">Достоинства Archi для Event Storming</a></h2> -<ol class="arabic simple"> -<li><p>On-Premise. Архитектурно-значимая информация не покидает закрытый периметр безопасности.</p></li> -<li><p>Open Source under MIT License</p></li> -<li><p>Наличие модели позволяет:</p> -<ol class="arabic simple"> -<li><p>Определять границы не только Ограниченных Контекстов, но и Микросервисов. Это является следствием наличия модели и возможности классифицировать связи, выделять из них связи, образующие Сoupling &amp; Сohesion, и с математической точностью определять наилучшую форму границ микросервисов.</p></li> -<li><p>Рассматривать любой элемент диаграммы в различных представлениях, например, мгновенно перейти с Context Map на Event Storming. См. вкладку "Properties" выбранного элемента, секция "Analisis".</p></li> -<li><p>Отслеживать трассировку как до выбранного элемента, так и после него. См. окно Window-Navigator и две кнопки: "Show target relations" и "Show source relations".</p></li> -<li><p>При разбиении большой диаграммы на части по некому признаку (например, по базовым сценариям использования), изменение в одной диаграмме (например, изменение целевого элемента связи) будет автоматически отражено на всех остальных диаграммах, что удешевляет сопровождение таких диаграмм. А при добавлении нового элемента из модели в диаграмму, вместе с ним добавляются и все существующие в модели его связи к уже добавленным в диаграмму элементам.</p></li> -</ol> -</li> -<li><p>Использование Git открывает следующие возможности:</p> -<ol class="arabic simple"> -<li><p>Историрование. Возможность восстановления одного из предыдущих состояний. Журналирование изменений.</p></li> -<li><p>Версионирование и ответвления - параллельная разработка различных версий решения.</p></li> -<li><p>Коллективная разработка. Доступ к информации задается обычной конфигурацией git-сервера (обычно средствами GitHub и GitLab).</p></li> -</ol> -</li> -<li><p>Использование <a class="reference external" href="https://pubs.opengroup.org/architecture/archimate31-doc/chap06.html#_Toc10045334">Motivation Elements</a> (Stakeholder, Driver, Assessment, Goal, Outcome, Principle, Requirement, and Constraint) позволяет осуществлять визуализацию факторов влияния на решение, а также фиксацию трассировки требований. -Возможность воплощения принципов <a class="reference external" href="https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=6470589">Twin Peak Model</a>. -В процессе проработки одной из альтернатив, обнаруживаются ее ограничения и новые драйверы, которые влияют на требования. -В визуальном виде аналитическая информация воспринимается намного легче, чем обычная свалка требований в PBI.</p></li> -<li><p>Богатое интеграционное API позволяет использовать модель для автоматизированной её сверки с реализацией или для генерации кода.</p></li> -<li><p>В <a class="reference external" href="https://www.archimatetool.com/blog/2020/04/18/c4-model-architecture-viewpoint-and-archi-4-7/">Archi можно также делать C4 Model</a>, используя единую модель и для C4 Model, и для Event Storming.</p></li> -<li><p><a class="reference external" href="https://community.opengroup.org/archimate-user-community/home/-/issues/8">В Archi можно сделать Context Map</a>, используя единую модель с Event Storming.</p></li> -</ol> -</section> -<section id="id3"> -<h2><a class="toc-backref" href="#id15" role="doc-backlink">Недостатки</a></h2> -<p>Резольв конфликта слияния через GUI для каждой отдельной диаграммы возможен только путем выбора одной из двух версии целиком - либо своей, либо сливаемой. -При просмотре версий диаграммы их различия никак визуально не выделяются и не подсвечиваются.</p> -<p>Сама модель сохраняется в файл <code class="docutils literal notranslate"><span class="pre">.git/temp.archimate</span></code>. -Преобразуется она в файлы Git репозитория только в момент коммита. -Этот момент нужно учитывать, т.к. изменения модели в Archi не отражаются мгновенно в файлах Git репозитория и, наоборот, изменения в файлах Git репозитория не отражаются мгновенно в модели Archi.</p> -<p>Мне известны два способа слить диаграммы в случае конфликта без утраты изменений обоих её версий.</p> -<section id="git"> -<h3><a class="toc-backref" href="#id16" role="doc-backlink">Средствами Git</a></h3> -<p>Резольва конфликта слияния средствами Git <a class="reference external" href="https://github.com/archi-contribs/archi-grafico-plugin/wiki/Merge-two-(or-more)-models">на уровне текстовых файлов</a>" (см. описание <a class="reference external" href="https://github.com/archi-contribs/archi-grafico-plugin/wiki/GRAFICO-explained">GRAFICO format</a>). -Не самый простой, но самый действенный вариант. -Впрочем, к нему быстро привыкаешь.</p> -<p>Чаще всего конфликты возникают в файлах диаграмм (Views), и их резольв усложняется тем, что в них присутствуют только идентификаторы конфликтующих элементоа. -И эти идентификаторы не сообщают никакой информации о своих элементах. -Чтобы определить смысл элемента по его идентификатору, можно предварительно (т.к. в процессе слияния элемент может быть уже удален из модели) заэкспортировать модель в *.CSV файлы. -Как вариант, можно также сохранить модель в *.archimate файл, если модель относительно небольшая, и затем использовать поиск по файлу. -Можно создать копию файловой структуры Git репозитория перед слиянием и грепать по её файлам.</p> -</section> -<section id="id4"> -<h3><a class="toc-backref" href="#id17" role="doc-backlink">Штатный механизм слияния модели</a></h3> -<p>Сохраняем модель одного бранча в *.archimate файл, а затем импортируем её в выбранную модель другого бранча. -Этот вариант дает меньше контроля над процессом слияния, но и уменьшает вероятность допущения ошибки.</p> -</section> -<section id="id5"> -<h3><a class="toc-backref" href="#id18" role="doc-backlink">Избегание конфликтов</a></h3> -<p>Резольв конфликта в Archi нетривиальный, и лучше его избегать. -На практике обычно кто-то один управляет доской в один момент времени, и, в случае необходимости, передает управление другому участнику.</p> -<p>Частые интеграции и блокировки организационными мерами позволяют снизить вероятность возникновения конфликта.</p> -</section> -</section> -<section id="id6"> -<h2><a class="toc-backref" href="#id19" role="doc-backlink">Установка</a></h2> -<p>Дистрибутив: <a class="reference external" href="https://www.archimatetool.com/download/">https://www.archimatetool.com/download/</a></p> -<p><a class="reference external" href="https://www.archimatetool.com/downloads/Archi%20User%20Guide.pdf">Документация</a> Archi.</p> -<p>Плагин коллективной разработки <a class="reference external" href="https://www.archimatetool.com/plugins/#coArchi">coArchi</a> (<a class="reference external" href="https://github.com/archimatetool/archi-modelrepository-plugin">Source Code</a>). <a class="reference external" href="https://github.com/archimatetool/archi-modelrepository-plugin/wiki">Документация</a> к плагину.</p> -<p>Актуальное <a class="reference external" href="https://github.com/archimatetool/archi-modelrepository-plugin/wiki/SSH-Authentication">руководство по генерации RSA-ключей</a>.</p> -</section> -<section id="id7"> -<h2><a class="toc-backref" href="#id20" role="doc-backlink">Определение границ микросервисов</a></h2> -<p>Изначально мы допускаем, что один микросервис == один агрегат. -Находим "болтливые" микросервисы. -Пробуем объединить болтливые микросервисы в общий микросервис и сравниваем, как изменились совокупный Coupling (внешние связи микросервиса(ов)) &amp; Cohesion (к-т реиспользования агрегатов внутри одного микросервиса). -Например, если у нас совокупный Coupling упал на 5 единиц, при этом Cohesion возрос, то объединение микросервисов оправдано.</p> -<p>Для этого, в каждом микросервисе выделяем отдельную директорию _coupling и _cohesion. -А также создаем отдельную директорию для каждого агрегата и связанной с ним логикой (той самой, которая будет вынесена из текущего микросервиса вместе с агрегатом, если такое понадобится, например, все представления (ReadModels) агрегата).</p> -<p>Дополнительная информация:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="http://www.sdml.cs.kent.edu/library/Allen99.pdf">Measuring Coupling and Cohesion: An Information Theory Approach</a>" by Edward B. Allen, Taghi M. Khoshgoftaar, Florida, Atlantic University Boca Raton, Florida USA</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/model/domain-analysis">Using domain analysis to model microservices</a>"</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/model/microservice-boundaries">Identifying microservice boundaries</a>"</p></li> -<li><p>"<a class="reference external" href="https://vladikk.com/2018/01/21/bounded-contexts-vs-microservices/">Bounded Contexts are NOT Microservices</a>" by Vladik Khononov</p></li> -<li><p>"<a class="reference external" href="https://vladikk.com/2018/02/28/microservices/">Tackling Complexity in Microservices</a>" by Vladik Khononov</p></li> -<li><p>"Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy" 1st Edition by Vlad Khononov</p></li> -<li><p>"Balancing Coupling in Software Design: Successful Software Architecture in General and Distributed Systems" by Vladislav Khononov</p></li> -</ul> -</section> -<section id="id8"> -<h2><a class="toc-backref" href="#id21" role="doc-backlink">Интеграция</a></h2> -<p>Из коробки Archi уже поддерживает экспорт модели в *.CSV файл.</p> -<p>Существует ряд плагинов, которые облегчают интеграцию:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://www.archimatetool.com/plugins/#exArchi">https://www.archimatetool.com/plugins/#exArchi</a></p></li> -<li><p><a class="reference external" href="https://github.com/archi-contribs/script-plugin">https://github.com/archi-contribs/script-plugin</a></p></li> -<li><p><a class="reference external" href="https://github.com/archi-contribs/database-plugin">https://github.com/archi-contribs/database-plugin</a></p></li> -</ul> -<p>С помощью этих плагинов Archi позволяет выгружать свою модель в RDBMS, в Excel, а также позволяет обращаться к модели через консольный интерфейс, используя SQL-подобный синтаксис.</p> -<p>С помощью этих плагинов очень легко генерировать PBI, Acceptance Criteria, BDD-specification или тестовые кейсы из <a class="reference external" href="https://pubs.opengroup.org/architecture/archimate31-doc/chap06.html#_Toc10045345">требований</a> модели, а из диаграммы Event Storming и C4 Model - генерировать код микросервисов или автоматизировать сверку модели с кодом.</p> -<p>Archimatetool использует Grafico format файлов:</p> -<blockquote> -<div><p>📝 "GRAFICO stands for "Git Friendly Archi File Collection" and is a way to persist an ArchiMate model in a bunch of XML files (one file per ArchiMate element or view)."</p> -<p class="attribution">—<a class="reference external" href="https://github.com/archi-contribs/archi-grafico-plugin/wiki/GRAFICO-explained">https://github.com/archi-contribs/archi-grafico-plugin/wiki/GRAFICO-explained</a></p> -</div></blockquote> -<section id="id9"> -<h3><a class="toc-backref" href="#id22" role="doc-backlink">Генерация документации</a></h3> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://habr.com/ru/post/583314/">Автоматизируем работу с ArchiMate в CI пайплайнах</a>" / Maxim Levchenko</p></li> -<li><p><a class="reference external" href="https://hub.docker.com/r/woozymasta/archimate-ci-image">Docker container</a> и <a class="reference external" href="https://github.com/marketplace/actions/deploy-archi-report">GH Action</a> для публикации Archimate модели на <a class="reference external" href="https://woozymasta.github.io/archimate-ci-image-example/?view=6875">GitHub</a>/<a class="reference external" href="https://woozymasta.gitlab.io/archimate-ci-image-example/?view=6213">GitLab</a> Pages. <a class="reference external" href="https://github.com/WoozyMasta/archimate-ci-image">Source Code</a>.</p></li> -<li><p><a class="reference external" href="https://github.com/abes-esr/archi-htmlreport-docker">archi-htmlreport-docker</a> (<a class="reference external" href="https://github.com/abes-esr/archi-model-example">example</a>)</p></li> -<li><p><a class="reference external" href="https://hub.docker.com/search?q=ArchiMate">Others...</a></p></li> -</ul> -</section> -</section> -<section id="id10"> -<h2><a class="toc-backref" href="#id23" role="doc-backlink">Стикеры</a></h2> -<p>В Archi есть <a class="reference external" href="https://devlog.archimatetool.com/2010/11/04/sketch/">доска со стикерами</a> (см. New Sketch View на <a class="reference external" href="https://www.archimatetool.com/downloads/Archi%20User%20Guide.pdf">стр. 110 документации</a>).</p> -<p>Можно делать Event Storming обычными стикерами, а не только используя "<a class="reference external" href="https://t.me/emacsway_log/253">C.1.10 Business Process Cooperation Viewpoint</a>".</p> -<p>Можно проводить сеанс Example Mapping и автоматизировать генерацию BDD-specification или тестовых кейсов.</p> -</section> -<section id="c4-model"> -<h2><a class="toc-backref" href="#id24" role="doc-backlink">C4 Model</a></h2> -<p>Event Storming гармонично сочетается с C4 Model, о чем говорил Сергей Баранов в своем <a class="reference external" href="https://habr.com/ru/company/oleg-bunin/blog/537862/">докладе</a>. -И вот тут еще одно интересное открытие - Simon Brown собственноручно <a class="reference external" href="https://c4model.com/">ссылается</a> на статью Jean-Baptiste Sarrodie о том, <a class="reference external" href="https://www.archimatetool.com/blog/2020/04/18/c4-model-architecture-viewpoint-and-archi-4-7/">как делать C4 Model в Archi</a>.</p> -<p>Там же Simon Brown ссылается на Guide <a class="reference external" href="https://publications.opengroup.org/g20e">Agile Architecture Modeling Using the ArchiMate® Language</a> на сайте OMG о том, как использовать C4 Model и Event Storming в Open Agile Architecture, используя Archi. -Jean-Baptiste Sarrodie собственноручно выложил <a class="reference external" href="https://community.opengroup.org/archimate-user-community/home/-/issues/8">демонстрационную модель C4 Model и Event Storming в Archi</a>.</p> -</section> -<section id="archimatetool-troubleshooting"> -<h2><a class="toc-backref" href="#id25" role="doc-backlink">Archimatetool troubleshooting</a></h2> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://github.com/archimatetool/archi/blob/master/com.archimatetool.editor/src/com/archimatetool/editor/model/messages.properties">Список ошибок</a>"</p></li> -<li><p>Расположение незакоммиченной, но сохраненной модели: <code class="docutils literal notranslate"><span class="pre">.git/temp.archimate</span></code>.</p></li> -<li><p>"<a class="reference external" href="https://github.com/archimatetool/archi/wiki/Archi-4.7-%28or-superior%29-can%27t-save-a-model-or-%28if-using-coArchi%29-can%27t-import%2C-refresh-or-publish-a-model-but-instead-gives-%22Error-in-model%22">Archi 4.7 (or superior) can't save a model or (if using coArchi) can't import, refresh or publish a model but instead gives "Error in model"</a>"</p></li> -</ul> -</section> -Tue, 04 Jul 2023 00:00:00 Repository and Causal Consistencyhttps://dckms.github.io/system-architecture/emacsway/it/ddd/tactical-design/repository/causal-consistency.html -<span id="emacsway-repository-in-causal-consistency"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> -<ul class="simple"> -<li><p><a class="reference internal" href="#repository-and-causal-consistency" id="id6">Repository and Causal Consistency</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id7">Контекст</a></p></li> -<li><p><a class="reference internal" href="#id3" id="id8">Варианты решений</a></p> -<ul> -<li><p><a class="reference internal" href="#bounded-context" id="id9">Версионирование состояния Bounded Context</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id10">Отдельная версия на Событие</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#id5" id="id11">Вывод</a></p></li> -</ul> -</li> -</ul> -</nav> -<section id="id2"> -<h2><a class="toc-backref" href="#id7" role="doc-backlink">Контекст</a></h2> -<p>Версия агрегата часто используется для организации "<a class="reference external" href="https://martinfowler.com/eaaCatalog/optimisticOfflineLock.html">Optimistic Offline Lock</a>". -С этой целью она обычно инкрементируется однократно на одну транзакцию, даже если при этом было создано несколько Domain Events (при их <strong>in-process обработке</strong>).</p> -<p>Иначе дело обстоит в Event Sourced Aggregate, где версия инкрементируется на каждое Доменное Событие, поскольку она определяет положение этого События в потоке/журнале Событий. -Взаимосвязанные События для обеспечения атомарности в таком случае помечаются идентификатором запроса в виде CorrelationId.</p> -<p>Проблема заключается в том, что если мы хотим сделать Domain Events публичными и отправить их в шину, либо сформировать на их основе Integration Events, то существует риск нарушения очередности их доставки.</p> -<p>Более подробно эта тема раскрывается в заметке "<a class="reference internal" href="../../../integration/asynchronous/message-ordering-in-competing-consumers.html#emacsway-message-ordering"><span class="std std-ref">О гонке сообщений в условиях конкурирующих подписчиков</span></a>".</p> -<p>Причин нарушения очередности доставки может быть несколько. -Например, <a class="reference external" href="https://learn.microsoft.com/en-us/azure/architecture/patterns/competing-consumers">Конкурирующие Подписчики</a>. -В таком случае проблема решается обычно партиционированием каналов шины, используя идентификатор агрегата для вычисления партиции, таким образом направляя все сообщения одного агрегата к единственному обработчику, устраняя петлю в топологии маршрута сообщений, а значит, устраняя условия для возникновения гонки сообщений.</p> -<p>Однако, не все шины поддерживают партиционирование каналов, либо эта поддержка оставляет желать лучшего. -Кроме того, в интервью "<a class="reference external" href="https://www.infoq.com/articles/modeling-uncertainty-reactive-ddd/">Modeling Uncertainty with Reactive DDD</a>" by Vaughn Vernon reviewed by Thomas Betts, Vaughn Vernon утверждает, что это не спасает.</p> -<p>В книге "Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" Vaughn Vernon объясняет почему: петля может быть образована не только конкурирующими подписчиками, но и самой топологией маршрутов сообщений. -Грубо говоря, если для одного сообщения у нас маршрут A-&gt;C а для другого A-B-&gt;C, то гонка уже не исключена.</p> -<p>В этой же книге Vaughn Vernon отсылает за решением к статьям:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">Don't Settle for Eventual Consistency. Stronger properties for low-latency geo-replicated storage.</a>" (<a class="reference external" href="https://dl.acm.org/ft_gateway.cfm?id=2610533&amp;ftid=1449165&amp;dwn=1">pdf</a>) by Wyatt Lloyd, Facebook; Michael J. Freedman, Princeton University; Michael Kaminsky, Intel Labs; David G. Andersen, Carnegie Mellon University</p></li> -<li><p>"<a class="reference external" href="http://www.bailis.org/papers/bolton-sigmod2013.pdf">Bolt-on Causal Consistency</a>" by Peter Bailis, Ali Ghodsi, Joseph M. Hellerstein†, Ion Stoica, UC Berkeley KTH/Royal Institute of Technology</p></li> -</ul> -<p>Рассмотрим классический пример. Глава родительского комитета школьного класса удалил классного руководителя из группы рассылки (E1), разослал всем оставшимся сообщение о сборе денег на подарок классному руководителю (E2), и вернул классного руководителя назад (E3).</p> -<p>Вот теперь давайте представим, что произойдет, если событие E1 где-то задержалось в шине, и было обработано после E2.</p> -<p>Решение сводится к организации <a class="reference external" href="https://jepsen.io/consistency/models/causal">Causal Consistency</a> посредством векторных часов, используя версию агрегата в качестве их значения. -Каждое сообщение снабжается списком своих Causal Dependencies.</p> -<p>И здесь обнажается проблема, т.к. при инкрементировании версии агрегата единожды на транзакцию, возникает риск образования более одного публичного Доменного События с одной и той же версией Агрегата. -А это означает, что версию Агрегата не получится использовать для восстановления очередности Событий.</p> -</section> -<section id="id3"> -<h2><a class="toc-backref" href="#id8" role="doc-backlink">Варианты решений</a></h2> -<section id="bounded-context"> -<h3><a class="toc-backref" href="#id9" role="doc-backlink">Версионирование состояния Bounded Context</a></h3> -<p>Для указания последовательности События можно использовать порядковый номер механизма доставки, например, автоинкрементальный первичный ключ таблицы Outbox внутри Bounded Context.</p> -<p>Недостатком такого решения является существенное понижение уровня параллелизма вплоть до Sequential Consistency.</p> -<p>Другим недостатком такого решения является трудоемкость миграции <a class="reference internal" href="../domain-model/domain-events/domain-events-in-ddd.html#emacsway-domain-event"><span class="std std-ref">с in-process обработки Доменных Событий на out-of-process</span></a>.</p> -</section> -<section id="id4"> -<h3><a class="toc-backref" href="#id10" role="doc-backlink">Отдельная версия на Событие</a></h3> -<p>Поскольку Доменное Событие является фактом изменения состояния Агрегата, логично предположить, что образование каждого нового События должно инкрементировать версию Агрегата, как это общепринято в Event Sourced Agregate.</p> -<p>Несущественным недостатком такого решения является усложнение реализации оптимистической блокировки, поскольку инкрементация теперь происходит вне SQL-запроса. -Критерий выборки обновляемой строки теперь будет вычисляться как математическая разница версии Агрегата и количества Доменных Событий в нем.</p> -<p>Несколько сложнее дело обстоит с объединением (пакетированием) SQL-запросов, сформированных не из состояния агрегата, а из доменных событий, т.к. версия агрегата сдвигается с каждым запросом. -Но этот вопрос тоже несущественный, и легко решается вынесением оптимистической блокировки в отдельный (либо в объединенный, при отсутствии изменения вложенных сущностей) SQL-запрос.</p> -<p>К достоинствам такого решения можно отнести простоту миграции <a class="reference internal" href="../domain-model/domain-events/domain-events-in-ddd.html#emacsway-domain-event"><span class="std std-ref">с in-process обработки Доменных Событий на out-of-process</span></a>, поскольку интерфейс событий остается неизменным.</p> -</section> -</section> -<section id="id5"> -<h2><a class="toc-backref" href="#id11" role="doc-backlink">Вывод</a></h2> -<p>Вариант с инкрементацией версии Агрегата на каждое Доменное Событие выглядит более приемлемым решением.</p> -</section> -Tue, 04 Jul 2023 00:00:00 Shotgun Surgeryhttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/shotgun-surgery.html -<span id="index-0"/> -<p>Может показаться, что используя Raw-SQL мы обретаем классифицированный Code Smell, известный как Shotgun Surgery (Разлет Дроби), ибо добавление одного поля в Сущность требует правки многих файлов. -Есть два способа решить эту проблему (и снизить Coupling), о которых писал Martin Fowler в главе "Metadata Mapping" книги "Patterns of Enterprise Application Architecture": "reflective program" и "code generation", причем, сам он лично предпочитает второй вариант:</p> -<blockquote> -<div><p>Generated code is more explicit so you can see what's going on in the debugger; -as a result I usually prefer generation to reflection, -and I think it's usually easier for less sophisticated developers -(which I guess makes me unsophisticated).</p> -<p class="attribution">—"Patterns of Enterprise Application Architecture" by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford</p> -</div></blockquote> -<p>Подавляющее большинство ORM использует "reflective program", в то время, как в Golang-сообществе традиционно широко применяется в практике "code generation".</p> -<p>В данном проекте, на определенном этапе развития, появится инструмент кодогенерации по образу <a class="reference external" href="https://github.com/kyleconroy/sqlc">sqlc</a>.</p> -Mon, 03 Jul 2023 00:00:00 Domain Events in DDDhttps://dckms.github.io/system-architecture/emacsway/it/ddd/tactical-design/domain-model/domain-events/domain-events-in-ddd.html -<span id="emacsway-domain-event"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<p>Существует множество спорных точек зрения среди практиков DDD по поводу реализации Domain Events. -Лучший способ понять суть вещей - это обратиться к первоисточнику, чтобы понять его мотивы и те проблемы, решение которым он стремился найти.</p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> -<ul class="simple"> -<li><p><a class="reference internal" href="#domain-events-in-ddd" id="id116">Domain Events in DDD</a></p> -<ul> -<li><p><a class="reference internal" href="#domain-event" id="id117">Назначение Domain Event</a></p></li> -<li><p><a class="reference internal" href="#eventual-consistency-vs-strong-transactional-consistency" id="id118">Eventual Consistency vs Strong (Transactional) Consistency</a></p> -<ul> -<li><p><a class="reference internal" href="#eventual-consistency" id="id119">Eventual Consistency - это следствие, а не причина</a></p></li> -<li><p><a class="reference internal" href="#id15" id="id120">Eventual Consistency предпочтительней</a></p></li> -<li><p><a class="reference internal" href="#id18" id="id121">Все решают бизнес-правила</a></p></li> -<li><p><a class="reference internal" href="#ask-whose-job-it-is" id="id122">Принцип "Ask Whose Job It Is"</a></p></li> -<li><p><a class="reference internal" href="#strong-consistency" id="id123">Strong Consistency - новичкам</a></p></li> -<li><p><a class="reference internal" href="#performance" id="id124">Интересы performance</a></p></li> -<li><p><a class="reference internal" href="#id25" id="id125">Обратная совместимость формата объектов событий</a></p></li> -<li><p><a class="reference internal" href="#net-microservices" id="id126">Рекомендации от ".NET Microservices"</a></p></li> -<li><p><a class="reference internal" href="#scott-millett-nick-tune" id="id127">Мнение Scott Millett и Nick Tune</a></p></li> -<li><p><a class="reference internal" href="#jimmy-bogard" id="id128">Мнение Jimmy Bogard</a></p></li> -<li><p><a class="reference internal" href="#kamil-grzybek" id="id129">Мнение Kamil Grzybek</a></p></li> -<li><p><a class="reference internal" href="#udi-dahan" id="id130">Мнение Udi Dahan</a></p></li> -<li><p><a class="reference internal" href="#cesar-de-la-torre" id="id131">Мнение Cesar De la Torre</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#in-process-vs-out-of-process" id="id132">In-process vs out-of-process</a></p></li> -<li><p><a class="reference internal" href="#internal-vs-external" id="id133">Internal vs External</a></p></li> -<li><p><a class="reference internal" href="#one-phase-vs-two-phase" id="id134">One-phase vs Two-phase</a></p></li> -<li><p><a class="reference internal" href="#id70" id="id135">Кто может издавать Domain Event?</a></p></li> -<li><p><a class="reference internal" href="#id73" id="id136">Может ли Domain Event отменить свою причину?</a></p></li> -<li><p><a class="reference internal" href="#id79" id="id137">Решение - это баланс стоимости и обретаемой выгоды</a></p> -<ul> -<li><p><a class="reference internal" href="#cqrs" id="id138">Может ли CQRS-команда возвращать результат?</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#atomicity-and-resiliency-of-integration-events" id="id139">Atomicity and Resiliency of Integration Events</a></p></li> -<li><p><a class="reference internal" href="#integration-events" id="id140">Проблема сохранения очередности Integration Events</a></p></li> -<li><p><a class="reference internal" href="#id104" id="id141">Где создавать Domain Event об удалении объекта?</a></p></li> -<li><p><a class="reference internal" href="#id108" id="id142">Почему важно читать оригиналы вместо переводов</a></p></li> -<li><p><a class="reference internal" href="#id111" id="id143">Послесловие</a></p></li> -</ul> -</li> -</ul> -</nav> -<p>Как сказал Bertrand Meyer,</p> -<blockquote> -<div><p>The zealots of an idea are often more extreme than its creators - the phase "more royalist than the King" captures that phenomenon - and you will find that foundational agile texts, such as those by Beck, Larman or Cockburn, occupy a higher plane of discourse; in particular they avoid below-the-belt hits at other approaches.</p> -<p>- "Agile!: The Good, the Hype and the Ugly" by Bertrand Meyer</p> -</div></blockquote> -<p>Поэтому, я буду начинать всегда с первоисточников, т.е. с Eric Evans, Bertrand Meyer и др. -Но также буду делать обзор мнений их ключевых последователей - Vaughn Vernon, Jimmy Bogard, Greg Young, Udi Dahan, Kamil Grzybek, Scott Millett, Nick Tune, коллектив авторов руководств Microsoft по архитектуре и др. -К счастью, при внимательном рассмотрении, противоречий между ними практически нет.</p> -<section id="domain-event"> -<h2><a class="toc-backref" href="#id117" role="doc-backlink">Назначение Domain Event</a></h2> -<blockquote> -<div><p>Something happened that domain experts care about. -Model information about activity in the domain as a series of discrete events. Represent each event as a domain object. -&lt;...&gt; -A domain event is a full-fledged part of the domain model, a representation of something that happened in the domain.</p> -<p>- "Domain-Driven Design Reference" <a class="footnote-reference brackets" href="#fndddr" id="id2" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Domain Events"</p> -</div></blockquote> -</section> -<section id="eventual-consistency-vs-strong-transactional-consistency"> -<h2><a class="toc-backref" href="#id118" role="doc-backlink">Eventual Consistency vs Strong (Transactional) Consistency</a></h2> -<section id="eventual-consistency"> -<h3><a class="toc-backref" href="#id119" role="doc-backlink">Eventual Consistency - это следствие, а не причина</a></h3> -<blockquote> -<div><p>A distinct, though related set of issues arises in distributed systems. -The state of a distributed system cannot be kept completely consistent at all times. -We keep the aggregates internally consistent at all times, while making other changes asynchronously. -As changes propagate across nodes of a network, it can be difficult to resolve multiple updates arriving out of order or from distinct sources.</p> -<p>- "Domain-Driven Design Reference" <a class="footnote-reference brackets" href="#fndddr" id="id3" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Domain Events"</p> -</div></blockquote> -<blockquote> -<div><p>It is difficult to guarantee the consistency of changes to objects in a model with complex associations. -Objects are supposed to maintain their own internal consistent state, but they can be blindsided by changes in other objects that are conceptually constituent parts. -Cautious database locking schemes cause multiple users to interfere pointlessly with each other and can make a system unusable. -Similar issues arise when distributing objects among multiple servers, or designing asynchronous transactions.</p> -<p>&lt;...&gt;</p> -<p>Use the same aggregate boundaries to govern transactions and distribution. -Within an aggregate boundary, apply consistency rules synchronously. Across boundaries, handle updates asynchronously. -Keep an aggregate together on one server. -Allow different aggregates to be distributed among nodes.</p> -<p>- "Domain-Driven Design Reference" <a class="footnote-reference brackets" href="#fndddr" id="id4" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Aggregates"</p> -</div></blockquote> -<p>Здесь мы видим, что краеугольной причиной Eventual Consistency является распределенное хранение данных. -Это значит, что, в силу <a class="reference external" href="http://ksat.me/a-plain-english-introduction-to-cap-theorem">CAP-теоремы</a> (<a class="reference external" href="https://habr.com/ru/post/130577/">перевод на Русский</a>), становится невозможно достигнуть одновременно Consistency и Availability при Partition Tolerance. -Это та самая причина, по которой концепция Агрегата лежит в основе практически любого распределенного NoSQL хранилища - агрегат просто хранится целиком на одном узле, поэтому, он всегда и доступен, и согласован одновременно.</p> -<p>Представьте на минутку, что узлы автомобиля хранятся на разных узлах, и они не успели прийти в согласованное состояние после обновления агрегата, в котором был заменен типоразмер шин. -Тогда у нас возникла бы вероятность получить из хранилища автомобиль с различными типоразмерами шин, что нарушило бы инвариант агрегата.</p> -<p>Иными словами, Eventual Consistency является не причиной, а следствием. И сохраняется агрегат одной транзакцией потому, что иное просто технически невозможно в условиях распределенности. Точнее, Агрегат является границей транзакции. И Вернон прибегает к Eventual Consistency потому что это лучше для high availability, чем Two-Phase Commit.</p> -<p>Таким образом, используя распределенное NoSQL хранилище или Actor Model, как правило, просто нет технической возможности сохранить более одного агрегата в одной транзакции. -Хотя, многие распределенные NoSQL хранилища и позволяют пакетировать несколько операций, транзакциями их считать нельзя.</p> -<p>Используя микросервисную архитектуру с RDBMS, существует техническая возможность сохранять более одного агрегата внутри <a class="reference external" href="https://martinfowler.com/bliki/IntegrationDatabase.html">одного и того же микросервиса</a> одной транзакцией. -Правда, это может ухудшить уровень параллелизма, поэтому важно стремиться достигать наименее возможных границ транзакции. -А вот синхронизация агрегатов различных сервисов может быть только асинхронной, либо же с использованием Two-Phase Commit. -То же самое справедливо и для Bounded Contexts DDD-монолита.</p> -<p>Стремление избежать Two-Phase Commit, в целях достижения highly scalable, подталкивает Vaughn Vernon к Eventual Consistency:</p> -<blockquote> -<div><p><strong>It can eliminate the need for two-phase commits (global transactions) and support of the rules of Aggregates (10).</strong> -One rule of Aggregates states that only a single instance should be modified in a single transaction, and all other dependent changes must occur in separate transactions. -So other Aggregate instances in the local Bounded Context may be synchronized using this approach. -We also bring remote dependencies into a consistent state with latency. -The decoupling helps provide <strong>a highly scalable</strong> and peak-performing set of cooperating services. -It also allows us to achieve loose coupling between systems.</p> -<p>-"Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id5" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "Chapter 8. Domain Events :: The When and Why of Domain Events"</p> -</div></blockquote> -<p>Но мы видим, что, кроме проблемы достижения одновременной Согласованности и Доступности при распределенном хранении агрегатов (и устойчивости к разделению), озвучивается еще одна причина - database locking. -Означает ли проблема database locking то, что коммититься должен только один агрегат в одной транзакции при использовании RDBMS (Relational Database Management System)? -Это означает только то, что транзакция должна быть fine-grained. -"Fine-grained system transaction" != "one aggregate per transaction".</p> -<blockquote> -<div><p>This rationale is based on embracing <strong>fine-grained transactions instead of transactions spanning many aggregates</strong> or entities. -The idea is that in the second case, the number of database locks will be substantial in large-scale applications with high scalability needs. -Embracing the fact that <strong>highly scalable</strong> applications need not have instant transactional consistency between multiple aggregates helps with accepting the concept of eventual consistency. -Atomic changes are often not needed by the business, and it is in any case the responsibility of the domain experts to say whether particular operations need atomic transactions or not. -If an operation always needs an atomic transaction between multiple aggregates, you might ask whether your aggregate should be larger or was not correctly designed.</p> -<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id6" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#single-transaction-across-aggregates-versus-eventual-consistency-across-aggregates">Domain events: design and implementation :: Single transaction across aggregates versus eventual consistency across aggregates</a>"</p> -</div></blockquote> -<p>О проблемах ухудшения параллелизма говорит и Vaughn Vernon, причем, причиной проблемы может стать даже один-единственный крупный агрегат. -Как видно, дело не столько в количестве агрегатов, сколько в размере границ транзакции.</p> -<blockquote> -<div><p>Smaller Aggregates not only perform and scale better, they are also biased toward transactional success, meaning that conflicts preventing a commit are rare.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id7" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "Chapter 10 Aggregates :: Rule: Design Small Aggregates"</p> -</div></blockquote> -<p>Сам Eric Evans в своем известном выражении, которое многие приводят как первопричину Eventual Consistency, вовсе не требует одну транзакцию на агрегат, а говорит лишь о том, что после коммита инвариант каждого из агрегатов должен соблюдаться:</p> -<blockquote> -<div><p>Invariants, which are consistency rules that must be maintained whenever data changes, will involve relationships between members of the AGGREGATE. -Any rule that <strong>spans AGGREGATES</strong> will <strong>not be expected</strong> to be up-to-date at all times. -Through event processing, batch processing, or other update mechanisms, other dependencies can be resolved within some specified time. -<strong>But the invariants applied within an AGGREGATE will be enforced with the completion of each transaction.</strong></p> -<p>- "Domain-Driven Design: Tackling Complexity in the Heart of Software" <a class="footnote-reference brackets" href="#fnddd" id="id8" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Six. The Life Cycle of a Domain Object :: Aggregates"</p> -</div></blockquote> -<blockquote> -<div><p>Leave transaction control to the client. Although the REPOSITORY will insert into and delete from the database, it will ordinarily not commit anything. -It is tempting to commit after saving, for example, but the client presumably has the context to correctly initiate and commit units of work. -Transaction management will be simpler if the REPOSITORY keeps its hands off.</p> -<p>- "Domain-Driven Design: Tackling Complexity in the Heart of Software" <a class="footnote-reference brackets" href="#fnddd" id="id9" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Six. The Life Cycle of a Domain Object :: Repositories"</p> -</div></blockquote> -<p>А здесь он говорит о корне агрегата во множественном числе:</p> -<blockquote> -<div><p>Schemes have been developed for defining ownership relationships in the model. The following simple but rigorous system, distilled from those concepts, includes a set of rules for implementing transactions that modify the objects and their owners.</p> -<p>- "Domain-Driven Design: Tackling Complexity in the Heart of Software" <a class="footnote-reference brackets" href="#fnddd" id="id10" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Six. The Life Cycle of a Domain Object :: Aggregates"</p> -</div></blockquote> -<p>Такую же причину озвучивает и Vaughn Vernon:</p> -<blockquote> -<div><p><strong>Transactions across distributed systems are not atomic.</strong> -<strong>The various systems bring multiple Aggregates into a consistent state eventually.</strong></p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id11" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Reference Other Aggregates by Identity :: Scalability and Distribution"</p> -</div></blockquote> -<blockquote> -<div><p>Accepting that <strong>all Aggregate instances in a large-scale, high-traffic enterprise are never completely consistent</strong> helps us accept that eventual consistency also makes sense in the smaller scale where just a few instances are involved.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id12" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary"</p> -</div></blockquote> -<p>Кстати, автором идеи агрегата является даже не Eric Evans, а David Siegel.</p> -<blockquote> -<div><p>Schemes have been developed for defining ownership relationships in the model. -The following simple but rigorous system, distilled from those concepts, includes a set of rules for implementing transactions that modify the objects and their owners. [1] -(<strong>David Siegel devised and used this system on projects in the 1990s but has not published it.</strong>)</p> -<p>First we need an abstraction for encapsulating references within the model. -An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. -Each AGGREGATE has a root and a boundary. -The boundary defines what is inside the AGGREGATE. -The root is a single, specific ENTITY contained in the AGGREGATE. -The root is the only member of the AGGREGATE that outside objects are allowed to hold references to, although objects within the boundary may hold references to each other. -ENTITIES other than the root have local identity, but that identity needs to be distinguishable only within the AGGREGATE, because no outside object can ever see it out of the context of the root ENTITY.</p> -<p>- "Domain-Driven Design: Tackling Complexity in the Heart of Software" <a class="footnote-reference brackets" href="#fnddd" id="id13" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Six. The Life Cycle of a Domain Object :: Aggregates"</p> -</div></blockquote> -<p>Оригинальная работа David Siegel к сожалению, не опубликована (по крайней мере, мне ее отыскать не удалось). -Но он упоминается также в PoEAA, где определение агрегата звучит так:</p> -<blockquote> -<div><p>Eric Evans and David Siegel [Evans] define an <strong>aggregate as a cluster of associated objects that we treat as a unit for data changes</strong>. -Each aggregate has a root that provides the only access point to members of the set and a boundary that defines what's included in the set. -The aggregate's characteristics call for a Coarse-Grained Lock, since working with any of its members requires locking all of them. Locking an aggregate yields an alternative to a shared lock that I call a root lock (see Figure 16.4). -By definition locking the root locks all members of the aggregate. The root lock gives us a single point of contention.</p> -<p>- "Patterns of Enterprise Application Architecture" <a class="footnote-reference brackets" href="#fnpoeaa" id="id14" role="doc-noteref"><span class="fn-bracket">[</span>10<span class="fn-bracket">]</span></a> by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford, Chapter "16. Offline Concurrency Patterns :: Coarse-Grained Lock"</p> -</div></blockquote> -<p>Здесь говорится про единицу изменения, про бизнес-транзакцию и блокировку, но о связи бизнес-транзакции с системной транзакцией говорится только то, что "the system transaction in which you commit the business transaction", т.е. границы системной транзакции включают в себя границы бизнес-транзакции, но не ограничиваются ими.</p> -</section> -<section id="id15"> -<h3><a class="toc-backref" href="#id120" role="doc-backlink">Eventual Consistency предпочтительней</a></h3> -<p>С одной стороны, Vaughn Vernon настоятельно рекомендует использовать Eventual Consistency между Агрегатами. -И тут же объясняет - агрегаты в высоконагруженных масштабируемых распределенных приложениях, устойчивых к разделению, никогда не бывают доступны и согласованы между собой одновременно.</p> -<blockquote> -<div><p>Thus, if executing a command on one Aggregate instance requires that additional business rules execute on one or more other Aggregates, <strong>use eventual consistency</strong>. -Accepting that all <strong>Aggregate instances in a large-scale, high-traffic enterprise are never completely consistent</strong> helps us accept that eventual consistency also makes sense in the smaller scale where just a few instances are involved.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id16" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary"</p> -</div></blockquote> -<blockquote> -<div><p>An invariant is a business rule that must always be consistent. -There are different kinds of consistency. One is transactional consistency, which is considered immediate and atomic. -There is also eventual consistency. When discussing invariants, we are referring to transactional consistency.</p> -<p>&lt;...&gt;</p> -<p>The consistency boundary logically asserts that everything inside adheres to a specific set of business invariant rules no matter what operations are performed. -The consistency of everything outside this boundary is irrelevant to the Aggregate. -Thus, Aggregate is synonymous with transactional consistency boundary.</p> -<p>&lt;...&gt;</p> -<p>When employing a typical persistence mechanism, we use a single <a class="reference external" href="https://martinfowler.com/eaaCatalog/unitOfWork.html">transaction</a> to manage consistency. -When the transaction commits, everything inside one boundary must be consistent. -A properly designed Aggregate is one that can be modified in any way required by the business with its invariants completely consistent within a single transaction. -And a properly designed Bounded Context modifies only one Aggregate instance per transaction in all cases. -What is more, we cannot correctly reason on Aggregate design without applying transactional analysis. -Limiting modification to one Aggregate instance per transaction may sound overly strict. -However, it is a rule of thumb and should be the goal in most cases. -It addresses the very reason to use Aggregates.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id17" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Model True Invariants in Consistency Boundaries"</p> -</div></blockquote> -</section> -<section id="id18"> -<h3><a class="toc-backref" href="#id121" role="doc-backlink">Все решают бизнес-правила</a></h3> -<p>С другой стороны, все решают бизнес-правила:</p> -<blockquote> -<div><p>The main point to remember from this section is that business rules are the drivers for determining what must be whole, complete, and consistent at the end of a single transaction.</p> -<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id19" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "5. Tactical Design with Aggregates :: Why Used"</p> -</div></blockquote> -</section> -<section id="ask-whose-job-it-is"> -<h3><a class="toc-backref" href="#id122" role="doc-backlink">Принцип "Ask Whose Job It Is"</a></h3> -<p>Тем не менее, Vaughn Vernon не считает вопрос Strong (Transactional) Consistency vs Eventual Consistency однозначным, и приводит четыре причины, по которым выбор может отдаваться в пользу Strong (Transactional) Consistency. -Цитировать все не буду - слишком много текста. -Кому интересно - глава "Chapter 10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary :: Ask Whose Job It Is" и далее, вплоть до главы "Gaining Insight through Discovery". -Приведу только отрывок:</p> -<blockquote> -<div><p>Ask Whose Job It Is</p> -<p>Some domain scenarios can make it very challenging to determine whether transactional or eventual consistency should be used. -Those who use DDD in a classic/traditional way may lean toward transactional consistency. -Those who use CQRS may tend toward eventual consistency. -But which is correct? -<strong>Frankly, neither of those tendencies provides a domain-specific answer, only a technical preference. Is there a better way to break the tie?</strong></p> -<p>Discussing this with Eric Evans revealed a very simple and sound guideline. -When examining the use case (or story), ask whether it's the job of the user executing the use case to make the data consistent. -<strong>If it is, try to make it transactionally consistent, but only by adhering to the other rules of Aggregates.</strong> -If it is another user's job, or the job of the system, allow it to be eventually consistent. -That bit of wisdom not only provides a convenient tie breaker, but it helps us gain a deeper understanding of our domain. -It exposes the real system invariants: the ones that must be kept transactionally consistent. -That understanding is much more valuable than defaulting to a technical leaning.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id20" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary :: Ask Whose Job It Is"</p> -</div></blockquote> -<p>В цитате Вона Вернона видно, что Эрик Эванс не спешит разделять стремление к одному агрегату на транзакцию, и предлагает рассматривать каждый случай отдельно.</p> -<p>Можно заметить, что принцип "When examining the use case (or story), ask whether it's the job of the user executing the use case to make the data consistent. <strong>If it is, try to make it transactionally consistent, but only by adhering to the other rules of Aggregates.</strong>" не противоречит приведенному ниже принципу "developers and architects like Jimmy Bogard are okay with spanning a single transaction across several aggregates - but only <strong>when those additional aggregates are related to side effects for the same original command</strong>."</p> -<p>Здесь же Vaughn Vernon напоминает нам, что во главе угла стоит, опять же, масштабирование и распределенность:</p> -<blockquote> -<div><p>We'll have <strong>consistency</strong> where necessary [имеется ввиду CAP-theorem], and support for optimally performing and <strong>highly scalable systems</strong>.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id21" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Reasons to Break the Rules :: Adhering to the Rules"</p> -</div></blockquote> -<p>Далее, в главе "Chapter 10 Aggregates :: Gaining Insight through Discovery :: Is It the Team Member's Job?" книги, он демонстрирует применение принципа "Ask Whose Job It Is" на практике.</p> -</section> -<section id="strong-consistency"> -<h3><a class="toc-backref" href="#id123" role="doc-backlink">Strong Consistency - новичкам</a></h3> -<p>Вот что советует новичкам Vaughn Vernon:</p> -<blockquote> -<div><p>There is nothing incredibly difficult about using eventual consistency. -Still, until you can gain some experience, you may be concerned about using it. -If so, you should still partition your model into Aggregates according to business-defined transactional boundaries. -<strong>However, there is nothing preventing you from committing modifications to two or more Aggregates in a single atomic database transaction.</strong> -You might choose to use this approach in cases that you know will succeed but use eventual consistency for all others. -<strong>This will allow you to get used to the techniques without taking too big an initial step.</strong> -<strong>Just understand that this is not the primary way that Aggregates are meant to be used, and you may experience transactional failures as a result.</strong></p> -<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id22" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "5. Tactical Design with Aggregates :: Rule 4: Update Other Aggregates Using Eventual Consistency"</p> -</div></blockquote> -</section> -<section id="performance"> -<h3><a class="toc-backref" href="#id124" role="doc-backlink">Интересы performance</a></h3> -<p>Ранее упоминалось, что одной из ключевых причин fine-grained транзакций является performance. -Но всегда ли? -На самом деле, все зависит от конкретных условий. -Забегая наперед, рассмотрим такое утверждение:</p> -<blockquote> -<div><p>NOTE: Try not to confuse this guideline with loading or creating aggregates. -It is perfectly fine to load multiple aggregates inside the same transaction as long as you save only one of them. -<strong>Equally, it is permissible to create multiple aggregates inside a single transaction because adding new aggregates should not cause concurrency issues.</strong></p> -<p>- "Patterns, Principles, and Practices of Domain-Driven Design" <a class="footnote-reference brackets" href="#fnpppddd" id="id23" role="doc-noteref"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></a> by Scott Millett, Nick Tune, Chapter "19 Aggregates :: Special Cases"</p> -</div></blockquote> -<p>Какое значение имеет это утверждение для performance? -Я обращусь к статьям двух известных организаций в области highload:</p> -<blockquote> -<div><p>This consistent insert throughput also persists when writing large batches of rows in single operations to TimescaleDB (instead of row-by-row). -Such batched inserts are common practice for databases employed in more high-scale production environments, e.g., when ingesting data from a distributed queue like Kafka. -<strong>In such scenarios, a single Timescale server can ingest 130K rows (or 1.3M metrics) per second, approximately 15x that of vanilla PostgreSQL once the table has reached a couple 100M rows.</strong></p> -<p>- "<a class="reference external" href="https://blog.timescale.com/blog/time-series-data-why-and-how-to-use-a-relational-database-instead-of-nosql-d0cd6975e87c/">Time-series data: Why (and how) to use a relational database instead of NoSQL</a>" by Mike Freedman, Timescale CTO and co-founder. Professor of Computer Science at Princeton.</p> -</div></blockquote> -<blockquote> -<div><ol class="arabic simple" start="7"> -<li><p>Insert rows in batches.</p></li> -</ol> -<p>In order to achieve higher ingest rates, you should insert your data with many rows in each INSERT call (or else use some bulk insert command, like COPY or our parallel copy tool).</p> -<p>Don't insert your data row-by-row – instead try at least hundreds (or thousands) of rows per INSERT. -This allows the database to spend less time on connection management, transaction overhead, SQL parsing, etc., and more time on data processing.</p> -<p>- "<a class="reference external" href="https://blog.timescale.com/blog/13-tips-to-improve-postgresql-insert-performance/">13 tips to improve PostgreSQL Insert performance</a>" by Mike Freedman, Timescale CTO and co-founder. Professor of Computer Science at Princeton.</p> -</div></blockquote> -<blockquote> -<div><p>It is of note here that each insert is a transaction. -What this means is Postgres is doing some extra coordination to make sure the transaction is completed before returning. -On every single write this takes some overhead. -Instead of single row transactions, if we wrap all of our inserts in a transaction like below, we'll see some nice performance gains:</p> -<div class="highlight-default notranslate"><div class="highlight"><pre><span/><span class="n">begin</span><span class="p">;</span> -<span class="n">insert</span> <span class="mi">1</span><span class="p">;</span> -<span class="n">insert</span> <span class="mi">2</span><span class="p">;</span> -<span class="n">insert</span> <span class="mi">3</span><span class="p">;</span> -<span class="o">...</span> -<span class="n">commit</span><span class="p">;</span> -</pre></div> -</div> -<p>This took my inserts down from 15 minutes 30 seconds to 5 minutes and 4 seconds. -We've suddenly boosted our throughput by 3x to about 3k inserts per second.</p> -<p>&lt;...&gt;</p> -<p>By batching our inserts into a single transaction, we saw our throughput go higher. -But hold on, there is even more we can do. The <code class="docutils literal notranslate"><span class="pre">\copy</span></code> mechanism gives a way to bulk load data in an even more performant manner.</p> -<p>&lt;...&gt;</p> -<p>Running this copy completes in 82 seconds! We're now processing over 10k writes per second on some fairly modest hardware.</p> -<p>- "<a class="reference external" href="https://www.citusdata.com/blog/2017/11/08/faster-bulk-loading-in-postgresql-with-copy/">Faster bulk loading in Postgres with copy</a>" by Craig Kerstiens, CitusData</p> -</div></blockquote> -<p>Вот что говорит по этому вопросу документация по PostgreSQL:</p> -<blockquote> -<div><p>When using multiple INSERTs, turn off autocommit and just do one commit at the end. -(In plain SQL, this means issuing BEGIN at the start and COMMIT at the end. Some client libraries might do this behind your back, in which case you need to make sure the library does it when you want it done.) -<strong>If you allow each insertion to be committed separately, PostgreSQL is doing a lot of work for each row that is added.</strong></p> -<p>- "<a class="reference external" href="https://www.postgresql.org/docs/11/populate.html#DISABLE-AUTOCOMMIT">PostgreSQL 11 Documentation :: 14.4. Populating a Database :: 14.4.1. Disable Autocommit</a>"</p> -</div></blockquote> -<p>Целесообразность использования Eventual Consistency в интересах performance нужно рассматривать в каждом конкретном случае отдельно. -Универсального рецепта не существует. -Этот вопрос особенно актуален при разработке сертифицированных приложений, где свобода выбора базы данных ограничена списком сертифицированных решений (зачастую вся свобода выбора сводится к RDBMS PostgresPro). -Организовать пакетирование запросов можно на уровне <a class="reference external" href="https://martinfowler.com/eaaCatalog/unitOfWork.html">Unit of Work</a>.</p> -<p>В контексте этого вопроса можно еще раз вспомнить утверждение Eric Evans:</p> -<blockquote> -<div><p>Discussing this with Eric Evans revealed a very simple and sound guideline. -When examining the use case (or story), ask whether it's the job of the user executing the use case to make the data consistent. -<strong>If it is, try to make it transactionally consistent, but only by adhering to the other rules of Aggregates.</strong></p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id24" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary :: Ask Whose Job It Is"</p> -</div></blockquote> -</section> -<section id="id25"> -<h3><a class="toc-backref" href="#id125" role="doc-backlink">Обратная совместимость формата объектов событий</a></h3> -<p>Другим достоинством Strong Consistency является отсутствие потребности в обеспечении обратной совместимости формата объектов событий, ведь их время жизни ограничено одной транзакцией. -При использовании же шины сообщений всегда сохраняется вероятность того, что обновленная версия программного обеспечения, после ее развертывания, получит из шины устаревший формат сообщения, отправленный в шину еще предыдущей версией программного обеспечения. -Кроме того, возникает потребность поддерживать оба формата сообщений для организации <a class="reference external" href="https://thenewstack.io/deployment-strategies/">blue-green deployment</a>.</p> -<p>Подробнее о версионировании сообщений смотрите в книге "<a class="reference external" href="https://leanpub.com/esversioning">Versioning in an Event Sourced System</a>" by Greg Young ("<a class="reference external" href="https://leanpub.com/esversioning/read">читать online</a>", "<a class="reference external" href="https://github.com/luque/Notes--Versioning-Event-Sourced-System">конспект книги</a>"), а так же в главе "<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/jj591577(v=pandp.10)#event-versioning">Event versioning</a> книги "CQRS Journey".</p> -</section> -<section id="net-microservices"> -<h3><a class="toc-backref" href="#id126" role="doc-backlink">Рекомендации от ".NET Microservices"</a></h3> -<p>".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id26" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> явно разделяет внутренние Domain Events (для подписчиков внутри Bounded Context) и внешние Integration Events. -Внутренние Domain Events рекомендуется использовать для синхронизации Агрегатов внутри Bounded Context.</p> -<blockquote> -<div><p>Domain events as a preferred way to trigger side effects across multiple aggregates within the same domain</p> -<p>If executing a command related to one aggregate instance requires additional domain rules to be run on one or more additional aggregates, you should design and implement those side effects to be triggered by domain events. -As shown in Figure 7-14, and as one of the most important use cases, a domain event should be used to propagate state changes across multiple aggregates within the same domain model.</p> -<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id27" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#domain-events-as-a-preferred-way-to-trigger-side-effects-across-multiple-aggregates-within-the-same-domain">Domain events: design and implementation :: Domain events as a preferred way to trigger side effects across multiple aggregates within the same domain</a>"</p> -</div></blockquote> -<p>Причем, Strong Consistency является приемлемым для внутренних Domain Events, синхронизирующих Агрегаты внутри Bounded Context:</p> -<blockquote> -<div><p>Be aware that transactional boundaries come into significant play here. -<strong>If your unit of work and transaction can span more than one aggregate (as when using EF Core and a relational database), this can work well.</strong> -But if the transaction cannot span aggregates, such as when you are using a NoSQL database like Azure CosmosDB, you have to implement additional steps to achieve consistency.</p> -<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id28" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#the-deferred-approach-to-raise-and-dispatch-events">Domain events: design and implementation :: Implement domain events :: The deferred approach to raise and dispatch events</a>"</p> -</div></blockquote> -<p>Оба подхода, и Strong Consistency, и Eventual Consistency, являются приемлемыми для синхронизации Агрегатов внутри Bounded Context:</p> -<blockquote> -<div><p><strong>Actually, both approaches (single atomic transaction and eventual consistency) can be right.</strong> -It really depends on your domain or business requirements and what the domain experts tell you. -It also depends on how scalable you need the service to be (more granular transactions have less impact with regard to database locks). -And it depends on how much investment you are willing to make in your code, since eventual consistency requires more complex code in order to detect possible inconsistencies across aggregates and the need to implement compensatory actions. -Consider that if you commit changes to the original aggregate and afterwards, when the events are being dispatched, if there is an issue and the event handlers cannot commit their side effects, you will have inconsistencies between aggregates.</p> -<p>A way to allow compensatory actions would be to store the domain events in additional database tables so they can be part of the original transaction. -Afterwards, you could have a batch process that detects inconsistencies and runs compensatory actions by comparing the list of events with the current state of the aggregates. -The compensatory actions are part of a complex topic that will require deep analysis from your side, which includes discussing it with the business user and domain experts.</p> -<p>In any case, you can choose the approach you need. -But the initial deferred approach—raising the events before committing, so you use a single transaction—is the simplest approach when using EF Core and a relational database. -It is easier to implement and valid in many business cases. -It is also the approach used in the ordering microservice in eShopOnContainers.</p> -<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id29" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#single-transaction-across-aggregates-versus-eventual-consistency-across-aggregates">Domain events: design and implementation :: Implement domain events :: Single transaction across aggregates versus eventual consistency across aggregates</a>"</p> -</div></blockquote> -</section> -<section id="scott-millett-nick-tune"> -<h3><a class="toc-backref" href="#id127" role="doc-backlink">Мнение Scott Millett и Nick Tune</a></h3> -<blockquote> -<div><p><strong>Sometimes it is actually good practice to modify multiple aggregates within a transaction.</strong> -But it's important to understand why the guidelines exist in the first place so that you can be aware of the consequences of ignoring them.</p> -<p><strong>When the cost of eventual consistency is too high, it's acceptable to consider modifying two objects in the same transaction.</strong> -Exceptional circumstances will usually be when the business tells you that the customer experience will be too unsatisfactory. -You shouldn't just accept the business's decision, though; it never wants to accept eventual consistency. -You should elaborate on the scalability, performance, and other costs involved when not using eventual consistency so that the business can make an informed, customer‐focused decision.</p> -<p><strong>Another time it's acceptable to avoid eventual consistency is when the complexity is too great.</strong> -You will see later in this chapter that robust eventually consistent implementations often utilize asynchronous, out‐of‐process workflows that add more complexity and dependencies.</p> -<p><strong>To summarize, saving one aggregate per transaction is the default approach.</strong> -But you should collaborate with the business, assess the technical complexity of each use case, and consciously ignore the guideline if there is a worthwhile advantage, such as a better user experience.</p> -<p>NOTE: Try not to confuse this guideline with loading or creating aggregates. -It is perfectly fine to load multiple aggregates inside the same transaction as long as you save only one of them. -<strong>Equally, it is permissible to create multiple aggregates inside a single transaction because adding new aggregates should not cause concurrency issues.</strong></p> -<p>&lt;...&gt;</p> -<p><strong>You should try to align your aggregate boundaries with transactions, because the higher the number of aggregates being modified in a single transaction, the greater the chance of a concurrency failure.</strong> -Therefore, strive to modify a single aggregate per use case to keep the system performant.</p> -<p>&lt;...&gt;</p> -<p>If you find that you are modifying more than one aggregate in a transaction, it may be a sign that your aggregate boundaries can be better aligned with the problem domain.</p> -<p>&lt;...&gt;</p> -<p>In a typical business use case there are often multiple actions that need to succeed or fail together inside a transaction. -By managing transactions in application services, you have full control over which operations that you request of the domain will live inside the same transaction boundary.</p> -<p>This can be demonstrated using an updated RecommendAFriendService. -Imagine the business has decided that if the referral policy cannot be applied, it should not create the new account. -Therefore, the transactional boundary encapsulates creating the new account and applying the referral policy to both accounts, as shown in Figure 25-3.</p> -<p>- "Patterns, Principles, and Practices of Domain-Driven Design" <a class="footnote-reference brackets" href="#fnpppddd" id="id30" role="doc-noteref"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></a> by Scott Millett, Nick Tune, Chapter "19 Aggregates :: Special Cases"</p> -</div></blockquote> -</section> -<section id="jimmy-bogard"> -<h3><a class="toc-backref" href="#id128" role="doc-backlink">Мнение Jimmy Bogard</a></h3> -<p>Вот что говорит ".NET Microservices: Architecture for Containerized .NET Applications" со ссылкой на Jimmy Bogard:</p> -<blockquote> -<div><p>However, other developers and architects like Jimmy Bogard are <strong>okay with spanning a single transaction across several aggregates - but only when those additional aggregates are related to side effects for the same original command</strong>. -For instance, in <a class="reference external" href="https://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/">A better domain events pattern</a>, Bogard says this:</p> -<blockquote> -<div><p>Typically, I want the side effects of a domain event to occur within the same logical transaction, but not necessarily in the same scope of raising the domain event [...] Just before we commit our transaction, we dispatch our events to their respective handlers.</p> -</div></blockquote> -<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id31" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#single-transaction-across-aggregates-versus-eventual-consistency-across-aggregates">Domain events: design and implementation :: Single transaction across aggregates versus eventual consistency across aggregates</a>"</p> -</div></blockquote> -<p>Сам Jimmy Bogard говорит следующее:</p> -<blockquote> -<div><p>Domain events are similar to messaging-style eventing, with one key difference. -With true messaging and a service bus, a message is fired and handled to asynchronously. -With domain events, the response is synchronous</p> -<p>- "Strengthening your domain: Domain Events" <a class="footnote-reference brackets" href="#fnjbde1" id="id32" role="doc-noteref"><span class="fn-bracket">[</span>18<span class="fn-bracket">]</span></a> by Jimmy Bogard</p> -</div></blockquote> -<blockquote> -<div><p>Transactions are handled in our unit of work wrapping each HTTP request. -Since our domain events are synchronous and on the same thread, they are part of the same transaction as the entity that first raised the event.</p> -<p>- "<a class="reference external" href="https://lostechies.com/jimmybogard/2010/04/08/strengthening-your-domain-domain-events/#comment-173067283">Strengthening your domain: Domain Events</a>", comment of Jimmy Bogard</p> -</div></blockquote> -<blockquote> -<div><p>With our domain event in place, we can ensure that our entire <strong>domain model stays consistent with the business rules applied, even when we need to notify other aggregate roots</strong> in our system when something happens. -We've also locked down all the ways the risk status could change (charged a new fee), so <strong>we can keep our Customer aggregate consistent even in the face of changes in a separate aggregate (Fee)</strong>.</p> -<p>This pattern isn't always applicable. -If I need to do something like send an email, notify a web service or any other potentially blocking tasks, I should revert back to normal asynchronous messaging. -But for synchronous messaging across disconnected aggregates, <strong>domain events are a great way to ensure aggregate root consistency across the entire model</strong>. -The alternative would be transaction script design, where consistency is enforced not by the domain model but by some other (non-intuitive) layer.</p> -<p>- "Strengthening your domain: Domain Events" <a class="footnote-reference brackets" href="#fnjbde1" id="id33" role="doc-noteref"><span class="fn-bracket">[</span>18<span class="fn-bracket">]</span></a> by Jimmy Bogard</p> -</div></blockquote> -<blockquote> -<div><p>Typically, I want the side effects of a domain event to occur within the same logical transaction, but not necessarily in the same scope of raising the domain event. If I cared enough to have the side effects occur, I would instead just couple myself directly to that other service as an argument to my domain's method.</p> -<p>Instead of dispatching to a domain event handler immediately, what if instead we recorded our domain events, and before committing our transaction, dispatch those domain events at that point? This will have a number of benefits, besides us not tearing our hair out. Instead of raising domain events, let's define a container for events on our domain object:</p> -<p>&lt;...&gt;</p> -<p>Just before we commit our transaction, we dispatch our events to their respective handlers.</p> -<p>- "A better domain events pattern" <a class="footnote-reference brackets" href="#fnjbde2" id="id34" role="doc-noteref"><span class="fn-bracket">[</span>19<span class="fn-bracket">]</span></a> by Jimmy Bogard</p> -</div></blockquote> -</section> -<section id="kamil-grzybek"> -<h3><a class="toc-backref" href="#id129" role="doc-backlink">Мнение Kamil Grzybek</a></h3> -<p>Вот что говорит Kamil Grzybek:</p> -<blockquote> -<div><p>The way of handling of domain events depends indirectly on publishing method. -If you use DomainEvents static class, you have to handle event immediately. -In other two cases you control when events are published as well handlers execution – in or outside existing transaction.</p> -<p>In my opinion <strong>it is good approach to always handle domain events in existing transaction</strong> and treat aggregate method execution and handlers processing as atomic operation. -This is good because if you have a lot of events and handlers you do not have to think about initializing connections, transactions and what should be treat in "all-or-nothing" way and what not.</p> -<p>- "How to publish and handle Domain Events" <a class="footnote-reference brackets" href="#fnkgde1" id="id35" role="doc-noteref"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> -</div></blockquote> -<blockquote> -<div><p>Thanks for question Andreas!</p> -<p>I know both books of Vaughn Vernon - they are great and must read for every DDD practitioner. From the DDD Distlled book (chapter 5 about aggregates):</p> -<blockquote> -<div><p><strong>...business rules are the drivers for determining what must be whole, complete, and consistent at the end of a single transaction.</strong></p> -</div></blockquote> -<p>So in general this is good rule to have separate transactions, but sometimes it is impossible or very hard to achieve.</p> -<p>My approach is similar to Vaughn Vernon - I try always handle event in separate transaction if it is possible. -To do that I have two types of events: <strong>Domain Events (private, handled in the same transaction)</strong> and <strong>Domain Events Notifications (handled outside transaction)</strong>. -Domain Event Notification often becomes an Integration Event which is send to Events Bus to other Bounded Context. -This way I support all cases - immediate consistency, eventual consistency and integrations scenarios.</p> -<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/how-to-publish-and-handle-domain-events/#comment-4602236620">How to publish and handle Domain Events</a>" <a class="footnote-reference brackets" href="#fnkgde1" id="id36" role="doc-noteref"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></a>, comment of Kamil Grzybek</p> -</div></blockquote> -<blockquote> -<div><p>Aggregates can publish multiple Domain Events, and for each Domain Event there can be many handlers responsible for different behavior. -This behavior can be communication with an external system or <strong>executing a Command on another Aggregate</strong>, which will again publish its events to which another part of our system will subscribe.</p> -<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id37" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> -</div></blockquote> -<blockquote> -<div><p>Let's assume that in this particular case <strong>both Order placement and Payment creation should take place in the same transaction</strong>. -If transaction is successful, we need to send 2 emails – about the Order and Payment.</p> -<p>&lt;...&gt;</p> -<ol class="arabic simple"> -<li><p><strong>Command Handler defines transaction boundary. Transaction is started when Command Handler is invoked and committed at the end.</strong></p></li> -<li><p><strong>Each Domain Event handler is invoked in context of the same transaction boundary.</strong></p></li> -<li><p>If we want to process something outside the transaction, we need to create a <strong>public event</strong> based on the Domain Event. I call it Domain Event Notification, <a class="reference external" href="http://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/">some people call it a public event</a>, but the concept is the same.</p></li> -</ol> -<p>The second most important thing is when to publish and process Domain Events? Events may be created after each action on the Aggregate, so we must publish them:</p> +<p>Очень кратко (всего 3 страницы) о методике оценивания PERT:</p> <ul class="simple"> -<li><p>after each Command handling (but BEFORE committing transaction)</p></li> -<li><p>after each Domain Event handling (but WITHOUT committing transaction)</p></li> +<li><p>"The Clean Coder" by Robert C. Martin, "Chapter 10 Estimation :: PERT"</p></li> +</ul> +<p>Статья, отвечающая на очень частый вопрос:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.mountaingoatsoftware.com/blog/how-do-story-points-relate-to-hours">How Do Story Points Relate to Hours?</a>" by Mike Cohn</p></li> +</ul> +<p>Оценка - это не единичное значение, а вероятностная распределённость:</p> +<ul class="simple"> +<li><p>YOW! 2016 Robert C. Martin - "<a class="reference external" href="https://youtu.be/eisuQefYw_o">Effective Estimation (or: How not to Lie)</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.mauvisoft.com/2020/10/08/how-to-read-lead-time-distribution/">How to Read Lead Time Distribution</a>" by Mauvisoft Team</p></li> </ul> -<p>&lt;...&gt;</p> -<p>The second thing we have to do is to save notifications about Domain Events that we want to process outside of the transaction.</p> -<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id38" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> -</div></blockquote> -<p>Обратите внимание, что, по приведенной им ссылке, под термином "public event" понимается сообщение, выходящее за пределы Bounded Context (к этому вопросу мы еще вернемся):</p> -<blockquote> -<div><p>Set up separate messaging channels for inside the Bounded Context and outside. Keep all events private by default, and indicate the ones you want to make public with an explicit @Public annotation, a marker interface, or an isPublic():bool method. When emitting events, the event publishing mechanism knows to read the annotation and either send the event on the private channel only, or on both the private and the public channel.</p> -<p class="attribution">—"<a class="reference external" href="https://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/">Patterns for Decoupling in Distributed Systems: Explicit Public Events</a>" by Mathias Verraes</p> -</div></blockquote> -<p>И, в своем демонстрационном приложении sample-dotnet-core-cqrs-api, <a class="reference external" href="https://github.com/kgrzybek/sample-dotnet-core-cqrs-api/blob/01a1d6517bc88773f004abc0cb9c6d79f537e575/src/SampleProject.Application/Orders/PlaceCustomerOrder/OrderPlacedDomainEventHandler.cs#L22">он демонстрирует обработку Domain Event в одной транзакции с агрегатом</a>.</p> </section> -<section id="udi-dahan"> -<h3><a class="toc-backref" href="#id130" role="doc-backlink">Мнение Udi Dahan</a></h3> -<blockquote> -<div><p>&gt; This might be a bit of a late question. But shouldn't domain events be handled after the transaction ends? -Is there any specific reason for handle domain events within the same transaction scoping DoSomething?</p> -<p>Domain events get handled by service layer objects in the same process which usually send out other messages – as such, we want those messages to be sent (or not) in the same transactional context.</p> -<p>- "<a class="reference external" href="http://udidahan.com/2009/06/14/domain-events-salvation/#comment-4723">Domain Events – Salvation</a>" <a class="footnote-reference brackets" href="#fnudde3" id="id39" role="doc-noteref"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></a> comment of Udi Dahan</p> -</div></blockquote> -<blockquote> -<div><p>&gt; In message number 120 above, Lars asks about how to access the data if the event is fired before the commit. -I didn't understand your response. -Maybe my situation is different so I'll explain.</p> -<p>&gt; I have 2 BCs. -One context deals with the merging of employee information. -I'd like to fire a domain event specifying that the employee was merged. -I'd like the 2nd BC to react to this event. -The issue is that the data won't be committed at that point, and this data that changed is vital to the 2nd BC to react.</p> -<p>&gt; Am I going down the wrong path by attempting to use domain events? Is there another solution you could suggest?</p> -<p>The question is whether you need both your BCs to be consistent with each other at *all* times – ergo in the same transaction.</p> -<p><strong>If the answer is yes, then you absolutely do want the event to be raised and handled in the same transaction – you'd also be deploying both BCs together.</strong></p> -<p>If the answer is no, then you should use some kind of message bus between the BCs. -The handler for the domain event would publish a message using the bus, and that would be enlisted in the same transaction – thus is the first BC rolled back, the message wouldn't be sent. -The second BC would be invoked by the bus when the message arrives at its queue where its handling would then be done in a separate transaction.</p> -<p>- "<a class="reference external" href="http://udidahan.com/2009/06/14/domain-events-salvation/#comment-4730">Domain Events – Salvation</a>" <a class="footnote-reference brackets" href="#fnudde3" id="id40" role="doc-noteref"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></a> comment of Udi Dahan</p> -</div></blockquote> -<blockquote> -<div><p>&gt; Shouldn't the event only be handled when the transaction commits? -Until the transaction commits, the change to the domain object isn't really permanent, right?</p> -<p>Not necessarily – sometimes you want loose-coupling within the same transaction.</p> -<p>I do agree that often where we find a place ready for logical decoupling it coincides with separate transaction boundaries. -In those cases, using a transactionally-aware technology like NServiceBus will be a better choice for publishing events.</p> -<p>- "<a class="reference external" href="http://udidahan.com/2009/06/14/domain-events-salvation/#comment-4773">Domain Events – Salvation</a>" <a class="footnote-reference brackets" href="#fnudde3" id="id41" role="doc-noteref"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></a> comment of Udi Dahan</p> -</div></blockquote> -<blockquote> -<div><p>&gt; Domain event could alter multiple aggregates which is common, wouldn't you be updating multiple aggregates in a single transaction?</p> -<p><strong>The more common case is where those multiple aggregates are updated in separate transactions</strong>, usually as a result of some kind of "service bus" event being transmitted from the domain events. -That service bus event gets routed to multiple subscribers, behind which you'd have each of the respective aggregates that would updated in their own transactions.</p> -<p>- "<a class="reference external" href="http://udidahan.com/2009/06/14/domain-events-salvation/#comment-74959">Domain Events – Salvation</a>" <a class="footnote-reference brackets" href="#fnudde3" id="id42" role="doc-noteref"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></a> comment of Udi Dahan</p> -</div></blockquote> +<section id="id32"> +<h3><a class="toc-backref" href="#id82" role="doc-backlink">Функциональное программирование</a></h3> +<ul class="simple"> +<li><p><a class="reference external" href="http://se.ethz.ch/~meyer/publications/functional/meyer_functional_oo.pdf">"Software architecture: object-oriented vs functional</a>" by Bertrand Meyer</p></li> +<li><p>"<a class="reference external" href="https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/">Category Theory for Programmers</a>" by Bartosz Milewski (<a class="reference external" href="https://github.com/hmemcpy/milewski-ctfp-pdf">unofficial PDF and LaTeX source</a>)</p></li> +<li><p>"<a class="reference external" href="https://fsharpforfunandprofit.com/books/">Domain Modeling Made Functional. Tackle Software Complexity with Domain-Driven Design and F#</a>" by Scott Wlaschin</p></li> +<li><p>"<a class="reference external" href="https://fsharpforfunandprofit.com/">F# for Fun and Profit</a>" by Scott Wlaschin</p></li> +<li><p>"Functional Programming for the Object-Oriented Programmer" by Brian Marick</p></li> +<li><p>"Functional Thinking" by Neal Ford</p></li> +<li><p>"<a class="reference external" href="https://en.wikibooks.org/wiki/Haskell">Haskell</a>"</p></li> +<li><p>"<a class="reference external" href="https://github.com/winitzki/sofp/blob/master/sofp-src/sofp.pdf">The Science of Functional Programming. A Tutorial, with Examples in Scala.</a>" by Sergei Winitzki, Ph.D.</p></li> +<li><p>"Microservices with Clojure. Develop event-driven, scalable, and reactive microservices with real-time monitoring" by Anuj Kumar</p></li> +</ul> +<p>Для Golang-разработчиков:</p> +<ul class="simple"> +<li><p>"Learning Functional Programming in Go: Change the way you approach your applications using functional programming in Go" by Lex Sheehan</p></li> +</ul> </section> -<section id="cesar-de-la-torre"> -<h3><a class="toc-backref" href="#id131" role="doc-backlink">Мнение Cesar De la Torre</a></h3> -<blockquote> -<div><p>When handling the event, any event handler subscribed to the event could run additional domain operations by using other AggregateRoot objects, but again, you still need to be within the same transaction scope.</p> -<p>&lt;..&gt;</p> -<p>for in-memory event based communication across disconnected aggregates that are part of the same domain model and part of the same transaction, domain events are great ensuring consistency across a single domain model within the same microservice or Bounded-Context.</p> -<p>- "Domain Events vs. Integration Events in Domain-Driven Design and microservices architectures" <a class="footnote-reference brackets" href="#fncdltdevie" id="id43" role="doc-noteref"><span class="fn-bracket">[</span>23<span class="fn-bracket">]</span></a> by Cesar De la Torre, Principal Program Manager, .NET</p> -</div></blockquote> -<p>Ссылки по теме:</p> +<section id="id33"> +<h3><a class="toc-backref" href="#id83" role="doc-backlink">Справочники</a></h3> <ul class="simple"> -<li><p>"<a class="reference external" href="https://www.allthingsdistributed.com/2008/12/eventually_consistent.html">Eventually Consistent - Revisited</a>" by Werner Vogels, CTO - Amazon.com</p></li> -<li><p>"<a class="reference external" href="https://www.allthingsdistributed.com/2007/12/eventually_consistent.html">Eventually Consistent</a>" by Werner Vogels, CTO - Amazon.com</p></li> +<li><p>"Computing Handbook. Computer Science and Software Engineering." 3d edition by Allen Tucker, Teofilo Gonzalez, Jorge Diaz-Herrera</p></li> </ul> </section> </section> -<section id="in-process-vs-out-of-process"> -<h2><a class="toc-backref" href="#id132" role="doc-backlink">In-process vs out-of-process</a></h2> -<p>Обычно считается, что in-process - это синхронное исполнение, а out-of-process - асинхронное. -Хотя, сугубо технически, асинхронное исполнение может быть как in-process, так и out-of-process. -К тому же асинхронное исполнение нужно подразделять на использующее event-loop (async/await) и использующее внешнюю инфраструктуру (external event bus).</p> -<p>В большинстве случаев, in-process подразумевает "в той же транзакции", т.е. Strong Consistency.</p> -<blockquote> -<div><p>The reference app uses MediatR to propagate domain events synchronously across aggregates, within a single transaction. -However, you could also use some AMQP implementation like RabbitMQ or Azure Service Bus to propagate domain events asynchronously, using eventual consistency but, as mentioned above, you have to consider the need for compensatory actions in case of failures.</p> -<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id44" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#conclusions-on-domain-events">Domain events: design and implementation :: Conclusions on domain events</a>"</p> -</div></blockquote> +<section id="id34"> +<h2><a class="toc-backref" href="#id84" role="doc-backlink">Справочная информация</a></h2> +<section id="body-of-knowledge"> +<h3><a class="toc-backref" href="#id85" role="doc-backlink">Body of Knowledge</a></h3> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.sebokwiki.org/wiki/Download_SEBoK_PDF">Guide to the Systems Engineering Body of Knowledge (SEBoK)</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.computer.org/education/bodies-of-knowledge/software-engineering">Software Engineering Body of Knowledge (SWEBOK) v.3</a>" (<a class="reference external" href="https://github.com/ligurio/swebok-2004-in-russian">на русском</a>)</p></li> +<li><p>"<a class="reference external" href="https://waseda.app.box.com/v/ieee-cs-swebok">Software Engineering Body of Knowledge (SWEBOK) v.4 (draft)</a>"</p></li> +<li><p>"<a class="reference external" href="https://itabok.iasaglobal.org/">The Information Technology Architecture Body of Knowledge (ITABoK)</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.mitre.org/publications/technical-papers/guide-to-the-evolving-enterprise-architecture-body-of-knowledge">The Enterprise Architecture Body of Knowledge (EABoK)</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.mitre.org/publications/technical-papers/the-mitre-systems-engineering-guide">MITRE Systems Engineering Guide</a></p></li> +<li><p>"<a class="reference external" href="https://www.businessarchitectureguild.org/page/BIZBOK">A Guide to the Business Architecture Body of Knowledge(R) (BIZBOK(R) Guide)</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.iiba.org/career-resources/a-business-analysis-professionals-foundation-for-success/babok/">A Guide to the Business Analysis Body of Knowledge (BABOK®)</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.iiba.org/career-resources/business-analysis-resources/iiba-bookstore/">Agile Extension to the BABOK® Guide</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.dama.org/content/what-data-management">DAMA-DMBOK: Data Management Body of Knowledge</a>" 2nd edition by DAMA International</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/foundational/pmbok">The Project Management Body of Knowledge (PMBoK)</a>" by Project Management Institute (PMI)</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute (PMI), 2017</p></li> +<li><p>"<a class="reference external" href="https://book4cio.ru/">Учебник 4CIO. Настольная книга ИТ-Директора</a>"</p></li> +<li><p>"<a class="reference external" href="https://4cio.ru/pages/570">Учебник 4CDTO. Настольная книга руководителя цифровой трансформации</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.incose.org/products-and-publications/se-handbook">Systems engineering handbook. A guide for System Life Cycle Processes and activities.</a>" by INCOSE</p></li> +<li><p>"<a class="reference external" href="https://sfia-online.org/en">The global skills and competency framework for a digital world</a>" by SFIA Foundation</p></li> +<li><p>"<a class="reference external" href="https://sfia-online.org/en/tools-and-resources/bodies-of-knowledge/list-of-bodies-of-knowledge">List of Bodies of Knowledge</a>" by SFIA Foundation</p></li> +<li><p>"<a class="reference external" href="https://mellarius.ru/">mellarius.ru</a>" - превосходный минималистичный и самодостаточный справочник по архитектуре, анализу, организации процессов, тестированию и т.п.</p></li> +</ul> </section> -<section id="internal-vs-external"> -<h2><a class="toc-backref" href="#id133" role="doc-backlink">Internal vs External</a></h2> -<p>Существует ряд методик (Anti-Corruption Layer, CQRS etc.), направленных на то, чтобы защитить изменения внутренних интерфейсов от изменения внешних и наоборот. -Это логично, так как они будут изменяться в разное время, с разной частотой и по разным причинам.</p> -<p>Domain Events могут покидать пределы Bounded Context:</p> -<blockquote> -<div><p>Using Domain Events will help you both to model explicitly and to share what has occurred within your model with the systems that need to know about it. -<strong>The interested parties might be your own local Bounded Context and other remote Bounded Contexts.</strong></p> -<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id45" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "1. DDD for Me :: Tactical Design"</p> -</div></blockquote> -<blockquote> -<div><p><strong>Publishing the Event outward to any number Bounded Contexts of other Subdomains (2) emphasizes the word Domain in the term Domain Event.</strong> -In other words, Events are a domain-wide concept, not just a concept in a single Bounded Context. -The contract of Event publishing should have the potential to be at least as broad as the enterprise, or even broader. -Yet, wide broadcast does not forbid delivery of Events by consumers in the same Bounded Context.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id46" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Publishing Events from the Domain Model :: Subscribers"</p> -</div></blockquote> -<p>Это выдвигает вопрос по отношению к Domain Events - нужно ли отделять внутренние от внешних? -Проблему озвучивает сам Vaughn Vernon:</p> -<blockquote> -<div><p><strong>Once your Domain Event is saved to the event store, it can be published to any interested parties . This might be within your own Bounded Context and to external Bounded Contexts.</strong> -This is your way of telling the world that something noteworthy has occurred in your Core Domain.</p> -<p>Are Domain Event Consumers Conformists? -<strong>You may be wondering how Domain Events can be consumed by another Bounded Context [это и есть тот самый волнующий вопрос - прим. мое] and not force that consuming Bounded Context into a Conformist relationship.</strong> -As recommended in Implementing Domain-Driven Design [IDDD] , and specifically in Chapter 13, "Integrating Bounded Contexts," <strong>consumers should not use the event types (e.g., classes) of an event publisher</strong>. -Rather, <strong>they should depend only on the schema of the events</strong>, that is, <strong>their Published Language</strong>. -This generally means that if the events are published as JSON, or perhaps a more economical object format, the consumer should consume the events by parsing them to obtain their data attributes."</p> -<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id47" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events:: Designing, Implementing, and Using Domain Events"</p> -</div></blockquote> -<p>Тут он четко обозначает проблему, которой рано или поздно задаются многие. И он делает две вещи:</p> -<ol class="arabic simple"> -<li><p>Он разделяет реализацию издания Domain Events внутри Bounded Context (ГОФ-паттерны), от реализации издания Domain Events для других Bounded Contexts (интеграционная шина), которая начинает выполняться после завершения первой.</p></li> -<li><p>Он разделяет Domain Events с публичной схемой, от остальных Domain Events. А это, по сути, и есть то самое, что в ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id48" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> именуется как Integration Event.</p></li> -</ol> -<p>Поскольку эти виды Ивентов имеют различные цели, различный способ доставки, различные реализации, различные категории подписчиков, различную область действия и различное назначение, то они, резонно, разделили их на два вида события:</p> -<ol class="arabic simple"> -<li><p>Domain Events, которые действуют исключительно внутри Bounded Context, и доставляются посредством ГОФ-паттернов синхронно или асинхронно (но исключительно in-process, используя event-loop и async/await конструкции) в той же транзакции.</p></li> -<li><p>Integration Event, которые выходят за пределы Bounded Context, доставляются интеграционной шиной, всегда асинхронны и в другой транзакции.</p></li> -</ol> -<p>Такого же мнения придерживается и Kamil Grzybek, называя внешние события (public event, которые уже упоминались) термином "Domain Event Notifications":</p> -<blockquote> -<div><p>Last thing to consider is processing of Domain Event Notifications (public events). We need to find a way to process them outside transaction and here Outbox Pattern comes in to play.</p> -<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id49" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> -</div></blockquote> -<blockquote> -<div><p>Sometimes, however, it is necessary to communicate with 3rd party service (for example e-mail or web service) based on Domain Event. -As we know, communication with 3rd party services is not usually transactional so we need some additional generic mechanism to handle these types of scenarios. -So I created Domain Events Notifications.</p> -<p>&lt;...&gt;</p> -<p>There is no such thing as domain events notifications in DDD terms. -I gave that name because I think it fits best – it is notification that domain event was published.</p> -<p>&lt;..&gt;</p> -<p>For non-trasactional operations Domain Events Notifications were introduced.</p> -<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/how-to-publish-and-handle-domain-events/">How to publish and handle Domain Events</a>" <a class="footnote-reference brackets" href="#fnkgde1" id="id50" role="doc-noteref"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> -</div></blockquote> -<p>В одном из своих комментариев он связывает "Domain Event Notification" с "Integration Events":</p> -<p>My approach is similar to Vaughn Vernon - I try always handle event in separate transaction if it is possible. To do that I have two types of events: Domain Events (private, handled in the same transaction) and Domain Events Notifications (handled outside transaction). Domain Event Notification often becomes an <strong>Integration Event</strong> which is send to Events Bus to other Bounded Context. This way I support all cases - immediate consistency, eventual consistency and integrations scenarios.</p> -<blockquote> -<div><p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/how-to-publish-and-handle-domain-events/#comment-4602236620">How to publish and handle Domain Events</a>" <a class="footnote-reference brackets" href="#fnkgde1" id="id51" role="doc-noteref"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></a>, comment of Kamil Grzybek</p> -</div></blockquote> -<p>Обратите внимание на окончание - там перечислены три сценария:</p> -<ol class="arabic simple"> -<li><p>Immediate consistency</p></li> -<li><p>Eventual consistency</p></li> -<li><p>Integrations scenarios</p></li> -</ol> -<p>В другом комментарии он вносит уточнение:</p> -<blockquote> -<div><p>Domain Event - private event, not persisted [Outbox], part of UL</p> -<p>Domain Event Notification - private event, persisted [Outbox], part of UL. Sometimes called "persisted event"</p> -<p>Integration event - public event, part of PL as you described</p> -<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/#comment-5205858557">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id52" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> -</div></blockquote> -<p>Здесь у него, правда, наблюдается небольшое противоречие с предыдущим его комментарием:</p> -<blockquote> -<div><p>If you want to process Domain Event in separate transaction, you need to create Domain Event Notification <strong>(public event)</strong> which is saved within the same transaction to the Outbox but processed in different (Outbox processing).</p> -<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/#comment-4507778871">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id53" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> -</div></blockquote> -<p>А так же, наблюдается противоречие с другим его выражением, где он, ссылаясь на определение Mathias Verraes, приравнивает Domain Event Notification к "public event":</p> -<blockquote> -<div><ol class="arabic simple" start="3"> -<li><p>If we want to process something outside the transaction, we need to create a <strong>public event</strong> based on the Domain Event. I call it Domain Event Notification, <a class="reference external" href="http://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/">some people call it a public event</a>, but the concept is the same.</p></li> -</ol> -<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id54" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> -</div></blockquote> -<p>Как уже упоминалось ранее, по приведенной им ссылке, под термином "public event" понимается сообщение, выходящее за пределы Bounded Context:</p> -<blockquote> -<div><p>Set up separate messaging channels for inside the Bounded Context and outside. Keep all events private by default, and indicate the ones you want to make public with an explicit @Public annotation, a marker interface, or an isPublic():bool method. When emitting events, the event publishing mechanism knows to read the annotation and either send the event on the private channel only, or on both the private and the public channel.</p> -<p class="attribution">—"<a class="reference external" href="https://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/">Patterns for Decoupling in Distributed Systems: Explicit Public Events</a>" by Mathias Verraes</p> -</div></blockquote> -<p>Но, в целом, понятно, что Domain Event обрабатывается внутри транзакции, Domain Event Notification - вне транзакции (и может требовать Outbox pattern), и Integration Event - за пределами Bounded Context.</p> -<p>Позже Kamil Grzybek публикует в Twitter <a class="reference external" href="https://twitter.com/kamgrzybek/status/1471756563400605701?t=DO3_TJK0jncMCGlvb34UuA&amp;s=19">следующее разъяснение</a>:</p> -<blockquote> -<div><p>In your system you should have 3 types of events:</p> -<ol class="arabic simple"> -<li><p>Private, domain events (sth important occured in your domain)</p></li> -<li><p>Private, persisted events (based on 1, for later async processing)</p></li> -<li><p>Public, integration events (based on 2, to integrate with another contexts, part of contract)</p></li> -</ol> -<p class="attribution">—<a class="reference external" href="https://twitter.com/kamgrzybek/status/1471756563400605701?t=DO3_TJK0jncMCGlvb34UuA&amp;s=19">Источник</a></p> -</div></blockquote> -<p>И сопровождает его <a class="reference external" href="https://twitter.com/kamgrzybek/status/1472232661938843657?t=czUCrilodujW8aAIdV6OBw&amp;s=19">иллюстрацией</a>:</p> -<figure class="align-left" id="id112"> -<a class="reference internal image-reference" href="../../../../../../_images/domain-vs-integration-event-by-kamil-grzybek.jpeg"><img alt="The difference between event types. The image source is https://twitter.com/kamgrzybek/status/1472232661938843657?t=czUCrilodujW8aAIdV6OBw&amp;s=19" src="../../../../../../_images/domain-vs-integration-event-by-kamil-grzybek.jpeg" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">The difference between event types.</span></p> -<div class="legend"> -<p>— <a class="reference external" href="https://twitter.com/kamgrzybek/status/1472232661938843657?t=czUCrilodujW8aAIdV6OBw&amp;s=19">Источник</a></p> -</div> -</figcaption> -</figure> -<p>Еще дальше идут авторы книги "Patterns, Principles, and Practices of Domain-Driven Design" <a class="footnote-reference brackets" href="#fnpppddd" id="id55" role="doc-noteref"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></a>, вводя явное разделение внутренних и внешних событий:</p> -<figure class="align-center" id="id113"> -<a class="reference internal image-reference" href="../../../../../../_images/pppddd-18.1.png"><img alt="FIGURE pppddd-18-1: Ensuring correct transactional behavior. The image source is &quot;Patterns, Principles, and Practices of Domain-Driven Design&quot; by Scott Millett, Nick Tune" src="../../../../../../_images/pppddd-18.1.png" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">FIGURE pppddd-18-1: Ensuring correct transactional behavior. The image source is "Patterns, Principles, and Practices of Domain-Driven Design" by Scott Millett, Nick Tune</span></p> -</figcaption> -</figure> -<blockquote> -<div><p>An important distinction needs to be made when using the domain events pattern to avoid confusion that can lead to poor technical implementations. It is crucial that you are aware of the difference between internal and external events. Internal events are internal to a domain model–they are not shared between bounded contexts. -In this chapter, you will see how the domain events pattern uses internal events, whereas you saw external events in Part II of this book.</p> -<p>Differentiating internal and external events is important because they have different characteristics. -Because internal events are limited in scope to a single bounded context, it is Ok to put domain objects on them, as the example in Listing 18‐1 showed. This poses no risk, because other bounded contexts cannot become coupled to these domain objects. -Conversely, external events tend to be flat in structure, exposing just a few properties—most of the time just correlational IDs, as typified in Listing 18‐3.</p> -<p>You learned in Part II that external events need to be versioned to avoid breaking changes. -This is another differentiator with internal events, because if you make breaking changes to an internal event your code will not compile (if using a compiled programming language). So there's no need to version internal events.</p> -<p>As you start to implement domain events, you will see that in a typical business use case there may be a number of internal events raised, and just one or two external events that are raised by the service layer. -Figure 18-2 illustrates how the sequence of events may occur in a typical use case.</p> -<p>With all of these differences in mind, it makes sense to put your events in different namespaces to accentuate those that are internal from those that are external.</p> -<p>- "Patterns, Principles, and Practices of Domain-Driven Design" <a class="footnote-reference brackets" href="#fnpppddd" id="id56" role="doc-noteref"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></a> by Scott Millett, Nick Tune, Chapter "18 Domain Events :: Internal vs External Events"</p> -</div></blockquote> -<figure class="align-center" id="id114"> -<a class="reference internal image-reference" href="../../../../../../_images/pppddd-18.2.png"><img alt="FIGURE pppddd-18-2: Flow of internal and external events in a typical business use case. The image source is &quot;Patterns, Principles, and Practices of Domain-Driven Design&quot; by Scott Millett, Nick Tune" src="../../../../../../_images/pppddd-18.2.png" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">FIGURE pppddd-18-2: Flow of internal and external events in a typical business use case. The image source is "Patterns, Principles, and Practices of Domain-Driven Design" by Scott Millett, Nick Tune</span></p> -</figcaption> -</figure> -<p>Разделяют Domain Events на внутренние и внешние и специалисты .NET.</p> -<blockquote> -<div><p>Basically, by differentiating between Domain Events and Integration Events you can solve the issue of dealing with transactions since domain events are always scoped within a transaction but integration events (using an EventBus.Publish()) are only published to the outside world if the transaction was committed successfully. -By doing this you can be sure that other domain-models, microservices and external systems do not react on something that in fact has rolled back and does not exist anymore.</p> -<p>- "Domain Events vs. Integration Events in Domain-Driven Design and microservices architectures" <a class="footnote-reference brackets" href="#fncdltdevie" id="id57" role="doc-noteref"><span class="fn-bracket">[</span>23<span class="fn-bracket">]</span></a> by Cesar De la Torre, Principal Program Manager, .NET</p> -</div></blockquote> -<blockquote> -<div><p>Domain events versus integration events</p> -<p>Semantically, domain and integration events are the same thing: notifications about something that just happened. -However, their implementation must be different. -Domain events are just messages pushed to a domain event dispatcher, which could be implemented as an in-memory mediator based on an IoC container or any other method.</p> -<p>On the other hand, the purpose of integration events is to propagate committed transactions and updates to additional subsystems, whether they are other microservices, Bounded Contexts or even external applications. -Hence, they should occur only if the entity is successfully persisted, otherwise it's as if the entire operation never happened.</p> -<p>As mentioned before, integration events must be based on asynchronous communication between multiple microservices (other Bounded Contexts) or even external systems/applications.</p> -<p>Thus, the event bus interface needs some infrastructure that allows inter-process and distributed communication between potentially remote services. -It can be based on a commercial service bus, queues, a shared database used as a mailbox, or any other distributed and ideally push based messaging system.</p> -<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id58" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#domain-events-versus-integration-events">Domain events: design and implementation :: Domain events versus integration events</a>"</p> -</div></blockquote> +<section id="id35"> +<h3><a class="toc-backref" href="#id86" role="doc-backlink">ГОСТы</a></h3> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://allgosts.ru/35/">База ГОСТов allgosts.ru - 35. ИНФОРМАЦИОННЫЕ ТЕХНОЛОГИИ. МАШИНЫ КОНТОРСКИЕ</a>"</p></li> +<li><p>"<a class="reference external" href="https://standartgost.ru/0/753-informatsionnye_tehnologii_mashiny_kontorskie">StandartGOST.ru - бесплатные ГОСТы и магазин документов. Информационные технологии. Машины конторские</a>"</p></li> +</ul> +</section> +<section id="online"> +<h3><a class="toc-backref" href="#id87" role="doc-backlink">Online-каталоги</a></h3> +<ul class="simple"> +<li><p><a class="reference external" href="http://www.refactoring.com/catalog/">Catalog of Refactorings</a></p></li> +<li><p><a class="reference external" href="http://c2.com/cgi/wiki?CodeSmell">Code Smell</a></p></li> +<li><p><a class="reference external" href="http://c2.com/cgi/wiki?AntiPatternsCatalog">Anti Patterns Catalog</a></p></li> +<li><p><a class="reference external" href="https://martinfowler.com/eaaCatalog/">Catalog of Patterns of Enterprise Application Architecture</a></p></li> +<li><p><a class="reference external" href="https://www.martinfowler.com/dslCatalog/">List of DSL Patterns</a></p></li> +<li><p><a class="reference external" href="http://www.enterpriseintegrationpatterns.com/">Enterprise Integration Patterns</a> (<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/download/EIPTutorialReferenceChart.pdf">шпаргалка по EIP</a>)</p></li> +<li><p><a class="reference external" href="https://verraes.net/2019/05/ddd-msg-arch/">DDD and Messaging Architectures</a> - an overview of different series on patterns in distributed systems by Mathias Verraes.</p></li> +<li><p><a class="reference external" href="http://servicedesignpatterns.com/">Service Design Patterns</a></p></li> +<li><p><a class="reference external" href="https://patterns.arcitura.com/soa-patterns">SOAPatterns.org</a></p></li> +<li><p><a class="reference external" href="https://patterns.arcitura.com/cloud-computing-patterns">CloudPatterns.org</a></p></li> +<li><p><a class="reference external" href="https://patterns.arcitura.com/big-data-patterns">BigDataPatterns.org</a></p></li> +<li><p><a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/">Cloud Design Patterns | Microsoft Docs</a></p></li> +<li><p><a class="reference external" href="http://workflowpatterns.com/patterns/">Workflow Patterns</a></p></li> +<li><p><a class="reference external" href="https://microservices.io/patterns/">Microservices Patterns</a></p></li> +<li><p><a class="reference external" href="https://www.manning.com/books/microservice-patterns">Microservices Patterns (book)</a></p></li> +<li><p><a class="reference external" href="https://samnewman.io/patterns/">Microservices Patterns from Sam Newman</a></p></li> +<li><p><a class="reference external" href="http://ddd.fed.wiki.org/">About DDD on the site of Ward Cunningham</a></p></li> +<li><p><a class="reference external" href="http://www.databaserefactoring.com/">Refactoring Databases</a></p></li> +<li><p><a class="reference external" href="http://xunitpatterns.com/">XUnit Test Patterns</a></p></li> +<li><p><a class="reference external" href="https://databaserefactoring.com/">Refactoring Databases</a></p></li> +<li><p><a class="reference external" href="http://www.agiledata.org/essays/databaseRefactoringCatalog.html">Catalog of Database Refactorings</a></p></li> +<li><p><a class="reference external" href="http://www.extremeprogramming.org/rules.html">Extreme Programming Rules</a></p></li> +<li><p><a class="reference external" href="https://jepsen.io/consistency">Consistency Models - a clickable map</a></p></li> +<li><p><a class="reference external" href="https://www.agilealliance.org/agile101/subway-map-to-agile-practices/">Subway Map to Agile Practices - a clickable map</a></p></li> +<li><p><a class="reference external" href="https://patterns.arcitura.com/">The Arcitura Education Patterns, Mechanisms and Metrics Master Catalog</a></p></li> +<li><p><a class="reference external" href="https://microservice-api-patterns.org/">Microservice API Patterns</a></p></li> +<li><p><a class="reference external" href="https://www.openapis.org/">OpenAPIs</a></p></li> +<li><p><a class="reference external" href="https://www.asyncapi.com/">AsyncAPI</a></p></li> +<li><p><a class="reference external" href="https://nocomplexity.com/documents/arplaybook/">Architecture Playbook</a> (<a class="reference external" href="https://github.com/nocomplexity/ArchitecturePlaybook">source</a>)</p></li> +<li><p><a class="reference external" href="https://www.viewpoints-and-perspectives.info/">Software Systems Architecture</a> - This web site contains a selection of supporting material for the book ("Software Systems Architecture: Working With Stakeholders Using Viewpoints and Perspectives" 2nd edition by Nick Rozanski, Eóin Woods), including sample chapters, references and white papers.</p></li> +</ul> +</section> +<section id="code-smell-catalogs"> +<h3><a class="toc-backref" href="#id88" role="doc-backlink">Code Smell catalogs</a></h3> +<ul class="simple"> +<li><p>Chapter 17: "Smells and Heuristics" of the book "Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p></li> +<li><p>Chapter 3. "Bad Smells in Code" of the book "Refactoring: Improving the Design of Existing Code" by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p></li> +<li><p><a class="reference external" href="http://c2.com/cgi/wiki?CodeSmell">Code Smell</a> catalog on the site of Ward Cunningham</p></li> +<li><p>"Refactoring To Patterns" by Joshua Kerievsky</p></li> +</ul> +</section> +<section id="id36"> +<h3><a class="toc-backref" href="#id89" role="doc-backlink">Другие подборки литературы</a></h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/sindresorhus/awesome">Awesome lists</a></p></li> +<li><p><a class="reference external" href="https://github.com/heynickc/awesome-ddd">Awesome Domain-Driven Design</a></p></li> +<li><p><a class="reference external" href="https://mehdihadeli.github.io/awesome-go-education/ddd/">Awesome Go Education: DDD</a></p></li> +<li><p><a class="reference external" href="https://mehdihadeli.github.io/awesome-go-education/cqrs/">Awesome Go Education: CQRS</a></p></li> +<li><p><a class="reference external" href="https://mehdihadeli.github.io/awesome-go-education/event-sourcing/">Awesome Go Education: Event Sourcing</a></p></li> +<li><p><a class="reference external" href="https://mehdihadeli.github.io/awesome-go-education/clean-architecture/">Awesome Go Education: Clean Architecture</a></p></li> +<li><p><a class="reference external" href="https://github.com/valignatev/ddd-dynamic">Domain Driven Design in Python, Ruby and other dynamic languages resources</a></p></li> +<li><p><a class="reference external" href="https://github.com/mfornos/awesome-microservices">Awesome Microservices</a></p></li> +<li><p><a class="reference external" href="https://github.com/unlight/solution-architecture">Solution Architecture links, articles, books, video lessons, etc.</a></p></li> +<li><p><a class="reference external" href="https://github.com/tayllan/awesome-algorithms">Awesome Algorithms</a></p></li> +<li><p><a class="reference external" href="https://github.com/gaerae/awesome-algorithms-education">Awesome Algorithms Education</a></p></li> +<li><p><a class="reference external" href="https://github.com/donnemartin/system-design-primer">The System Design Primer</a> - Learn how to design large-scale systems. Prep for the system design interview.</p></li> +<li><p><a class="reference external" href="https://github.com/prakhar1989/awesome-courses">List of awesome university courses for learning Computer Science</a></p></li> +<li><p><a class="reference external" href="http://e-maxx.ru/bookz/">MAXimal :: bookz - электронные версии различных книг по алгоритмам</a></p></li> +<li><p><a class="reference external" href="http://www.kamilgrzybek.com/programming-and-design-resources/">Programming and design learning resources by Kamil Grzybek</a></p></li> +<li><p><a class="reference external" href="https://sergeyteplyakov.blogspot.com/2013/08/blog-post.html">Список книг от Сергея Теплякова</a></p></li> +<li><p><a class="reference external" href="https://handbookofsoftwarearchitecture.com/books/">Список книг от Grady Booch</a></p></li> +<li><p><a class="reference external" href="https://www.luxoft-training.ru/about/experts/answers/302/30945/">Книги по направлению Архитектура и проектирование ПО от эксперта luxoft</a></p></li> +<li><p><a class="reference external" href="https://architectelevator.com/architecture/architect-path/">The Architect's Path (Part 1 - Model)</a> by Gregor Hohpe</p></li> +<li><p><a class="reference external" href="https://architectelevator.com/architecture/architect-bookshelf/">The Architect's Path (Part 2 - Implementation)</a> by Gregor Hohpe</p></li> +<li><p><a class="reference external" href="https://www.developertoarchitect.com/books.html">Software Architecture Book References</a> by Mark Richards</p></li> +<li><p><a class="reference external" href="https://ruxpert.ru/%D0%98%D1%81%D0%BA%D1%83%D1%81%D1%81%D1%82%D0%B2%D0%BE_%D1%81%D0%BF%D0%BE%D1%80%D0%B0_(%D0%BE%D0%B1%D1%83%D1%87%D0%B0%D1%8E%D1%89%D0%B8%D0%B5_%D0%BC%D0%B0%D1%82%D0%B5%D1%80%D0%B8%D0%B0%D0%BB%D1%8B)">Искусство спора (обучающие материалы)</a></p></li> +<li><p><a class="reference external" href="https://m.vk.com/wall-56611080_127534">Книги по риторике</a></p></li> +</ul> +</section> +<section id="id37"> +<h3><a class="toc-backref" href="#id90" role="doc-backlink">Почтовые рассылки и сообщества</a></h3> +<ul class="simple"> +<li><p><a class="reference external" href="http://dddcommunity.org/">Domain Driven Design Community</a></p></li> +<li><p><a class="reference external" href="http://dddweekly.com/">Domain Driven Design Weekly</a></p></li> +<li><p><a class="reference external" href="https://microserviceweekly.com/">Microservice Weekly</a></p></li> +</ul> +</section> +</section> +<section id="emacsway-reference-applications"> +<span id="id38"/><h2><a class="toc-backref" href="#id91" role="doc-backlink">Эталонные демонстрационные приложения</a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers">eShopOnContainers</a> (CQRS, DDD, Microservices)</p></li> +<li><p><a class="reference external" href="https://github.com/microsoftarchive/cqrs-journey">Microsoft patterns &amp; pratices CQRS Journey sample application</a> (CQRS, DDD, Event Sourcing, SAGA transactions)</p></li> +</ul> <blockquote> -<div><p>Domain events can generate integration events to be published outside of the microservice boundaries</p> -<p>Finally, it's important to mention that you might sometimes want to propagate events across multiple microservices. -That propagation is an integration event, and it could be published through an event bus from any specific domain event handler.</p> -<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id59" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#domain-events-can-generate-integration-events-to-be-published-outside-of-the-microservice-boundaries">Domain events: design and implementation :: Implement domain events :: Domain events can generate integration events to be published outside of the microservice boundaries</a>"</p> +<div><p>"A perfect example of this [you can see] if you go look at the CQRS and Event Sourcing by Microsoft Patterns and Practices, which is heavily focused on doing this inside of Azure using their toolkits."</p> +<p>- Greg Young, "<a class="reference external" href="https://youtu.be/LDW0QWie21s?t=1092">A Decade of DDD, CQRS, Event Sourcing</a>" at 18:15</p> </div></blockquote> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd">Full Modular Monolith application with Domain-Driven Design approach</a> by Kamil Grzybek</p></li> +<li><p><a class="reference external" href="https://github.com/kgrzybek/sample-dotnet-core-cqrs-api">Sample .NET Core REST API CQRS implementation with raw SQL and DDD using Clean Architecture</a> by Kamil Grzybek</p></li> +<li><p><a class="reference external" href="https://github.com/kgrzybek/refactoring-from-anemic-to-rich-domain-model-example">Refactoring from anemic to rich Domain Model example</a> by Kamil Grzybek</p></li> +<li><p><a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET">Sample Bounded Contexts for C#.NET from the book "Implementing Domain-Driven Design"</a> by Vaughn Vernon</p></li> +<li><p><a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples">Sample Bounded Contexts from the book "Implementing Domain-Driven Design"</a> by Vaughn Vernon</p></li> +<li><p><a class="reference external" href="https://github.com/vlingo/xoom-examples">xoom-examples</a> - the VLINGO XOOM examples demonstrating features and functionality available in the reactive components.</p></li> +<li><p>Implementation of samples from the book "Domain-Driven Design" by Eric Evans in <a class="reference external" href="https://github.com/citerus/dddsample-core">Java</a>, <a class="reference external" href="https://github.com/SzymonPobiega/DDDSample.Net">C#</a>, <a class="reference external" href="https://github.com/paulrayner/ddd_sample_app_ruby">Ruby</a>, <a class="reference external" href="https://github.com/marcusolsson/goddd">Golang</a> (<a class="reference external" href="https://github.com/go-kit/kit/tree/master/examples/shipping">yet another Golang</a>). See also <a class="reference external" href="https://www.citerus.se/go-ddd">the article</a>.</p></li> +<li><p><a class="reference external" href="https://goa.design/">Goa</a> provides a holistic approach for developing remote APIs and microservices in Go.</p></li> +<li><p><a class="reference external" href="https://github.com/gregoryyoung/m-r">Simple CQRS example</a> by Greg Young (приложение так же реализует Event Sourcing)</p></li> +<li><p><a class="reference external" href="https://github.com/thinkbeforecoding/m-r">Greg Young's Simple CQRS in F#</a> by Jérémie Chassaing</p></li> +<li><p><a class="reference external" href="https://github.com/EventStore/training-advanced-go">Golang DDD ES/CQRS Reference Application</a> by EventStore contributors</p></li> +<li><p><a class="reference external" href="https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example">Complete serverless application to show how to apply DDD, Clean Architecture, and CQRS by practical refactoring of a Go project</a> (<a class="reference external" href="https://threedots.tech/post/serverless-cloud-run-firebase-modern-go-application/">more info</a>) by Robert Laszczak</p></li> +<li><p><a class="reference external" href="https://github.com/ThreeDotsLabs/monolith-microservice-shop">Clean Monolith Shop</a> by Robert Laszczak - Source code for article "<a class="reference external" href="https://threedots.tech/post/microservices-or-monolith-its-detail/">Why using Microservices or Monolith can be just a detail?</a>"</p></li> +<li><p><a class="reference external" href="https://github.com/AntonStoeckl/go-iddd">go-iddd - showcase project for implementing DDD in Go</a> by Anton Stöckl (see more info <a class="reference external" href="https://medium.com/@TonyBologni/implementing-domain-driven-design-and-hexagonal-architecture-with-go-1-292938c0a4d4">here</a> and <a class="reference external" href="https://medium.com/@TonyBologni/implementing-domain-driven-design-and-hexagonal-architecture-with-go-2-efd432505554">here</a>).</p></li> +<li><p><a class="reference external" href="https://github.com/agiledragon/transfer-money-go">transfer-money-go</a> by Zhang Xiaolong - A sample of DDD and DCI in Go.</p></li> +<li><p><a class="reference external" href="https://github.com/agiledragon/ddd-sample-in-golang">ddd-sample-in-golang</a> by Zhang Xiaolong.</p></li> +<li><p><a class="reference external" href="https://github.com/shijuvar/go-distributed-sys">go-distributed-sys</a> - Guidance for building distributed systems and Microservices in Go. "<a class="reference external" href="https://shijuvar.medium.com/building-event-driven-distributed-systems-in-go-with-grpc-nats-jetstream-and-cockroachdb-c4b899c8636d">Building Event-Driven Distributed Systems in Go with gRPC, NATS JetStream and CockroachDB</a>" by Shiju Varghese</p></li> +<li><p><a class="reference external" href="https://github.com/asynkron/realtimemap-go">Real-time Map</a> displays real-time positions of public transport vehicles in Helsinki. It's a showcase for <a class="reference external" href="https://proto.actor/">Proto.Actor</a> - an ultra-fast distributed actors solution for Go, C#, and Java/Kotlin. See also <a class="reference external" href="https://github.com/asynkron/realtimemap-dotnet">realtimemap-dotnet</a> implementation in .NET.</p></li> +<li><p><a class="reference external" href="https://github.com/johnbywater/es-example-taxi-demo">Demo taxi system, using eventsourcing library</a> by John Bywater</p></li> +<li><p><a class="reference external" href="https://github.com/johnbywater/es-example-bank-accounts">Example "bank accounts" application using the Python eventsourcing library</a> by John Bywater</p></li> +<li><p><a class="reference external" href="https://github.com/johnbywater/es-example-cargo-shipping">Example "cargo shipping" application using the Python eventsourcing library</a> by John Bywater</p></li> +<li><p><a class="reference external" href="https://github.com/johnbywater/eventsourcing/tree/main/eventsourcing/examples">Examples of using eventsourcing library</a> by John Bywater</p></li> +<li><p><a class="reference external" href="https://github.com/microservices-patterns/ftgo-application">FTGO example application. Example code for the book Microservice patterns</a> by Chris Richardson</p></li> +<li><p><a class="reference external" href="https://github.com/eventuate-tram/eventuate-tram-examples-customers-and-orders/">Eventuate Tram Customers and Orders</a> by Chris Richardson</p></li> +<li><p><a class="reference external" href="https://github.com/eventuate-examples/eventuate-tram-core-dotnet-examples-customers-and-orders">Eventuate Tram Customers and Orders - .NET version</a> by Chris Richardson</p></li> +<li><p><a class="reference external" href="https://github.com/eventuate-examples">eventuate-examples</a> by Chris Richardson</p></li> +<li><p><a class="reference external" href="https://github.com/elbandit/PPPDDD">Sample code for the book Principles, Practices and Patterns of Domain-Driven Design</a> by Scott Millett, Nick Tune</p></li> +<li><p><a class="reference external" href="https://github.com/PacktPublishing/Hands-On-Domain-Driven-Design-with-.NET-Core">Hands-On Domain-Driven Design with .NET Core, published by Packt</a> by Alexey Zimarev</p></li> +<li><p>"<a class="reference external" href="https://github.com/Eventuous/dotnet-sample">dotnet-sample</a>" - Sample application using Eventuous .NET by Alexey Zimarev</p></li> +<li><p><a class="reference external" href="https://github.com/swlaschin/DomainModelingMadeFunctional">Extended code samples related to the book "Domain Modeling Made Functional"</a> by Scott Wlaschin</p></li> +<li><p><a class="reference external" href="https://github.com/swlaschin/Railway-Oriented-Programming-Example">Railway-Oriented-Programming-Example</a> by Scott Wlaschin</p></li> +<li><p><a class="reference external" href="https://github.com/andorp/order-taking">Order Taking Service</a> - Idris version of Domain Modeling Made Functional Book.</p></li> +<li><p><a class="reference external" href="https://github.com/VaughnVernon/DDDwithActors">DDD with Actors</a> by Vaughn Vernon</p></li> +<li><p><a class="reference external" href="https://github.com/VaughnVernon/ReactiveMessagingPatterns_ActorModel">The examples for the book "Reactive Messaging Patterns with the Actor Model"</a> by Vaughn Vernon</p></li> +<li><p><a class="reference external" href="https://github.com/VaughnVernon/reactive-stock-trader">A Stock Trader system to demonstrate reactive systems development</a> (<a class="reference external" href="https://github.com/RedElastic/reactive-stock-trader">source</a> by RedElastic)</p></li> +<li><p><a class="reference external" href="https://github.com/jbogard/ContosoUniversityDotNetCore-Pages">ContosoUniversityDotNetCore-Pages</a> by Jimmy Bogard</p></li> +<li><p><a class="reference external" href="https://github.com/RedElastic/reactive-stock-trader">RedElastic: reactive-stock-trader</a> - A reference architecture for stock trading to demonstrate the concepts of reactive systems development. Based on the original Stock Trader by IBM and implemented with Lagom by Lightbend. "<a class="reference external" href="https://developer.ibm.com/series/reactive-in-practice/">Reactive in practice: A complete guide to event-driven systems development in Java.</a>"</p></li> +<li><p><a class="reference external" href="https://github.com/IBMStockTrader">IBM Stock Trader</a> - Org containing a repository per microservice in the IBM Stock Trader cloud-native sample application. "<a class="reference external" href="https://developer.ibm.com/blogs/introducing-stocktrader/">Introduction to the IBM Stock Trader sample.</a>"</p></li> +<li><p><a class="reference external" href="https://github.com/vkhorikov/AnemicDomainModel">Refactoring from Anemic Domain Model Towards a Rich One</a> by Vladimir Khorikov</p></li> +<li><p><a class="reference external" href="https://github.com/vkhorikov/DddInAction">DDD in Practice</a> by Vladimir Khorikov</p></li> +<li><p><a class="reference external" href="https://github.com/vkhorikov/DddAndEFCore">DDD and EF Core</a> by Vladimir Khorikov</p></li> +<li><p><a class="reference external" href="https://github.com/vkhorikov/CqrsInPractice">CQRS in Practice</a> by Vladimir Khorikov</p></li> +<li><p><a class="reference external" href="https://github.com/vkhorikov/FuntionalPrinciplesCsharp">Applying Functional Principles in C#</a> by Vladimir Khorikov</p></li> +<li><p><a class="reference external" href="https://github.com/vkhorikov/SpecPattern">Specification Pattern in C#</a> by Vladimir Khorikov</p></li> +<li><p><a class="reference external" href="https://github.com/vkhorikov/SpecificationPattern">Specification pattern implementation in C#</a> by Vladimir Khorikov</p></li> +<li><p><a class="reference external" href="https://github.com/vkhorikov/ValidationInDDD">Validation in DDD course</a> by Vladimir Khorikov</p></li> +</ul> +<p>Варианты реализации OO/Functional Aggregates на примере Reference Applications by Chris Richardson:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/cer/event-sourcing-examples/tree/master/java-spring">Traditional OO mutable Domain Objects</a></p></li> +<li><p><a class="reference external" href="https://github.com/cer/event-sourcing-using-scala-typeclasses">Functional Scala witn immutable Domain Objects</a></p></li> +<li><p><a class="reference external" href="https://github.com/cer/event-sourcing-examples/tree/master/scala-spring">Hybrid OO/Functional Scala with immutable Domain Objects</a></p></li> +</ul> +<p>Others:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/heynickc/awesome-ddd#sample-projects">DDD Sample Projects</a></p></li> +</ul> +</section> +</section> +Sat, 21 Oct 2023 00:00:00 Разрешение конфликтов на почве недостатка знанийhttps://dckms.github.io/system-architecture/emacsway/soft-skills/knowledge-vs-opinion.html<span class="target" id="index-0"/><section id="emacsway-knowledge-vs-opinion-in-psychology"> +<span id="id1"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id2"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#emacsway-knowledge-vs-opinion-in-psychology" id="id10">Разрешение конфликтов на почве недостатка знаний</a></p> +<ul> +<li><p><a class="reference internal" href="#id3" id="id11">Теория - это обобщенная практика</a></p></li> +<li><p><a class="reference internal" href="#emacsway-opinion-in-psychology" id="id12">О мнениях</a></p></li> +<li><p><a class="reference internal" href="#emacsway-knowledge-in-psychology" id="id13">О знаниях</a></p></li> +<li><p><a class="reference internal" href="#id6" id="id14">Решение</a></p></li> +<li><p><a class="reference internal" href="#emacsway-theory" id="id15">О роли теории</a></p></li> +<li><p><a class="reference internal" href="#id8" id="id16">Рождается ли в споре истина?</a></p></li> +</ul> +</li> +</ul> +</nav> +<p>Нередко наблюдаю на практике возникновение конфликтов в коллективе практически на пустом месте, по причине принуждения коллектива к принятию решения в условиях недостаточной информированности.</p> +<section id="id3"> +<h2><a class="toc-backref" href="#id11" role="doc-backlink">Теория - это обобщенная практика</a></h2> +<p>Основное отличие <strong>знания</strong> от <strong>мнения</strong> заключается <em>в широте охвата опыта, которым оно было произведено</em>. +Грубо говоря, <strong>теория - это обобщенная практика</strong> (в рассматриваемом нами контексте):</p> <blockquote> -<div><p>Model information about activity in the domain as a series of discrete events. Represent each event as a domain object. These are distinct from system events that reflect activity within the software itself, although often a system event is associated with a domain event, either as part of a response to the domain event or as a way of carrying information about the domain event into the system.</p> -<p>- "Domain-Driven Design Reference" <a class="footnote-reference brackets" href="#fndddr" id="id60" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Domain Events"</p> +<div><p>📝 "<strong>Теория</strong> — (1) система научных идей и принципов, <strong>обобщающих практический опыт</strong>, отражающих объективные природные закономерности и положения, которые образуют науку (см.) или раздел какой-либо науки, а также совокупность правил в области какого-либо знания млн. мастерства (Т. вождения или полётов);"</p> +<p class="attribution">—"<a class="reference external" href="https://polytechnic_dictionary.academic.ru/2647/%D0%A2%D0%95%D0%9E%D0%A0%D0%98%D0%AF">Большая политехническая энциклопедия.</a>" - М.: Мир и образование. Рязанцев В. Д.. 2011.</p> </div></blockquote> <blockquote> -<div><p>More importantly, the outside API is tightly coupled to the internal structure of the Bounded Context. Changing the internals would force an API change.</p> -<p>&lt;..&gt;</p> -<p>Set up separate messaging channels for inside the Bounded Context and outside.</p> -<p>&lt;..&gt;</p> -<p>In general, my feeling is that the problem seldom occurs when the Domain Events have been chosen carefully to reflect the business domain, using Ubiquitous Language, and at the right granularity. -These events then tend to become stable very quickly during development, and rarely need to be altered. -When there are significant changes in the domain, the events may need to change, but in these cases you'll need an API change anyway.</p> -<p>That said, it's a universally useful heuristic in software design to keep everything as closed off as possible, and only open up things where there's a good case for it.</p> -<p>- "Patterns for Decoupling in Distributed Systems: Explicit Public Events" <a class="footnote-reference brackets" href="#fnmvpe" id="id61" role="doc-noteref"><span class="fn-bracket">[</span>25<span class="fn-bracket">]</span></a> by Mathias Verraes</p> +<div><p>💬 "Their ideas are not "just theory". It's years of accumulated practice and insights. They work — often in many different contexts. We're lucky: we can build on top of their ideas."</p> +<p class="attribution">—"<a class="reference external" href="https://verraes.net/2014/10/software-design-is-just-theory/">Software design is just theory</a>" by Mathias Verraes.</p> </div></blockquote> </section> -<section id="one-phase-vs-two-phase"> -<h2><a class="toc-backref" href="#id134" role="doc-backlink">One-phase vs Two-phase</a></h2> -<p>Ответ на вопрос о разделении доставки Domain Events во многом зависит от того, разделять ли Domain Events на внутренние и внешние?</p> -<p>Хотя у Vaughn Vernon такое разделение не совсем очевидное, он разделяет реализацию доставки для подписчиков внутри Bounded Context и за его пределами.</p> -<figure class="align-center" id="id115"> -<a class="reference internal image-reference" href="../../../../../../_images/iddd-8.1.png"><img alt="Figure 8.1. Aggregates create Events and publish them. Subscribers may store Events and then forward them to remote subscribers, or just forward them without storing. Immediate forwarding requires XA (two-phase commit) unless messaging middleware shares the model's data store. The image source is &quot;Implementing Domain-Driven Design&quot; by Vaughn Vernon" src="../../../../../../_images/iddd-8.1.png" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">Figure 8.1. Aggregates create Events and publish them. -<strong>Subscribers may store Events and then forward them to remote subscribers, or just forward them without storing.</strong> -Immediate forwarding requires XA (two-phase commit) unless messaging middleware shares the model's data store. -The image source is "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id62" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon</span></p> -</figcaption> -</figure> +<section id="emacsway-opinion-in-psychology"> +<span id="id4"/><h2><a class="toc-backref" href="#id12" role="doc-backlink">О мнениях</a></h2> +<p>Обратимся к энциклопедии:</p> <blockquote> -<div><p>Forwarding the Event via a messaging infrastructure would allow asynchronous delivery to out-of-band subscribers. -Each of those asynchronous subscribers could arrange to modify an additional Aggregate instance in one or more separate transactions. -The additional Aggregate instances could be in the same Bounded Context or in others. -Publishing the Event outward to any number Bounded Contexts of other Subdomains (2) emphasizes the word Domain in the term Domain Event. -In other words, Events are a domain-wide concept, not just a concept in a single Bounded Context. -The contract of Event publishing should have the potential to be at least as broad as the enterprise, or even broader. -Yet, wide broadcast does not forbid delivery of Events by consumers in the same Bounded Context. -Refer back to Figure 8.1.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id63" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Publishing Events from the Domain Model :: Subscribers"</p> +<div><p>📝 "Там, где заканчивается <strong>знание</strong>, начинается <strong>мнение</strong>".</p> +<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/737/%D0%9C%D0%9D%D0%95%D0%9D%D0%98%D0%95">Философия: Энциклопедический словарь.</a>" — М.: Гардарики. Под редакцией А.А. Ивина. 2004.</p> </div></blockquote> -<p>В качестве первой ступени доставки Domain Events внутренним подписчикам, Vaughn Vernon предлагает использовать обычные GOF-паттерны (Mediator, Observer), которые вызывают подписчиков в том же самом потоке и в той же самой транзакции.</p> <blockquote> -<div><p>Publishing Events from the Domain Model</p> -<p>Avoid exposing the domain model to any kind of middleware messaging infrastructure. -Those kinds of components live only in the infrastructure. -And while the domain model might at times use such infrastructure indirectly, it would never explicitly couple to it. We'll use an approach that completely avoids the use of infrastructure.</p> -<p>One of the simplest and most effective ways to publish Domain Events without coupling to components outside the domain model is to create a lightweight Observer [Gamma et al.]. -For the sake of naming I use Publish-Subscribe, which is acknowledged by [Gamma et al.] as another name for the same pattern. -The examples in that pattern and my use of it are lightweight because there is no network involved in subscribing to Events and publishing them. -All registered subscribers execute in the same process space with the publisher and run on the same thread. -When an Event is published, each subscriber is notified synchronously, one by one. -This also implies that <strong>all subscribers are running within the same transaction</strong>, perhaps controlled by an Application Service that is the direct client of the domain model.</p> -<p>Considering the two halves of Publish-Subscribe separately helps to explain them in a DDD context.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id64" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Publishing Events from the Domain Model"</p> +<div><p>📝 "Со времен элеатов, атомистов и Платона <strong>знание</strong> характеризуется через противоположность <strong>мнению</strong>."</p> +<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">Новая философская энциклопедия: В 4 тт.</a>" М.: Мысль. Под редакцией В. С. Стёпина. 2001.</p> </div></blockquote> <blockquote> -<div><p>What components register subscribers to Domain Events? -Generally speaking, Application Services (14), and sometimes Domain Services, will. -<strong>The subscriber may be any component that is running on the same thread as the Aggregate that publishes the Event</strong>, and that can subscribe prior to the Event being published. -This means that <strong>the subscriber is registered in the method execution path that uses the domain model</strong>.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id65" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Publishing Events from the Domain Model :: Subscribers"</p> +<div><p>📝 "К отличительным особенностям научного знания в настоящее время относят: непротиворечивость, <strong>эмпирическую проверяемость</strong>, логическую или <strong>эмпирическую обоснованность</strong>."</p> +<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">Философия: Энциклопедический словарь.</a>" — М.: Гардарики. Под редакцией А.А. Ивина. 2004.</p> </div></blockquote> -<p>При этом, Vaughn Vernon делает предостережение относительно первой ступени доставки, т.е. внутренних подписчиков, впрочем, это предостережение зависит от уже рассмотренного ранее вопроса Eventual Consistency vs Strong (Transactional) Consistency.</p> <blockquote> -<div><p>Remember, the Application Service controls the transaction. -Don't use the Event notification to modify a second Aggregate instance. -That breaks a rule of thumb to modify one Aggregate instance per transaction.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id66" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Publishing Events from the Domain Model :: Subscribers"</p> +<div><p>📝 "Знание есть такой результат познавательной деятельности, который обладает непреходящей истинностью, может быть логически или фактически обоснован и допускает <strong>эмпирическую или практическую проверку</strong>."</p> +<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">Философия: Энциклопедический словарь.</a>" — М.: Гардарики. Под редакцией А.А. Ивина. 2004.</p> </div></blockquote> -<p>В другом месте Vaughn Vernon приводит небольшой пример, по которому создается иллюзия, что якобы асинхронные подписчики уведомляются непосредственно (однофазно):</p> <blockquote> -<div><p>There is a practical way to support eventual consistency in a DDD model. -An Aggregate command method publishes a Domain Event that is in time delivered to one or more asynchronous subscribers:</p> -<p>Each of these subscribers then retrieves a different yet corresponding Aggregate instance and executes its behavior based on it. -Each of the subscribers executes in a separate transaction, obeying the rule of Aggregates to modify just one instance per transaction.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id67" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary"</p> +<div><p>📝 "3нание, являясь <strong>обобщением</strong> достоверных <strong>фактов</strong>, за случайным находит необходимое и закономерное, за единичным и частным — общее."</p> +<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">Философский энциклопедический словарь.</a>" — М.: Советская энциклопедия. Гл. редакция: Л. Ф. Ильичёв, П. Н. Федосеев, С. М. Ковалёв, В. Г. Панов. 1983.</p> </div></blockquote> -<p>Однако, если найти этот пример в коде, то эта иллюзия рассеивается. -См. <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_agilepm/Domain.Model/Products/BacklogItems/BacklogItem.cs#L201">здесь</a> и <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_common/Domain.Model/DomainEventPublisher.cs#L77">здесь</a></p> -<p>Kamil Grzybek вводит явное разделение механизма доставки на две ступени, первая - для внутренних Domain Events, вторая - для внешних:</p> <blockquote> -<div><p>Domain Events Notifications</p> -<p>There is no such thing as domain events notifications in DDD terms. -I gave that name because I think it fits best – it is notification that domain event was published.</p> -<p>Mechanism is pretty simple. -If I want to inform my application that domain event was published I create notification class for it and as many handlers for this notification as I want. -I always publish my notifications after transaction is committed. -The complete process looks like this:</p> -<ol class="arabic simple"> -<li><p>Create database transaction.</p></li> -<li><p>Get aggregate(s).</p></li> -<li><p>Invoke aggregate method.</p></li> -<li><p>Add domain events to Events collections.</p></li> -<li><p>Publish domain events and handle them.</p></li> -<li><p>Save changes to DB and commit transaction.</p></li> -<li><p>Publish domain events notifications and handle them.</p></li> -</ol> -<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/how-to-publish-and-handle-domain-events/">How to publish and handle Domain Events</a>" <a class="footnote-reference brackets" href="#fnkgde1" id="id68" role="doc-noteref"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> +<div><p>📝 "Знание есть не только <strong>преобразование опыта</strong> в сознание путем структуризации, обозначения его элементов, не только фиксация опыта в социальной памяти. +Оно является способом трансформации знаковых систем, сознания, деятельности и общения, придания им новой формы, т. е. нового смысла и значения. +Знание возникает как осмысление человеком контекстов своего <strong>опыта</strong>."</p> +<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">Новая философская энциклопедия: В 4 тт.</a>" М.: Мысль. Под редакцией В. С. Стёпина. 2001.</p> </div></blockquote> -<p>А вот Udi Dahan в своей статье "Domain Events – Salvation" <a class="footnote-reference brackets" href="#fnudde3" id="id69" role="doc-noteref"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></a> предложил использовать единый Mediator как для внутренних синхронных подписчиков, вызываемых в той же транзакции, так и для асинхронных подписчиков.</p> -</section> -<section id="id70"> -<h2><a class="toc-backref" href="#id135" role="doc-backlink">Кто может издавать Domain Event?</a></h2> <blockquote> -<div><p>One more point about what can cause a Domain Event is noteworthy. -Although often it is a user-based command emitted by the user interface that causes an event to occur, sometimes Domain Events -can be caused by a different source. -This might be from a timer that expires, such as at the end of the business day or the end of a week, month, or year. -In cases like this it won't be a command that causes the event, because the ending of some time period is a matter of fact. -You can't reject the fact that some time frame has expired, and if the business cares about this fact, the time expiration is modeled as a Domain Event, and not as a command.</p> -<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id71" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events :: Designing, Implementing, and Using Domain Events"</p> +<div><p>📝 "В совр. методологии науки принято выделять след. осн. компоненты теории:</p> +<ol class="arabic simple"> +<li><p>исходную эмпирич. основу, которая включает множество зафиксированных в данной области знания фактов, достигнутых в ходе экспериментов и требующих теоретич. объяснения;</p></li> +<li><p>исходную теоретич. основу — множество первичных допущений, постулатов, аксиом, общих законов Т., в совокупности описывающих идеализированный объект Т.;</p></li> +<li><p>логику Т.— множество допустимых в рамках Т. правил ло-гич. вывода и доказательства;</p></li> +<li><p>совокупность выведенных в Т. утверждений с их доказательствами, составляющую осн. массив теоретич. знания."</p></li> +</ol> +<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/1215/%D0%A2%D0%95%D0%9E%D0%A0%D0%98%D0%AF">Философский энциклопедический словарь.</a>" — М.: Советская энциклопедия. Гл. редакция: Л. Ф. Ильичёв, П. Н. Федосеев, С. М. Ковалёв, В. Г. Панов. 1983.</p> </div></blockquote> +<p>Когда в коллективе недостаточно знаний, столкновения мнений и конфликты всегда неизбежны. +Потому что <strong>мнение</strong> выражает индивидуальный опыт человека, которым оно призведено. +А это значит, что любое несогласие с его мнением воспринимается как недооценка его опыта, ущемление компетентности и угроза социальному положению, что может усиливаться рядом <a class="reference internal" href="cognitive-biases.html#emacsway-cognitive-biases"><span class="std std-ref">когнитивых искажений</span></a>. +Этим объясняется повышенная токсичность online IT-сообществ.</p> +</section> +<section id="emacsway-knowledge-in-psychology"> +<span id="id5"/><h2><a class="toc-backref" href="#id13" role="doc-backlink">О знаниях</a></h2> +<p><strong>Знания</strong> же человек не отождествляет с персональной компетентностью, поскольку знания производятся гораздо более широким охватом опыта. +Соответственно, он уже не воспринимает несогласие с его позицией как ущемление достоинства. +Как говорится, "мопед не мой".</p> <blockquote> -<div><p>Sometimes Events are designed to be created by direct request from clients. -This is done in response to some occurrence that is not the direct result of executing behavior on an instance of an Aggregate in the model. -Possibly a user of the system initiates some action that is considered an Event in its own right. -When that happens, the Event can be modeled as an Aggregate and retained in its own Repository. -Since it represents some past occurrence, its Repository would not permit its removal. -When Events are modeled in this way, like Aggregates they become part of the model's structure. -Thus, they are not just a record of some past occurrence, although they are that also.</p> -<p>-"Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id72" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "Chapter 8. Domain Events :: Modeling Events :: With Aggregate Characteristics"</p> +<div><p>📝 "As Issac Newton <a class="reference external" href="https://en.wikipedia.org/wiki/Standing_on_the_shoulders_of_giants">said</a>: "If I have seen further, it is by standing on the shoulders of giants.""</p> +<p class="attribution">—Mike Cohn, "<a class="reference external" href="https://www.mountaingoatsoftware.com/blog/my-favorite-resource-for-agile-advice-support-and-answers">My Favorite Resource for Agile Advice, Support, and Answers</a>". +Isaac Newton wrote in a 1675 letter to fellow scientist Robert Hooke.</p> </div></blockquote> +</section> +<section id="id6"> +<h2><a class="toc-backref" href="#id14" role="doc-backlink">Решение</a></h2> +<p>Мне известны два способа решения такого рода конфликтов:</p> +<ol class="arabic"> +<li><p>Восполнить информационный вакуум путем обращения к расширенному обобщенному опыту, т.е. к теории, дабы восполнить недостающие точки зрения, возникшие в силу заведомой ограниченности индивидуального опыта. +Причем, этот метод требует деликатности, ибо знания могут быть отторгнуты коллективом в силу эффекта "<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологической Защиты</a>", так как выводят коллектив из зоны комфорта, и могут спровоцировать чувство ущербности на фоне осведомленности спикера. +Лучшая форма донесения новых знаний - это постановка перед коллективом таких вопросов, которые способны пролить свет на недостающие точки зрения. +Не говорить, а спрашивать. +Об этом писали Kent Beck, Neal Ford, Gregor Hohpe и др. +Это раздвигает границы опыта человека, на котором он основывает свое мнение, и вынуждает переосмыслить его.</p> <blockquote> -<div><p>Events are facts happening in the domain. There's no implicit filter on the source: in fact, they can happen for different reasons: -- they might be the consequence of some User Initiated Action, -- they might be coming from some external system, -- they might be the result of time passing, -- they might be the direct consequence of some other event.</p> -<p class="attribution">—"Leanpub: Introducing EventStorming" by Alberto Brandolini</p> +<div><p>📝 "Неприступные крепости легче всего берутся изнутри".</p> </div></blockquote> +<p>Дело может существенно облегчиться, если у коллектива имеются общепризнанные им авторитетные авторы, освещающие решаемый вопрос. +Зачастую помогают стандарты и материалы для сертификации уровня знаний.</p> +<p>Сам по себе отсыл к авторитету не является доказательством, однако, авторитеты находятся в более выгодном положении перед практикующими специалистами, поскольку занимаются этим профессионально, в то время как практикующий специалист основную часть ресурсов времени тратит на добывание средств к существованию, и не располагает ресурсами для обеспечения соизмеримой широты дивергентной фазы исследования и глубины конвергентной её проработки.</p> +<p>Иными словами, обобщение и систематизация коллективного опыта требует таких ресурсов времени, которыми обычный практик, как правило, не располагает (хотя бывают исключения). +Как гласит народная мудрость, "скажи мне, кто твой друг, и я скажу, кто ты", а "лучший друг - это книга".</p> +<p>Тем не менее, авторитеты тоже люди, и тоже могут ошибаться, пусть и реже. +Так, например, как показала эволюция архитектурной области знаний, границы микросервисов все-таки не должны соответствовать границам Bounded Context, как считал Sam Newman на заре микросервисной архитектуры. +Так что критического мышления никто не отменял.</p> +<p>Разработка стандартов располагает еще большими финансовыми ресурсами для исследовательской фазы:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.iec.ch/standards-development/stages">https://www.iec.ch/standards-development/stages</a></p></li> +<li><p><a class="reference external" href="https://standards.ieee.org/develop/">https://standards.ieee.org/develop/</a></p></li> +</ul> +<p>Стандарты тоже устаревают и регулярно пересматриваются и актуализируются.</p> +</li> +<li><p>Не настаивать на принятии решения в условиях недостаточной информированности. Дейл Карнеги в свое время дал такой совет для борьбы со стрессом - не пытайтесь принять решение в условиях недостаточной информированности. +Просто собирайте информацию, и решение придет само.</p> +<p>Если продолжать настаивать ("Вы должны сегодня определиться!..."), то возможны два сценария развития ситуации:</p> +<ol class="arabic simple"> +<li><p>Силы консолидации коллектива возобладают над силой внешнего принуждения коллектива. Принуждение будет отторгнуто ("А нам это не нужно...").</p></li> +<li><p>Сила внешнего принуждения возобладает над силами консолидации коллектива. Участники коллектива поймут, что защищать свое мнение в виде собственного достоинства легче сообща, и начнут объединяться по признаку отождествления общих угроз, что приведет к расколу коллектива по группам. Исправить такой раскол может оказаться сложно и долго.</p></li> +</ol> +</li> +</ol> </section> -<section id="id73"> -<h2><a class="toc-backref" href="#id136" role="doc-backlink">Может ли Domain Event отменить свою причину?</a></h2> +<section id="emacsway-theory"> +<span id="id7"/><h2><a class="toc-backref" href="#id15" role="doc-backlink">О роли теории</a></h2> <blockquote> -<div><p>Domain events are ordinarily immutable, as they are <strong>a record of something in the past</strong>. -In addition to a description of the event, a domain event typically contains a timestamp for the time the event occurred and the identity of entities involved in the event.</p> -<p>- "Domain-Driven Design Reference" <a class="footnote-reference brackets" href="#fndddr" id="id74" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Domain events"</p> +<div><p>📝</p> +<div class="line-block"> +<div class="line">— Эй, там болото, вот карта моих попыток пройти.</div> +<div class="line">— Зачем тратить время на чтение, если можно совершить собственный поход и вляпаться самолично!</div> +</div> +<p class="attribution">—<a class="reference external" href="http://mellarius.ru/">mellarius.ru</a></p> </div></blockquote> <blockquote> -<div><p>A command is different from a Domain Event in that a command can be rejected as inappropriate in some cases, such as due to supply and availability of some resources (product, funds, etc.), or another kind of business-level validation. -<strong>So, a command may be rejected, but a Domain Event is a matter of history and cannot logically be denied.</strong> -Even so, in response to a time-based Domain Event it could be that the application will need to generate one or more commands in order to ask the application to carry out some set of actions.</p> -<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id75" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events :: Designing, Implementing, and Using Domain Events"</p> +<div><p>📝 "Всякий, кто полагается на практику, не зная теории, подобен кормчему, вступающему на судно без руля и компаса, – он не знает, куда плывет. +Практика всегда должна опираться на твердые теоретические основания."</p> +<p class="attribution">—Леонардо да Винчи</p> </div></blockquote> <blockquote> -<div><p>Your Domain Event type names should be <strong>a statement of a past occurrence</strong>, that is, a verb in the past tense. -Here are some examples from the Agile Project Management Context : ProductCreated, for instance, states that a Scrum product was created at some past time. -Other Domain Events are ReleaseScheduled, SprintScheduled, BacklogItemPlanned, and BacklogItemCommitted. -Each of the names clearly and concisely states what happened in your Core Domain.</p> -<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id76" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events :: Designing, Implementing, and Using Domain Events"</p> +<div><p>📝 "Знание букв еще не делает человека поэтом."</p> +<p class="attribution">—Автор неизвестен</p> </div></blockquote> <blockquote> -<div><p>As noted earlier, an important characteristic of events is that since an event is something that happened in the past, it should not change. -Therefore, it must be an immutable class. You can see in the previous code that the properties are read-only. -There's no way to update the object, you can only set values when you create it.</p> -<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id77" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#implement-domain-events">Domain events: design and implementation :: Implement domain events</a>"</p> +<div><p>💬 "Умный учится на своих ошибках, мудрый учится на чужих, а дурак не учится никогда."</p> +<p class="attribution">—Народная мудрость</p> </div></blockquote> -<p>Таким образом, Событие не может изменить прошлого, хотя и может <a class="reference external" href="https://microservices.io/patterns/data/saga.html">инициировать компенсационную транзакцию</a> и изменить будущее. -Если вы когда-нибудь работали с Emacs, то заметили, что его команда Undo <a class="reference external" href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Undo.html">не возвращает в прошлое</a>, а компенсирует ранее выполненные команды. -По этой причине в Emacs отсутствует Redo.</p> +<p>Здесь, наверное, было бы уместно сделать небольшое отступление. +Распространенным заблуждением начинающих и толковых ребят является вера в то, что практика и опыт могут заменить работу с теорией, в частности - с литературой.</p> +<p>Во-первых, среднестатистический коммерческий проект на рынке не так уж и часто может служить источником качественной практики (если даже не наоборот). +Более лучшим источником качественной практики могут служить <a class="reference internal" href="../it/self-education/self-education-for-software-engineer.html#emacsway-reference-applications"><span class="std std-ref">открытые проекты</span></a>, основанные компетентными сообществами.</p> +<p>А во-вторых, помните что Дейкстра говорил о строго ограниченных размерах человеческого черепа?</p> <blockquote> -<div><p>Starting from that moment, the entire sequence of undo commands that you have just performed are themselves placed into the undo record. -Therefore, to re-apply changes you have undone, type C-f or any other command that harmlessly breaks the sequence of undoing; then type C-/ one or more times to undo some of the undo commands.</p> -<p>- <a class="reference external" href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Undo.html">The Emacs Editor</a></p> +<div><p>📝 "The competent programmer is fully aware of the strictly limited size of his own skull; +therefore, he approaches the programming task in full humility"</p> +<p class="attribution">—Edsger W. Dijkstra, 1972</p> </div></blockquote> -<p>Однако, рассмотрение <a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/compensating-transaction">компенсационных транзакций</a> уже выходит за рамки данного поста.</p> +<p>Намерение воспроизвести в одиночку эволюцию целой индустрии - это весьма самонадеянно. +Может не хватить жизни. +Или вы учитесь на своих ошибках, или на чужих. Последний вариант выгодней. +Можно, конечно, попытаться изобрести колесо, и в одиночку обобщить и систематизировать весь совокупный опыт индустрии, и, если человек обладает интеллектом Эриха Гаммы или Мартина Фаулера, и сможет изыскать времени в половину жизни на эти исследования, то у него может даже и получиться. +Вот только совокупный обобщенный опыт индустрии выражается, опять же, в литературе. +Круг замкнулся.</p> +<p>Возьмем пример из спорта. +Сколько бы вы не смотрели выполнение задней подножки на практике, но, без знания теоретической составляющей, выполнить ее вы не сможете. +Более того, при попытке ее провести, вы поставите себя в уязвимое положение, и, с высокой долей вероятности, будете успешно контратакованы. +Это потому, что самая важная часть ее подготовки - перераспределение нагрузки, снаружи не видна, но играет решающую роль. +Множество людей годами систематизировали практику, и создавали теорию. +Благодаря теории, теперь не нужно проживать несколько жизней, чтобы все это постигнуть. +Это я говорил про Самбо - не самая теоретическая наука по сравнению с разработкой программного обеспечения.</p> +<p>Игнорирование теории по сути является проявлением "<a class="reference external" href="https://sergeyteplyakov.blogspot.com/2013/09/blog-post_24.html">Культа Карго</a>". +Еще одним ярким примером игнорирования теории является эпизод о том, как нарисовать семь перпендикулярных линий игнорируя геометрию, из известной короткометражки "<a class="reference external" href="https://youtu.be/UoKlKx-3FcA?t=269">The Expert</a>" (<a class="reference external" href="https://youtu.be/BKorP55Aqvg?t=269">in English</a>, оригинальный текст - "<a class="reference external" href="https://alex-aka-jj.livejournal.com/66984.html">Совещание</a>" / Алексей Березин).</p> <blockquote> -<div><p>Eventual consistency can lead to undesirable scenarios. -For example, if a payment has been rejected, you can't just roll back the transaction and not create the order (as many non‐eventually consistent systems would); the order was already created as part of a previous transaction in a different component and currently lives in that component's database. -What you can do, though, is roll forward into a new state. -You'd probably tell the customer the order could not be completed because payment failed. -Ideally you would tell her immediately when she tries to place an order. -However, you have to remember that you're trying to build a scalable fault‐tolerant solution and you need to make sacrifices. -Upsetting the few customers who cannot successfully place orders so that everybody else gets a superior user experience is often an acceptable trade‐off. -When you are in an inconsistent state, you need to roll forward into a new state that represents the wishes of the business or the real‐world domain processes you are modeling.</p> -<p>- "Patterns, Principles, and Practices of Domain-Driven Design" <a class="footnote-reference brackets" href="#fnpppddd" id="id78" role="doc-noteref"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></a> by Scott Millett, Nick Tune, Chapter "12 Integrating via Messaging :: Building an E‐Commerce Application with NServiceBus :: Eventual Consistency in Practice :: Dealing with Inconsistency"</p> +<div><p>📝 "Есть одно только благо – знание, и одно только зло – невежество." - Сократ</p> </div></blockquote> -</section> -<section id="id79"> -<h2><a class="toc-backref" href="#id137" role="doc-backlink">Решение - это баланс стоимости и обретаемой выгоды</a></h2> -<p>Любое решение - это баланс выгод и затрат на его реализацию. -Решение не должно базироваться на <a class="reference external" href="https://youtu.be/LDW0QWie21s?t=1363">"религиозном" догматизме</a>, основываясь на бездумной вере только в то, что кто-то так сказал, не понимая при этом причин и следствий. -Нужно понимать причину решения, решаемую им проблему, и применять его сообразно стоящими перед конкретным проектом проблемами.</p> -<section id="cqrs"> -<span id="emacsway-domain-event-cqrs-command-result"/><h3><a class="toc-backref" href="#id138" role="doc-backlink">Может ли CQRS-команда возвращать результат?</a></h3> -<p>Хорошим примером, демонстрирующим архитектурную гибкость мышления, является ответ Jimmy Bogard по поводу того, может ли Команда в CQRS возвращать результат?</p> <blockquote> -<div><p>It might seem rather strange that commands always have a result, but it's much, much easier to deal with side effects of commands through return parameters than through some other means (global registry, static field, re-querying some object, collecting parameter, etc.). <strong>For commands that create an item, I usually want to redirect to a screen showing that item, very easily accomplished when I can get the created item and as for its ID.</strong></p> -<p>This is a bit controversial, but don't frankly care, as it's the simplest thing that could possibly work. If I want to have a command that returns Void, I could steal a page from F# and have a Command base class that returns a Unit type:</p> -<p>- "<a class="reference external" href="https://lostechies.com/jimmybogard/2013/12/19/put-your-controllers-on-a-diet-posts-and-commands/">Put your controllers on a diet: POSTs and commands</a>" by Jimmy Bogard</p> +<div><p>📝 "Те компании, которые не осознают, что знания являются средством производства более важным, чем земля, труд или капитал, постепенно умрут и никогда не поймут, что их погубило."</p> +<p class="attribution">—Ларри Прусак</p> </div></blockquote> -<p>Причины такого решения он раскрывает в другой своей статье:</p> <blockquote> -<div><p>Myth #2 – CQRS requires an eventual consistent read store</p> -<p>No, it does not. You can make your read store immediately consistent. That is, your read store can be updated when your command side succeeds (in the same transaction).</p> -<p>For many legacy/existing apps, transitioning to eventually consistent read stores will either force you to go through bogus hoops of mimicking synchronous calls. Users will bang down on your door with pitchforks and torches if you try and transition to an asynchronous model if you don't change their business process first.</p> -<p>Instead, you can start with immediate consistency and transition where and when it's needed. Unless a user expects a confirmation page, making every command page have a series of confirmations of "your request was received" is going to annoy the snot out of your users.</p> -<p>Myth #3 – CQRS requires a bus/queues/asynchronous messaging</p> -<p>See above myth. <strong>Nothing about CQRS says "thou shalt use NServiceBus". It's just not there. You're merely separating infrastructure between handling commands and queries, but the how is quite varied. Don't start with a bus until you prove you need eventual consistency.</strong></p> -<p>Consistency models are a business decision because it directly impacts user experience. An eventually consistent model requires a different user experience than an immediate one, and this is not something you can just "slip in" to your users, or try to emulate. If you're attempting to emulate immediate consistency in an eventually consistent model, you're doing something wrong.</p> -<p>- "<a class="reference external" href="https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/">Busting some CQRS myths</a>" by Jimmy Bogard</p> +<div><p>📝 "Глупость — дар Божий, но злоупотреблять им не следует."</p> +<p class="attribution">—Отто фон Бисмарк</p> </div></blockquote> -<p>Что он также подтверждает своим комментарием к этой статье:</p> <blockquote> -<div><p>Scaling and CQRS are orthogonal, it's highly contextual and certainly doesn't require async.</p> -<p>- "<a class="reference external" href="https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/#comment-3422377189">Busting some CQRS myths</a>" by Jimmy Bogard</p> +<div><p>📝 "Nothing will come of nothing."</p> +<p class="attribution">—William Shakespeare,"King Lear"</p> </div></blockquote> -<p>Итак, ответ прост - если вы не используете асинхронное исполнение Команды посредством инфраструктуры (Command Bus), то ничто не препятствует вам получить идентификатор вновь созданной записи БД в возвращаемом командой результате, и реализацию можно существенно упростить.</p> -<p>Вы можете удивиться, какая связь между Командами CQRS и Domain Events? -А связь заключается в том, что и в первом, и во втором случае, отступление от принципа приводит к упрощению реализации, но к ухудшению возможностей масштабирования. -И в том, и в другом случае, решением является баланс между простотой реализации и потребностью в масштабировании.</p> -<p>Впрочем, вопрос относительно того, должна ли Команда CQRS возвращать результат, и не противоречит ли это CQS принципу Bertrand Meyer, заслуживает на "<a class="reference internal" href="../../cqrs/cqrs-command-and-result.html"><span class="doc">отдельное исследование</span></a>". -Как известно, термин CQRS ввел Greg Young, разделив CQS на два отдельных класса.</p> +</section> +<section id="id8"> +<h2><a class="toc-backref" href="#id16" role="doc-backlink">Рождается ли в споре истина?</a></h2> +<p>Вообще, как показывает практика, в спорах люди ищут самоутверждение, а не истину. +Поэтому, они редко когда заканчиваются истиной. +Каждый хочет, чтобы правда была на его стороне, но не каждый хочет быть на стороне правды.</p> +<p>В спорах сходится два <a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/737">мнения</a>. Мнения могут быть противоречивы, т.к. они могут производиться разным подмножеством опыта двух субъектов спора.</p> +<p>Максимум, что можно достигнуть в споре - это выработать "коллективное мнение". Но оно производится все тем же ограниченным, хотя теперь уже и объединенным, мнением. Это пока еще не знание. Для обретения <a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">знания</a> нужно обратиться к максимально широкому опыту индустрии, произвести широкую дивергентную исследовательскую фазу, выявить все существующие в отрасли мнения, обнаружить их противоречия, и путем обобщения и систематизации вывести такую непротиворечивую форму информации, которая, в определенных обстоятельствах, может стать знанием. А эта активность выходит далеко за пределы спора и отличается от спора именно тем, что субъекты не настаивают на своей ограниченной позиции, и прилагают все усилия для максимального расширения того опыта, которым эта позиция формируется.</p> +<p>Иными словами, цель спора - присадить оппонента до своего уровня. А цель постижения знаний - максимально расширить свой охват опыта. Вопрос в том, что если человек хочет расширить свой охват опыта, то он в споре, как в малоэффективном инструменте, не нуждается, поскольку существуют другие, более эффективные источники обретения обобщенного и систематизированного коллективного опыта индустрии.</p> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference internal" href="../it/self-education/self-education-for-software-engineer.html#emacsway-self-education-literature"><span class="std std-ref">Список литературы для самообучения разработчика программного обеспечения</span></a>"</p></li> +<li><p>"<a class="reference internal" href="planning-in-psychology.html#emacsway-planning-in-psychology"><span class="std std-ref">Психологическое значение планирования</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../it/sdlc/uncertainty-management/adaptation/software-design/patterns.html#emacsway-agile-patterns"><span class="std std-ref">Role of Design Patterns in Agile</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../it/team-topologies/harlan-mills%27-proposal.html#emacsway-brooks-s-law"><span class="std std-ref">Закон Брукса</span></a>"</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/BoiledCarrot.html">Boiled Carrot</a>" by Martin Fowler</p></li> +<li><p>"<a class="reference external" href="http://lib.ru/LITRA/KRYLOW/basni.txt">Мартышка и очки</a>" / И.А. Крылов</p></li> +</ul> +</div> +</section> +</section> +Sat, 21 Oct 2023 00:00:00 Что такое Agile Developmenthttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/agile/agile.html +<span id="emacsway-agile-development"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#agile-development" id="id10">Что такое Agile Development</a></p> +<ul> +<li><p><a class="reference internal" href="#id2" id="id11">Определение</a></p></li> +<li><p><a class="reference internal" href="#id3" id="id12">История</a></p></li> +<li><p><a class="reference internal" href="#emacsway-agile-development-essence" id="id13">Суть</a></p></li> +<li><p><a class="reference internal" href="#emacsway-agile-development-difficulties" id="id14">О сложностях</a></p> +<ul> +<li><p><a class="reference internal" href="#id6" id="id15">Пример</a></p></li> +</ul> +</li> +</ul> +</li> +</ul> +</nav> +<section id="id2"> +<h2><a class="toc-backref" href="#id11" role="doc-backlink">Определение</a></h2> <blockquote> -<div><p>Starting with CQRS, CQRS is simply the creation of two objects where there was previously only one. -The separation occurs based upon whether the methods are a command or a query (the same definition that is used by Meyer in Command and Query Separation, a command is any method that mutates state and a query is any method that returns a value).</p> -<p>- "CQRS, Task Based UIs, Event Sourcing agh!" <a class="footnote-reference brackets" href="#fngycqrs" id="id80" role="doc-noteref"><span class="fn-bracket">[</span>26<span class="fn-bracket">]</span></a> by Greg Young</p> +<div><p>💬 "Agile development - software development approach based on <a class="reference internal" href="../iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a> development, frequent inspection and <a class="reference internal" href="../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">adaptation</span></a>, and <a class="reference internal" href="../incremental.html#emacsway-incremental-development"><span class="std std-ref">incremental</span></a> deliveries, in which requirements and solutions evolve through collaboration in cross‐functional teams and through continual stakeholder feedback."</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> </div></blockquote> -<p>Забегая наперед, скажу, что не противоречит, при соблюдении определенных условий.</p> -<p>Во-первых, в основе CQS лежит принцип функциональной чистоты:</p> <blockquote> -<div><p>Command-Query Separation principle - Functions should not produce abstract side effects.</p> -<p>- "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id81" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Objects as machines"</p> +<div><p>💬 "Scrum is, as the reader supposedly knows, an agile method. +The agile family of development methods evolved from the old and well-known <a class="reference internal" href="../iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a> and <a class="reference internal" href="../incremental.html#emacsway-incremental-development"><span class="std std-ref">incremental</span></a> life-cycle approaches. +They were born out of a belief that an approach more grounded in human reality – and the product development reality of learning, innovation, and change – would yield better results."</p> +<p class="attribution">—"Jeff Sutherland's Scrum Handbook" by Jeff Sutherland</p> </div></blockquote> -<p>Во-вторых, кроме функций-команд и функций-запросов, Bertrand Meyer вводит еще и функции-конструкторы. И тут кроется интересное:</p> <blockquote> -<div><p>From a mathematical perspective we may pretend that all of the objects of interest, for all times past, present and future, are already inscribed in the Great Book of Objects; <strong>a creation instruction is just a way to obtain one of them, but it does not by itself change anything in the environment</strong>. It is common, and legitimate, for a function to create, initialize and return such an object. -<strong>These observations assume that in the second form the creation procedure make does not produce side effects on any object other than the one being created.</strong></p> -<p>- "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id82" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Functions that create objects"</p> +<div><p>💬 ""Agile" methods actually can be applied within a variety of models. +While Agile methods are common in executing an evolutionary lifecycle model, they can be used in other lifecycle models at various stages. +What the methods have in common is an emphasis on continuous inspection and collaboration in the rapid production of working software in an environment where changes, including changes to requirements, are expected."</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> </div></blockquote> -<p>Этот пример наглядно демонстрирует нам, почему важно всегда изучать мнение первоисточника. -Сравните это с тем, какие выводы можно сделать на основе утверждений Vaughn Vernon и Википедии:</p> <blockquote> -<div><p>This principle, devised by Bertrand Meyer, asserts the following:</p> -<blockquote> -<div><dl class="simple"> -<dt>Every method should be either a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer.</dt><dd><p>More formally, methods should return a value only if they are referentially transparent and hence possess no side effects. [Wikipedia, CQS]</p> -</dd> -</dl> +<div><p>💬 "As discussed in 5.4.2, the life cycle models used in agile projects are often highly <a class="reference internal" href="../incremental.html#emacsway-incremental-development"><span class="std std-ref">incremental</span></a> and <a class="reference internal" href="../evolutionary.html#emacsway-evolutionary-development"><span class="std std-ref">evolutionary</span></a>."</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> </div></blockquote> -<p>At an object level this means:</p> -<ol class="arabic simple"> -<li><p>If a method modifies the state of the object, it is a command, and its method must not return a value. In Java and C# the method must be declared void .</p></li> -<li><p><strong>If a method returns some value, it is a query</strong>, and it must not directly or indirectly cause the modification of the state of the object. In Java and C# the method must be declared with the type of the value it returns.</p></li> -</ol> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id83" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "4. Architecture :: Command-Query Responsibility Segregation, or CQRS"</p> +<blockquote> +<div><p>💬 "Unlike Waterfall, Agile emphasizes <strong>iterative</strong> development, or building software <strong>in pieces</strong> <em>[i.e. incremental]</em>. +Agile teams typically work in short cycles—which are called "sprints" in Scrum, today one of the most widely used forms of Agile—that usually last two weeks each."</p> +<p class="attribution">—"<a class="reference external" href="https://www.theatlantic.com/technology/archive/2017/12/agile-manifesto-a-history/547715/">The Winter Getaway That Turned the Software World Upside Down</a>" by Caroline Mimbs Nyce</p> </div></blockquote> -<p>Или из CQRS Journey:</p> <blockquote> -<div><p>A query returns data and does not alter the state of the object; a command changes the state of an object but does not return any data.</p> -<p>- "<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/jj591573(v=pandp.10)#what-is-cqrs">CQRS Journey :: Reference 2: Introducing the Command Query Responsibility Segregation Pattern :: What is CQRS?</a>"</p> +<div><p>💬 In the software world, “waterfall” is commonly used to describe a style of software process, one that contrasts with the ideas of iterative, or agile styles.</p> +<p>💬 "Certainly agile processes require an iterative approach and cannot work in a waterfall style."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/WaterfallProcess.html">Waterfall Process</a>" by Martin Fowler</p> </div></blockquote> -<p>Но как быть, если команда исполняется асинхронно, используя инфраструктуру (Command Bus), и мы должны вернуть результат команды в исполнение требований <a class="reference external" href="https://tools.ietf.org/html/rfc7231#page-25">RFC-7231</a> для HTTP-method POST REST API:</p> +</section> +<section id="id3"> +<h2><a class="toc-backref" href="#id12" role="doc-backlink">История</a></h2> +<p>В заметке "<a class="reference internal" href="../../uncertainty-management/prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Что такое Prediction</span></a>" было сформировано противоречие, которое заключается в том, что для того, чтобы снизить стоимость разработки, нам необходимо повысить точность прогнозирования (повысить полноту требований), но повышение точности прогнозирования, в свою очередь, повышает стоимость разработки (возникает отрицательная обратная связь). +Причем, повышает её экспоненциально, в то время как бизнес-выгоды от этой точности возрастают логарифмически. +Иными словами, точность прогнозирования всегда имеет предел экономической целесообразности, который определяется пересечением этих двух графиков (за вычетом стоимости реализации, разумеется).</p> +<p>Мы не можем повышать точность прогнозирования, т.к. она превысит предел экономической целесообразности, но мы вынуждены её повысить для того, чтобы принимать решения в момент наименьшей стоимости их реализации.</p> +<p>Как можно разрешить этот "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A3%D0%BB%D0%BE%D0%B2%D0%BA%D0%B0-22">Catch-22</a>"? +Согласно "Первому закону диалектики", противоречие должно привести к синтезу, т.е. к качественному изменению.</p> +<p>И решение этого противоречия схоже с решением противоречия "<a class="reference internal" href="../../../team-topologies/harlan-mills%27-proposal.html#emacsway-brooks-s-law"><span class="std std-ref">Закона Брукса</span></a>", в виде автономных команд. +Или же с решением в виде Bounded Context, которое разрешает противоречие, заключающееся в том, что при стремлении выровнять язык по всей модели, он стремится к противоречивости (и неоднозначности). +Т.е. стремление следовать предметной области вынуждает отступать от неё. +В нашем случае решение так же заключается в разбиении целого (процесса разработки) на части (итерации), только вместо согласованности единого языка здесь критерием разделения выступает достаточность полноты требований.</p> +<p>Agile является естественным следствием эволюции итеративной разработки, краткий обзор которой можно посмотреть в превосходной статье Craig Larman "<a class="reference external" href="https://www.craiglarman.com/wiki/downloads/misc/history-of-iterative-larman-and-basili-ieee-computer.pdf">Iterative and Incremental Development: A Brief History</a>". +В ней говорится о том, что цикл PDSA известен еще с 1930 года, в 1957 году впервые была применена <a class="reference internal" href="../incremental.html#emacsway-incremental-development"><span class="std std-ref">инкрементальная</span></a> модель разработки, а в 1968 году - <a class="reference internal" href="../iterative.html#emacsway-iterative-development"><span class="std std-ref">итеративная</span></a>.</p> +<p>Как уже говорилось ранее, итеративная модель разработки открывает широкие возможности для <a class="reference internal" href="../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">удешевления обработки неопределенности</span></a>. +Однако долгое время эти возможности оставались экономически нецелесообразными по причине быстрорастущего характера роста стоимости <a class="reference internal" href="../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Adaptation</span></a>, приближющегося к экспоненциальному. +При таком характере роста возникает экономическая целесообразность принимать решения в момент наименьшей стоимости их реализации, вплоть до заблаговременного проектирования (BDUF).</p> <blockquote> -<div><p>the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created (Section 7.1.2) and a representation that describes the status of the request while referring to the new resource(s).</p> -<p>- "<a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-4.3.3">Section 4.3.3. POST of RFC-7231</a>"</p> +<div><p>💬 "WaterFall is based on the empirical observation of 30 years ago (ref: BarryBoehm, Software Engineering Economics, Prentice Hall, 1981.) that the cost of change rises exponentially (base 10) by phases. The conclusion is that you should make the big decisions up front, because changing them is so expensive."</p> +<p class="attribution">—"<a class="reference external" href="https://wiki.c2.com/?WaterFall">Water Fall</a>" at c2.com</p> </div></blockquote> -<p>Есть два варианта (помимо того, что можно просто запросить идентификатор у сервера предварительно).</p> -<p>Первый предлагает Udi Dahan:</p> +<figure class="align-left" id="id7"> +<a class="reference internal image-reference" href="../../../../../_images/exponential-cost-of-change.png"><img alt="Figure 1. The cost of change rising exponentially over time. The image source is &quot;Extreme Programming Explained&quot; 1st edition by Kent Beck, &quot;Chapter 5. Cost of Change&quot;." src="../../../../../_images/exponential-cost-of-change.png" style="width: 90%;"/></a> +<figcaption> +<p><span class="caption-text">Figure 1. The cost of change rising exponentially over time. The image source is "Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change".</span></p> +</figcaption> +</figure> +<p>Однако, в конце 1990-х - начале 2000-х, в архитектурном мире произошли существенные изменения - обрели массовую популярность высокоуровневые объектно-ориентированные языки, появились <a class="reference internal" href="../../uncertainty-management/adaptation/software-design/patterns.html#emacsway-agile-patterns"><span class="std std-ref">шаблоны</span></a> и принципы проектирования, методики управления сложностью (ROM, POSA, GOF, OOAD, <a class="reference internal" href="../../uncertainty-management/adaptation/software-design/solid.html#emacsway-agile-solid"><span class="std std-ref">SOLID</span></a>, Use Case Driven Approach, Object-Oriented Software Construction etc.), появились <a class="reference internal" href="../../../tdd/tdd.html#emacsway-tdd"><span class="std std-ref">TDD</span></a>, Refactoring и т.п.</p> +<p>Унификация знаний в области архитектуры, переход ментального оперирования на элементы унифицированных шаблонных конструкций более высокого уровня абстракции, позволили сократить когнитивную и коммуникативную нагрузку на разработчика, уменьшить порог вхождения в новый проект, смягчить негативное воздействие <a class="reference internal" href="../../../team-topologies/harlan-mills%27-proposal.html#emacsway-brooks-s-law"><span class="std std-ref">Закона Брукса</span></a>.</p> +<figure class="align-left" id="id8"> +<a class="reference internal image-reference" href="../../../../../_images/historical-cost-of-exploration.png"><img alt="FIGURE 3.8 Historical cost of exploration. The image source is &quot;Essential Scrum: A Practical Guide to the Most Popular Agile Process&quot; by Kenneth Rubin, &quot;Chapter 3 Agile Principles :: Prediction and Adaptation&quot;." src="../../../../../_images/historical-cost-of-exploration.png" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">FIGURE 3.8 Historical cost of exploration. The image source is "Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation".</span></p> +</figcaption> +</figure> +<p>Рост количественных изменений привел к изменениям качественным ("Второй закон диалектики") - ведущим умам архитектуры своего времени удалось снизить характер роста стоимости адаптации вплоть до пологого графика, максимально приближенного к горизонтальной асимптоте. +Это означало, что стоимость реализации решения больше не зависело от момента его принятия, что позволило отказаться от заблаговременного проектирования и откладывать принятие решения до момента наибольшей полноты информированности, даже после частичной реализации продукта.</p> <blockquote> -<div><p>If the data is needed by the client as soon as it is submitted, it is there – on the client that submitted it. No need to poll the query side. The only thing that might not have been there is an ID from the database – which is easily solved with client-generated GUIDs instead of database-generated IDs.</p> -<p>- "<a class="reference external" href="http://udidahan.com/2009/12/09/clarified-cqrs/#comment-5118">Clarified CQRS</a>" comment 68 of Udi Dahan</p> +<div><p>💬 "What would we do if all that investment paid off? +What if all that work on languages and databases and whatnot actually got somewhere? +What if the cost of change didn't rise exponentially overtime, but rose much more slowly, <strong>eventually reaching an asymptote</strong>? +What if tomorrow's software engineering professor draws Figure 3 on the board?"</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change"</p> </div></blockquote> -<p>Мы просто генерируем идентификатор на стороне клиента (используя <a class="reference external" href="https://en.wikipedia.org/wiki/Universally_unique_identifier">UUID</a>, <a class="reference external" href="https://en.wikipedia.org/wiki/Hi/Lo_algorithm">Hi/Lo algorithm</a> и т.п.), а затем применяем <a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-4.3.4">PUT Request Method</a> для создания объекта.</p> +<figure class="align-left" id="id9"> +<a class="reference internal image-reference" href="../../../../../_images/flatten-cost-of-change.png"><img alt="Figure 3. The cost of change may not rise dramatically over time. The image source is &quot;Extreme Programming Explained&quot; 1st edition by Kent Beck, &quot;Chapter 5. Cost of Change&quot;." src="../../../../../_images/flatten-cost-of-change.png" style="width: 90%;"/></a> +<figcaption> +<p><span class="caption-text">Figure 3. The cost of change may not rise dramatically over time. The image source is "Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change".</span></p> +</figcaption> +</figure> +<p>Что такое асимтота, можно посмотреть в "§284 Асимтоты" Справочника по высшей математике / М.Я. Выгодский:</p> <blockquote> -<div><p>The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. &lt;...&gt; If the target resource does not have a current representation and the PUT successfully creates one, then the origin server MUST inform the user agent by sending a 201 (Created) response.</p> -<p>- "<a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-4.3.4">Section 4.3.4. PUT of RFC-7231</a>"</p> +<div><p>💬 "Прямая АВ называется асимптотой линии L, если расстояние МК (черт. 297) от точки М линии L до прямой АВ стремится к нулю при удалении точки М в бесконечность."</p> +<p class="attribution">—"Справочник по высшей математике" / М.Я. Выгодский</p> </div></blockquote> -<p>Идею второго варианта выразил самим Bertrand Meyer, в виде введения концепции буфера:</p> +<p>В нашем случае, нас интересует Асимптоты, параллельная оси абсцисс (там же):</p> <blockquote> -<div><p>buffer — the concurrent equivalent of a first-in, first out queue.</p> -<p>- "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id84" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Objections"</p> +<div><p>💬 "Для разыскания горизонтальных асимптот линии y = f(х) ищем пределы f(х) при х -&gt; +∞ и при х -&gt; -∞. Если lim х-&gt;∞ f(x) = b, то прямая у = b - асимптота (при бесконечном удалении вправо; черт. 299)."</p> +<p class="attribution">—"Справочник по высшей математике" / М.Я. Выгодский</p> </div></blockquote> -<p>И приводит пример:</p> -<div class="highlight-default notranslate"><div class="highlight"><pre><span/><span class="n">next_element</span> <span class="o">:=</span> <span class="n">buffer</span><span class="o">.</span><span class="n">item</span> -<span class="n">buffer</span><span class="o">.</span><span class="n">remove</span> -</pre></div> -</div> +</section> +<section id="emacsway-agile-development-essence"> +<span id="id4"/><h2><a class="toc-backref" href="#id13" role="doc-backlink">Суть</a></h2> +<p>Коротко говоря, Agile модель является итеративно-инкрементальной моделью разработки, на которую наложен ряд филосовско-психологических принципов с целью снизить напряжение между техническими специалистами и представителями бизнеса. +Морально-психологический климат в ИТ-индустрии того времени был, мягко говоря, напряженным:</p> <blockquote> -<div><p>With the notation of this chapter, it is easy to obtain exclusive access without sacrificing the Command-Query Separation principle: simply enclose the two instructions above, with buffer replaced by b, in a procedure of formal argument b, and call that procedure with the attribute buffer as argument.</p> -<p>- "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id85" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition by Bertrand Meyer, chapter "30.12 DISCUSSION :: Support for command-query separation"</p> +<div><p>💬 "For example, I think that ultimately, Extreme Programming has mushroomed in use and interest, not because of pair-programming or refactoring, but because, taken as a whole, the practices define a developer community freed from the baggage of Dilbertesque corporations. +Kent Beck tells the story of an early job in which he estimated a programming effort of six weeks for two people. +After his manager reassigned the other programmer at the beginning of the project, he completed the project in twelve weeks—and felt terrible about himself! +The boss—of course—harangued Kent about how slow he was throughout the second six weeks. +Kent, somewhat despondent because he was such a "failure" as a programmer, finally realized that his original estimate of 6 weeks was extremely accurate—for 2 people—and that his "failure" was really the manager's failure, indeed, the failure of the standard "fixed" process mindset that so frequently plagues our industry.</p> +<p>This type of situation goes on every day—marketing, or management, or external customers, internal customers, and, yes, even developers — don't want to make hard trade-off decisions, so they impose irrational demands through the imposition of corporate power structures. +This isn't merely a software development problem, it runs throughout Dilbertesque organizations.</p> +<p>In order to succeed in the new economy, to move aggressively into the era of e-business, e-commerce, and the web, companies have to rid themselves of their Dilbert manifestations of make-work and arcane policies. +This freedom from the inanities of corporate life attracts proponents of Agile Methodologies, and scares the begeebers (you can't use the word 'shit' in a professional paper) out of traditionalists. +Quite frankly, the Agile approaches scare corporate bureaucrats — at least those that are happy pushing process for process' sake versus trying to do the best for the "customer" and deliver something timely and tangible and "as promised" — because they run out of places to hide.</p> +<p>The Agile movement is not anti-methodology, in fact, many of us want to restore credibility to the word methodology. +We want to restore a balance. We embrace modeling, but not in order to file some diagram in a dusty corporate repository. +We embrace documentation, but not hundreds of pages of never-maintained and rarely-used tomes. We plan, but recognize the limits of planning in a turbulent environment. +Those who would brand proponents of XP or SCRUM or any of the other Agile Methodologies as "hackers" are ignorant of both the methodologies and the original definition of the term hacker."</p> +<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/history.html">History: The Agile Manifesto</a>"</p> </div></blockquote> -<p>Если транслировать этот же принцип на REST-API, то мы получим паттерн "<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/async-request-reply">Asynchronous Request-Reply pattern</a>", использующий <a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-6.3.3">202 Response Status Code</a>.</p> -<p>У Bertrand Meyer в главе "23.1 SIDE EFFECTS IN FUNCTIONS :: Pseudo-random number generators: a design exercise" книги "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id86" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition, есть пример с генератором случайных чисел, который решает задачу, аналогичную задаче с получением идентификатора ресурса. -Цитировать не буду, ибо много текста, если интересно, можно посмотреть в книге. -На примере с генератором случайных чисел хорошо видно, какую критическую роль играет правильное именование и правильное моделирование процессов предметной области. -И как легко можно создать кривое решение, если не иметь ясного понимания этих процессов, или если использовать недостаточно ясное именование.</p> -<p>Также он разделяет абстрактное состояние от конкретного состояния, и приводит пример, в значительной мере похожий на добавление нового ресурса через REST-API:</p> <blockquote> -<div><p>What this means for us is that a function that modifies a concrete object is harmless if the result of this modification still represents the same abstract object — yields the same a value. -For example assume in a function on stacks contains the operation</p> -<p>representation.put (some_value, count + 1)</p> -<p>(with the guarantee that the array's capacity is at least count + 1). -<strong>This side effect changes a value above the stack-significant section of the array; it can do no ill.</strong></p> -<p>- "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id87" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Abstract state, concrete state"</p> +<div><p>💬 "I think the Agile Manifesto has helped teams around the world rethink their priorities, and in the process has helped re-humanize software development."</p> +<p class="attribution">—"<a class="reference external" href="https://pragdave.me/blog/2007/02/24/some-agile-history.html">Some Agile History</a>" by Dave Thomas</p> </div></blockquote> -<p>Как видно, внимательное изучение первоисточника дает глубокое понимание целей, причин, спектра решаемых проблем, достоинств и недостатков, и, как следствие, приводит к более гибким и менее догматичным архитектурным решениям.</p> -<p>Как результат, в одном из лучших демонстрационных приложений, Команда возвращает результат, смотрите <a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs#L151">здесь</a> и <a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderDraftCommandHandler.cs#L40">здесь</a>.</p> -</section> -</section> -<section id="atomicity-and-resiliency-of-integration-events"> -<h2><a class="toc-backref" href="#id139" role="doc-backlink">Atomicity and Resiliency of Integration Events</a></h2> -<p>Если отправить Integration Event до коммита транзакции базы данных, то другой процесс не увидит изменений. -К тому же, может произойти откат транзакции, и согласованность данных будет утрачена. -А если после коммита, то существует вероятность, что процесс может аварийно завершиться, и сообщение так и не будет отправлено, что приведет к утрате согласованности данных.</p> -<p>Подробно эта проблема рассмотрена в главе "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/subscribe-events#designing-atomicity-and-resiliency-when-publishing-to-the-event-bus">Subscribing to events :: Publishing events through the event bus :: Designing atomicity and resiliency when publishing to the event bus</a>" книги ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id88" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos.</p> -<p>Chris Richardson называет эту проблему <a class="reference external" href="https://microservices.io/patterns/#transactional-messaging">Transactional messaging</a> рассматривает ее в главе "<a class="reference external" href="https://livebook.manning.com/book/microservices-patterns/chapter-3/section-3-3-7?origin=product-toc">3.3.7 Transactional messaging</a>" книги "Microservices Patterns: With examples in Java" <a class="footnote-reference brackets" href="#fnmsp" id="id89" role="doc-noteref"><span class="fn-bracket">[</span>14<span class="fn-bracket">]</span></a>.</p> -<p>Vaughn Vernon посвящает этой проблеме главу "8 Domain Events :: Spreading the News to Remote Bounded Contexts :: Messaging Infrastructure Consistency" книги "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id90" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>.</p> -<p>Очень глубокое понимание этой проблемы и способов ее решения дается в главе "10.Messaging Endpoints :: Transactional Client" книги "Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions" <a class="footnote-reference brackets" href="#fneip" id="id91" role="doc-noteref"><span class="fn-bracket">[</span>11<span class="fn-bracket">]</span></a> by Gregor Hohpe, Bobby Woolf.</p> -<p>А также эта тема затрагивается в главе "Chapter 9. Message Endpoints :: Transactional Client/Actor" книги "Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" <a class="footnote-reference brackets" href="#fnrmp" id="id92" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> by Vaughn Vernon.</p> -<p>Существует три основных способа решения этой проблемы:</p> -<ol class="arabic simple"> -<li><p><a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing">Event Sourcing pattern</a> (сюда же относится <a class="reference external" href="https://github.com/obsidiandynamics/goharvest/wiki/Comparison-of-messaging-patterns#front-door-queue">Front-Door Queue</a> pattern и Transactional Consumer <a class="footnote-reference brackets" href="#fneip" id="id93" role="doc-noteref"><span class="fn-bracket">[</span>11<span class="fn-bracket">]</span></a> vs Transactional Sender)</p></li> -<li><p><a class="reference external" href="https://www.scoop.it/t/sql-server-transaction-log-mining">Transaction log mining</a> (и <a class="reference external" href="https://microservices.io/patterns/data/transaction-log-tailing.html">еще</a>)</p></li> -<li><p><a class="reference external" href="https://www.kamilgrzybek.com/design/the-outbox-pattern/">Outbox pattern</a></p></li> -</ol> -<p>Говорят, что "Transactional Outbox" под названием "Local Messaging" впервые был опубликован в статье "<a class="reference external" href="https://dl.acm.org/doi/10.1145/1394127.1394128">BASE: An Acid Alternative: In partitioned databases, trading some consistency for availability can lead to dramatic improvements in scalability</a>" to ACM by ebay architect Dan Pritchett in 2008.</p> -<p>Ссылки по теме:</p> +<p>Основой этой филосовско-психологической прослойки <a class="reference external" href="https://www.informit.com/articles/article.aspx?p=2990402&amp;seqNum=3">стал</a> документ "<a class="reference external" href="http://www.agilenutshell.com/bill_of_rights">Bill of Rights</a>", который является результатом глубокого аналитического труда Kent Beck в области психологии. +Дело в том, что Kent Beck имел превосходную эрудированность в области психологии, философии и менеджмента.</p> +<blockquote> +<div><p>💬 "<strong>Customer Bill of Rights</strong></p> <ul class="simple"> -<li><p><a class="reference external" href="https://dzone.com/articles/event-driven-data-management-for-microservices-1">Event-Driven Data Management for Microservices</a></p></li> -<li><p><a class="reference external" href="https://github.com/ThreeDotsLabs/watermill/tree/master/_examples/real-world-examples/transactional-events">Готовая реализация паттерна outbox на Golang с примером использования (см. README)</a></p></li> +<li><p>You have the right to an overall plan, to know what can be accomplished when and at what cost.</p></li> +<li><p>You have the right to get the most possible value out of every programming week.</p></li> +<li><p>You have the right to see progress in a running system, proven to work by passing repeatable tests that you specify.</p></li> +<li><p>You have the right to change your mind, to substitute functionality, and to change priorities without paying exorbitant costs.</p></li> +<li><p>You have the right to be informed of schedule changes, in time to choose how to reduce the scope to restore the original date. You can cancel at any time and be left with a useful working system reflecting investment to date.</p></li> </ul> -</section> -<section id="integration-events"> -<h2><a class="toc-backref" href="#id140" role="doc-backlink">Проблема сохранения очередности Integration Events</a></h2> -<p>Подписчики не всегда получают Integration Events в той же последовательности, в которой они были отправлены, по ряду причин. -Одно из решений этой проблемы заключается в том, что, если получатель обнаруживает, что сообщение не соответствует ожидаемому порядку, то он просто не забирает его из очереди.</p> -<blockquote> -<div><p>Note that just saving the Domain Event in its causal order doesn't guarantee that it will arrive at other distributed nodes in the same order. -Thus, it is also the responsibility of the consuming Bounded Context to recognize proper causality. -It might be the Domain Event type itself that can indicate causality, or it may be metadata associated with the Domain Event, such as a sequence or causal identifier. -The <strong>sequence</strong> or <strong>causal identifier</strong> would indicate <strong>what caused this Domain Event</strong>, and <strong>if the cause was not yet seen, the consumer must wait to apply the newly arrived event until its cause arrives</strong>. -In some cases it is possible to ignore latent Domain Events that have already been superseded by the actions associated with a later one; in this case causality has a dismissible impact.</p> -<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id94" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events:: Designing, Implementing, and Using Domain Events"</p> +<p><strong>Programmer Bill of Rights</strong></p> +<ul class="simple"> +<li><p>You have the right to know what is needed, with clear declarations of priority.</p></li> +<li><p>You have the right to produce quality work at all times.</p></li> +<li><p>You have the right to ask for and receive help from peers, managers, and customers.</p></li> +<li><p>You have the right to make and update your own estimates.</p></li> +<li><p>You have the right to accept your responsibilities instead of having them assigned to you."</p></li> +</ul> +<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler</p> </div></blockquote> -<p>В книге "Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" <a class="footnote-reference brackets" href="#fnrmp" id="id95" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> by Vaughn Vernon также говорится о том, что Actor должен сам решать, принимать ли ему сообщение:</p> <blockquote> -<div><p>Actors must be prepared to accept and reject messages based on their current state, which is reflected by the order in which previous messages were received. -Sometimes a latent message could be accepted even if it is not perfect timing, but the actor's reaction to the latent message may have to carefully take into account its current state beforehand. -This may be dealt with more gracefully by using the actors become() capabilities.</p> -<p>- "Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" <a class="footnote-reference brackets" href="#fnrmp" id="id96" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "5. Messaging Channels :: Point-to-Point Channel"</p> +<div><p>💬 "During the <a class="reference external" href="https://martinfowler.com/articles/agileStory.html">Snowbird meeting</a>, Kent Beck said that the goal of Agile was to heal the divide between business and development. +To that end, the following "bill of rights" was developed by Kent, Ward Cunningham, and Ron Jeffries, among others."</p> +<p class="attribution">—"Clean Agile: Back to Basics" by Robert C. Martin</p> </div></blockquote> -<p>Этой же проблеме посвящена и глава "Chapter 7 Message Routing :: Resequencer" <a class="footnote-reference brackets" href="#fnrmp" id="id97" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> той же книги.</p> -<p>Pattern <a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/Resequencer.html">Resequencer</a> описан также и в главе "7.Message Routing :: Resequencer" книги "Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions" <a class="footnote-reference brackets" href="#fneip" id="id98" role="doc-noteref"><span class="fn-bracket">[</span>11<span class="fn-bracket">]</span></a> by Gregor Hohpe, Bobby Woolf.</p> -<p>Существует open source integration framework <a class="reference external" href="https://camel.apache.org/">Camel</a>, который предоставляет <a class="reference external" href="https://camel.apache.org/components/latest/eips/resequence-eip.html">готовую из коробки реализацию паттерна Resequencer</a>. -Он легко интегрируется с различными системами обмена сообщениями, например, <a class="reference external" href="https://camel.apache.org/components/latest/nats-component.html">с Nats</a> (<a class="reference external" href="https://nats.io/blog/apache-camel-nats-connector/">подробнее</a>).</p> -<p>В "CQRS Journey" <a class="footnote-reference brackets" href="#fncqrsj" id="id99" role="doc-noteref"><span class="fn-bracket">[</span>8<span class="fn-bracket">]</span></a> предлагается два варианта решения:</p> +<p>Kent Beck выяснил, что напряжение являлось ни чем иным, как упреждающими защитным механизмом, спровоцированным страхами обоих сторон процесса разработки.</p> +<p>Идея Bill of Rights возникла на основе идеи Declaration of Independence (<a class="reference external" href="http://www.hist.msu.ru/ER/Etext/indpndnc.htm">перевод</a>):</p> <blockquote> -<div><p>The first option is to <strong>use message sessions</strong>, a feature of the Azure Service Bus. If you use message sessions, this guarantees that messages within a session are delivered in the same order that they were sent.</p> -<p>The second alternative is to modify the handlers within the application to detect out-of-order messages through the use of sequence numbers or timestamps added to the messages when they are sent. -<strong>If the receiving handler detects an out-of-order message, it rejects the message and puts it back onto the queue or topic to be processed later</strong>, after it has processed the messages that were sent before the rejected message.</p> -<p>- "CQRS Journey" <a class="footnote-reference brackets" href="#fncqrsj" id="id100" role="doc-noteref"><span class="fn-bracket">[</span>8<span class="fn-bracket">]</span></a> by Dominic Betts, Julián Domínguez, Grigori Melnik, Fernando Simonazzi, Mani Subramanian, Chapter "<a class="reference external" href="https://docs.microsoft.com/ru-ru/previous-versions/msp-n-p/jj591565(v=pandp.10)#message-ordering">Journey 6: Versioning Our System :: Message ordering</a>"</p> -</div></blockquote> -<p>Проблема сохранения очередности сообщений в условиях конкурирующих подписчиков рассматривается и в главе "<a class="reference external" href="https://livebook.manning.com/book/microservices-patterns/chapter-3/section-3-3-5?origin=product-toc">3.3.5 Competing receivers and message ordering</a>" книги "Microservices Patterns: With examples in Java" <a class="footnote-reference brackets" href="#fnmsp" id="id101" role="doc-noteref"><span class="fn-bracket">[</span>14<span class="fn-bracket">]</span></a> by Chris Richardson, где для решения проблемы предлагается использовать партиционирование каналов.</p> -<p>Но даже если подписчик всего один, и сообщения доставляются последовательно, то и тогда очередность обработки сообщений может быть нарушена:</p> +<div><p>💬 "Software development is risky. People involved have many fears of what may go wrong.</p> +<p>To develop effectively we must acknowledge these fears. Why do we need a software process? For the same reason that we need laws, governments, and taxes: fear.</p> +<p>The Declaration of Independence says:</p> <blockquote> -<div><p>With the redelivery feature, order can't be guaranteed, since by definition server will resend messages that have not been acknowledged after a period of time. Suppose your consumer receives messages 1, 2 and 3, does not acknowledge 2. Then message 4 is produced, server sends this message to the consumer. The redelivery timer then kicks in and server will resend message 2. The consumer would see messages: 1, 2, 3, 4, 2, 5, etc...</p> -<p>In conclusion, the server does not offer this guarantee although it tries to redeliver messages first thing on startup. That being said, if the durable is stalled (number of outstanding messages &gt;= MaxInflight), then the redelivery will also be stalled, and new messages will be allowed to be sent. When the consumer resumes acking messages, then it may receive redelivered and new messages interleaved (new messages will be in order though).</p> -<p>- nats-streaming-server, <a class="reference external" href="https://github.com/nats-io/nats-streaming-server/issues/187#issuecomment-257024506">issue #187 "Order of delivery"</a>, comment by Ivan Kozlovic</p> +<div><p>That among these [rights] are life, liberty, and the pursuit of happiness. That to secure these rights, governments are instituted among men, deriving their just powers from the consent of the governed.</p> </div></blockquote> -<p>Ну а лучше всего эта тема раскрывается в Chapter "12 The Future of Data Systems :: Data Integration :: Combining Specialized Tools by Deriving Data :: Ordering events to capture causality" книги "Designing Data-Intensive Applications. The Big Ideas Behind Reliable, Scalable, and Maintainable Systems" <a class="footnote-reference brackets" href="#fnddia" id="id102" role="doc-noteref"><span class="fn-bracket">[</span>12<span class="fn-bracket">]</span></a> by Martin Kleppmann.</p> -<p>Еще проблемы распределенности хорошо освещаются в книге "Database Reliability Engineering. Designing and Operating Resilient Database Systems." <a class="footnote-reference brackets" href="#fndre" id="id103" role="doc-noteref"><span class="fn-bracket">[</span>13<span class="fn-bracket">]</span></a> by Laine Campbell and Charity Majors.</p> -<p>Ссылки по теме:</p> +<p>Though the profundity of these words may distract us, consider the word secure. We institute governments because we are afraid of losing our rights. By the same token, we institute software processes because we are afraid.</p> +<p><strong>Customers are afraid that</strong></p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">Don't Settle for Eventual Consistency. Stronger properties for low-latency geo-replicated storage.</a>" (<a class="reference external" href="https://dl.acm.org/ft_gateway.cfm?id=2610533&amp;ftid=1449165&amp;dwn=1">pdf</a>) by Wyatt Lloyd, Facebook; Michael J. Freedman, Princeton University; Michael Kaminsky, Intel Labs; David G. Andersen, Carnegie Mellon University</p></li> -<li><p>"<a class="reference external" href="http://www.bailis.org/papers/bolton-sigmod2013.pdf">Bolt-on Causal Consistency</a>" by Peter Bailis, Ali Ghodsi, Joseph M. Hellerstein†, Ion Stoica, UC Berkeley KTH/Royal Institute of Technology</p></li> -<li><p>"<a class="reference external" href="https://disco.ethz.ch/courses/hs08/seminar/papers/mattern4.pdf">Detecting Causal Relationships in Distributed Computations:In Search of the Holy Grail</a>" by Reinhard Schwarz, Friedemann Mattern</p></li> -<li><p>"<a class="reference external" href="https://www.microsoft.com/en-us/research/publication/principles-of-eventual-consistency/">Principles of Eventual Consistency</a>" (<a class="reference external" href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/final-printversion-10-5-14.pdf">pdf</a>) by Sebastian Burckhardt, Microsoft Research</p></li> -<li><p>"<a class="reference external" href="https://eventsourcing.readthedocs.io/en/stable/topics/process.html#causal-dependencies">Causal dependencies at eventsourcing framework by Python</a>" by John Bywater</p></li> -<li><p>"<a class="reference external" href="http://labix.org/vclock">The vclock package</a> offers full vector clock support for the Go language. Vector clocks allow recording and analyzing the inherent partial ordering of events in a distributed system in a comfortable way." by Gustavo Niemeyer (<a class="reference external" href="https://blog.labix.org/2010/12/21/vector-clock-support-for-go">more info</a>)</p></li> +<li><p>They won't get what they asked for.</p></li> +<li><p>They'll ask for the wrong thing.</p></li> +<li><p>They'll pay too much for too little.</p></li> +<li><p>They must surrender control of their career to techies who don't care.</p></li> +<li><p>They won't ever see a meaningful plan.</p></li> +<li><p>The plans they do see will be fairy tales.</p></li> +<li><p>They won't know what's going on.</p></li> +<li><p>They'll be held to their first decisions and won't be able to react to changes in the business.</p></li> +<li><p>No one will tell them the truth.</p></li> </ul> -<p>Ссылки для начинающих в Integration Events:</p> +<p><strong>Developers are afraid, too. They fear that</strong></p> <ul class="simple"> -<li><p>Хороший лаконичный обзорный блог-пост по возможностям NATS Streaming Server "<a class="reference external" href="https://nats.io/blog/use-cases-for-persistent-logs-with-nats-streaming/">Guest Post: Use cases for persistent logs with NATS Streaming</a>" by Byron Ruth</p></li> -<li><p>Лучше один раз увидеть. <a class="reference external" href="https://github.com/bruth/code-examples/tree/master/patterns-nats-streaming">Живые примеры по работе с NATS Streaming Server</a>.</p></li> +<li><p>They will be told to do more than they know how to do.</p></li> +<li><p>They will be told to do things that don't make sense.</p></li> +<li><p>They are too stupid.</p></li> +<li><p>They are falling behind technically.</p></li> +<li><p>They will be given responsibility without authority.</p></li> +<li><p>They won't be given clear definitions of what needs to be done.</p></li> +<li><p>They'll have to sacrifice quality for deadlines.</p></li> +<li><p>They'll have to solve hard problems without help.</p></li> +<li><p>They won't have enough time to succeed."</p></li> </ul> -<p>Более подробно тема раскрывается в заметке "<a class="reference internal" href="../../../../integration/asynchronous/message-ordering-in-competing-consumers.html#emacsway-message-ordering"><span class="std std-ref">О гонке сообщений в условиях конкурирующих подписчиков</span></a>".</p> -</section> -<section id="id104"> -<h2><a class="toc-backref" href="#id141" role="doc-backlink">Где создавать Domain Event об удалении объекта?</a></h2> -<p>Информации по этому вопросу практически нет, поэтому, я поделюсь своими мыслями.</p> -<p>В Английском языке есть <a class="reference external" href="https://english.stackexchange.com/a/52509">разница</a> между словом "delete" и "remove". -"Delete" подразумевает "уничтожить". -"Remove" - "изъять", "вынести".</p> -<p>Кстати, русское слово "удалить" <a class="reference external" href="https://ru.wiktionary.org/wiki/%D1%83%D0%B4%D0%B0%D0%BB%D0%B8%D1%82%D1%8C#%D0%AD%D1%82%D0%B8%D0%BC%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F">происходит</a> от слова "даль". -Например, "Удалить ненужные вещи из комнаты", "Удалить занозу".</p> -<p>Термин "remove" (удаление) применим к Коллекции, содержащей объект, и означает то, что объект удаляется от Коллекции (в даль). -Но при этом, объект, сам по себе, продолжает существовать. -Он может быть удален от (из) одной Коллекции, а затем вставлен в иную Коллекцию. -Как говорилось ранее, источником Domain Event не обязательно должен быть Агрегат или Команда. -Источником может быть и Коллекция, т.е. Repository.</p> -<p>Но если мы будем говорить не об удалении, а об "уничтожении" ("delete"), то мы говорим о состоянии, т.е. о части жизненного цикла объекта. -В таком случае было бы уместно, чтобы событие о переходе в новое состояние жизненного цикла объекта создавал сам объект. -Это становится особенно заметно, если мы используем soft delete (смотрите статью "<a class="reference external" href="http://udidahan.com/2009/09/01/dont-delete-just-dont/">Don't Delete – Just Don't</a>" by Udi Dahan по этому поводу). -Пример можно посмотреть <a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd/blob/78810bb44ae10cd88ca12b8d81712ba20c0ca43f/src/Modules/Meetings/Domain/Meetings/MeetingAttendee.cs#L124">здесь</a> (вызывается <a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd/blob/78810bb44ae10cd88ca12b8d81712ba20c0ca43f/src/Modules/Meetings/Domain/Meetings/Meeting.cs#L289">здесь</a>). -Это не Агрегат - это вложенная Сущность.</p> -<p>В другом <a class="reference external" href="https://github.com/kgrzybek/sample-dotnet-core-cqrs-api/blob/1d344b90658c6593993eaa1391410b5ab1ebabfc/src/SampleProject.Domain/Customers/Orders/Order.cs#L111">примере</a> реализации soft delete, событие <a class="reference external" href="https://github.com/kgrzybek/sample-dotnet-core-cqrs-api/blob/01a1d6517bc88773f004abc0cb9c6d79f537e575/src/SampleProject.Domain/Customers/Customer.cs#L89">создается</a> Агрегатом, владеющим Сущностью. -Похожие примеры можно найти и у Vaughn Vernon, см. <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_identityaccess/Domain.Model/Identity/Group.cs#L159">здесь</a> и <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_identityaccess/Domain.Model/Identity/Group.cs#L142">здесь</a>.</p> -<p>Посмотреть <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_agilepm/Domain.Model/Products/BacklogItems/BacklogItem.cs#L360">пример реализации soft delete Агрегата</a> (а не Сущности) можно у Vaughn Vernon (Агрегат BacklogItem хоть и <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_agilepm/Domain.Model/Products/Product.cs#L128">создается</a> Агрегатом Product, но является самостоятельным корнем).</p> -<p>Скрыть присутствие Repository помогает pattern "<a class="reference external" href="https://martinfowler.com/eaaCatalog/unitOfWork.html">Unit of Work</a>". -В одноименной главе книги "Patterns of Enterprise Application Architecture" <a class="footnote-reference brackets" href="#fnpoeaa" id="id105" role="doc-noteref"><span class="fn-bracket">[</span>10<span class="fn-bracket">]</span></a> приводится пример класса DomainObject, который содержит метод markRemoved().</p> +<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler</p> +</div></blockquote> +<blockquote> +<div><p>💬 "But it was here, nestled in the white-capped mountains at a ski resort, that a group of software rebels gathered in 2001 to frame and sign one of the most important documents in its industry's history, a sort of Declaration of Independence for the coding set."</p> +<p class="attribution">—"<a class="reference external" href="https://www.theatlantic.com/technology/archive/2017/12/agile-manifesto-a-history/547715/">The Winter Getaway That Turned the Software World Upside Down</a>" by Caroline Mimbs Nyce</p> +</div></blockquote> +<p>Вся суть Agile (итеративной) модели разработки была лаконично и метко выражена Кент Беком всего одним предложением:</p> +<blockquote> +<div><p>💬 "Сделайте изменение легким, а потом делай легко изменение.</p> +<p><strong>Make the change easy then make the easy change.</strong>"</p> +<p class="attribution">—Kent Beck, "<a class="reference external" href="https://youtu.be/3gib0hKYjB0?t=2662">Continued Learning: The Beauty of Maintenance - Kent Beck - DDD Europe 2020</a>"</p> +</div></blockquote> <blockquote> -<div><p>With object registration (Figure 11.2), the onus is removed from the caller. -The usual trick here is to place registration methods in object methods. Loading an object from the database registers the object as clean; -the setting methods register the object as dirty. -For this scheme to work the Unit of Work needs either to be passed to the object or to be in a well-known place. -Passing the Unit of Work around is tedious but usually no problem to have it present in some kind of session object.</p> -<p>- "Patterns of Enterprise Application Architecture" <a class="footnote-reference brackets" href="#fnpoeaa" id="id106" role="doc-noteref"><span class="fn-bracket">[</span>10<span class="fn-bracket">]</span></a> by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford, Chapter "16. Offline Concurrency Patterns :: Coarse-Grained Lock"</p> +<div><p>Thanks to Vladik Khononov for <a class="reference external" href="https://youtu.be/ybYtgII151g?t=9808">https://youtu.be/ybYtgII151g?t=9808</a></p> </div></blockquote> -<p>Для этих целей удобно применять Aspect-oriented programming:</p> +<p>Невероятный талант Kent Beck объяснять сложные вещи простым языком. +Именно об этом я говорил в статье "<a class="reference internal" href="../../../../soft-skills/learning.html#emacsway-learning-in-psychology"><span class="std std-ref">Кристаллизация знаний. Как читать и не превратиться в коллекционера информации.</span></a>". +И это при необычайной эрудированности Kent Beck. Cписок использованной литературы в его книгах просто ошеломляет.</p> +<p>Более развернутый вариант его фразы:</p> <blockquote> -<div><p>This is a natural place for code generation to generate appropriate calls, but that only works when you can clearly separate generated and nongenerated code. -This problem turns out to be particularly suited to aspect-oriented programming. -I've also come across post-processing of the object files to pull this off. -In this example a post-processor examined all the Java .class files, looked for the appropriate methods and inserted registration calls into the byte code. -Such finicking around feels dirty, but it separates the database code from the regular code. -Aspect-oriented programming will do this more cleanly with source code, and as its tools become more commonplace I expect to see this strategy being used.</p> -<p>- "Patterns of Enterprise Application Architecture" <a class="footnote-reference brackets" href="#fnpoeaa" id="id107" role="doc-noteref"><span class="fn-bracket">[</span>10<span class="fn-bracket">]</span></a> by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford, Chapter "16. Offline Concurrency Patterns :: Coarse-Grained Lock"</p> +<div><p>💬 "At the core of understanding this argument is the software change curve. +The change curve says that as the project runs, it becomes exponentially more expensive to make changes. +The change curve is usually expressed in terms of phases "a change made in analysis for $1 would cost thousands to fix in production". +This is ironic as most projects still work in an ad-hoc process that doesn't have an analysis phase, but the exponentiation is still there. +<strong>The exponential change curve means that evolutionary design cannot possibly work.</strong> +It also conveys why planned design must be done carefully because any mistakes in planned design face the same exponentiation.</p> +<p><strong>The fundamental assumption underlying XP is that it is possible to flatten the change curve enough to make evolutionary design work.</strong> +This flattening is both enabled by XP and exploited by XP. +This is part of the coupling of the XP practices: specifically <strong>you can't do those parts of XP that exploit the flattened curve without doing those things that enable the flattening.</strong> +This is a common source of the controversy over XP. +Many people criticize the exploitation without understanding the enabling. +Often the criticisms stem from critics' own experience where they didn't do the enabling practices that allow the exploiting practices to work. +As a result they got burned and when they see XP they remember the fire."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by M.Fowler</p> </div></blockquote> -<p>Также существует разница и между термином "insert" ("вставить") и "create" ("создать"). -Первый применим к Коллекции объектов (как и "remove"), а второй - к состоянию жизненного цикла самого объекта (как и "delete").</p> -<p>Вопрос о том, где создавать Domain Event об уничтожении/удалении объекта, во многом зависит от того, где создавался Domain Event о его создании/вставке, который, в свою очередь, зависит от того, каким образом создается идентификатор создаваемого объекта, если он необходим для Domain Event.</p> -<p>Как вариант, если нужно создавать Domain Event о создании ("create") объекта внутри него самого, но при этом используется автоинкрементный первичный ключ базы данных, то обойти это ограничение можно вложив сам экземпляр созданного объекта в Domain Event. -Тогда, в момент вызова обработчика Domain Event, если он, конечно, будет происходить после сохранения созданного объекта в Хранилище (хотя и до коммита), созданному объекту уже будет присвоен идентификатор. -Агрегат, в таком случае, можно снабдить методом <a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/blob/1d8c6178de2830ad809eae138a0a99011c26ac2c/src/Services/Ordering/Ordering.Domain/SeedWork/Entity.cs#L42">IsTransient</a>. -Другим возможным вариантом обхода этого ограничения может быть передача в Domain Event объекта отложенного значения (в крайнем случае - указателя на значение). -Ну и, разумеется, можно использовать <a class="reference external" href="https://en.wikipedia.org/wiki/Universally_unique_identifier">UUID</a>, <a class="reference external" href="https://en.wikipedia.org/wiki/Hi/Lo_algorithm">Hi/Lo algorithm</a> и т.п.</p> -<p>В целом я придерживаюсь такого правила - если Domain Event о "вставке" ("insert") объекта создает Коллекция (Repository), то и Domain Event об "удалении" ("remove") объекта должна создавать тоже Коллекция (Repository), на том же уровне абстракции. -А если Domain Event о "создании" ("create") объекта создает сам объект, как уведомление о переходе в новое состояние своего жизненного цикла, то и Domain Event об "уничтожении" ("delete") объекта должен создавать он же.</p> -</section> -<section id="id108"> -<h2><a class="toc-backref" href="#id142" role="doc-backlink">Почему важно читать оригиналы вместо переводов</a></h2> -<p>В самом начале этого поста я говорил, что важно читать первоисточники. -Теперь я хочу показать, почему важно читать оригиналы, а не их переводы.</p> -<p>Возьмем известную фразу Эрика Эванса, которая послужила первопричиной для eventual consistency между агрегатами. Сравните ее смысл в оригинале:</p> <blockquote> -<div><p>Invariants, which are consistency rules that must be maintained whenever data changes, will involve relationships between members of the AGGREGATE. -<strong>Any rule that spans AGGREGATES [мн. число] will not be expected to be up-to-date at all times.</strong> -Through event processing, batch processing, or other update mechanisms, other dependencies can be resolved within some specified time. -But the invariants applied within an AGGREGATE will be enforced with the completion of each transaction.</p> -<p>- "Domain-Driven Design: Tackling Complexity in the Heart of Software" <a class="footnote-reference brackets" href="#fnddd" id="id109" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Six. The Life Cycle of a Domain Object:: Aggregates"</p> +<div><p>💬 "<strong>Именно это является одной из предпосылок ХР</strong>. +<strong>Это техническая предпосылка ХР.</strong> +[в оригинальном переводе: <em>Именно это является одним из основных предположений ХР. Это техническое предположение ХР.</em>] +Если стоимость внесения в систему изменений со временем растет достаточно медленно, стратегия разработки программы должна быть совершенно другой, отличной от той, которая используется в случае, если стоимость внесения в систему изменений со временем растет экспоненциально. +В подобной ситуации вы можете откладывать решение важных задач на более поздние сроки. +Вы получаете возможность принимать важные решения настолько поздно, насколько это возможно. +Это делается для того, чтобы осуществлять связанные с этим затраты как можно позже. +Кроме того, если вы откладываете решение важных вопросов на более поздний срок, тем самым вы повышаете вероятность того, что выбранное вами решение окажется правильным. +Другими словами, сегодня вы должны реализовать только то, без чего сегодня не обойтись, при этом вы можете рассчитывать на то, что проблемы, решение которых вы отложили до завтра, развеются сами собой, то есть перестанут быть актуальными. +Вы можете добавлять в дизайн новые элементы только в случае, если эти новые элементы упрощают код или делают написание следующего фрагмента кода более простым.</p> +<p><strong>Если пологая кривая роста затрат делает ХР возможным, то экспоненциальная кривая роста затрат делает ХР невозможным.</strong> +Если изменение обойдется вам в кругленькую сумму, вы сойдете с ума, пытаясь предугадать, каким образом это изменение повлияет на работу системы. +Если же изменение обходится вам дешево, вы всегда можете рискнуть и проверить, что будет, если вы тем или иным образом измените код, — позже вы всегда можете изменить систему так, как это будет лучше.</p> +<p><strong>This is one of the premises of XP. It is the technical premise of XP.</strong> +If the cost of change rose slowly over time, you would act completely differently from how you do under the assumption that costs rise exponentially. +You would make big decisions as late in the process as possible, to defer the cost of making the decisions and to have the greatest possible chance that they would be right. +You would only implement what you had to, in hopes that the needs you anticipate for tomorrow wouldn't come true. +You would introduce elements to the design only as they simplified existing code or made writing the next bit of code simpler.</p> +<p><strong>If a flattened change cost curve makes XP possible, a steep change cost curve makes XP impossible.</strong> +If change is ruinously expensive, you would be crazy to charge ahead without careful forethought. +But if change stays cheap, the additional value and reduced risk of early concrete feedback outweighs the additional cost of early change."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 5. Cost of Change", перевод ООО Издательство "Питер"</p> </div></blockquote> -<p>И ее смысл в переводе:</p> +<p>Поскольку это было произнесено еще до встречи 2001 года и принятия Agile Manifesto, то под XP следует понимать Agile (или даже любую итератиную модель разработки) в принципе, поскольку XP - это частный случай Agile.</p> +<p>Иными словами, внутреннее качество программы является первичным условием в Agile, как и в любой другой итеративной разработке.</p> <blockquote> -<div><p>Из взаимосвязей между объектами АГРЕГАТА можно составить так называемые инварианты, т.е. правила совместности, которые должны соблюдаться при любых изменениях данных. -<strong>Не всякое правило, распространяющееся на АГРЕГАТ [ед. число], обязано выполняться непрерывно.</strong> -Восстановить нужные взаимосвязи за определенное время можно с помощью обработки событий, пакетной обработки и других механизмов обновления системы. -Но соблюдение инвариантов, имеющих силу внутри агрегата, должно контролироваться немедленно по завершении любой транзакции.</p> +<div><p>💬 "Engineers who don't understand exponential growth and the cost curve as economies of scale kick in come to wildly incorrect conclusions."</p> +<p class="attribution">—<a class="reference external" href="https://twitter.com/KentBeck/status/1402276528910704655?s=19">Kent Beck</a></p> </div></blockquote> -<p>Смысл утрачен. А этот смысл имеет ключевое значение - он говорит о распространении правил между агрегатами.</p> -<p>Или другой пример.</p> <blockquote> -<div><p>There are several possible ways for remote Bounded Contexts to become aware of Events that occur in your Bounded Context. -The primary idea is that some form of messaging takes place, and an enterprise messaging mechanism is needed. -To be clear, the mechanism being spoken of here goes well beyond the simple, lightweight Publish-Subscribe components just discussed. -Here we are discussing what takes over <strong>where the lightweight mechanism leaves off</strong>.</p> -<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id110" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Spreading the News to Remote Bounded Contexts"</p> +<div><p>💬 "Continuous attention to technical excellence and good design enhances agility."</p> +<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/principles.html">Principles behind the Agile Manifesto</a>"</p> </div></blockquote> -<p>Сравните с русским переводом:</p> <blockquote> -<div><p>Существует несколько способов сообщить удаленным ОГРАНИЧЕННЫМ КОНТЕКСТАМ о событии, произошедшем в вашем ОГРАНИЧЕННОМ КОНТЕКСТЕ. -Основная идея заключается в том, чтобы организовать какую-то форму передачи сообщений и создать механизм передачи сообщений в масштабе предприятия. -Точнее говоря, механизм, о котором идет речь, выходит далеко за рамки простых облегченных компонентов шаблона ИЗДАТЕЛЬ - ПОДПИСЧИК. -Ниже мы обсудим, что произойдет, <strong>если отказаться от этого упрощенного механизма</strong>.</p> +<div><p>💬 "The incremental and iterative nature of Agile development can facilitate <strong>efficient technical and management processes and practices to reduce the cost associated with change</strong>. +In comparison, projects managed at the waterfall end of the continuum seek to reduce total rework cost by minimizing the number of changes, limiting the number of control points, and baselining detailed specifications which are reviewed and traced throughout the project."</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> +</div></blockquote> +<p>При соблюдении этого условия, использование <a class="reference internal" href="../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Adaptation</span></a> обретает экономическую целесообразность:</p> +<blockquote> +<div><p>💬 "Responding to change over following a plan"</p> +<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/">Manifesto for Agile Software Development</a>"</p> +</div></blockquote> +<blockquote> +<div><p>💬 "Welcome changing requirements, even late in development. Agile processes harness change for the customer's competitive advantage."</p> +<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/principles.html">Principles behind the Agile Manifesto</a>"</p> </div></blockquote> -<p>Русский перевод не отражает оригинального смысла, который, кстати, опять же имеет немаловажное значение. -И даже если считать оригинальный смысл недостаточно ясным, допускающим несколько трактовок, из которых можно выбрать наиболее корректную исходя из контекста и предыдущих утверждений автора, то русский перевод такой возможности нас лишает. -Я трактую эту фразу так, чтобы она находилась в согласованности с другими утверждениями Вернона, т.е. "Ниже мы обсудим, что произойдет <strong>за пределами этого упрощенного механизма</strong>", что полностью соответствует рис.8.1. и его описанию.</p> -</section> -<section id="id111"> -<h2><a class="toc-backref" href="#id143" role="doc-backlink">Послесловие</a></h2> -<p>Эта статья отражает мое мнение на текущий момент времени, которое, однако, я не спешил бы называть окончательно сформированным, поскольку существует еще достаточно большой пласт информации по этому вопросу, который мне только предстоит переработать. -Основной посыл статьи - больше внимания уделять первоисточникам, и быть более гибким в принятии решений, хорошо осознавая их причины и следствия.</p> -<p class="rubric">Footnotes</p> -<aside class="footnote-list brackets"> -<aside class="footnote brackets" id="fnddd" role="note"> -<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id8">1</a>,<a role="doc-backlink" href="#id9">2</a>,<a role="doc-backlink" href="#id10">3</a>,<a role="doc-backlink" href="#id13">4</a>,<a role="doc-backlink" href="#id109">5</a>)</span> -<p>"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p> -</aside> -<aside class="footnote brackets" id="fndddr" role="note"> -<span class="label"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id2">1</a>,<a role="doc-backlink" href="#id3">2</a>,<a role="doc-backlink" href="#id4">3</a>,<a role="doc-backlink" href="#id60">4</a>,<a role="doc-backlink" href="#id74">5</a>)</span> -<p>"<a class="reference external" href="https://domainlanguage.com/ddd/reference/">Domain-Driven Design Reference</a>" by Eric Evans</p> -</aside> -<aside class="footnote brackets" id="fniddd" role="note"> -<span class="label"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id5">1</a>,<a role="doc-backlink" href="#id7">2</a>,<a role="doc-backlink" href="#id11">3</a>,<a role="doc-backlink" href="#id12">4</a>,<a role="doc-backlink" href="#id16">5</a>,<a role="doc-backlink" href="#id17">6</a>,<a role="doc-backlink" href="#id20">7</a>,<a role="doc-backlink" href="#id21">8</a>,<a role="doc-backlink" href="#id24">9</a>,<a role="doc-backlink" href="#id46">10</a>,<a role="doc-backlink" href="#id62">11</a>,<a role="doc-backlink" href="#id63">12</a>,<a role="doc-backlink" href="#id64">13</a>,<a role="doc-backlink" href="#id65">14</a>,<a role="doc-backlink" href="#id66">15</a>,<a role="doc-backlink" href="#id67">16</a>,<a role="doc-backlink" href="#id72">17</a>,<a role="doc-backlink" href="#id83">18</a>,<a role="doc-backlink" href="#id90">19</a>,<a role="doc-backlink" href="#id110">20</a>)</span> -<p>"<a class="reference external" href="https://kalele.io/books/">Implementing Domain-Driven Design</a>" by Vaughn Vernon</p> -</aside> -<aside class="footnote brackets" id="fndddd" role="note"> -<span class="label"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id19">1</a>,<a role="doc-backlink" href="#id22">2</a>,<a role="doc-backlink" href="#id45">3</a>,<a role="doc-backlink" href="#id47">4</a>,<a role="doc-backlink" href="#id71">5</a>,<a role="doc-backlink" href="#id75">6</a>,<a role="doc-backlink" href="#id76">7</a>,<a role="doc-backlink" href="#id94">8</a>)</span> -<p>"<a class="reference external" href="https://kalele.io/books/">Domain-Driven Design Distilled</a>" by Vaughn Vernon</p> -</aside> -<aside class="footnote brackets" id="fnrmp" role="note"> -<span class="label"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id92">1</a>,<a role="doc-backlink" href="#id95">2</a>,<a role="doc-backlink" href="#id96">3</a>,<a role="doc-backlink" href="#id97">4</a>)</span> -<p>"<a class="reference external" href="https://kalele.io/books/">Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka</a>" by Vaughn Vernon</p> -</aside> -<aside class="footnote brackets" id="fnpppddd" role="note"> -<span class="label"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id23">1</a>,<a role="doc-backlink" href="#id30">2</a>,<a role="doc-backlink" href="#id55">3</a>,<a role="doc-backlink" href="#id56">4</a>,<a role="doc-backlink" href="#id78">5</a>)</span> -<p>"Patterns, Principles, and Practices of Domain-Driven Design" by Scott Millett, Nick Tune</p> -</aside> -<aside class="footnote brackets" id="fnnetms" role="note"> -<span class="label"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id6">1</a>,<a role="doc-backlink" href="#id26">2</a>,<a role="doc-backlink" href="#id27">3</a>,<a role="doc-backlink" href="#id28">4</a>,<a role="doc-backlink" href="#id29">5</a>,<a role="doc-backlink" href="#id31">6</a>,<a role="doc-backlink" href="#id44">7</a>,<a role="doc-backlink" href="#id48">8</a>,<a role="doc-backlink" href="#id58">9</a>,<a role="doc-backlink" href="#id59">10</a>,<a role="doc-backlink" href="#id77">11</a>,<a role="doc-backlink" href="#id88">12</a>)</span> -<p>"<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/index">.NET Microservices: Architecture for Containerized .NET Applications</a>" edition v2.2.1 (<a class="reference external" href="https://aka.ms/microservicesebook">mirror</a>) by Cesar de la Torre, Bill Wagner, Mike Rousos</p> -</aside> -<aside class="footnote brackets" id="fncqrsj" role="note"> -<span class="label"><span class="fn-bracket">[</span>8<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id99">1</a>,<a role="doc-backlink" href="#id100">2</a>)</span> -<p>"<a class="reference external" href="https://docs.microsoft.com/en-US/previous-versions/msp-n-p/jj554200(v=pandp.10)">CQRS Journey</a>" by Dominic Betts, Julián Domínguez, Grigori Melnik, Fernando Simonazzi, Mani Subramanian</p> -</aside> -<aside class="footnote brackets" id="fnoosc" role="note"> -<span class="label"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id81">1</a>,<a role="doc-backlink" href="#id82">2</a>,<a role="doc-backlink" href="#id84">3</a>,<a role="doc-backlink" href="#id85">4</a>,<a role="doc-backlink" href="#id86">5</a>,<a role="doc-backlink" href="#id87">6</a>)</span> -<p>"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer</p> -</aside> -<aside class="footnote brackets" id="fnpoeaa" role="note"> -<span class="label"><span class="fn-bracket">[</span>10<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id14">1</a>,<a role="doc-backlink" href="#id105">2</a>,<a role="doc-backlink" href="#id106">3</a>,<a role="doc-backlink" href="#id107">4</a>)</span> -<p>"<a class="reference external" href="https://www.martinfowler.com/books/eaa.html">Patterns of Enterprise Application Architecture</a>" by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford</p> -</aside> -<aside class="footnote brackets" id="fneip" role="note"> -<span class="label"><span class="fn-bracket">[</span>11<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id91">1</a>,<a role="doc-backlink" href="#id93">2</a>,<a role="doc-backlink" href="#id98">3</a>)</span> -<p>"<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/">Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions</a>" by Gregor Hohpe, Bobby Woolf</p> -</aside> -<aside class="footnote brackets" id="fnddia" role="note"> -<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id102">12</a><span class="fn-bracket">]</span></span> -<p>"<a class="reference external" href="https://dataintensive.net/">Designing Data-Intensive Applications. The Big Ideas Behind Reliable, Scalable, and Maintainable Systems</a>" by Martin Kleppmann</p> -</aside> -<aside class="footnote brackets" id="fndre" role="note"> -<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id103">13</a><span class="fn-bracket">]</span></span> -<p>"Database Reliability Engineering. Designing and Operating Resilient Database Systems." by Laine Campbell and Charity Majors</p> -</aside> -<aside class="footnote brackets" id="fnmsp" role="note"> -<span class="label"><span class="fn-bracket">[</span>14<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id89">1</a>,<a role="doc-backlink" href="#id101">2</a>)</span> -<p>"<a class="reference external" href="https://www.manning.com/books/microservice-patterns">Microservices Patterns: With examples in Java</a>" 1st edition by Chris Richardson (<a class="reference external" href="https://microservices.io/book">more info</a>)</p> -</aside> -<aside class="footnote brackets" id="fnkgde1" role="note"> -<span class="label"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id35">1</a>,<a role="doc-backlink" href="#id36">2</a>,<a role="doc-backlink" href="#id50">3</a>,<a role="doc-backlink" href="#id51">4</a>,<a role="doc-backlink" href="#id68">5</a>)</span> -<p>"<a class="reference external" href="http://www.kamilgrzybek.com/design/how-to-publish-and-handle-domain-events/">How to publish and handle Domain Events</a>" by Kamil Grzybek</p> -</aside> -<aside class="footnote brackets" id="fnkgde2" role="note"> -<span class="label"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id37">1</a>,<a role="doc-backlink" href="#id38">2</a>,<a role="doc-backlink" href="#id49">3</a>,<a role="doc-backlink" href="#id52">4</a>,<a role="doc-backlink" href="#id53">5</a>,<a role="doc-backlink" href="#id54">6</a>)</span> -<p>"<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/">Handling Domain Events: Missing Part</a>" by Kamil Grzybek</p> -</aside> -<aside class="footnote brackets" id="fnkgoutbox" role="note"> -<span class="label"><span class="fn-bracket">[</span>17<span class="fn-bracket">]</span></span> -<p>"<a class="reference external" href="https://www.kamilgrzybek.com/design/the-outbox-pattern/">The Outbox Pattern</a> by Kamil Grzybek</p> -</aside> -<aside class="footnote brackets" id="fnjbde1" role="note"> -<span class="label"><span class="fn-bracket">[</span>18<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id32">1</a>,<a role="doc-backlink" href="#id33">2</a>)</span> -<p>"<a class="reference external" href="https://lostechies.com/jimmybogard/2010/04/08/strengthening-your-domain-domain-events/">Strengthening your domain: Domain Events</a>" by Jimmy Bogard</p> -</aside> -<aside class="footnote brackets" id="fnjbde2" role="note"> -<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id34">19</a><span class="fn-bracket">]</span></span> -<p>"<a class="reference external" href="https://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/">A better domain events pattern</a>" by Jimmy Bogard</p> -</aside> -<aside class="footnote brackets" id="fnudde1" role="note"> -<span class="label"><span class="fn-bracket">[</span>20<span class="fn-bracket">]</span></span> -<p>"<a class="reference external" href="http://udidahan.com/2008/02/29/how-to-create-fully-encapsulated-domain-models/">How to create fully encapsulated Domain Models</a>" by Udi Dahan</p> -</aside> -<aside class="footnote brackets" id="fnudde2" role="note"> -<span class="label"><span class="fn-bracket">[</span>21<span class="fn-bracket">]</span></span> -<p>"<a class="reference external" href="http://udidahan.com/2008/08/25/domain-events-take-2/">Domain Events – Take 2</a>" by Udi Dahan</p> -</aside> -<aside class="footnote brackets" id="fnudde3" role="note"> -<span class="label"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id39">1</a>,<a role="doc-backlink" href="#id40">2</a>,<a role="doc-backlink" href="#id41">3</a>,<a role="doc-backlink" href="#id42">4</a>,<a role="doc-backlink" href="#id69">5</a>)</span> -<p>"<a class="reference external" href="http://udidahan.com/2009/06/14/domain-events-salvation/">Domain Events – Salvation</a>" by Udi Dahan</p> -</aside> -<aside class="footnote brackets" id="fncdltdevie" role="note"> -<span class="label"><span class="fn-bracket">[</span>23<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id43">1</a>,<a role="doc-backlink" href="#id57">2</a>)</span> -<p>"<a class="reference external" href="https://devblogs.microsoft.com/cesardelatorre/domain-events-vs-integration-events-in-domain-driven-design-and-microservices-architectures/">Domain Events vs. Integration Events in Domain-Driven Design and microservices architectures</a>" by Cesar De la Torre, Principal Program Manager, .NET</p> -</aside> -<aside class="footnote brackets" id="fnntuhbr" role="note"> -<span class="label"><span class="fn-bracket">[</span>24<span class="fn-bracket">]</span></span> -<p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/uncovering-hidden-business-rules-with-ddd-aggregates-67fb02abc4b">Uncovering Hidden Business Rules with DDD Aggregates</a> by Nick Tune</p> -</aside> -<aside class="footnote brackets" id="fnmvpe" role="note"> -<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id61">25</a><span class="fn-bracket">]</span></span> -<p>"<a class="reference external" href="https://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/">Patterns for Decoupling in Distributed Systems: Explicit Public Events</a>" by Mathias Verraes</p> -</aside> -<aside class="footnote brackets" id="fngycqrs" role="note"> -<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id80">26</a><span class="fn-bracket">]</span></span> -<p>"<a class="reference external" href="http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/">CQRS, Task Based UIs, Event Sourcing agh!</a>" by Greg Young</p> -</aside> -<aside class="footnote brackets" id="fnvkdesars" role="note"> -<span class="label"><span class="fn-bracket">[</span>27<span class="fn-bracket">]</span></span> -<p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-events-simple-reliable-solution/">Domain events: simple and reliable solution</a>" by Vladimir Khorikov</p> -</aside> -<aside class="footnote brackets" id="fnvkmdebd" role="note"> -<span class="label"><span class="fn-bracket">[</span>28<span class="fn-bracket">]</span></span> -<p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/merging-domain-events-dispatching/">Merging domain events before dispatching</a>" by Vladimir Khorikov</p> -</aside> -</aside> -</section> -Mon, 03 Jul 2023 00:00:00 Immutabilityhttps://dckms.github.io/system-architecture/emacsway/it/ddd/tactical-design/domain-model/value-objects/immutability.html -<span id="emacsway-immutability-in-value-object"/> -<section id="id1"> -<h2>Что делать, если ЯП не поддерживает неизменяемость?</h2> -<p>Когда язык программирования не поддерживает неизменяемость, то странствующий Value Object копируется:</p> <blockquote> -<div><p>💬 В принципе два объекта Человек могут и не нуждаться в собственных экземплярах объекта-имени. -Один и тот же объект Имя может совместно использоваться двумя объектами Человек (в каждом будет содержаться указатель на один и тот же экземпляр Имени ), и при этом никаких изменений в их поведении или способе идентификации не потребуется. -То есть, они будут работать правильно, пока у одного человека не изменится имя. -Тогда так же изменится имя и другого человека! -Чтобы этого избежать и сделать совместное использование объекта безопасным, его нужно сделать неизменяемым запрещенным для любых изменений иначе как путем полной замены.</p> -<p>Та же проблема возникает, когда объект передает один из своих атрибутов другому объекту в качестве аргумента или возвращаемого значения. -Со странствующим объектом может случиться все, что угодно, за то время, пока он не находится под контролем владельца. -3НАЧЕНИЕ (VALUE) может измениться таким образом, что будет поврежден и объект-владелец путем искажения его инвариантов. -Чтобы избежать этого, передаваемый объект делают неизменяемым или же передают его КОПИЮ.</p> -<p>In fact, the two Person objects might not need their own name instances. -The same Name object could be shared between the two Person objects (each with a pointer to the same name instance) with no change in their behavior or identity. -That is, their behavior will be correct until some change is made to the name of one person. Then the other person's name would change also! -To protect against this, in order for an object to be shared safely, it must be immutable: it cannot be changed except by full replacement.</p> -<p>The same issues arise when an object passes one of its attributes to another object as an argument or return value. -Anything could happen to the wandering object while it is out of control of its owner. -The VALUE could be changed in a way that corrupts the owner, by violating the owner's invariants. -This problem is avoided either by making the passed object immutable, or by passing a copy.</p> -<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> +<div><p>💬️ "We considered a bunch of names, and agreed eventually on <strong>"agile"</strong> as we felt that captured the <strong>adaptiveness</strong> and <strong>response to change</strong> which we felt was so important to our approach."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/agileStory.html">Writing The Agile Manifesto</a>" by Martin Fowler</p> +</div></blockquote> +<blockquote> +<div><p>💬 "‘<strong>Agile!</strong> Oh great, let’s go,’” Cockburn tells me. “It was really a lot of work.” The other finalist, he says, was <strong>“Adaptive.”</strong>"</p> +<p class="attribution">—"<a class="reference external" href="https://www.theatlantic.com/technology/archive/2017/12/agile-manifesto-a-history/547715/">The Winter Getaway That Turned the Software World Upside Down</a>" by Caroline Mimbs Nyce</p> +</div></blockquote> +<blockquote> +<div><p>💬 "<strong>Agile</strong> methods are <strong>adaptive</strong> rather than predictive."</p> +<p class="attribution">—"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html">The New Methodology</a>" by Martin Fowler</p> +</div></blockquote> +<p>О том, почему я обратился к высказываю Kent Beck в этом вопросе, неплохо поясняет Martin Fowler:</p> +<blockquote> +<div><p>💬 "Extreme Programming (XP) is a software development methodology developed primarily by Kent Beck. +XP was one of the first agile methods, indeed XP was the dominant agile method in the late 90s and early 00s before Scrum became dominant as the noughties passed. +Many people (including myself) consider XP to be the primary catalyst that got attention to agile methods, and superior to Scrum as a base for starting out in agile development."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/ExtremeProgramming.html">Extreme Programming</a>" by Martin Fowler</p> </div></blockquote> </section> -Mon, 03 Jul 2023 00:00:00 Repository and Anticorruption Layerhttps://dckms.github.io/system-architecture/emacsway/it/ddd/tactical-design/repository/anticorruption-layer.html -<span id="emacsway-repository-in-anticorruption-layer"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<section id="emacsway-agile-development-difficulties"> +<span id="id5"/><h2><a class="toc-backref" href="#id14" role="doc-backlink">О сложностях</a></h2> +<p>Вернемся еще раз к выражению Kent Beck "<em>сделайте изменение легким, а потом делай легко изменение</em>". +Оно состоит из двух частей, причем, первая из них предшествует второй. +Как раз именно первую часть нередко забывают сделать на современном рынке, а без первой части вторая часть работает не будет, как это нетрудно догадаться. +Так недалеко и до полного Уроборос.</p> <blockquote> -<div><p>💬 In Implementing #DDDesign why use Anticorruption Layer rather than a Repository to integrate with another Bounded Context?</p> -<p>Typically the Repository pattern is used as an Adapter in front of a database. -In general you could think of a Repository as an AcL over a database.</p> -<p>But then again, an AcL is at least both of these: (1) an Adapter, and (2) a Translator. -Typically a Repository doesn't translate from database data into a model's data. -Usually database data is at most reshaped when hydrating models. In other words, you think of an AcL more as a translator between two different model languages, where one language might not be carefully defined. -<strong>A Repository isn't translating between languages, just adapting database data shapes to/from domain model data shapes.</strong></p> -<p>With AcL, make sure you have very good reason to duplicate data across context boundaries. -In general replicating/duplicating data across boundaries is a bad thing.</p> -<p>Every chapter of Implementing #DDDesign, and Chapter 13 in this case, demonstrates different ways of handling similar challenges. The Agile PM Context has a very high autonomy quality attribute. -The Collaboration Context is designed earlier before SaaSOvation had a lot of experience with DDD. -Decisions are never static and certainly imperfect. -Continuous improvement matters.</p> -<p>If you are going to deliver software that is useful and provides valuable customer outcomes, you must make decisions now and later.</p> -<p>As with all software decisions, pattern choice depends. This thread should help make choices clearer.</p> -<p class="attribution">—<a class="reference external" href="https://twitter.com/VaughnVernon/status/1506090113582841859?s=20">Vaughn Vernon</a></p> +<div><p>💬 "Scrum is ok if you do it right."</p> +<p class="attribution">—<a class="reference external" href="https://youtu.be/0oGpWmS0aYQ?t=921">OOP 2015 Keynote - Robert C. Martin ("Uncle Bob"): Agility and Architecture at 15:21</a></p> </div></blockquote> -<p>Другим отличительным признаком Repository от Adapter (<a class="reference external" href="https://alistair.cockburn.us/hexagonal-architecture/">Ports &amp; Adapter</a>) является их цель: Adapter реализует Port, который явно обозначает границу компонента, в то время как Repository имеет цель эту границу скрыть, и подделать удаленный источник локальным:</p> <blockquote> -<div><p>💬 Mediates between the domain and data mapping layers using <strong>a collection-like interface</strong> for accessing domain objects.</p> -<p>💬 A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. -Client objects construct query specifications declaratively and submit them to Repository for satisfaction. -<strong>Objects can be added to and removed from the Repository, as they can from a simple collection of objects</strong>, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes.</p> -<p class="attribution">—<a class="reference external" href="https://martinfowler.com/eaaCatalog/repository.html">Repository homepage</a></p> +<div><p>💬 "One pattern I see time and time again on software teams is that they adopt Scrum, pay little attention to technical practices, and they're able to consistently increase their velocity for the first few years. +But after about three or four years the technical debt they've accumulated in their code is so great that their velocity starts to grind to a halt and they find it difficult to even get simple features implemented. +This is a place you do not want to get to, though I see it far too often in the software community—teams stuck there without a clue how to get out."</p> +<p class="attribution">—"<a class="reference external" href="https://www.agilealliance.org/how-to-increase-velocity/">How to Increase Velocity</a>" by David Bernstein</p> </div></blockquote> -Mon, 03 Jul 2023 00:00:00 О гонке сообщений в условиях конкурирующих подписчиковhttps://dckms.github.io/system-architecture/emacsway/it/integration/asynchronous/message-ordering-in-competing-consumers.html<span class="target" id="index-0"/><section id="emacsway-message-ordering"> -<span id="id1"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<p>Одной из непростых тем в DDD и микросервисной архитектуре является т.н. <strong>проблема "конкурирующих подписчиков"</strong>. Это когда два причинно-зависимых события попадают на конкурирующие узлы обработки событий, и второе событие может "обогнать" первое, например, по причине того, что при обработке первого события возникли сетевые издержки, или запустился сборщик мусора, или по какой-либо причине первое сообщение не было обработано и подтверждено (ack) с первого раза. Возникает гонка сообщений.</p> -<nav class="contents" id="id2"> -<p class="topic-title">Содержание</p> -<ul class="simple"> -<li><p><a class="reference internal" href="#emacsway-message-ordering" id="id7">О гонке сообщений в условиях конкурирующих подписчиков</a></p> -<ul> -<li><p><a class="reference internal" href="#id3" id="id8">Поддержка коммутативности</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id9">Исключение причин нарушения очередности событий</a></p></li> -<li><p><a class="reference internal" href="#id5" id="id10">Восстановление очередности сообщений</a></p></li> -<li><p><a class="reference internal" href="#id6" id="id11">Восстановление очередности обработки сообщений</a></p></li> -</ul> -</li> -</ul> -</nav> -<p>Например, <a class="reference external" href="https://docs.nats.io/nats-concepts/queue">NATS использует Round-robin для балансировки подписчиков группы</a>, и там эта проблема хорошо проявляется. Партиционирование каналов <a class="reference external" href="https://bravenewgeek.com/building-a-distributed-log-from-scratch-part-5-sketching-a-new-system/">появилось</a> только в пока еще нестабильном <a class="reference external" href="https://github.com/nats-io/jetstream">jetstream</a>.</p> +<p>Происходит это во многом потому, что:</p> <blockquote> -<div><p>Scaling with queue subscribers</p> -<p>This is ideal <strong>if you do not rely on message order</strong>.</p> -<p class="attribution">—"<a class="reference external" href="https://docs.nats.io/running-a-nats-service/nats_admin/slow_consumers#handling-slow-consumers">Slow Consumers - NATS Docs</a>"</p> +<div><p>💬 "Я узнал от Jeff Sutherland, что первый Scrum на самом деле использовал все XP практики. +Но Ken Schwaber убедил его оставить инженерные практики за рамками Scrum, чтобы упростить модель и позволить командам брать на себя ответственность за выбор тех или иных практик. +Возможно, это ускорило распространение Scrum, но с другой стороны многие команды страдают из-за отсутствия технических практик, позволяющих поддерживать постоянный темп гибкой разработки.</p> +<p>I learned from Jeff Sutherland that the first Scrum actually did all the XP practices. +But Ken Schwaber convinced him to leave the engineering practices out of Scrum, to keep the model simple and let the teams take responsibility for the tech practices themselves. +Perhaps this helped spread Scrum faster, but the downside is that a lot of teams suffer because they lack the technical practices that enable sustainable agile development."</p> +<p class="attribution">—"Scrum and XP from the Trenches: How We Do Scrum" 2nd edition by Henrik Kniberg, перевод под редакцией Алексея Кривицкого</p> </div></blockquote> -<p>Обходной путь:</p> +<p>Последнее предложение приведенной выше цитаты выражает то же самое, но другими словами. +А ведь еще в 2004 г., в книге "Agile Project Management with Scrum" by Ken Schwaber, Scrum назывался методологий.</p> +<p>Позвольте еще раз повторить слова Kent Beck:</p> <blockquote> -<div><p>Create a subject namespace that can scale</p> -<p>You can distribute work further through the subject namespace, with some forethought in design. This approach is useful if you need to preserve message order. The general idea is to publish to a deep subject namespace, and consume with wildcard subscriptions while giving yourself room to expand and distribute work in the future.</p> -<p>For a simple example, if you have a service that receives telemetry data from IoT devices located throughout a city, you can publish to a subject namespace like Sensors.North, Sensors.South, Sensors.East and Sensors.West. Initially, you'll subscribe to Sensors.&gt; to process everything in one consumer. As your enterprise grows and data rates exceed what one consumer can handle, you can replace your single consumer with four consuming applications to subscribe to each subject representing a smaller segment of your data. Note that your publishing applications remain untouched.</p> -<p class="attribution">—"<a class="reference external" href="https://docs.nats.io/running-a-nats-service/nats_admin/slow_consumers#handling-slow-consumers">Slow Consumers - NATS Docs</a>"</p> +<div><p>💬 "If a flattened change cost curve makes XP possible, a steep change cost curve makes XP impossible."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck</p> </div></blockquote> -<p>Еще одина возможная причина нарушения очередности обработки сообщений:</p> +<p>Impossible. Точка.</p> +<p>Если говорить более развернуто, то, конечно же, это не совсем "Impossible", просто это становится экономически нецелесообразным, поскольку при быстрорастущем графике изменения кода возникает экономическая целесообразность принимать решения в момент наименьшей стоимости их реализации, вплоть до заблаговременного проектирования.</p> <blockquote> -<div><p>Note: For a given subscription, messages are dispatched serially, one message at a time. If your application <strong>does not care about processing ordering</strong> and would prefer the messages to be dispatched concurrently, it is the application's responsibility to move them to some internal queue to be picked up by threads/go routines.</p> -<p class="attribution">—"<a class="reference external" href="https://docs.nats.io/using-nats/developer/receiving/async">Asynchronous Subscriptions - NATS Docs</a>"</p> +<div><p>💬 "To make agile work, you need solid technical practices. +A lot of agile education under-emphasizes these, but if you skimp on this you won't gain the productivity and responsiveness benefits that agile development can give you (stranding you at level 1 of the agile fluency model.) +This is one of the reasons that I still think that Extreme Programming is the most valuable of the named agile methods as a core and starting point."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/agile.html">Agile Software Development</a>" by Martin Fowler</p> </div></blockquote> -<p>Кроме того, доставка сообщений может пакетироваться из соображений оптимизации.</p> -<p>Один из примеров, который мне запомнился (с какой-то статьи) - это когда один из пользователей соц.сети удаляет из списка друзей другого пользователя, и тут же шлет оставшимся друзьям письмо, в котором дискредитирует удаленного друга. Возникает два события, первое - на удаление друга, второе - на отправку сообщения списку оставшихся друзей. Причем, второе сообщение находится в причинной зависимости от первого, и должно быть обработано после первого. Возникает гонка событий.</p> -<p>В условиях конкурирующих подписчиков, хронология обработки событий может измениться. И тогда, в момент отправки дискредитирующего письма списку друзей, удаленный пользователь все еще будет присутствовать в списке получателей.</p> -<p>Существует несколько стратегий решения этой проблемы:</p> -<ol class="arabic simple"> -<li><p>Нивелировать побочные эффекты (устранить симптомы) от нарушения очередности событий (коммутативность).</p></li> -<li><p>Исключить причины нарушения очередности событий.</p></li> -<li><p>Восстановить очередность сообщений.</p></li> -<li><p>Восстановить очередность обработки сообщений.</p></li> -</ol> -<p>Будем рассматривать каждый из вариантов поочередно в отдельных постах.</p> -<p>А пока - список литературы, который хорошо освещает эту проблему:</p> -<ul class="simple"> -<li><p>"Designing Data-Intensive Applications. The Big Ideas Behind Reliable, Scalable, and Maintainable Systems" by Martin Kleppmann</p></li> -<li><p>"<a class="reference external" href="https://martin.kleppmann.com/2020/11/18/distributed-systems-and-elliptic-curves.html">Lecture notes (PDF) (including exercises)</a>" by Martin Kleppmann (<a class="reference external" href="https://www.cl.cam.ac.uk/teaching/2021/ConcDisSys/dist-sys-notes.pdf">download</a>, <a class="reference external" href="https://github.com/ept/dist-sys">source code</a>, <a class="reference external" href="https://www.youtube.com/playlist?list=PLeKd45zvjcDFUEv_ohr_HdUFe97RItdiB">video</a>)</p></li> -<li><p>"Database Internals: A Deep Dive into How Distributed Data Systems Work" by Alex Petrov</p></li> -<li><p>"Distributed systems: principles and paradigms" 3d edition by Andrew S. Tanenbaum, Maarten Van Steen</p></li> -<li><p>"<a class="reference external" href="http://books.ifmo.ru/file/pdf/1551.pdf">Введение в распределенные вычисления</a>" / Косяков М. С. — СПб: НИУ ИТМО, 2014. — С. 75-82. — 155 с.</p></li> -<li><p>"Building Event-Driven Microservices" by Adam Bellemare, "<a class="reference external" href="https://www.oreilly.com/library/view/building-event-driven-microservices/9781492057888/ch06.html">Chapter 6. Deterministic Stream Processing</a>"</p></li> -<li><p>"<a class="reference external" href="http://book.mixu.net/distsys/">Distributed systems: for fun and profit</a>" (2013). An introduction to distributed systems. (<a class="reference external" href="https://github.com/mixu/distsysbook">source code</a>)</p></li> -<li><p>"Database Reliability Engineering. Designing and Operating Resilient Database Systems." by Laine Campbell and Charity Majors</p></li> -<li><p>"Streaming Systems: The What, Where, When, and How of Large-Scale Data Processing", by Tyler Akidau, Slava Chernyak, and Reuven Lax, "Chapter 2. The What, Where, When, and How of Data Processing", "Chapter 3. Watermarks"</p></li> -<li><p>"<a class="reference external" href="https://oreil.ly/WO2OC">The Dataflow Model: A Practical Approach to Balancing Correctness, Latency, and Cost in Massive-Scale, Unbounded, Out-of-Order Data Processing</a>" by Tyler Akidau, Robert Bradshaw, Craig Chambers, Slava Chernyak, Rafael J. Fernandez-Moctezuma, Reuven Lax, Sam McVeety, Daniel Mills, Frances Perry, Eric Schmidt, Sam Whittle; Google</p></li> -<li><p>"<a class="reference external" href="https://leanpub.com/dddwithpython">Event Sourced Building Blocks for Domain-Driven Design with Python</a>" by John Bywater</p></li> -</ul> -<p>Статьи по теме:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">Don't Settle for Eventual Consistency. Stronger properties for low-latency geo-replicated storage.</a>" (<a class="reference external" href="https://dl.acm.org/ft_gateway.cfm?id=2610533&amp;ftid=1449165&amp;dwn=1">pdf</a>) by Wyatt Lloyd, Facebook; Michael J. Freedman, Princeton University; Michael Kaminsky, Intel Labs; David G. Andersen, Carnegie Mellon University</p></li> -<li><p>"<a class="reference external" href="http://www.bailis.org/papers/bolton-sigmod2013.pdf">Bolt-on Causal Consistency</a>" by Peter Bailis, Ali Ghodsi, Joseph M. Hellerstein†, Ion Stoica, UC Berkeley KTH/Royal Institute of Technology</p></li> -<li><p>"<a class="reference external" href="https://disco.ethz.ch/courses/hs08/seminar/papers/mattern4.pdf">Detecting Causal Relationships in Distributed Computations:In Search of the Holy Grail</a>" by Reinhard Schwarz, Friedemann Mattern</p></li> -<li><p>"<a class="reference external" href="https://www.microsoft.com/en-us/research/publication/principles-of-eventual-consistency/">Principles of Eventual Consistency</a>" (<a class="reference external" href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/final-printversion-10-5-14.pdf">pdf</a>) by Sebastian Burckhardt, Microsoft Research</p></li> -<li><p>"<a class="reference external" href="https://habr.com/ru/company/ua-hosting/blog/487638/">HighLoad++, Михаил Тюленев (MongoDB): Causal consistency: от теории к практике</a>"</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/articles/patterns-of-distributed-systems/version-vector.html">Version Vector</a>" by Unmesh Joshi</p></li> -<li><p>"<a class="reference external" href="https://www.infoq.com/articles/no-reliable-messaging/">Nobody Needs Reliable Messaging</a>" by Marc de Graauw</p></li> -<li><p>"<a class="reference external" href="https://www.infoq.com/articles/modeling-uncertainty-reactive-ddd/">Modeling Uncertainty with Reactive DDD</a>" by Vaughn Vernon reviewed by Thomas Betts</p></li> -<li><p>"<a class="reference external" href="https://queue.acm.org/detail.cfm?id=3025012">Life Beyond Distributed Transactions</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.confluent.io/blog/error-handling-patterns-in-kafka/">Error Handling Patterns for Apache Kafka Applications</a>" by Gerardo Villeda</p></li> -<li><p>"<a class="reference external" href="https://learn.microsoft.com/en-us/azure/architecture/patterns/competing-consumers">Competing Consumers pattern</a>"</p></li> -</ul> -<p>Список литературы по интеграционным паттернам:</p> -<ul class="simple"> -<li><p>"Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions" by Gregor Hohpe, Bobby Woolf</p></li> -<li><p>"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon</p></li> -<li><p>"Camel in Action" 2nd Edition by Claus Ibsen and Jonathan Anstey</p></li> -</ul> -<p>Примеры интеграционных паттернов:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://github.com/VaughnVernon/ReactiveMessagingPatterns_ActorModel">https://github.com/VaughnVernon/ReactiveMessagingPatterns_ActorModel</a></p></li> -<li><p><a class="reference external" href="https://camel.apache.org/components/latest/eips/enterprise-integration-patterns.html">https://camel.apache.org/components/latest/eips/enterprise-integration-patterns.html</a></p></li> -<li><p><a class="reference external" href="https://github.com/camelinaction/camelinaction2">https://github.com/camelinaction/camelinaction2</a></p></li> -<li><p><a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/">https://www.enterpriseintegrationpatterns.com/patterns/messaging/</a></p></li> -</ul> -<p>Каталог моделей согласованности:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://jepsen.io/consistency">https://jepsen.io/consistency</a></p></li> -</ul> -<p>Шпаргалка по EIP-паттернам:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/download/EIPTutorialReferenceChart.pdf">Enterprise Integration Patterns Tutorial Reference Chart</a>"</p></li> -</ul> -<p>Каталоги:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/">Cloud Design Patterns</a>"</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn568099(v=pandp.10)">Cloud Design Patterns. Prescriptive architecture guidance for cloud applications</a>" by Alex Homer, John Sharp, Larry Brader, Masashi Narumoto, Trent Swanson.</p></li> -</ul> -<p>Code Samples:</p> -<ul class="simple"> -<li><p><a class="reference external" href="http://aka.ms/cloud-design-patterns-sample">http://aka.ms/cloud-design-patterns-sample</a></p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/best-practices/">Cloud Best Practices</a>" by Microsoft Corporation and community</p></li> -</ul> -<section id="id3"> -<h2><a class="toc-backref" href="#id8" role="doc-backlink">Поддержка коммутативности</a></h2> -<p>Первая из перечисленных стратегий решения проблемы "конкурирующих подписчиков" - это "<strong>нивелировать побочные эффекты (устранить симптомы) от нарушения очередности событий (коммутативность)</strong>".</p> -<p>Часто бывает так, что два действия подряд над одним и тем же агрегатом приводят к тому, что, в условиях конкурирующих подписчиков, сообщение второго события может обогнать сообщение первого события. Если при этом используется "<strong>Event-Carried State Transfer</strong>" ( <a class="reference external" href="https://martinfowler.com/articles/201701-event-driven.html">https://martinfowler.com/articles/201701-event-driven.html</a> ), то при обработке следующего сообщения (которое было отправлено первым), система будет оперировать уже устаревшими данными.</p> -<p>Как один из вариантов решения проблемы в таком случае, может быть переход на "<strong>Event Notification</strong>". В некоторых случаях прокатывает. Но он ухудшает availability (CAP-Theorem) из-за каскадного синхронного запроса.</p> -<p>В некоторых случаях также прокатывает игнорирование предыдущего события, если последующее событие уже было обработано.</p> -</section> -<section id="id4"> -<h2><a class="toc-backref" href="#id9" role="doc-backlink">Исключение причин нарушения очередности событий</a></h2> -<p>Вторая из перечисленных стратегий решения проблемы "конкурирующих подписчиков" - это "<strong>исключить причины нарушения очередности событий</strong>".</p> -<p>Этому способу решения проблемы посвящена глава "<a class="reference external" href="https://livebook.manning.com/book/microservices-patterns/chapter-3/section-3-3-5?origin=product-toc">3.3.5 Competing receivers and message ordering</a>" книги "Microservices Patterns: With examples in Java" by Chris Richardson</p> -<p>Если mеssaging system не поддерживает партиционирование каналов, то его можно реализовать с помощью паттерна EIP "<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/ContentBasedRouter.html">Content-Based Router</a>"</p> -<p>Например, <a class="reference external" href="https://camel.apache.org/components/latest/eips/content-based-router-eip.html">используя Camel Framework</a>.</p> -<p>С помощью партиционирования каналов мы добиваемся того, что все сообщения одного и того же <strong>причинно-зависимого (causal) потока</strong> попадают на один и тот же узел группы подписчиков. Нет конкуренции - нет проблемы. Здесь вводится новый и достаточно обширный термин "<strong>Causal Consistency</strong>", имеющий критически важное значение для всех, кто имеет дело с распределенными системами.</p> -<p>Vaughn Vernon в "Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" (RMPwAM) ссылается на следующие две статьи по этому вопросу:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">https://queue.acm.org/detail.cfm?id=2610533</a></p></li> -<li><p><a class="reference external" href="http://www.bailis.org/papers/bolton-sigmod2013.pdf">http://www.bailis.org/papers/bolton-sigmod2013.pdf</a></p></li> +<blockquote> +<div><p>💬 "We need to stress that you shouldn't worry too much about the issue of reworking. +<strong>XP's practices are all about reducing the cost of reworking to manageable levels.</strong> +If you find yourself in a situation <strong>where the cost of reworking is prohibitive, then you should either not use XP or you should use an environment that makes rework easier</strong>."</p> +<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler</p> +</div></blockquote> +<p>Этому вопросу посвящена статья "<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler.</p> +<blockquote> +<div><p>💬 "In its common usage, evolutionary design is a disaster. +The design ends up being the aggregation of a bunch of ad-hoc tactical decisions, each of which makes the code harder to alter. +In many ways you might argue this is no design, certainly it usually leads to a poor design. +As Kent puts it, <strong>design is there to enable you to keep changing the software easily in the long term.</strong> +<strong>As design deteriorates, so does your ability to make changes effectively.</strong> +You have the state of software entropy, over time the design gets worse and worse. +Not only does this make the software harder to change, it also makes bugs both easier to breed and harder to find and safely kill. +This is the "code and fix" nightmare, where the bugs become exponentially more expensive to fix as the project goes on."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler</p> +</div></blockquote> +<blockquote> +<div><p>💬 "If you're a manager or customer how can you tell if the software is well designed? +It matters to you because poorly designed software will be more expensive to modify in the future."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler</p> +</div></blockquote> +<p>И очень удачно по этому вопросу высказался Grady Booch:</p> +<blockquote> +<div><p>💬 "Grady Booch has also provided a set of guidelines for an agile architecture (which in turn imply some duties for the agile architect). +Booch claims that all good software-intensive architectures are agile. +What does he mean by this? He means that a successful architecture is resilient and loosely coupled. +It is composed of a core set of well-reasoned design decisions but still contains some "wiggle room" that allows modifications to be made and refactorings to be done, without ruining the original structure.</p> +<p>Booch also notes that an effective agile process will allow the architecture to grow incrementally as the system is developed and matures. +The key to success is to have decomposability, separation of concerns, and near-independence of the parts. +(Sound familiar? These are all modifiability tactics.)</p> +<p>Finally, Booch notes that to be agile, the architecture should be visible and self-evident in the code; this means making the design patterns, cross-cutting concerns, and other important decisions obvious, well communicated, and defended. +This may, in turn, require documentation. +But whatever architectural decisions are made, the architect must make an effort to "socialize" the architecture."</p> +<p class="attribution">—"Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman</p> +</div></blockquote> +<blockquote> +<div><p>💬 "After all software is supposed to be soft."</p> +<p class="attribution">—"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html">The New Methodology</a>" by Martin Fowler</p> +</div></blockquote> +<section id="id6"> +<h3><a class="toc-backref" href="#id15" role="doc-backlink">Пример</a></h3> +<blockquote> +<div><p>💬 I had a chance to witness the pitfalls of this trap firsthand. +Working with Nokia, I noticed that management was measuring the success of its digital transformation by how many people were trained on Agile software development methodologies and were onboarded onto Agile tools. +These activity-based proxy metrics had nothing to do with business outcomes. +As I will summarize in Part I, Nokia’s transformation efforts failed to address the core platform problems that made it so <strong>difficult for the company to adapt to the changing market</strong>. +In spite of what appeared to be a well-planned transformation, management was not able to realize this until too late. +I watched with frustration as Nokia lost the mobile market it had created, in spite of the heroic efforts of my colleagues, who were doing everything they could to save the company.</p> +<p>...</p> +<p>Even if the teams had attained a theoretical ideal of agility, would Nokia have been <strong>able to adapt more quickly</strong> without upstream changes to how the business was measuring delivery? +Or <strong>adapt</strong> downstream changes in how the software was deployed? Or the <strong>architecture changes that were slowing developers down in the first place</strong>? +In my opinion, that narrow-minded and activity-oriented view of Agile was the root cause of Nokia’s failed digital transformation. +The failed transformation made fast iteration and learning from the market impossible, as the lead times for delivering new features, such as an app store and an elegant home screen, were far too slow. +This hindered the business’s ability to learn and adapt, and that inability to adapt was a key factor in Nokia’s downfall.</p> +<p class="attribution">—"Project to Product: How to Survive and Thrive in the Age of Digital Disruption with the Flow Framework" by Mik Kersten</p> +</div></blockquote> +<p>Cм. также:</p> +<blockquote> +<div><ul class="simple"> +<li><p>"<a class="reference external" href="https://martinfowler.com/articles/agileStory.html">Writing The Agile Manifesto</a>" by Martin Fowler</p></li> +<li><p>"<a class="reference external" href="https://www.informit.com/articles/article.aspx?p=2990402">The Reasons for Agile</a>" by Robert C. Martin</p></li> +<li><p>"<a class="reference external" href="https://www.theatlantic.com/technology/archive/2017/12/agile-manifesto-a-history/547715/">The Winter Getaway That Turned the Software World Upside Down</a>" by Caroline Mimbs Nyce</p></li> +<li><p>"<a class="reference external" href="https://pragdave.me/blog/2007/02/24/some-agile-history.html">Some Agile History</a>" by Dave Thomas</p></li> +<li><p>"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html">The New Methodology</a>" by Martin Fowler</p></li> +<li><p>"<a class="reference external" href="http://agilemanifesto.org/history.html">History: The Agile Manifesto</a>"</p></li> </ul> -<p>Каталог моделей согласованности:</p> +</div></blockquote> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> <ul class="simple"> -<li><p><a class="reference external" href="https://jepsen.io/consistency">https://jepsen.io/consistency</a></p></li> +<li><p>"<a class="reference internal" href="../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../uncertainty-management/prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Что такое Prediction</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../uncertainty-management/balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">Balancing Prediction/Adaptation</span></a>"</p></li> +<li><p>"<a class="reference internal" href="analysis/concerns/balancing-business-technical-concerns.html#emacsway-agile-business-concerns-predominance"><span class="std std-ref">Преобладание бизнес-интересов</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../uncertainty-management/adaptation/software-design/software-design.html"><span class="doc">Role of Software Design in Agile</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../uncertainty-management/adaptation/crash-course-in-software-development-economics.html"><span class="doc">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> </ul> -<p>Было бы, наверное, уместно упомянуть в контексте этого обсуждения пару превосходных материалов на тему CAP-theorem и Consistency:</p> -<p>Самое понятное объяснение CAP-Theorem, которое я когда-либо видел:</p> +</div> +</section> +</section> +Fri, 20 Oct 2023 00:00:00 Iterative Developmenthttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/iterative.html +<span id="emacsway-iterative-development"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<blockquote> +<div><p>📝 "The "iterative development" model performs initial planning and then consists of a cyclic process of prototyping, testing, analyzing and refining the requirements and the solution. +"Iterative" models repeatedly perform the life cycle processes to deliver prioritized system functions sooner, with refined or more complex elements of the system coming in later iterations."</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> +</div></blockquote> +<figure class="align-left" id="id1"> +<a class="reference internal image-reference" href="../../../../_images/iterating.jpg"><img alt="Iterative Development. The image source is &quot;Don't Know What I Want, But I Know How to Get It&quot; by Jeff Patton &amp; Associates https://www.jpattonassociates.com/dont_know_what_i_want/" src="../../../../_images/iterating.jpg" style="width: 90%;"/></a> +<figcaption> +<p><span class="caption-text">Iterative Development. The image source is "<a class="reference external" href="https://www.jpattonassociates.com/dont_know_what_i_want/">Don't Know What I Want, But I Know How to Get It</a>" by Jeff Patton &amp; Associates</span></p> +</figcaption> +</figure> +<blockquote> +<div><p>💬 If you run into a dead end in one of the areas, <strong>iterate</strong>! +Incremental refinement is a powerful tool for managing complexity. +As Polya recommended in mathematical problem solving, understand the problem, devise a plan, carry out the plan, and then look back to see how you did [Polya 1957].</p> +<blockquote> +<div><p>— "Code Complete" 2nd edition by Steve McConnell</p> +</div></blockquote> +</div></blockquote> +<blockquote> +<div><p>💬 ""Iteration" here means applying a function to itself."</p> +<p class="attribution">—"Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik</p> +</div></blockquote> +<p>В математике итерация - это применение функции самой к себе, и именно этим обеспечивается "Responding", т.к. каждый новый вызов получает на вход результат работы предыдущего вызова.</p> +<blockquote> +<div><p>💬 The key to iterative development is to frequently produce working versions of the final system that have a subset of the required features.</p> +<p>💬 Iterative development makes sense in predictable processes as well. +But it is essential in adaptive processes because an adaptive process needs to be able to deal with changes in required features. +This leads to a style of planning where long term plans are very fluid, and the only stable plans are short term plans that are made for a single iteration. +Iterative development gives you a firm foundation in each iteration that you can base your later plans around.</p> +<p class="attribution">—"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html">The New Methodology</a>" by Martin Fowler</p> +</div></blockquote> +<blockquote> +<div><p>💬 In this thinking waterfall means "do one activity at a time for all the features" while iterative means "do all activities for one feature at a time".</p> +<p>💬 Indeed we've found that delivering a subset of features does more than anything to help clarify what needs to be done next, so an iterative approach allows us to shift to an adaptive planning approach where we update our plans as we learn what the real software needs are.</p> +<p>💬 But it is easy to follow an iterative approach (i.e. non-waterfall) but not be agile. +I might do this by taking 100 features and dividing them up into ten iterations over the next year, and then expecting that each iteration should complete on time with its planned set of features. +If I do this, my initial plan is a predictive plan, if all goes well I should expect the work to closely follow the plan. +But adaptive planning is an essential element of agile thinking. +I expect features to move between iterations, new features to appear, and many features to be discarded as no longer valuable enough.</p> +<p>My rule of thumb is that anyone who says "we were successful because we were on-time and on-budget" is thinking in terms of predictive planning, even if they are following an iterative process, and thus is not thinking with an agile mindset. +In the agile world, success is all about business value - regardless of what was written in a plan months ago. +Plans are made, but updated regularly. +They guide decisions on what to do next, but are not used as a success measure.</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/WaterfallProcess.html">Waterfall Process</a>" by Martin Fowler</p> +</div></blockquote> +<p>Итерация может дать Responding, а может и не дать. +Важны не итерации сами по себе, а именно Responding. +Поэтому в Agile Manifesto пишут про Responding, а не про итерации.</p> +<p>Ключевым элементом итеративной разработки является <a class="reference internal" href="../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Adaptation</span></a>.</p> +<p>См. также:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="http://ksat.me/a-plain-english-introduction-to-cap-theorem">A plain english introduction to CAP Theorem</a>" by Kaushik Sathupadi (<a class="reference external" href="https://habr.com/ru/post/130577/">перевод на русский</a>)</p></li> +<li><p>"<a class="reference external" href="https://www.agilealliance.org/glossary/iteration">Iteration</a>" at Glossary of agilealliance.org</p></li> </ul> -<p>Превосходная статья от CTO of Amazon.com Werner Vogels:</p> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://www.allthingsdistributed.com/2008/12/eventually_consistent.html">Eventually Consistent - Revisited</a>"</p></li> +<li><p>"<a class="reference internal" href="../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> +<li><p>"<a class="reference internal" href="agile/agile.html#emacsway-agile-development"><span class="std std-ref">Что такое Agile Development</span></a>"</p></li> </ul> -<p>Превосходная статья по Causal Consistency (Causal Dependencies) доступным языком:</p> +</div> +Fri, 20 Oct 2023 00:00:00 Что такое Adaptationhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.html +<span id="emacsway-adaptation"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://habr.com/ru/company/ua-hosting/blog/487638/">HighLoad++, Михаил Тюленев (MongoDB): Causal consistency: от теории к практике</a>"</p></li> +<li><p><a class="reference internal" href="#adaptation" id="id7">Что такое Adaptation</a></p> +<ul> +<li><p><a class="reference internal" href="#id2" id="id8">Суть Адаптации</a></p></li> +<li><p><a class="reference internal" href="#id3" id="id9">Назначение Адаптации</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id10">Немножко о продуктовом подходе</a></p></li> +<li><p><a class="reference internal" href="#refactoring" id="id11">Причем здесь refactoring?</a></p></li> </ul> -</section> -<section id="id5"> -<h2><a class="toc-backref" href="#id10" role="doc-backlink">Восстановление очередности сообщений</a></h2> -<p>Третья из перечисленных стратегий решения проблемы "конкурирующих подписчиков" - это "<strong>восстановить очередность сообщений</strong>".</p> -<blockquote> -<div><p>📝 "Хьюитт был против включения требований о том, что сообщения должны прибывать в том порядке, в котором они отправлены на модель актора. Если желательно упорядочить входящие сообщения, то это можно смоделировать с помощью очереди акторов, которая обеспечивает такую функциональность. Такие очереди акторов упорядочивали бы поступающие сообщения так, чтобы они были получены в порядке FIFO. В общем же случае, если актор X отправляет сообщение M1 актору Y, а затем тот же актор X отправляет другое сообщение M2 к Y, то не существует никаких требований о том, что M1 придёт к Y раньше M2."</p> -<p class="attribution">—Pаздел "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2#%D0%9D%D0%B8%D0%BA%D0%B0%D0%BA%D0%B8%D1%85_%D1%82%D1%80%D0%B5%D0%B1%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B9_%D0%BE_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BA%D0%B5_%D0%BF%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D0%B9">Никаких требований о порядке поступления сообщений</a>" статьи "Модель акторов" Википедии</p> -</div></blockquote> -<p>Для решения этой задачи можно использовать EIP Pattern "<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/Resequencer.html">Resequencer</a>". Например, <a class="reference external" href="https://camel.apache.org/components/latest/eips/resequence-eip.html">используя Camel Framework</a>.</p> -</section> -<section id="id6"> -<h2><a class="toc-backref" href="#id11" role="doc-backlink">Восстановление очередности обработки сообщений</a></h2> -<p>Четвертая из перечисленных стратегий решения проблемы "конкурирующих подписчиков" - это "<strong>восстановить очередность обработки сообщений</strong>".</p> -<p>Иными словами, можно пойти другим путем, и отказаться от гарантированной очередности доставки сообщений. Но, в таком случае, подписчик сам должен будет решать, может ли он обработать поступившее сообщение, или же причинно-предшествующее сообщение еще пока не было обработано, и тогда он должен оставить поступившее сообщение в очереди. Правда, на выяснение этого требуется потратить ресурсы (где-то нужно фиксировать обработку сообщений и потом удостоверяться, что предшествующее причинное сообщение уже было обработано).</p> -<p>Как красиво заметил Alexey Zimarev, "мир occasionally-connected устройств по определению не упорядочен".</p> -<p>Такой подход применяется в Actor Model:</p> +</li> +</ul> +</nav> +<section id="id2"> +<h2><a class="toc-backref" href="#id8" role="doc-backlink">Суть Адаптации</a></h2> <blockquote> -<div><p>📝 "... модель акторов зеркально отражает систему коммутации пакетов, которая не гарантирует, что пакеты будут получены в порядке отправления. Отсутствие гарантий порядка доставки сообщений позволяет системе коммутации пакетов буферизовать пакеты, использовать несколько путей отправки пакетов, повторно пересылать повреждённые пакеты и использовать другие методы оптимизации."</p> -<p class="attribution">—Pаздел "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2#%D0%9D%D0%B8%D0%BA%D0%B0%D0%BA%D0%B8%D1%85_%D1%82%D1%80%D0%B5%D0%B1%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B9_%D0%BE_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BA%D0%B5_%D0%BF%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D0%B9">Никаких требований о порядке поступления сообщений</a>" статьи "Модель акторов" Википедии</p> +<div><p>📝 "No crystal balls. +Humans are not able to predict the future. +For example, your competition makes an announcement that was not expected. +Unanticipated technical problems crop up that force a change in direction. +Furthermore, people are particularly bad at planning uncertain things far into the future – guessing today how you will be spending your week eight months from now is something of a fantasy. +It has been the downfall of many a carefully constructed Gantt chart."</p> +<p class="attribution">—"Jeff Sutherland's Scrum Handbook" by Jeff Sutherland</p> </div></blockquote> <blockquote> -<div><p>📝 "Messages in the Actor model are generalizations of packets in Internet computing in that they need not be received in the order sent. Not implementing the order of delivery, allows packet switching to buffer packets, use multiple paths to send packets, resend damaged packets, and to provide other optimizations.</p> -<p>For example, Actors are allowed to pipeline the processing of messages. What this means is that in the course of processing a message m1, an Actor can designate how to process the next message, and then in fact begin processing another message m2 before it has finished processing m1. Just because an Actor is allowed to pipeline the processing of messages does not mean that it must pipeline the processing. Whether a message is pipelined is an engineering tradeoff."</p> -<p class="attribution">—"<a class="reference external" href="https://arxiv.org/abs/1008.1459">Actor Model of Computation: Scalable Robust Information Systems</a>" by Carl Hewitt</p> +<div><p>📝 "Глаза боятся - руки делают."</p> +<p class="attribution">—Народная пословица.</p> </div></blockquote> -<p>Тут нужно сделать короткое отступление. Хотя, как говорилось ранее, "<em>Хьюитт был против включения требований о том, что сообщения должны прибывать в том порядке, в котором они отправлены на модель актора</em>", в современных реализациях Actor Model mailbox представлен как FIFO-queue:</p> +<p>Суть Adaptation (Адаптации) заключается в том, что мы не пытаемся разрешить неопределенность заблаговременно путем логического вывода, а, в противовес <a class="reference internal" href="../prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Prediction</span></a>, разрешаем неопределенность опытным, экспериментальным путем (широко известным как "метод научного тыка" 🙂️). +Выдвигаем гипотезу, вносим её в план, реализуем Системный Инкремент, инспектируем результат на практике, и адаптируем план на следующую итерацию. +Этот цикл образует <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">итерацию</span></a>.</p> +<p>Полученные практическим способом знания, снижающие неопределенность, являются входными аргументами для следующей <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">итерации</span></a>.</p> <blockquote> -<div><p>📝 "One of the guarantees of the Actor model is sequential message delivery. That is, by default actor mailboxes are first-in, first-out (FIFO) channels. When a message arrives through the actor's channel, it will be received in the order in which it was sent. Thus, if actor A sends a message to actor B and then actor A sends a second message to actor B, the message that was sent first will be the first message received by actor B."</p> +<div><p>📝 ""Iteration" here means applying a function to itself."</p> +<p class="attribution">—"Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik</p> </div></blockquote> -<p>Однако, вопрос все-равно остается открытым:</p> +<p>Как сказал Томас Эдисон: «Я не терпел поражений. Я просто нашёл 10 000 способов, которые не работают».</p> +</section> +<section id="id3"> +<h2><a class="toc-backref" href="#id9" role="doc-backlink">Назначение Адаптации</a></h2> +<p>Рость неопределенности приводит к росту стоимости Prediction по мере роста его точности. +Предел экономической целесообразности Prediction определяется пересечением графика роста стоимости Prediction (в зависимости от его точности) с графиком роста бизнес-выгод от точности Прогнозирования.</p> +<p>Там, где сумма произведений количества Адаптаций Системного Инкремента на стоимость Адаптации системного инкремена для каждой итерации пересечет сумму экономически целесообразной стоимости Prediction на горизонте планирования, возникает предел экономической целесообразности эмпирического способа обработки неопределенности Проекта при допущении, что остаточная стоимость самой реализации (которая не имеет отношения к разрешению неопределенности) остается неизменной в обоих случаях. +Обратите внимание, в данном случае речь идет о стоимости Адаптации Системного Инкремента, а не Плана. +Т.е. речь идет о стоимости экспериментального разрешения неопределенности (цикл ошибка - исправление).</p> +<p>Prediction при этом не исчезает полностью, а понижает свою точность и дополняется Адаптацией. +Для наилучшего совокупного экономического эффекта важно правильно находить <a class="reference internal" href="../balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">баланс между Prediction и Adaptation</span></a>, а также обеспечивать <a class="reference internal" href="../../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">характер роста стоимости Adaptation максимально приближенный к горизонтальной асимптоте</span></a>, поскольку, чем больше Адаптаций Системного Инкремента возникает на горизонте планирования, тем дороже становится экспериментальный способ разрешения неопределенности по сравнению с логическим.</p> +<p>При этом нужно учитывать, что стоимость Prediction также не константна по отношению к жизненному циклу системы, а имеет тенденцию к понижению. +Т.е. чем большая часть системы уже реализована, тем больше баланс экономической целесообразности смещается от Adaptation к Prediction.</p> +<figure class="align-left" id="id5"> +<a class="reference internal image-reference" href="../../../../../_images/cost-of-decision-over-time.png"><img alt="FIGURE 3.6 Make decisions at the last responsible moment. The image source is &quot;Essential Scrum: A Practical Guide to the Most Popular Agile Process&quot; by Kenneth Rubin, &quot;Chapter 3 Agile Principles :: Prediction and Adaptation&quot;." src="../../../../../_images/cost-of-decision-over-time.png" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">FIGURE 3.6 Make decisions at the last responsible moment. The image source is "Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation".</span></p> +<div class="legend"> <blockquote> -<div><p>📝 "What if you introduce a third actor, C? Now actor A and actor C both send one or more messages to actor B. There is no guarantee which message actor B will receive first, either the first from actor A or the first from actor C. Nevertheless, the first message from actor A will always be received by actor B before the second message that actor A sends, and the first message from actor C will always -be received by actor B before the second message that actor C sends...</p> -<p>What is implied? Actors must be prepared to accept and reject messages based on their current state, which is reflected by the order in which previous messages were received. Sometimes a latent message could be accepted even if it is not perfect timing, but the actor's reaction to the latent message may have to carefully take into account its current state beforehand. This may be dealt with more gracefully by using the actors become() capabilities."</p> -<p class="attribution">—"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon, Chapter "5. Messaging Channels :: Point-to-Point Channel"</p> +<div><p>📝 "Most of us would prefer to wait until we have more information so that we can make a more informed decision. +When dealing with important or irreversible decisions, if we decide too early and are wrong, we will be on the exponential part of the cost-of-deciding curve in Figure 3.6. +As we acquire a better understanding regarding the decision, the cost of deciding declines (the likelihood of making a bad +decision declines because of increasing market or technical certainty). +That's why we should wait until we have better information before committing to a decision."</p> +<p class="attribution">—"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation"</p> </div></blockquote> -<p>Кроме того,</p> +</div> +</figcaption> +</figure> +<p>Это и есть та самая причина, по которой выбор SDLC-модели является неотъемлемой частью процесса проектирования, и изучается архитектурой. +Ведь различные SDLC-модели (итеративные, инкрементальные, спиральные, гибридные, каскадные), реализованные в виде Scrum, RUP, SAFe, BDUF etc., обладают различным соотношением Prediction vs. Adaptation, имеют разные подходы к масштабированию команд и различные ограничения. +Выбор SDLC-модели сильно зависит от ситуативного контекста проектирования. +Повторюсь, основная цель итеративной разработки - удешевить стоимость проектирования в условиях неопределенности.</p> +<p>Об этом Брукс писал в Мифическом человеко-месяце еще до появления Agile Manifesto:</p> <blockquote> -<div><p>📝 "Because individual messages may follow different routes, some messages are likely to pass through the processing steps sooner than others, <strong>resulting in the messages getting out of order</strong>. However, some subsequent processing steps do require in-sequence processing of messages, for example to maintain referential integrity.</p> -<p>One common way things get out of sequence is the fact that different messages may take different processing paths. Let's look at a simple example. Let's assume we are dealing with a numbered sequence of messages. If all even numbered messages have to undergo a special transformation whereas all odd numbered messages can be passed right through, then odd numbered messages will appear on the resulting channel while the even ones queue up at the transformation. If the transformation is quite slow, all odd messages may appear on the output channel before a single even message makes it, bringing the sequence completely out of order.</p> -<p>To avoid getting the messages out of order, we could introduce a loop-back (acknowledgment) mechanism that makes sure that only one message at a time passes through the system. The next message will not be sent until the last one is done processing. This conservative approach will resolve the issue, but has two significant drawbacks. First, it can slow the system significantly. If we have a large number of parallel processing units, we would severely underutilize the processing power. In many instances, the reason for parallel processing is that we need to increase performance, so throttling traffic to one message at a time would complete erase the purpose of the solution. The second issue is that this approach requires us to have control over messages being sent into the processing units. However, often we find ourselves at the receiving end of an out-of-sequence message stream without having control over the message origin."</p> -<p class="attribution">—"Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions" by Gregor Hohpe, Bobby Woolf</p> +<div><p>📝 "Therefore the most important function that software builders do for their clients is the <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a> <strong>extraction and refinement of the product requirements</strong>...</p> +<p>I would go a step further and assert that it is really impossible for clients, even those working with software engineers, to specify completely, precisely, and correctly the exact requirements of a modern software product before having built and tried some versions of the product they are specifying.</p> +<p>Therefore one of the most promising of the current technological efforts, and one which attacks the essence, not the accidents, of the software problem, is the development of approaches and tools for rapid prototyping of systems as part of the <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a> <strong>specification of requirements</strong>."</p> +<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr.</p> </div></blockquote> -<p>Решение?</p> <blockquote> -<div><p>📝 "While not discussed in detail here, Message Metadata can be used to achieve causal consistency [<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">AMC-Causal Consistency</a>] among Messages (130) that must be replicated across a network with full ordering preserved [<a class="reference external" href="http://www.bailis.org/papers/bolton-sigmod2013.pdf">Bolt-on Causal Consistency</a>]."</p> -<p class="attribution">—"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon, Chapter "10. System Management and Infrastructure :: Message Metadata/History"</p> +<div><p>💬 Furthermore, a waterfall approach forces us into a predictive style of planning, it assumes that once you are done with a phase, such as requirements analysis, the resulting deliverable is a stable platform for later phases to base their work on. +In practice the vast majority of software projects find they need to change their requirements significantly within a few months, due to everyone learning more about the domain, the characteristics of the software environment, and changes in the business environment. +Indeed we've found that delivering a subset of features does more than anything to help clarify what needs to be done next, so an iterative approach allows us to shift to an adaptive planning approach where we update our plans as we learn what the real software needs are.</p> +<p>These are the major reasons why I've <a class="reference external" href="https://martinfowler.com/books/uml.html">glibly said that</a> "you should use iterative development only in projects that you want to succeed".</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/WaterfallProcess.html">Waterfall Process</a>" by Martin Fowler</p> </div></blockquote> +<p>Конечно, сугубо семантически, термин "<a class="reference internal" href="../../models/agile/analysis/requirements/requirements.html#emacsway-agile-requirements"><span class="std std-ref">requirements</span></a>" немного вводит в заблуждение в Agile, ведь заранее требования к продукту неизвестны полностью, и они изменяются по мере реализации продукта. +А в таком случае, как они могут что-то требовать? +Вы, наверное, встречали картинку с треугольником "<a class="reference external" href="https://www.atlassian.com/agile/agile-at-scale/agile-iron-triangle">Iron Triangle</a>" (Requirements/Scope, Cost, Time), где в waterfall он обращен вершиной Requirements вниз (константная область), а в Agile - вверх (переменная область). The iron triangle of planning:</p> +<figure class="align-left" id="id6"> +<a class="reference internal image-reference" href="../../../../../_images/iron-triangle.png"><img alt="Iron Triangle. Agile fixes the date and resources and varies the scope. The image source is &quot;Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise&quot; by Dean Leffingwell" src="../../../../../_images/iron-triangle.png" style="width: 90%;"/></a> +<figcaption> +<p><span class="caption-text">Iron Triangle. Agile fixes the date and resources and varies the scope. The image source is "Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</span></p> +</figcaption> +</figure> +<p>Итеративная разработка востребована, когда невозможно достигнуть полноты (Complete) требований (set of <a class="reference internal" href="../../models/agile/analysis/requirements/requirements.html#emacsway-agile-requirements"><span class="std std-ref">requirements</span></a>).</p> <blockquote> -<div><p>📝 "Even so, a technique called causal consistency [<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">AMC-Causal Consistency</a>] can be used to achieve the same."</p> -<p class="attribution">—"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon, Chapter "10. System Management and Infrastructure :: Message Journal/Store"</p> +<div><p>📝 "Agile methods are most valuable when we're dealing with high levels of uncertainty."</p> +<p class="attribution">—"<a class="reference external" href="https://architectelevator.com/transformation/agile_architecture/">Agile and Architecture: Friend, not Foe</a>" by Gregor Hohpe</p> </div></blockquote> <blockquote> -<div><p>📝 "To see the full power that results from using Domain Events , consider the concept of causal consistency. A business domain provides causal consistency if its operations that are causally related —one operation causes another—are seen by every dependent node of a distributed system in the same order [<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">Causal</a>] . This means that causally related operations must occur in a specific order, and thus one thing cannot happen unless another thing happens before it. Perhaps this means that one Aggregate cannot be created or modified until it is clear that a specific operation occurred to another -Aggregate."</p> -<p class="attribution">—"Domain-Driven Design Distilled" by Vaughn Vernon</p> +<div><p>📝 "Complete. +The set of requirements stands alone such that it sufficiently describes the necessary capabilities, characteristics, constraints or quality factors to meet entity needs without needing further information. +In addition, the set does not contain any To Be Defined (TBD), To Be Specified (TBS), or To Be Resolved (TBR) clauses. +Resolution of the TBx designations may be iterative and there is an acceptable timeframe for TBx items, determined by risks and dependencies."</p> +<p class="attribution">—"ISO/IEC/IEEE 29148:2018 Systems and software engineering - Life cycle processes - Requirements engineering"</p> </div></blockquote> -<p>Посмотреть вживую <a class="reference external" href="https://eventsourcing.readthedocs.io/en/v8.3.0/topics/process.html#causal-dependencies">обеспечение Causal Consistency</a> на уровне подписчика можно в EventSourcing Framework. Реализация <a class="reference external" href="https://github.com/johnbywater/eventsourcing/blob/fd73c5dbd97c0ae759c59f7bb0700afb12db7532/eventsourcing/application/process.py#L273">здесь</a>.</p> -<p>Собственно, Causal является промежуточным уровнем строгости согласованности, чтобы избежать строгую линеаризацию сообщений (которая часто избыточна) из соображений сохранения параллелизма и повышения производительности, но при этом, не допускать параллелизма в потоках причинно-зависимых сообщений (где очередность сообщений, действительно, востребована).</p> -<p>Обычно идентификатором потока (<code class="docutils literal notranslate"><span class="pre">streamId</span></code>) выступает идентификатор агрегата. А идентификатором последовательности события в этом потоке (<code class="docutils literal notranslate"><span class="pre">position</span></code>) обычно <a class="reference external" href="https://github.com/johnbywater/eventsourcing/blob/fd73c5dbd97c0ae759c59f7bb0700afb12db7532/eventsourcing/application/process.py#L82">выступает номер версии агрегата</a></p> -<p>Другой пример кода, реализующего Causal Store можно посмотреть в главе "6.4.2 Causal Store" статьи "<a class="reference external" href="https://www.microsoft.com/en-us/research/publication/principles-of-eventual-consistency/">Principles of Eventual Consistency</a>" (<a class="reference external" href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/final-printversion-10-5-14.pdf">pdf</a>) by Sebastian Burckhardt, Microsoft Research.</p> -<p>Реализация Vector Clock на Golang - <a class="reference external" href="https://labix.org/vclock">vclock</a>. -Статья об этой библиотеке на сайте автора: "<a class="reference external" href="https://blog.labix.org/2010/12/21/vector-clock-support-for-go">Vector clock support for Go</a>" by Gustavo Niemeyer.</p> +<p>Но это и не требуется стандартом по SDLC:</p> <blockquote> -<div><p>📝 "Note that just <strong>saving the Domain Event in its causal order doesn't guarantee that it will arrive at other distributed nodes in the same order</strong>. Thus, it is also the responsibility of the consuming Bounded Context to recognize proper <strong>causality</strong>. It might be the Domain Event type itself that can indicate causality, or it may be <strong>metadata</strong> associated with the Domain Event, such as a <strong>sequence</strong> or <strong>causal identifier</strong>. The <strong>sequence</strong> or <strong>causal identifier</strong> would <strong>indicate what caused this Domain Event, and if the cause was not yet seen, the consumer must wait to apply the newly arrived event until its cause arrives</strong>. In some cases it is possible to ignore latent Domain Events that have already been superseded by the actions associated with a later one; in this case causality has a dismissible impact [об этом способе уже говорилось ранее, прим. моё]."</p> -<p class="attribution">—"Domain-Driven Design Distilled" by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events:: Designing, Implementing, and Using Domain Events"</p> +<div><p>📝 "To deal with the <strong>issues of incompletely known requirements</strong> and inaccurate estimates, a number of other types of models have been proposed: <a class="reference internal" href="../../models/incremental.html#emacsway-incremental-development"><span class="std std-ref">incremental</span></a>, <a class="reference internal" href="../../models/spiral.html#emacsway-spiral-development"><span class="std std-ref">spiral</span></a>, <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a>, and <a class="reference internal" href="../../models/evolutionary.html#emacsway-evolutionary-development"><span class="std std-ref">evolutionary (adaptive)</span></a>.</p> +<p>&lt;...&gt;</p> +<p>The "<a class="reference internal" href="../../models/evolutionary.html#emacsway-evolutionary-development"><span class="std std-ref">evolutionary model</span></a>" is intended to deal with <strong>incomplete knowledge of requirements</strong>."</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> </div></blockquote> +<p>Как можно заметить, неполнота требований здесь первична, и именно для её разрешения и применяются такие SDLC-модели, как <a class="reference internal" href="../../models/incremental.html#emacsway-incremental-development"><span class="std std-ref">incremental</span></a>, <a class="reference internal" href="../../models/spiral.html#emacsway-spiral-development"><span class="std std-ref">spiral</span></a>, <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a>, and <a class="reference internal" href="../../models/evolutionary.html#emacsway-evolutionary-development"><span class="std std-ref">evolutionary (adaptive)</span></a>.</p> +<p>Интересно, что, во времена появления термина User Story, полнота требований так же не требовалась старым стандартом:</p> <blockquote> -<div><p>📝 "The first option is to use message sessions, a feature of the Azure Service Bus. If you use <strong>message sessions</strong>, this guarantees that messages within a session are delivered in the same order that they were sent. -The second alternative is to modify the handlers within the application to detect out-of-order messages through the use of sequence numbers or timestamps added to the messages when they are sent. <strong>If the receiving handler detects an out-of-order message, it rejects the message and puts it back onto the queue or topic to be processed later, after it has processed the messages that were sent before the rejected message.</strong>"</p> -<p class="attribution">—"CQRS Journey" by Dominic Betts, Julián Domínguez, Grigori Melnik, Fernando Simonazzi, Mani Subramanian, Chapter "<a class="reference external" href="https://docs.microsoft.com/ru-ru/previous-versions/msp-n-p/jj591565(v=pandp.10)#message-ordering">Journey 6: Versioning Our System :: Message ordering</a>"</p> +<div><p>📝 "The SRS may need to evolve as the development of the software product progresses. It may be impossible to specify some details at the time the project is initiated.</p> +<p>&lt;...&gt;</p> +<p>Requirements should be specified as completely and thoroughly as is known at the time, even if evolutionary revisions can be foreseen as inevitable. The fact that they are incomplete should be noted."</p> +<p class="attribution">—"IEEE Std 830-1998, IEEE Std 830-1993 IEEE Recommended Practice for Software Requirements Specifications"</p> </div></blockquote> +<p>Таким образом, использование термина <a class="reference internal" href="../../models/agile/analysis/requirements/requirements.html#emacsway-agile-requirements"><span class="std std-ref">requirements</span></a>, несмотря на то, что вызывает вопросы относительно семантики, никоим образом не противоречит использованию его в Agile SDLC-моделе, которая, кстати, описана тем же стандартом - ISO/IEC/IEEE 12207:2017, в разделах "5.4.2. Life cycle model for the software system" и "Annex H".</p> +</section> +<section id="id4"> +<h2><a class="toc-backref" href="#id10" role="doc-backlink">Немножко о продуктовом подходе</a></h2> <blockquote> -<div><p>📝 "<strong>Actors must be prepared to accept and reject messages based on their current state, which is reflected by the order in which previous messages were received.</strong> Sometimes a latent message could be accepted even if it is not perfect timing, but the actor's reaction to the latent message may have to carefully take into account its current state beforehand. This may be dealt with more gracefully by using the actors become() capabilities."</p> -<p class="attribution">—"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon, Chapter "5. Messaging Channels :: Point-to-Point Channel"</p> +<div><p>💬 Product-mode: For building, running and <strong>iterating</strong> on the solution or <strong>even pivoting to a different solution</strong> till the underlying problem is <strong>verifiably</strong> solved.</p> +<p>💬 <strong>To migrate to product-mode, it is best to adopt an iterative</strong> and fail cheap approach. Start with a pilot or two, <strong>learn and adapt</strong>. +Although it may feel unsound to those who are used to approving big change programs with detailed roadmaps, it is the essence of a Lean-Agile mindset to <strong>avoid overinvesting before validating actual (not projected) benefits</strong>.</p> +<p>💬 Product-mode: Product owners prove actual benefits either with data <strong>from A/B testing, analytics, user surveys, etc. or with feedback from business</strong>. This ability is dependent on good engineering <strong>capability to develop and release frequently</strong> in small chunks and good analytics capability to determine delta changes in adoption, conversion etc.</p> +<p>There is relatively <strong>less emphasis on assessing projected benefits upfront</strong>, especially amongst the best such teams that execute with short cycle times and can therefore try new ideas without incurring a high cost of failure. +The product owner is empowered to approve development of roadmap items as they see fit. By developing in small, end-to-end <strong>iterations</strong>, product owners are able to detect early any efforts that miss the mark and thereby fail-fast (fail-cheap).</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/products-over-projects.html">Products Over Projects</a>" by Sriram Narayan</p> </div></blockquote> -<p>Возникает вопрос о том, нужно ли заниматься восстановлением очередности сообщений на уровне Domain Logic, или на уровне Application Logic. -В статье "<a class="reference external" href="https://www.infoq.com/articles/no-reliable-messaging/">Nobody Needs Reliable Messaging</a>" by Marc de Graauw приводятся убедительные аргументы о том, что если это важно для бизнеса, то это должно быть на уровне бизнес-логики (Domain Logic). -Однако, нужно учитывать, что термина "Сообщение" в предметной области вообще не существует (есть только "Событие"). -Зато существует термин "время", которое едино для всего в предметной области, в отличии от времени приложения в распределенной системе.</p> -<p>Таким образом, очередность доставки сообщений - это проблема, свойственная не предметной области, а приложению. -Нужно ли решать её на уровне бизнеса? -Ответ зависит от конкретных обстоятельств.</p> -<p>Еще один из способов решения проблемы согласованности - это дублирование данных, сохранение, обработка и передача зависимых данных атомарно. -Этот прием часто используется для обеспечения границ согласованности Aggregate в DDD, для обеспечения автономности микросервисов и Bounded Contexts.</p> +</section> +<section id="refactoring"> +<h2><a class="toc-backref" href="#id11" role="doc-backlink">Причем здесь refactoring?</a></h2> <blockquote> -<div><p>An implementation consistent with this model would guarantee the invariant relating PO [Purchase Order] and its items, while changes to the price of a part would not have to immediately affect the items that reference it. -Broader consistency rules could be addressed in other ways. -For example, the system could present a queue of items with outdated prices to the users each day, so they could update or exempt each one. -But this is not an invariant that must be enforced at all times. -By making the dependency of line items on parts looser, we avoid contention and reflect the realities of the business better. -At the same time, tightening the relationship of the PO and its line items guarantees that an important business rule will be followed.</p> -<p class="attribution">—"Domain-Driven Design" by Eric Evans</p> -</div></blockquote> -<p>Родственные EIP patterns:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/CorrelationIdentifier.html">Correlation Identifier</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/MessageSequence.html">Message Sequence</a>"</p></li> -</ul> -<p>Применяется в том числе и в Event Sourcing.</p> -<p>В метаданных eventstore есть переменные <code class="docutils literal notranslate"><span class="pre">$causationid</span></code> and <code class="docutils literal notranslate"><span class="pre">$correlationid</span></code>.</p> +<div><p>💬 I thought borrowing money was a good idea, I thought that rushing software out the door to <strong>get some experience</strong> with it was a good idea, but that of course, you would eventually go back and <strong>as you learned things about that software</strong> you would repay that loan by refactoring the program <strong>to reflect your experience as you acquired it</strong>.</p> +<p class="attribution">—"<a class="reference external" href="http://wiki.c2.com/?WardExplainsDebtMetaphor">Ward Explains Debt Metaphor</a>" by Ward Cunningham</p> +</div></blockquote> <blockquote> -<div><p>📝 "The are both really simple patterns I have never quite understood why they end up so misunderstood. -Let's say every message has 3 ids. 1 is its id. Another is correlation the last it causation. -The rules are quite simple. If you are responding to a message, you copy its correlation id as your correlation id, its message id is your causation id. -This allows you to see an entire conversation (correlation id) or to see what causes what (causation id). -Cheers, -Greg Young"</p> -<p><a class="reference external" href="https://discuss.eventstore.com/t/causation-or-correlation-id/828/4">https://discuss.eventstore.com/t/causation-or-correlation-id/828/4</a></p> +<div><p>💬 McConnell writes, "In ten years the pendulum has swung from 'design everything' to 'design nothing.' But the alternative to BDUF [Big Design Up Front] isn't no design up front, it's a Little Design Up Front (LDUF) or Enough Design Up Front (ENUF)." +This is a strawman argument. +<strong>The alternative to designing before implementing is designing after implementing.</strong> Some design up-front is necessary, but just enough to get the initial implementation. +Further design takes place once the implementation is in place and the real constraints on the design are obvious. +Far from "design nothing," the XP strategy is "design always."</p> +<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck</p> </div></blockquote> -<p>Примеры:</p> +<p>См. также:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://github.com/microsoftarchive/cqrs-journey/blob/6ffd9a8c8e865a9f8209552c52fa793fbd496d1f/scripts/CreateDatabaseObjects.sql#L57-L62">раз</a></p></li> -<li><p><a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd/blob/4e2d66d16f97b3c863fbecd072dad52338516882/src/Modules/Payments/Infrastructure/AggregateStore/SqlStreamAggregateStore.cs#L44-L45">два</a></p></li> +<li><p>"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html#PredictiveVersusAdaptive">The New Methodology :: Predictive versus Adaptive</a>" by Martin Fowler</p></li> </ul> -<p>Шпаргалка по EIP-паттернам:</p> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/download/EIPTutorialReferenceChart.pdf">Enterprise Integration Patterns Tutorial Reference Chart</a>"</p></li> +<li><p>"<a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">Iterative Development</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">Что такое Agile Development</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../models/agile/index.html"><span class="doc">Agile</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../models/agile/analysis/requirements/requirements.html#emacsway-agile-requirements"><span class="std std-ref">Agile Requirements</span></a>"</p></li> </ul> -<p>Но даже если подписчик всего один, и сообщения доставляются последовательно, то и тогда очередность обработки сообщений может быть нарушена. Пример из NATS Streaming Server:</p> -<blockquote> -<div><p>📝 "With the redelivery feature, order can't be guaranteed, since by definition server will resend messages that have not been acknowledged after a period of time. Suppose your consumer receives messages 1, 2 and 3, does not acknowledge 2. Then message 4 is produced, server sends this message to the consumer. The redelivery timer then kicks in and server will resend message 2. The consumer would see messages: 1, 2, 3, 4, 2, 5, etc...</p> -<p>In conclusion, the server does not offer this guarantee although it tries to redeliver messages first thing on startup. That being said, if the durable is stalled (number of outstanding messages &gt;= MaxInflight), then the redelivery will also be stalled, and new messages will be allowed to be sent. When the consumer resumes acking messages, then it may receive redelivered and new messages interleaved (new messages will be in order though)."</p> -<p class="attribution">—nats-streaming-server, <a class="reference external" href="https://github.com/nats-io/nats-streaming-server/issues/187#issuecomment-257024506">issue #187 "Order of delivery"</a>, comment by Ivan Kozlovic</p> -</div></blockquote> -<p>Кстати, проблема очередности доставки сообщений хорошо описана в главе "Projections and Queries :: Building read models from events :: Subscriptions" книги "<a class="reference external" href="https://www.amazon.com/Hands-Domain-Driven-Design-NET-ebook/dp/B07C5WSR9B">Hands-On Domain-Driven Design with .NET Core: Tackling complexity in the heart of software by putting DDD principles into practice</a>" by Alexey Zimarev. И он добавил несколько <a class="reference external" href="https://t.me/emacsway_chat/85">интересных аргументов в чат канала</a>.</p> -</section> +</div> </section> -Mon, 03 Jul 2023 00:00:00 Может ли CQRS-команда возвращать результат?https://dckms.github.io/system-architecture/emacsway/it/ddd/tactical-design/cqrs/cqrs-command-and-result.html -<span id="emacsway-cqrs-command-result"/> +Fri, 20 Oct 2023 00:00:00 Role of Simplicity in Agilehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.html +<span id="emacsway-agile-simplicity"/> <p><em>Автор раздела: Ivan Zakrevsky</em></p> -<p>Статья посвящена довольно дискуссионному вопросу о том, может ли CQRS-команда возвращать результат.</p> <nav class="contents" id="id1"> <p class="topic-title">Содержание</p> <ul class="simple"> -<li><p><a class="reference internal" href="#cqrs" id="id10">Может ли CQRS-команда возвращать результат?</a></p> +<li><p><a class="reference internal" href="#role-of-simplicity-in-agile" id="id5">Role of Simplicity in Agile</a></p> <ul> -<li><p><a class="reference internal" href="#reference-transparency" id="id11">Значение Reference Transparency в распределенной среде</a></p></li> -<li><p><a class="reference internal" href="#cqrs-cqs" id="id12">Чем отличается CQRS от CQS?</a></p></li> -<li><p><a class="reference internal" href="#id2" id="id13">А есть ли противоречие в авторитетных точках зрения?</a></p></li> -<li><p><a class="reference internal" href="#cqs-referential-transparency-query" id="id14">CQS - это больше о referential transparency для Query</a></p></li> -<li><p><a class="reference internal" href="#command" id="id15">Может ли Command возвращать служебную информацию (код ошибки или успешность выполнения)?</a></p></li> -<li><p><a class="reference internal" href="#command-query" id="id16">Кроме Command и Query существуют еще и функции-конструкторы</a></p></li> -<li><p><a class="reference internal" href="#query-abstract-side-effect-concrete-side-effect" id="id17">Query не должен иметь abstract side effect, но может иметь concrete side effect</a></p></li> -<li><p><a class="reference internal" href="#emacsway-cqs-atomic-routine" id="id18">Что делать с атомарными операциями?</a></p> +<li><p><a class="reference internal" href="#id2" id="id6">Единица измерения</a></p></li> +<li><p><a class="reference internal" href="#id3" id="id7">Качественный код всегда прост!</a></p> <ul> -<li><p><a class="reference internal" href="#emacsway-cqs-reference-argument" id="id19">Процедура не возвращает значения, но может изменить ссылочный аргумент</a></p></li> -<li><p><a class="reference internal" href="#emacsway-cqs-buffer" id="id20">Концепция буфера для разделения атомарных операций Command и Query</a></p></li> +<li><p><a class="reference internal" href="#eric-evans" id="id8">Eric Evans</a></p></li> +<li><p><a class="reference internal" href="#edsger-w-dijkstra" id="id9">Edsger W. Dijkstra</a></p></li> +<li><p><a class="reference internal" href="#steve-mcconnell" id="id10">Steve McConnell</a></p></li> +<li><p><a class="reference internal" href="#kent-beck" id="id11">Kent Beck</a></p></li> +<li><p><a class="reference internal" href="#martin-fowler" id="id12">Martin Fowler</a></p></li> +<li><p><a class="reference internal" href="#robert-c-martin" id="id13">Robert C. Martin</a></p></li> +<li><p><a class="reference internal" href="#bjarne-stroustrup" id="id14">Bjarne Stroustrup</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id15">Другие</a></p></li> </ul> </li> -<li><p><a class="reference internal" href="#emacsway-cqrs-command-resource-id" id="id21">Что делать, если CQRS-команда должна вернуть идентификатор созданного ресурса?</a></p></li> -<li><p><a class="reference internal" href="#emacsway-cqrs-one-way-data-flow" id="id22">Однонаправленный поток изменений</a></p></li> -<li><p><a class="reference internal" href="#jimmy-bogard" id="id23">Точка зрения Jimmy Bogard</a></p></li> -<li><p><a class="reference internal" href="#id8" id="id24">Вывод</a></p></li> </ul> </li> </ul> </nav> -<section id="reference-transparency"> -<span id="emacsway-reference-transparency-in-distributed-systems"/><h2><a class="toc-backref" href="#id11" role="doc-backlink">Значение Reference Transparency в распределенной среде</a></h2> -<p>В последнее время наметилась определенная поляризация парадигм программирования в индустрии.</p> -<p>Стремительный рост объема обрабатываемых данных, потребность в масштабировании, распределенном хранении и параллельной обработке данных, пробудили интерес к функциональному программированию.</p> -<blockquote> -<div><p>📝 "Все состояния гонки (race condition), взаимоблокировки (deadlocks) и проблемы параллельного обновления обусловлены изменяемостью переменных. Если в программе нет изменяемых переменных, она никогда не окажется в состоянии гонки и никогда не столкнется с проблемами одновременного изменения. В отсутствие изменяемых блокировок программа не может попасть в состояние взаимоблокировки.</p> -<p>All race conditions, deadlock conditions, and concurrent update problems are due to mutable variables. You cannot have a race condition or a concurrent update problem if no variable is ever updated. You cannot have deadlocks without mutable locks."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin, перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>Однако, индустрия не готова отказаться от императивных подвидов парадигм, таких как OOP.</p> -<p>Можно ли их сочетать, используя достоинства обоих видов парадигм, в зависимости от контекста использования? Как эффективно использовать мультипарадигменные языки, такие как F#, Scala, Elixir?</p> -<p>B.Meyer утверждает, что OOP и FP не противопоставляются, а дополняют друг друга, и ключем к достижению этого является принцип <a class="reference external" href="https://martinfowler.com/bliki/CommandQuerySeparation.html">CQS</a>.</p> -<blockquote> -<div><p>Интервью с Бертраном Мейером</p> -<p>- В последнее время наметилась тенденция в популяризации функциональных языков и функциональной парадигмы программирования. Что вы скажите, является ли объектная технология конкурентом функциональному программированию?</p> -<p>- Нет, эти две парадигмы не являются конкурентами, они успешно могут дополнять друг друга. Тем не менее, тенденция к функциональному программированию является важной и интересной.</p> -<p>На мой взгляд, когда речь идет о высокоуровневой структуре приложения (особенно больших программ), то в мире нет ничего лучше объектного подхода. Я просто не вижу, как можно писать действительно большую программу исключительно на функциональном языке.</p> -<p>С другой стороны, если общая структура приложения построена на основе объектов, то очень даже полезно, если некоторые ее части будут написаны на функциональном языке, для обеспечения простоты и возможности доказательства корректности, о которых я говорил ранее.</p> -<p>Несколько лет назад я опубликовал статью на эту тему, где сравнивал ОО и ФП подходы. В ней я постарался показать, что ОО метод включает функциональное программирование, а не наоборот.</p> -<p>- Да, я кажется читал эту статью, которая затем вошла в качестве одной из глав в книгу "Beautiful Architecture".</p> -<p>- Вы знаете об этом? Я очень впечатлен.</p> -<p>- (Смеюсь...) Да, и насколько я помню, это был ваш ответ на статью Саймона Пейтона Джонса, в которой автор старался показать, что ФП подход является более предпочтительным.</p> -<p>- Да, совершенно верно.</p> -<p>ПРИМЕЧАНИЕ: Речь идет о статье Бертрана "<a class="reference external" href="http://se.ethz.ch/~meyer/publications/functional/meyer_functional_oo.pdf">Software Architecture: Functional vs. Object-Oriented Design in Beautiful Architecture</a>", опубликованной в книге "<a class="reference external" href="https://www.amazon.com/Beautiful-Architecture-Leading-Thinkers-Software/dp/059651798X">Идеальная архитектура. Ведущие специалисты о красоте программных архитектур.</a>". -Эта статья Мейера была ответом на статью Саймона "Composing contracts: an adventure in financial engineering."</p> -<p>- Давайте все же немного вернемся к вопросу OOP vs FP. Какие именно преимущества у функционального подхода на "низком уровне"?</p> -<p>- В Eiffel существует очень важный принцип, под названием <strong>Command-Query Separation Principle, который можно рассматривать, в некотором роде, как сближение ОО и ФП миров</strong>. Я не считаю, что наличие состояния – это однозначно плохо. Но <strong>очень важно, чтобы мы могли ясно различать операции, которые это состояние изменяют (т.е. командами), и операции, которые лишь возвращают информацию о состоянии, его не изменяя (т.е. запросами)</strong>. В других языках эта разница отсутствует. Так, например, в С/С++ часто пишут функции, которые возвращают результат и изменяют состояние. <strong>Следование этому принципу позволяет безопасно использовать выражения с запросами зная, что они не изменяют состояние.</strong> В некоторых случаях можно пойти еще дальше и работать в чисто функциональном мире с полным отсутствием побочных эффектов."</p> -<p class="attribution">—Bertrand Meyer в интервью Сергея Теплякова "<a class="reference external" href="https://sergeyteplyakov.blogspot.com/2014/05/interview-with-bertrand-meyer.html">Интервью с Бертраном Мейером</a>"</p> -</div></blockquote> -<blockquote> -<div><p>📝 "For both theoretical and practical reasons detailed elsewhere [10], the command-query separation principle is a methodological rule, not a language feature, but all serious software developed in Eiffel observes it scrupulously, to great referential transparency advantage. Although other schools of object-oriented programming regrettable do not apply it (continuing instead the C style of calling functions rather than procedures to achieve changes), but in my view it is a key element of the object-oriented approach. It seems like a viable way to obtain the referential transparency goal of functional programming — since expressions, which only involve queries, will not change the state, and hence can be understood as in traditional mathematics or a functional language — while acknowledging, through the notion of command, the fundamental role of the concept of state in modeling systems and computations."</p> -<p class="attribution">—"<a class="reference external" href="http://se.ethz.ch/~meyer/publications/functional/meyer_functional_oo.pdf">Software architecture: object-oriented vs functional</a>" by Bertrand Meyer</p> -</div></blockquote> -<p>Две известные статьи от Rober Martin на тему OOP vs FP:</p> -<ul class="simple"> -<li><p><a class="reference external" href="http://blog.cleancoder.com/uncle-bob/2014/11/24/FPvsOO.html">http://blog.cleancoder.com/uncle-bob/2014/11/24/FPvsOO.html</a></p></li> -<li><p><a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2018/04/13/FPvsOO.html">https://blog.cleancoder.com/uncle-bob/2018/04/13/FPvsOO.html</a></p></li> -</ul> -<p>Ну а я, как поклонник Emacs и Lisp, не могу обойти вниманием его статью про Clojure:</p> -<ul class="simple"> -<li><p><a class="reference external" href="http://blog.cleancoder.com/uncle-bob/2019/08/22/WhyClojure.html">http://blog.cleancoder.com/uncle-bob/2019/08/22/WhyClojure.html</a></p></li> -</ul> -<p>Хорошая статья "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/what-is-functional-programming/">What is functional programming?</a>" by Vladimir Khorikov.</p> -</section> -<section id="cqrs-cqs"> -<span id="emacsway-cqrs-vs-cqs"/><h2><a class="toc-backref" href="#id12" role="doc-backlink">Чем отличается CQRS от CQS?</a></h2> -<p><a class="reference external" href="https://martinfowler.com/bliki/CQRS.html">CQRS</a> лишь немного отличается от <a class="reference external" href="https://martinfowler.com/bliki/CommandQuerySeparation.html">CQS</a> по исполнению. -Ввел этот термин Greg Young, поэтому, к нему и обратимся:</p> -<blockquote> -<div><p>📝 "<strong>Starting with CQRS, CQRS is simply the creation of two objects where there [CQS] was previously only one.</strong> The separation occurs based upon whether the methods are a command or a query (the same definition that is used by Meyer in Command and Query Separation, a command is any method that mutates state and a query is any method that returns a value)... That is it. That is the entirety of the CQRS pattern. There is nothing more to it than that…" -— "<a class="reference external" href="http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/">CQRS, Task Based UIs, Event Sourcing agh!</a>" by Greg Young</p> -</div></blockquote> -<blockquote> -<div><p>📝 "Command and Query Responsibility Segregation was originally considered just to be an extension of this [CQS] concept."</p> -<p>📝 "Command and Query Responsibility Segregation (CQRS) originated with Bertrand Meyer's Command and Query Separation Principle."</p> -<p>📝 "Command and Query Responsibility Segregation uses the same definition of Commands and Queries that Meyer used and maintains the viewpoint that they should be pure. <strong>The fundamental difference is that in CQRS objects are split into two objects, one containing the Commands one containing the Queries.</strong>"</p> -<p class="attribution">—"<a class="reference external" href="https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf">CQRS Documents by Greg Young</a>"</p> -</div></blockquote> -<p>Хорошая статья про CQRS: "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/types-of-cqrs/">Types of CQRS</a>" by Vladimir Khorikov. -Обратите внимание на комментарии внизу статьи - ее прорецензировал собственноручно Greg Young, автор термина CQRS.</p> -</section> -<section id="id2"> -<h2><a class="toc-backref" href="#id13" role="doc-backlink">А есть ли противоречие в авторитетных точках зрения?</a></h2> -<p>В одном из самых авторитетных reference application eShopOnContainers от Microsoft, одна из CQRS-команд возвращает результат:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderDraftCommandHandler.cs#L40">раз</a></p></li> -<li><p><a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs#L151">два</a></p></li> -</ul> -<p>Однако, в известной "Красной книге", Vaughn Vernon пишет:</p> -<blockquote> -<div><p>📝 "This principle, devised by Bertrand Meyer, asserts the following:</p> -<p>"Every method should be either a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer.More formally, methods should return a value only if they are referentially transparent and hence possess no side effects." [Wikipedia, CQS]</p> -<p>At an object level this means:</p> -<ol class="arabic simple"> -<li><p>If a method modifies the state of the object, it is a command, and its method must not return a value. In Java and C# the method must be declared void.</p></li> -<li><p><strong>If a method returns some value, it is a query, and it must not directly or indirectly cause the modification of the state of the object.</strong> In Java and C# the method must be declared with the type of the value it returns."</p></li> -</ol> -<p class="attribution">—"Implementing Domain-Driven Design" by Vaughn Vernon, Chapter "4. Architecture :: Command-Query Responsibility Segregation, or CQRS"</p> -</div></blockquote> -<p>Другое, не менее авторитетное архитектурное руководство от Microsoft, утверждает:</p> -<blockquote> -<div><p>📝 "A query returns data and does not alter the state of the object; <strong>a command changes the state of an object but does not return any data.</strong>"</p> -<p class="attribution">—"<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/jj591573(v=pandp.10)#what-is-cqrs">CQRS Journey :: Reference 2: Introducing the Command Query Responsibility Segregation Pattern :: What is CQRS?</a>"</p> -</div></blockquote> -<p>Противоречие? Архитектура - это, как известно, наука об ограничениях, о том, как не надо делать. -Почему же тогда одно из самых авторитетных reference application, консультантами которого являются такие светила, как Cesar De la Torre, Jimmy Nilsson, Udi Dahan, Jimmy Bogard, и другие, это ограничение нарушает? -Что это - компромисс, вызванный практической целесообразностью, или демонстрация принципиального архитектурно чистого решения?</p> -<p>Ответ на этот вопрос мы попытаемся найти в этой статье.</p> -</section> -<section id="cqs-referential-transparency-query"> -<span id="emacsway-cqs-query-referential-transparency"/><h2><a class="toc-backref" href="#id14" role="doc-backlink">CQS - это больше о referential transparency для Query</a></h2> -<p>Итак, начнем по порядку, с принципа CQS:</p> +<p>Не очень глубоко осведомленные в архитектуре люди почему-то иногда думают, что архитектурное решение всегда несет перфекционизм и overengineering. +Вероятно, они просто не знакомы с "<a class="reference internal" href="software-design.html#emacsway-primary-technical-imperative"><span class="std std-ref">The Primary Technical Imperative</span></a>".</p> +<p>На самом деле, overengineering означает решение не соответствующее контексту, т.е. когда <a class="reference internal" href="patterns.html#emacsway-agile-patterns"><span class="std std-ref">уровень привнесенной сложности превышает уровень управляемой сложности</span></a>. +С точки зрения "<a class="reference internal" href="software-design.html#emacsway-primary-technical-imperative"><span class="std std-ref">The Primary Technical Imperative</span></a>" это значит, что он ухудшает внутреннее качество программы, а не повышает его.</p> +<p>Более того, хороший архитектор стремится исключить само возникновение сложной проблемы, нежели пытаться героически ее решить.</p> <blockquote> -<div><p>📝 "Command-Query Separation <strong>principle - Functions should not produce abstract side effects</strong>."</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +<div><p>📝 "Усложнять - просто, упрощать - сложно".</p> +<p class="attribution">—"Закон Мейера"</p> </div></blockquote> -<p id="emacsway-cqs-concrete-side-effect">Обратите внимание на термин abstract. B.Meyer различает abstract и concrete side effects.</p> +<p>Вершиной простоты авиационной инженерной мысли был, пожалуй, самолет Ил-62.</p> +<p>См. видео "<a class="reference external" href="https://youtu.be/VyrN9AJm7sk">Ил-62 - идеальный вариант</a>" / @SkyShips.</p> +<p>Его конструкция получилась настолько удачной и простой, что огромный межконтинентальный лайнер управлялся исключительно мускульной силой пилотов посредством безбустерной (т.е. без усилителей) системы управления, что стало возможным благодаря удачно выбранной балансировке. +Для этого, правда, пришлось привнести в конструкцию заднюю штангу - довольно простое решение, которое на корню исключило возникновение довольно сложной проблемы. +Идеальный пример воплощения <a class="reference external" href="https://people.apache.org/~fhanik/kiss.html">KISS-principle</a>. +Более того, этот лайнер не имел даже предкрылков, благодаря оригинальному аэродинамическому решению в виде "зуба" на передней кромки крыла.</p> +<p>Это яркий пример того, как, вместо того, чтобы создавать сложные решения для сложных проблем, можно просто не допускать самого возникновения этих сложных проблем, благодаря простым и удачным проектным решениям.</p> <blockquote> -<div><p>📝 "Definition: concrete side effect: A function produces a concrete side effect if its body contains any of the following: -1. An assignment, assignment attempt or creation instruction whose target is an attribute. -2. A procedure call."</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> -</div></blockquote> -<span class="target" id="emacsway-cqs-abstract-side-effect"/><blockquote> -<div><p>📝 "Since not every class definition is accompanied by a full-fledged specification of the underlying abstract data type, we need a more directly usable definition of "abstract side effect". This is not difficult. In practice, the abstract data type is defined by the interface offered by a class to its clients (expressed for example as the short form of the class). A side effect will affect the abstract object if it changes the result of any query accessible to these clients. Hence the definition:</p> -<p>Definition: abstract side effect: An abstract side effect is a concrete side effect that can change the value of a non-secret query.</p> -<p>The definition refers to "non-secret" rather than exported queries. The reason is that in-between generally exported and fully secret status, we must permit a query to be selectively exported to a set of clients. As soon as a query is non-secret — exported to any client other than NONE — we consider that changing its result is an abstract side effect, since the change will be visible to at least some clients."</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +<div><p>📝 "Вобрав в себя лучшие технологические наработки, лайнер сохранил идеологию простоты конструкции и систем, что сделало его оптимальным для магистральных перевозок в СССР и одним из лучших самолетов своего времени."</p> +<p class="attribution">—"<a class="reference external" href="https://youtu.be/VyrN9AJm7sk">Ил-62 - идеальный вариант</a>" / @SkyShips</p> </div></blockquote> <blockquote> -<div><p>📝 "The Command-Query Separation principle brings <strong>referential transparency</strong> back."</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> -</div></blockquote> -<span class="target" id="emacsway-reference-transparency"/><blockquote> -<div><p>📝 "Definition: referential transparency: An expression e is referentially transparent if it is possible to exchange any subexpression with its value without changing the value of e."</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +<div><p>📝 Дальнейший этап в творческой деятельности Ильюшина – пассажирский трансконтинентальный лайнер Ил-62, вышедший на воздушные линии в 1967 году и его модификация Ил-62М, ставший флагманом Аэрофлота. +Примечательно, что даже такой очень большой самолет сохранил простоту и легкость управления, присущую всем "илам". +В этом – одно из проявлений творческого стиля С.В.Ильюшина, стиля, которому свойственно стремление к оптимальному проектированию, упорство в достижении максимальной надежности и безопасности самолета в сочетании с высокой экономичностью или боевой эффективностью.</p> +<p>Характерной чертой творческой деятельности Ильюшина являлась простота проектных решений. +В своих воспоминаниях генеральный конструктор, академик А.С.Яковлев особо отмечает эту черту, называя Ильюшина "мастером простых решений". +Конечно, эта "простота" требовала огромного творческого напряжения и совершенно четкого и ясного представления эксплуатационной жизни проектируемого самолета.</p> +<p>В каждом самолете, созданном в конструкторском бюро под руководством С.В.Ильюшина, воплощены творческие особенности Генерального конструктора. +Умение технически просто решать сложные, а порой противоречивые проблемы – это талант, это стиль С.В.Ильюшина, конструктора и ученого, инженера и творца авиационной техники, что позволяло создавать такие машины, которые сыграли значительную роль в развитии Военно-Воздушных Сил СССР и обеспечили выполнение большой доли работы гражданского воздушного транспорта. +Они заняли достойное место в истории отечественной авиации.</p> +<p>Успех С.В.Ильюшиным достигался в результате решения технических задач на основе последних достижений науки, путем смелого внедрения нового и благодаря его исключительной дальновидности.</p> +<p>От легкого планера с полетным весом 100 кг до межконтинентального лайнера с полетным весом 160 т прошло почти 40 лет. +Под руководством С.В.Ильюшина спроектировано, построено и испытано в полете десятки машин, многие из которых оказались непревзойденными по летным характеристикам, простоте конструкции, технологии и надежности.</p> +<p class="attribution">—"<a class="reference external" href="https://www.ilyushin.org/about/history/biography/">Биография Ильюшина</a>" / ПАО "Ил" ("Ильюшин" - группа компаний ОАК)</p> </div></blockquote> -<p>Подведу короткое резюме всему ранее сказанному: CQS не запрещает изменять состояние, если оно не нарушает ссылочную прозрачность. Соблюдение этого условия открывает нам возможность пользоваться всеми преимуществами функционального программирования. Это и есть цель CQS.</p> -</section> -<section id="command"> -<span id="emacsway-cqs-command-status-code"/><h2><a class="toc-backref" href="#id15" role="doc-backlink">Может ли Command возвращать служебную информацию (код ошибки или успешность выполнения)?</a></h2> -<p>Не Команде запрещено возвращать информацию об объекте, а Запросу на получение информации об объекте запрещено нарушать ссылочную прозрачность. -На это указывает и сам B. Meyer (учтите, что <a class="reference external" href="https://fsharpforfunandprofit.com/rop/">Railway Oriented Programming</a> и <a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/results">Result type</a> в то время еще не было):</p> +<p>Давайте послушем другого известного "мастера простых решений", оружейного конструктора, создавшего наиболее надежный и простой автомат в истории:</p> <blockquote> -<div><p>📝 "It is important here two deal with two common objections to the side-effect-free style.</p> -<p>The first has to do with error handling. Sometimes a function with side effects is really a procedure, which in addition to doing its job returns a status code indicating how things went. But there are better ways to do this; roughly speaking, the proper O-O technique is to <strong>enable the client, after an operation on an object, to perform a query on the status, represented for example by an attribute of the object</strong>, as in</p> -<p>target.some_operation(...)</p> -<p>how_did_it_go := target.status</p> -<p>Note that the technique of returning a status as function result is lame anyway. It transforms a procedure into a function by adding the status as a result; <strong>but it does not work if the routine was already a function, which already has a result of its own</strong>. It is also problematic if you need more than one status indicator. In such cases the C approach is either to return a "structure" (the equivalent of an object) with several components, which is getting close to the above scheme, or to use global variables — which raises a whole set of new problems, especially in a large system where many modules can trigger errors."</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +<div><p>📝 "хочу сказать, что сделать простое иногда во много раз сложнее, чем сложное."</p> +<p class="attribution">—М.Т. Калашников в интервью журналисту газеты "Metro Москва", 2009 год.</p> </div></blockquote> -<p>Таким образом, строгого запрета на возврат командой чего-либо (например, информации об ошибке выполнения) не существует. -Существует только пояснение почему и в пользу чего нужно стремиться этого избегать, где основной причиной для избегания является как раз именно то, что <strong>команда может возвращать значение, отличное от информации об ошибке</strong>.</p> -<p>Таким образом, мы выяснили, что команда может быть функцией, возвращающей служебную информацию об успешности выполнения, если иной способ невозможен.</p> -<p>Вернемся к основам:</p> +<p>И послушаем выдающегося русского художника Илью Ефимовича Репина:</p> <blockquote> -<div><p>📝 "Commands and queries.</p> -<p>A few reminders on terminology will be useful. The features that characterize a class are divided into commands and queries. <strong>A command serves to modify objects, a query to return information about objects. A command is implemented as a procedure.</strong> A query may be implemented either as an attribute, that is to say by reserving a field in each run-time instance of the class to hold the corresponding value, or as a function, that is to say through an algorithm that computes the value when needed. Procedures (which also have an associated algorithm) and functions are together called routines.</p> -<p><strong>The definition of queries does not specify whether in the course of producing its result a query may change objects.</strong> For commands, the answer is obviously yes, since it is the role of commands (procedures) to change things. Among queries, the question only makes sense for functions, since accessing an attribute cannot change anything. A change performed by a function is known as a side effect to indicate that it is ancillary to the function's official purpose of answering a query. Should we permit side effects?"</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +<div><p>📝 "Сначала художник рисует плохо и просто. Потом сложно и плохо. Потом сложно и хорошо. И только потом - просто и хорошо."</p> +<p class="attribution">—И.Е. Репин</p> </div></blockquote> -<p>Отсюда следует ряд выводов. Основной вопрос CQS лежит в плоскости Queries, и сводится с ссылочной прозрачности.</p> -<p>Хотя B.Meyer и использует термин procedure, которая, по определению ничего не возвращает ("Procedure - A routine which does not return a result. (The other form of routine is the function.)" - glossary книги "Object-Oriented Software Construction" 2nd edition by Bertrand Meyer), он ясно выразил разделение Команд и Запросов <strong>по назначению</strong>: "A command serves to modify objects, a query to return information about objects."</p> -<p>Это определение не отвечает на вопрос, изменится ли суть команды, если она будет возвращать служебную информацию о процессе выполнения, которая не является информацией об объекте, и не нарушает ссылочную прозрачность (которая по определению не применима к командам). -Этот момент очень важен, и в будущем мы еще к нему вернемся. -Но, зато, он ясно дал понять, что команда может возвращать значение, и именно поэтому, желательно избегать возврата ею информации об ошибке. -В наши дни, напомню, такая проблема больше не актуальна. -Тем более, она не актуальна при переносе этого вопроса на способы сетевого взаимодействия.</p> -</section> -<section id="command-query"> -<span id="emacsway-cqs-factory-result"/><h2><a class="toc-backref" href="#id16" role="doc-backlink">Кроме Command и Query существуют еще и функции-конструкторы</a></h2> -<p>А теперь самое важное. -При обсуждении CQRS этот момент часто незаслуженно опускается. -Кроме процедур-команд и функций-запросов, Bertrand Meyer вводит еще и <strong>функции-конструкторы</strong>! -И вот тут кроется интересное. -Накладывается ли на функцию-конструктор ограничение на side effect - зависит от контекста её применения:</p> <blockquote> -<div><p>📝 "Functions that create objects.</p> -<p>A technical point needs to be clarified before we examine further consequences of the Command-Query Separation principle: <strong>should we treat object creation as a side effect</strong>?</p> -<p>The answer is yes, as we have seen, if the target of the creation is an attribute a: in this case, the instruction !! a changes the value of an object's field. The answer is no if the target is a local entity of the routine. But what if the target is the result of the function itself, as in !! Result or the more general form !! Result.make (...)?</p> -<p>Such a creation instruction need not be considered a side effect. It does not change any existing object and so does not endanger referential transparency (at least if we assume that there is enough memory to allocate all the objects we need).</p> -<p>From a mathematical perspective we may pretend that all of the objects of interest, for all times past, present and future, are already inscribed in the Great Book of Objects; <strong>a creation instruction is just a way to obtain one of them, but it does not by itself change anything in the environment</strong>. It is common, and legitimate, for a function to create, initialize and return such an object.</p> -<p><strong>These observations assume that in the second form the creation procedure make does not produce side effects on any object other than the one being created.</strong>"</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +<div><p>💬 Simplicity is the ultimate sophistication.</p> +<p class="attribution">—Leonardo da Vinci</p> </div></blockquote> -<p>Это замечание B.Meyer является очень важным, так как наиболее частый вопрос CQRS - это возврат идентификатора созданного ресурса и исполнение требований RFC-7231 для HTTP-method POST REST API:</p> +<section id="id2"> +<h2><a class="toc-backref" href="#id6" role="doc-backlink">Единица измерения</a></h2> +<p>Посмотрим, к примеру, мотивацию Mediator pattern:</p> <blockquote> -<div><p>📝 "the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created (Section 7.1.2) and a representation that describes the status of the request while referring to the new resource(s).</p> -<p class="attribution">—"<a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-4.3.3">Section 4.3.3. POST of RFC-7231</a>"</p> +<div><p>📝 "Mediator promotes loose <strong>coupling</strong> by keeping objects from referring to each other explicitly, +and it lets you vary their interaction independently."</p> +<p class="attribution">—"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides</p> </div></blockquote> -</section> -<section id="query-abstract-side-effect-concrete-side-effect"> -<span id="emacsway-cqs-query-side-effect"/><h2><a class="toc-backref" href="#id17" role="doc-backlink">Query не должен иметь abstract side effect, но может иметь concrete side effect</a></h2> -<p>Говоря о "<a class="reference internal" href="#emacsway-cqs-query-referential-transparency"><span class="std std-ref">side effect</span></a>", B.Meyer накладывает ограничение на "<a class="reference internal" href="#emacsway-cqs-abstract-side-effect"><span class="std std-ref">abstract side effect</span></a>", и поясняет на примере. -Сразу скажу, без прочтения главы 11 вряд ли можно понять о чем здесь идет речь. -Но обойти вниманием этот пример тоже нельзя.</p> +<p>Конечно, тут важно найти <a class="reference internal" href="software-design.html#emacsway-kent-beck-constantine-s-law"><span class="std std-ref">баланс между стоимостью Coupling и стоимостью Decoupling</span></a>. +Но ключевой целью принципа "<a class="reference external" href="http://wiki.c2.com/?CouplingAndCohesion">Low Coupling &amp; High Cohesion</a>" является управление сложностью, т.е. упрощение, а не усложнение! +Именно это позволяет <a class="reference internal" href="../../../../../soft-skills/icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">рассматривать фрагмент кода изолированно в пределах возможностей краткосрочной памяти человека</span></a>.</p> +<p>Поэтому размер программного элемента исчисляется количеством его обязанностей, а не количеством символов. +Если кто-то считает иначе, и думает, что меньше сложности означает "меньше кода", тогда попробуйте понять, что делает этот, весьма лаконичный, код:</p> <blockquote> -<div><p>📝 "Unfortunately, this would be unacceptably restrictive, explaining why the Command-Query Separation principle only prohibits abstract side effects, a notion that will now be defined. The problem is that some concrete side effects are not only harmless but necessary. They are of two kinds.</p> -<p>&lt;...&gt;</p> -<p>Side effects of the second acceptable category may change the state of the object, but only affecting properties that are not visible to clients. To understand the concepts in depth, it will be useful to make sure that you are familiar with the discussion of "abstraction function" and "implementation invariants" in the presentation of Design by Contract. (In particular, take a look at the accompanying figures to refresh your memory.)</p> -<p>We saw then that an object of our software (a concrete object) is the representation of an abstract object, and that two concrete objects may represent the same abstract object.</p> -<p>For example two different stack representations, each made of an array and a top marker count, represent the same stack if they have the same value for count and the same array elements up to index count. They may differ in other properties, such as the array sizes and the values stored at indices above count. In mathematical terms, every concrete object belongs to the domain of the abstraction function a, and we can have c1 ≠ c2 even with a(c1) = a(c2).</p> -<p>What this means for us is that a function that modifies a concrete object is harmless if the result of this modification still represents the same abstract object — yields the same a value. For example assume in a function on stacks contains the operation</p> -<p>representation.put (some_value, count + 1)</p> -<p>(with the guarantee that the array's capacity is at least count + 1). <strong>This side effect changes a value above the stack-significant section of the array; it can do no ill.</strong></p> -<p>More generally, a concrete side effect which changes the concrete state of an object c is an abstract side effect if it also changes its abstract state, that is to say the value of a (c) (a more directly usable definition of abstract side effects will appear shortly). If a side effect is only concrete — does not affect the abstract state — it is harmless.</p> -<p>In the object-as-machine metaphor, functions producing concrete-only side effects correspond to query buttons that may produce an internal state change having absolutely no effect on the answers given by any query button. For example the machine might save energy by automatically switching off some internal circuits if nobody presses a button for some time, and turning them on again whenever someone presses any button, queries included. Such an internal state change is unnoticeable from the outside and hence legitimate."</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +<div><div class="highlight-bash notranslate" id="emacsway-rm-rf"><div class="highlight"><pre><span/> <span class="nb">echo</span> <span class="s2">"test... test... test..."</span> <span class="p">|</span> perl -e <span class="s1">'$??s:;s:s;;$?::s;;=]=&gt;%-{&lt;-|}&lt;&amp;|{;;y; -/:-@[-{-};`-{/" -;;s;;$_;see'</span> +</pre></div> +</div> +<p>P.S.: Не вздумайте запустить! Он выполняет <code class="docutils literal notranslate"><span class="pre">rm</span> <span class="pre">-rf</span> <span class="pre">/*</span></code>.</p> +<p class="attribution">—"<a class="reference external" href="https://ru.stackoverflow.com/questions/1144804/%D0%A7%D1%82%D0%BE-%D0%B4%D0%B5%D0%BB%D0%B0%D0%B5%D1%82-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9-%D0%BE%D0%B4%D0%BD%D0%BE%D1%81%D1%82%D1%80%D0%BE%D1%87%D0%BD%D0%B8%D0%BA-%D0%BD%D0%B0-perl">Источник 1</a>", "<a class="reference external" href="https://lurkmore.to/Rm_-rf">Источник 2</a>"</p> </div></blockquote> -<p>Что это означает в контексте REST-API, мы увидим ниже.</p> -<p>И последнее на тему CQS. -Далее мы будем рассматривать уже CQRS. -Как видим, тема CQS намного более обширна и тонка, чем может показаться на первый взгляд. -И за один день её точно не освоить.</p> +<p>Как красиво сказал Vladik Khononov: "абзац - это единица измерения мыслей, а не количества слов". +Лаконичность кода определяется уровнем его сложности на горизонте его рассмотрения (т.е. на рассматриваемом уровне абстракции), а не количеством символов.</p> </section> -<section id="emacsway-cqs-atomic-routine"> -<span id="id3"/><h2><a class="toc-backref" href="#id18" role="doc-backlink">Что делать с атомарными операциями?</a></h2> -<p>Для погружения в CQRS нужно обратить внимание на еще два существенных момента.</p> -<section id="emacsway-cqs-reference-argument"> -<span id="id4"/><h3><a class="toc-backref" href="#id19" role="doc-backlink">Процедура не возвращает значения, но может изменить ссылочный аргумент</a></h3> -<p>Момент первый - routine может возвращать информацию наружу не только в виде возвращаемого значения, но и путем изменения объекта, переданного аргументом по ссылке.</p> +<section id="id3"> +<h2><a class="toc-backref" href="#id7" role="doc-backlink">Качественный код всегда прост!</a></h2> +<section id="eric-evans"> +<h3><a class="toc-backref" href="#id8" role="doc-backlink">Eric Evans</a></h3> <blockquote> -<div><p>📝 "Function clone creates a new object as a carbon copy of an existing one. Sometimes the target object already exists; all we want to do is to overwrite its fields. Procedure copy achieves this. It is called through the instruction x.copy (y)"</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "8.6 OPERATIONS ON REFERENCES :: Object copying"</p> +<div><p>📝 "Software design is a constant battle with complexity."</p> +<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p> </div></blockquote> -<p>Именно на этом основан <a class="reference external" href="https://martinfowler.com/eaaDev/Notification.html">Notification Pattern</a>, который широко применяется в языках, не поддерживающих механизм исключений (Golang, например).</p> -<p>Как можно организовать ссылочную связь через сетевое взаимодействие? -Через идентификатор адресации в виде callback url.</p> </section> -<section id="emacsway-cqs-buffer"> -<span id="id5"/><h3><a class="toc-backref" href="#id20" role="doc-backlink">Концепция буфера для разделения атомарных операций Command и Query</a></h3> -<p>И второй момент - это известный кейс с примером, широко известным как метод .pop(), который одновременно и удаляет, и возвращает элемент списка.</p> -<p>B.Meyer решает эту проблему с помощью концепции буффера:</p> +<section id="edsger-w-dijkstra"> +<h3><a class="toc-backref" href="#id9" role="doc-backlink">Edsger W. Dijkstra</a></h3> <blockquote> -<div><p>📝 "buffer — the concurrent equivalent of a first-in, first out queue."</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Objections"</p> +<div><p>📝 "Simplicity and elegance are unpopular because they require hard work and discipline to achieve and education to be appreciated."</p> +<p class="attribution">—Edsger W. Dijkstra</p> </div></blockquote> -<p>И приводит пример:</p> <blockquote> -<div><p>next_element := buffer.item -buffer.remove</p> -<p>📝 "With the notation of this chapter, it is easy to obtain exclusive access without sacrificing the Command-Query Separation principle: simply enclose the two instructions above, with buffer replaced by b, in a procedure of formal argument b, and call that procedure with the attribute buffer as argument."</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "30.12 DISCUSSION :: Support for command-query separation"</p> +<div><p>📝 "Simplicity is prerequisite for reliability."</p> +<p class="attribution">—Edsger W. Dijkstra</p> </div></blockquote> -<p>Вы уже, наверное, догадались, что я подвожу к паттерну "<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/async-request-reply">Asynchronous Request-Reply pattern</a>", использующему "<a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-6.3.3">202 Response Status Code</a>".</p> -</section> -</section> -<section id="emacsway-cqrs-command-resource-id"> -<span id="id6"/><h2><a class="toc-backref" href="#id21" role="doc-backlink">Что делать, если CQRS-команда должна вернуть идентификатор созданного ресурса?</a></h2> -<p>Вернемся к вопросу о возврате ID созданного ресурса в ответ на POST запрос REST-API. -Как говорилось <a class="reference internal" href="#emacsway-cqs-factory-result"><span class="std std-ref">ранее</span></a>, RFC-7231 требует, чтобы REST API вернул идентификатор созданного ресурса в ответ на HTTP POST запрос.</p> -<p>Какие вообще есть альтернативы?</p> <blockquote> -<div><p>📝 "If the data is needed by the client as soon as it is submitted, it is there – on the client that submitted it. No need to poll the query side. The only thing that might not have been there is an ID from the database – which is easily solved with client-generated GUIDs instead of database-generated IDs."</p> -<p class="attribution">—"Clarified CQRS" <a class="reference external" href="http://udidahan.com/2009/12/09/clarified-cqrs/#comment-5118">comment 68</a> of Udi Dahan</p> +<div><p>📝 "Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. +And to make matters worse: complexity sells better."</p> +<p class="attribution">—Edsger W. Dijkstra, 1984 <a class="reference external" href="http://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD896.html">On the nature of Computing Science</a> (EWD896)</p> </div></blockquote> -<p>Идентификатор может быть сгенерирован на стороне клиентского приложения, используя <a class="reference external" href="https://en.wikipedia.org/wiki/Universally_unique_identifier">UUID</a>, <a class="reference external" href="https://github.com/ulid/spec">ULID</a>, <a class="reference external" href="https://en.wikipedia.org/wiki/Hi/Lo_algorithm">Hi/Lo algorithm</a> и т.п. -После этого, ресурс может быть создан посредством PUT Request Method:</p> <blockquote> -<div><p>📝 "The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. &lt;...&gt; If the target resource does not have a current representation and the PUT successfully creates one, then the origin server MUST inform the user agent by sending a 201 (Created) response."</p> -<p class="attribution">—"<a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-4.3.4">Section 4.3.4. PUT of RFC-7231</a>"</p> +<div><p>📝 "Хороший специалист всегда осознает строго ограниченные размеры своего черепа, поэтому подходит к задачам с максимальной скромностью.</p> +<p>The competent programmer is fully aware of the strictly limited size of his own skull; +therefore, he approaches the programming task in full humility"</p> +<p class="attribution">—Edsger W. Dijkstra, 1972</p> </div></blockquote> -<p>Другим вариантом, как говорилось <a class="reference internal" href="#emacsway-cqs-buffer"><span class="std std-ref">ранее</span></a>, может быть "<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/async-request-reply">Asynchronous Request-Reply pattern</a>", использующий <a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-6.3.3">202 Response Status Code</a>.</p> -<p>Но действительно ли нам нужно получать идентификатор в ответ на команду? Часто такая потребность возникает просто из-за недостаточного понимания тех выгод, которые предоставляет CQS и Referential Transparency - однонаправленный поток изменений и единственный источник истины.</p> </section> -<section id="emacsway-cqrs-one-way-data-flow"> -<span id="id7"/><h2><a class="toc-backref" href="#id22" role="doc-backlink">Однонаправленный поток изменений</a></h2> -<p>Referential Transparency означает, что вызов функции можно многократно повторять без какого-либо ущерба, и она всегда будет возвращать один и тот же результат.</p> -<p>Более того, - возникает возможность легко управлять потоком изменений, сделав его однонаправленным, и сформировав единственный источник истины (single source of truth - один из ключевых принципов <a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/three-principles">Redux</a>, который <a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/motivation">следует принципам CQRS</a>).</p> +<section id="steve-mcconnell"> +<h3><a class="toc-backref" href="#id10" role="doc-backlink">Steve McConnell</a></h3> <blockquote> -<div><p>Following in the steps of <a class="reference external" href="https://facebook.github.io/flux">Flux</a>, <a class="reference external" href="https://martinfowler.com/bliki/CQRS.html">CQRS</a>, and <a class="reference external" href="https://martinfowler.com/eaaDev/EventSourcing.html">Event Sourcing</a>, Redux attempts to make state mutations predictable by imposing certain restrictions on how and when updates can happen. These restrictions are reflected in the <a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/three-principles">three principles</a> of Redux.</p> -<p class="attribution">—"<a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/motivation">Motivation</a>"</p> +<div><p>📝 "Главным Техническим Императивом Разработки ПО является управление сложностью. +Управлять сложностью будет гораздо легче, если при проектировании вы будете стремиться к простоте.</p> +<p>Есть два общих способа достижения простоты: +минимизация объема существенной сложности, с которой приходится иметь дело в любой конкретный момент времени, +и подавление необязательного роста несущественной сложности.</p> +<p>Software's Primary Technical Imperative is managing complexity. +This is greatly aided by a design focus on simplicity.</p> +<p>Simplicity is achieved in two general ways: +minimizing the amount of essential complexity that anyone's brain has to deal with at any one time, +and keeping accidental complexity from proliferating needlessly."</p> +<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell, перевод: Издательско-торговый дом "Русская Редакция"</p> </div></blockquote> +</section> +<section id="kent-beck"> +<h3><a class="toc-backref" href="#id11" role="doc-backlink">Kent Beck</a></h3> <blockquote> -<div><p>Redux can be described in three fundamental principles: 1) Single source of truth... 2) State is read-only... 3) Changes are made with pure functions</p> -<p>&lt;...&gt;</p> -<p>The only way to change the state is to emit an action, an object describing what happened.</p> -<p class="attribution">—"<a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/three-principles">Three Principles</a>"</p> +<div><p>📝 "On the surface, being an XP programmer looks a lot like being a programmer within other software development disciplines. +You spend your time working with programs, making them bigger, simpler, faster. +Beneath the surface, however, the focus is quite different. +Your job isn't over when the computer understands what to do. +Your first value is communication with other people. +If the program runs, but there is some vital component of communication left to be done, you aren't done. +You write tests that demonstrate some vital aspect of the software. +You break the program into more smaller pieces, or merge pieces that are too small into larger, more coherent pieces. +You find a system of names that more accurately reflects your intent.</p> +<p>This may sound like a high-minded pursuit of perfection. +It is anything but. +You try to develop the most valuable software for the customer, but not to develop anything that isn't valuable. +If you can reduce the size of the problem enough, then you can afford to be careful with the work you do on what remains. +Then, you are careful by habit."</p> +<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> </div></blockquote> <blockquote> -<div><p>Redux uses a "one-way data flow" app structure</p> -<p class="attribution">—"<a class="reference external" href="https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow">Redux Fundamentals, Part 2: Concepts and Data Flow</a>"</p> +<div><p>📝 "Of course, you can do a better job if you have more tools in your toolbox than if you have fewer, but it is much more important to have a handful of tools that you know when not to use, than to know everything about everything and risk using too much solution."</p> +<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> </div></blockquote> <blockquote> -<div><p>ORMs are complex because they have to handle a bi-directional mapping. A uni-directional problem is much easier to work with, particularly if your needs aren't too complex and you are comfortable with SQL. This is one of the arguments for CQRS.</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/OrmHate.html">Orm Hate</a>" by Martin Fowler</p> +<div><p>📝 Mastery - The spirit of xUnit is simplicity. +Martin Fowler said, "Never in the annals of software engineering was so much owed by so many to so few lines of code." +Some of the implementations have gotten a little complicated for my taste. +Rolling your own will give you a tool over which you have a feeling of mastery.</p> +<p class="attribution">—"Test-Driven Development By Example" by Kent Beck</p> </div></blockquote> -<p>Это существенно облегчает создание сложных приложений, используя Task Based UI, позволяет легко организовать репликацию и кэширование, устранить задержки. -Подробнее эти вопросы хорошо раскрывает Udi Dahan в монументальной статье "<a class="reference external" href="http://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>".</p> -<p>Статья доступна для скачивания <a class="reference external" href="https://udidahan.com/wp-content/uploads/Clarified_CQRS.pdf">в формате pdf</a>.</p> -<p>Представьте, что пользователь добавил в корзину последний товар, используя совмещенную операцию Команды и Запроса. В ответ на Команду, сервер сообщил, что товар снят с продажи. Клиентское приложение пользователя обновило свое состояние, и заблокировало в UI возможность заказать уже недоступный товар.</p> -<p>Я намеренно примитивизирую ситуацию - на самом деле она гораздо более сложнее в распределенных системах:</p> +<blockquote> +<div><p>📝 Travel light - You can't expect to carry a lot of baggage and move fast. +The artifacts we maintain should be:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://youtu.be/fWU8ZK0Dmxs">Udi Dahan - If (domain logic) then CQRS, or Saga?</a>"</p></li> -<li><p>хороший пример с overbooking в книге <a class="reference external" href="https://martinfowler.com/books/nosql.html">NoSQL Distilled</a>.</p></li> +<li><p>Few</p></li> +<li><p>Simple</p></li> +<li><p>Valuable</p></li> </ul> -<p>Проблема в том, что между пользователем и сервером существует двунаправленный поток изменений, который недоступен остальным пользователям, так как операция модификации и чтения данных совмещена.</p> -<p>Другой пользователь, для которого источником истины является локальное состояние его клиентского приложения, ничего не знает о том, что товар уже недоступен, пытается его заказать, но, вместо подтверждения заказа, получает сообщение о недоступности товара.</p> -<p>Сюда можно добавить еще время, требуемое на обновление реплик чтения.</p> +<p>The XP team becomes intellectual nomads, always prepared to quickly pack up the tents and follow the herd. +The herd in this case might be a design that wants to go a different direction than anticipated, or a customer that wants to go a different direction than anticipated, or a team member who leaves, or a technology that suddenly gets hot, or a business climate that shifts.</p> +<p>Like the nomads, the XP team gets used to traveling light. +They don't carry much in the way of baggage except what they must have to keep producing value for the customer—tests and code.</p> +<p>&lt;...&gt;</p> +<p>Travel light - suggests that the manager doesn't impose a lot of overhead - long all-hands meetings, lengthy status reports. +Whatever the manager requires of the programmers shouldn't take much time to fulfill.</p> +<p>&lt;...&gt;</p> +<p>Travel light - The design strategy should produce no "extra" design. +There should be enough to suit our current purposes (the need to do quality work), but no more. +If we embrace change, we will be willing to start simple and continually refine.</p> +<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> +</div></blockquote> <blockquote> -<div><p>📝 "Staleness refers to the fact that in a collaborative environment, once data has been shown to a user, that same data may have been changed by another actor – it is stale. Almost any system which makes use of a cache is serving stale data – often for performance reasons. What this means is that we cannot entirely trust our users decisions, as they could have been made based on out-of-date information."</p> -<p class="attribution">—"<a class="reference external" href="https://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" by Udi Dahan</p> +<div><p>📝 "It's hard to do simple things. +It seems crazy, but sometimes it is easier to do something more complicated than to do something simple. +This is particularly true when you have been successful doing the complicated thing in the past. +Learning to see the world in the simplest possible terms is a skill and a challenge. +The challenge is that you may have to change your value system. +Instead of being impressed when someone (like you, for instance) gets something complicated to work, you have to learn to be dissatisfied with complexity, not to rest until you can't imagine anything simpler working."</p> +<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> </div></blockquote> -<p>Отделение Команд от Запросов позволяет организовать однонаправленный поток изменений, и тогда оба пользователя одновременно получат сообщение о событии, что последний товар закончился.</p> -<figure class="align-center" id="id9"> -<a class="reference internal image-reference" href="../../../../../_images/cqrs.png"><img alt="CQRS. The image from &quot;Clarified CQRS&quot; by Udi Dahan https://udidahan.com/2009/12/09/clarified-cqrs/" src="../../../../../_images/cqrs.png" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">CQRS. The image from "<a class="reference external" href="https://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" by Udi Dahan</span></p> -</figcaption> -</figure> <blockquote> -<div><p>📝 "After the command-processing autonomous component has decided to accept a command, modifying its persistent store as needed, it publishes an event notifying the world about it."</p> -<p class="attribution">—"<a class="reference external" href="https://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" by Udi Dahan</p> +<div><p>📝 "I'm not a great programmer; I'm just a good programmer with great habits."</p> +<p class="attribution">—Kent Beck at "Refactoring: Improving the Design of Existing Code" 1st edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p> </div></blockquote> <blockquote> -<div><p>📝 "CQRS is about coming up with an appropriate architecture for multi-user collaborative applications. It explicitly takes into account factors like data staleness and volatility and exploits those characteristics for creating simpler and more scalable constructs."</p> -<p class="attribution">—"<a class="reference external" href="https://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" by Udi Dahan</p> +<div><p>📝 "Solution Complexity</p> +<p>Sometimes systems grow big and complicated, out of proportion to the problem they solve. +The challenge is to stop making the problem worse. +It is difficult for a struggling team to keep going when every defect fixed creates three more. +XP can help.</p> +<p>One client began by getting the build process under control. +The team improved the build so instead of taking 24 hours on a dedicated machine with lots of manual intervention, the build took an hour and could run completely automatically on any machine. +Then, the team instituted stories and a story board so everyone knew who was working on what and how long they were taking. +After two years of steady improvement the team reduced costs 60%, going from seventy engineers to twenty; reduced the time to fix defects 66%; and reduced the time to release for major and minor point releases by 75%, from ten weeks to two weeks. +Once the team had stopped digging itself in deeper, it began to climb out by eliminating excess complexity while also fixing defects.</p> +<p>The XP strategy for dealing with excess complexity is always the same: chip away at the complexity while continuing to deliver. +Brighten the corner where you are. +If you are fixing a defect in an area, clean up while you are there. +One objection is that this "extra" cleanup takes too long. +The team is likely wasting time on interruptions to fix defects. +Cleaning up helps reduce the overhead of work. +Visible planning can make it easier for every one to see where the time is already going so it is easier to accept the estimates necessary to do the job right."</p> +<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Chapter 15. Scaling XP :: Solution Complexity"</p> </div></blockquote> -<p>Теперь, понимая важность однонаправленного потока изменений в условиях collaborative evironment, нам становится легче понять разницу между abstract side effect и concrete side effect.</p> -<p>В <a class="reference external" href="https://youtu.be/fWU8ZK0Dmxs">этом видео</a> Udi Dahan использовал термин sandbox.</p> -<p>Часто ресурс начинает создаваться как черновик. -Он не доступен никому через публичный интерфейс, кроме его автора. -Никто не должен знать о его существовании, кроме его автора. -И если мы нарушим здесь CQS, то никто этого не заметит. -На ресурс распространяется <strong>concrete side effect</strong>:</p> -<ul class="simple"> -<li><p>"<a class="reference internal" href="#emacsway-cqs-query-referential-transparency"><span class="std std-ref">CQS - это больше о referential transparency для Query</span></a>"</p></li> -<li><p>"<a class="reference internal" href="#emacsway-cqs-query-side-effect"><span class="std std-ref">Query не должен иметь abstract side effect, но может иметь concrete side effect</span></a>"</p></li> -</ul> -<p>Другое дело, когда мы должны опубликовать этот ресурс - тогда он должен появиться у всех, кто просматривает коллекцию, содержащую опубликованный ресурс (если, разумеется, это имеет ценность с точки зрения предметной области), а не только инициатор публикации. -И все пользователи, включая автора, должны получить уведомление о публикации ресурса, через единый однонаправленный канал потока изменений.</p> -<p>Такой же вывод возникает и из принципа <strong>функции-конструктора</strong> - до тех пор, пока ресурс не принадлежит ни к одной из публичных коллекций, доступной остальным пользователям, <a class="reference internal" href="#emacsway-cqs-factory-result"><span class="std std-ref">side effect не имеет последствий</span></a>.</p> -<p>Но когда коллекция изменилась, то все пользователи, просматривающие эту коллекцию, должны быть уведомлены единовременно.</p> </section> -<section id="jimmy-bogard"> -<h2><a class="toc-backref" href="#id23" role="doc-backlink">Точка зрения Jimmy Bogard</a></h2> -<p>Ответ Jimmy Bogard по поводу того, может ли CQRS-Команда возвращать результат:</p> +<section id="martin-fowler"> +<h3><a class="toc-backref" href="#id12" role="doc-backlink">Martin Fowler</a></h3> <blockquote> -<div><p>📝 "It might seem rather strange that commands always have a result, but it's much, much easier to deal with side effects of commands through return parameters than through some other means (global registry, static field, re-querying some object, collecting parameter, etc.). <strong>For commands that create an item, I usually want to redirect to a screen showing that item, very easily accomplished when I can get the created item and as for its ID.</strong></p> -<p>This is a bit controversial, but don't frankly care, as it's the simplest thing that could possibly work. If I want to have a command that returns Void, I could steal a page from F# and have a Command base class that returns a Unit type:"</p> -<p class="attribution">—"<a class="reference external" href="https://lostechies.com/jimmybogard/2013/12/19/put-your-controllers-on-a-diet-posts-and-commands/">Put your controllers on a diet: POSTs and commands</a>" by Jimmy Bogard</p> +<div><p>📝 "A little time spent refactoring can make the code better communicate its purpose. Programming in this mode is all about saying exactly what you mean."</p> +<p class="attribution">—"Refactoring: Improving the Design of Existing Code", Martin Fowler</p> </div></blockquote> -<p>Обратите внимание, в последнем предложении он говорит о том, как вернуть и результат, и ошибку одновременно. -Это является решением именно того вопроса, который пытался разрешить B.Meyer с помощью <a class="reference internal" href="#emacsway-cqs-command-status-code"><span class="std std-ref">side-effect-free style</span></a>.</p> -<p>Причины такого решения он раскрывает в другой своей статье:</p> +</section> +<section id="robert-c-martin"> +<h3><a class="toc-backref" href="#id13" role="doc-backlink">Robert C. Martin</a></h3> <blockquote> -<div><p>📝 "Myth #2 – CQRS requires an eventual consistent read store</p> -<p>No, it does not. You can make your read store immediately consistent. That is, your read store can be updated when your command side succeeds (in the same transaction).</p> -<p>For many legacy/existing apps, transitioning to eventually consistent read stores will either force you to go through bogus hoops of mimicking synchronous calls. Users will bang down on your door with pitchforks and torches if you try and transition to an asynchronous model if you don't change their business process first.</p> -<p>Instead, you can start with immediate consistency and transition where and when it's needed. Unless a user expects a confirmation page, making every command page have a series of confirmations of "your request was received" is going to annoy the snot out of your users.</p> -<p>Myth #3 – CQRS requires a bus/queues/asynchronous messaging</p> -<p>See above myth. <strong>Nothing about CQRS says "thou shalt use NServiceBus". It's just not there. You're merely separating infrastructure between handling commands and queries, but the how is quite varied. Don't start with a bus until you prove you need eventual consistency.</strong></p> -<p>Consistency models are a business decision because it directly impacts user experience. An eventually consistent model requires a different user experience than an immediate one, and this is not something you can just "slip in" to your users, or try to emulate. If you're attempting to emulate immediate consistency in an eventually consistent model, you're doing something wrong.</p> -<p class="attribution">—"<a class="reference external" href="https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/">Busting some CQRS myths</a>" by Jimmy Bogard</p> +<div><p>📝 "Professionals avoid getting so vested in an idea that they can't abandon it and turn around. +They keep an open mind about other ideas so that when they hit a dead end they still have other options."</p> +<p class="attribution">—"The Clean Coder: a code of conduct for professional programmers" by Robert C. Martin</p> </div></blockquote> -<p>Что он также подтверждает своим комментарием к этой статье:</p> <blockquote> -<div><p>📝 "Scaling and CQRS are orthogonal, it's highly contextual and certainly doesn't require async."</p> -<p class="attribution">—"<a class="reference external" href="https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/#comment-3422377189">Busting some CQRS myths</a>" by Jimmy Bogard</p> +<div><p>📝 "A good architecture comes from understanding it more as a journey than as a destination, more as an ongoing process of enquiry than as a frozen artifact."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> </div></blockquote> </section> -<section id="id8"> -<h2><a class="toc-backref" href="#id24" role="doc-backlink">Вывод</a></h2> -<p>Итак, ответ прост - если вы не используете асинхронное исполнение Команды посредством инфраструктуры (Command Bus), то ничто не препятствует вам получить идентификатор вновь созданной записи БД в возвращаемом командой результате, и реализацию можно существенно упростить. -Впрочем, возвратить результат можно даже используя Command Bus, но тут вопрос к потреблению ресурсов (все зависит от конкретного случая).</p> -<p>Вопрос не в том, возвращает ли команда результат (при этом нужно отличать результат от служебной информации, например, от успешности валидации и принятия команды), а в том, можно ли получить информацию о ресурсе без abstract side effect, т.е. смогут ли другие клиенты получить ту же информацию, если она им нужна.</p> -<p>Этот вопрос также разбирали следующие авторы:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://habr.com/ru/post/347908/">CQRS. Факты и заблуждения</a>" / Максим Аршинов</p></li> -<li><p>"<a class="reference external" href="https://event-driven.io/en/can_command_return_a_value/">Can command return a value?</a>" by Oskar Dudycz</p></li> -<li><p>"<a class="reference external" href="https://event-driven.io/en/cqrs_facts_and_myths_explained/">CQRS facts and myths explained</a>" by Oskar Dudycz</p></li> -<li><p>"<a class="reference external" href="https://blog.ploeh.dk/2014/08/11/cqs-versus-server-generated-ids/">CQS versus server generated IDs</a>" by Mark Seemann</p></li> -<li><p>"<a class="reference external" href="https://blogs.cuttingedge.it/steven/posts/2012/returning-data-from-command-handlers/">Returning data from command handlers</a>" by Steven van Deursen</p></li> -</ul> -<p>Ранее, этот вопрос <a class="reference internal" href="../domain-model/domain-events/domain-events-in-ddd.html#emacsway-domain-event-cqrs-command-result"><span class="std std-ref">частично уже рассматривался</span></a>.</p> -</section> -Wed, 28 Jun 2023 00:00:00 Файловая структура Доменной моделиhttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/file-structure.html -<span id="id1"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<p>О причинах образования такой файловой структуры.</p> -<nav class="contents" id="id2"> -<p class="topic-title">Содержание</p> -<ul class="simple"> -<li><p><a class="reference internal" href="#emacsway-golang-domain-file-structure" id="id7">Файловая структура Доменной модели</a></p> -<ul> -<li><p><a class="reference internal" href="#bounded-context-internal" id="id8">Зачем в каждом Bounded Context директория internal?</a></p></li> -<li><p><a class="reference internal" href="#id3" id="id9">Почему агрегаты резмещены в собственных директориях?</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id10">Почему Сущности Агрегатов выделены в отдельные директории?</a></p></li> -<li><p><a class="reference internal" href="#id5" id="id11">Почему в директории Агрегата нет директории для его Объектов-значений?</a></p></li> -<li><p><a class="reference internal" href="#id6" id="id12">Почему Доменные События размещены в директории Агрегата и его Сущностей?</a></p></li> -</ul> -</li> -</ul> -</nav> -<section id="bounded-context-internal"> -<h2><a class="toc-backref" href="#id8" role="doc-backlink">Зачем в каждом Bounded Context директория internal?</a></h2> -<p>Доменная модель должна быть инкапсулирована. -Другим Bounded Contexts должны быть доступны только CQRS-Commands и Public Domain Events (Integration Events).</p> -</section> -<section id="id3"> -<h2><a class="toc-backref" href="#id9" role="doc-backlink">Почему агрегаты резмещены в собственных директориях?</a></h2> -<p>Причины две:</p> -<ol class="arabic simple"> -<li><p>Чтобы подчеркнуть High Cohesion, см. главу "Chapter Five. A Model Expressed in Software :: Modules" книги "Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans.</p></li> -<li><p>В Golang это необходимо для реализации <a class="reference internal" href="aggregate-encapsulation.html#emacsway-golang-encapsulation"><span class="std std-ref">инкапсуляции Агрегата</span></a>, чтобы ограничить доступ к защищенным атрибутам Агрегата извне.</p></li> -</ol> +<section id="bjarne-stroustrup"> +<h3><a class="toc-backref" href="#id14" role="doc-backlink">Bjarne Stroustrup</a></h3> <blockquote> -<div><p>💬 "МОДУЛИ дают возможность посмотреть на модель с разных сторон: -во-первых, можно изучить подроб­ности устройства модуля, не вникая в сложное целое; -во-вторых, удобно рассматривать взаимоотношения между модулями, не вдаваясь в детали их внутреннего устройства.</p> -<p>&lt;...&gt;</p> -<p>То, что при делении на модули должна соблюдаться низкая внешняя зависимость (low coupling) при высокой внутренней связности (high cohesion)- это общие слова. -Определения зависимости и связности грешат уклоном в чисто технические, количест­венные критерии, по которым их якобы можно измерить, подсчитав количество ассо­циаций и взаимодействий. -Но это не просто механические характеристики подразде­ления кода на модули, а идейные концепции. -Человек не может одновременно удер­живать в уме слишком много предметов (отсюда низкая внешняя зависимость). -А плохо связанные между собой фрагменты информации так же трудно понять, как неструктурированную "кашу" из идей (отсюда высокая внутренняя связность).</p> -<p>MODULES give people two views of the model: -They can look at detail within a MODULE without being overwhelmed by the whole, or they can look at relationships between MODULES in views that exclude interior detail.</p> -<p>&lt;...&gt;</p> -<p>It is a truism that there should be low coupling between MODULES and high cohesion within them. -Explanations of coupling and cohesion tend to make them sound like technical metrics, to be judged mechanically based on the distributions of associations and interactions. Yet it isn't just code being divided into MODULES, but concepts. -There is a limit to how many things a person can think about at once (hence low coupling). -Incoherent fragments of ideas are as hard to understand as an undifferentiated soup of ideas (hence high cohesion)."</p> -<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> +<div><p>📝 "I like my code to be elegant and efficient. +The logic should be straightforward to make it hard for bugs to hide, +the dependencies minimal to ease maintenance, error handling complete according to an articulated strategy, +and performance close to optimal so as not to tempt people to make the code messy with unprincipled optimizations. +Clean code does one thing well."</p> +<p class="attribution">—Bjarne Stroustrup, inventor of C++ and author of The C++ Programming Language. +"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p> </div></blockquote> </section> <section id="id4"> -<h2><a class="toc-backref" href="#id10" role="doc-backlink">Почему Сущности Агрегатов выделены в отдельные директории?</a></h2> -<p>Чтобы логически выделить связанные этой Сущностью объекты. -Не очень удобно рассматривать винегрет вложенных объектов различных Сущностей, поскольку они нерелевантны в момент рассмотрения и повышают когнитивную нагрузку.</p> -<p>Впрочем, это решение является пока что экспериментальным и не окончательным.</p> -<p>Есть у этого решения контраргумент, который заключается в том, что Сущность, хотя и кратковременно, но может отдаваться наружу Агрегата, если при этом она остается неизменяемой.</p> +<h3><a class="toc-backref" href="#id15" role="doc-backlink">Другие</a></h3> <blockquote> -<div><p>💬️ "Группируйте СУЩНОСТИ и ОБЪЕКТЫ-ЗНАЧЕНИЯ в АГРЕГАТЫ и определяйте границы каждого из них. -Выберите о дин объект-СУЩНОСТЬ и сделайте его корневым. -Осуществляйте все обращения к объектам в границах АГРЕГАТА только через его корневой объект. -Разрешайте внешним объектам хранить ссылки только на корневой объект. -<strong>Ссылки на внутренние объекты АГРЕГАТА следует передавать только во временное пользование, на время одной операции.</strong> -<strong>Поскольку доступ к объектам АГРЕГАТА кон­тролируется через корневой объект, неожиданные изменения внутренних объектов невозможны.</strong> -В такой схеме разумно требовать удовлетворения всех инвариантов для объектов в АГРЕГАТЕ и для всего АГРЕГАТА в целом при любом изменении состояния.</p> -<p>Cluster the ENTITIES and VALUE OBJECTS into AGGREGATES and define boundaries around each. -Choose one ENTITY to be the root of each AGGREGATE, and control all access to the objects inside the boundary through the root. -Allow external objects to hold references to the root only. -<strong>Transient references to internal members can be passed out for use within a single operation only.</strong> -<strong>Because the root controls access, it cannot be blindsided by changes to the internals.</strong> -This arrangement makes it practical to enforce all invariants for objects in the AGGREGATE and for the AGGREGATE as a whole in any state change."</p> -<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> +<div><p>📝 "Simplicity—the art of maximizing the amount of work not done—is essential."</p> +<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/principles.html">Principles behind the Agile Manifesto</a>"</p> </div></blockquote> -<p>О чем это говорит? -Это говорит о том, что если мы разместим Сущность в одном пакете с Агрегатом, то это значит, что Агрегату не требуются публичные методы для того, чтобы иметь доступ к своей Сущности. -Это значит, что Агрегат обладает другим уровнем доступа, нежели посторонние клиенты. -Это значит, что посторонние клиенты не получат доступа к мутирующим методам Сущности только потому, что они нужны Агрегату.</p> -<p>Но здесь возникает другой вопрос - следовать ли <a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D0%94%D0%B5%D0%BC%D0%B5%D1%82%D1%80%D1%8B">Law of Demeter</a> внутри Агрегата? -Следует ли ограничивать прямой доступ Агрегата к Сущностям его Сущностей? -Плоская структура файлов Агрегата не позволяет это обеспечить.</p> -</section> -<section id="id5"> -<h2><a class="toc-backref" href="#id11" role="doc-backlink">Почему в директории Агрегата нет директории для его Объектов-значений?</a></h2> -<p>Причина, по которой эта директория была вначале, заключалась в необходимости реализации ациклического графа зависимостей с целью исключения циклических импортов. -Это было связано с тем, что Сущности Агрегата имели собственную директорию. -Например, Агрегат может быть осведомлен о своей Сущности, а Сущность может быть осведомлена об Объекте-значении Агрегата.</p> -<p>По этой причине, все Объекты-значения Агрегата/Сущности были выделены в отдельную директорию внутри директории Агрегата/Сущности. -Иначе пришлось бы абсолютно все Cущности и Объекты-значения Агрегата разметить плоским списком в одной директории, что затрудняло навигацию по файловой структуре.</p> -<p>Позже я обнаружил еще один способ решения проблемы циклического импорта - для этого было достаточно, чтобы Агрегат заимствовавал Объект-значение у Сущности, а не наоборот.</p> -<p>В крайнем случае, внутри директории Агрегата можно делать директорию <code class="docutils literal notranslate"><span class="pre">shared</span></code>, <code class="docutils literal notranslate"><span class="pre">common</span></code>, или <code class="docutils literal notranslate"><span class="pre">aggregate_name</span></code>, для реализации ациклического графа зависимостей.</p> -<p>Этот вариант также может оказаться востребованным, если Доменные События расположены в поддиректории, например, <code class="docutils literal notranslate"><span class="pre">events</span></code>, и используют Объекты-значения Агрегатов. -В таком случае, директория для совместно используемых Объектов-значений может иметь название (в дополнение к уже перечисленным) <code class="docutils literal notranslate"><span class="pre">exportable</span></code>, <code class="docutils literal notranslate"><span class="pre">public</span></code>.</p> <blockquote> -<div><p>All Value Objects which are part of a Customer live in another subpackage named value. I have to do this because in Go circular dependencies are not allowed. If I would put the Value Objects into the customer package then Commands and Events in domain would import the Value Objects from customer and functions in customer would import Commands and Events from domain. Having them in a subpackage additionally gives more privacy for the Value Objects. Not even functions of the Customer Aggregate can access private parts or create/modify a value without using the proper methods.</p> -<p class="attribution">—"<a class="reference external" href="https://medium.com/@TonyBologni/implementing-domain-driven-design-and-hexagonal-architecture-with-go-2-efd432505554">Implementing Domain-Driven Design and Hexagonal Architecture with Go (2)</a>" by Anton Stöckl — Part 2 — How I implement tactical DDD patterns — the Domain layer.</p> +<div><p>📝 "The design goal for Eventlet's API is simplicity and readability. +You should be able to read its code and understand what it's doing. +Fewer lines of code are preferred over excessively clever implementations."</p> +<p class="attribution">—"<a class="reference external" href="http://eventlet.net/doc/basic_usage.html">Eventlet's docs</a>"</p> </div></blockquote> -<p>Еще одним способом предотвращения циклических импортов является использование интерфейсов, размещенных в отдельном пакете либо продублированных у своих клиентов (но это привело бы к дублированию интерфейсов-экспортеров). -Интерфейс дает то, что требуется сигнатурой методов клиента, не тащит за собой кучу зависимостей, необходимых для реализации, и даже может быть объявлен локально у своего клиента.</p> -<p>Попробовав различные варианты, я решил не выделять доменные события в отдельную директорию, т.к. избыток директорий создает ощущение переусложненности.</p> +<blockquote> +<div><p>📝 "Будьте скромны, не считайте себя супергением — это ваша первая ошибка. +Оставаясь скромным, вы в конечном итоге достигнете уровня супергения, и даже если нет, какая разница. +Ваш код должен быть прост настолько, что вам не нужно быть гением, чтобы работать с ним.</p> +<p>Be Humble, don't think of yourself as a super genius, this is your first mistake. +By being humble, you will eventually achieve super genius status =), and even if you don't, who cares! +your code is stupid simple, so you don't have to be a genius to work with it."</p> +<p class="attribution">—"<a class="reference external" href="https://people.apache.org/~fhanik/kiss.html">KISS principle</a>"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Когда кто-либо привязывается к одной какой-нибудь, хотя бы и верной, идее, то он, в сущности, попадает в то же положение, в каком находился бы человек, привязавший себя к столбу, для того чтобы не заблудиться. +То, что может быть желанной истиной на известной ступени духовного роста, может быть помехой к этому росту и заблуждением на другой, более высокой ступени."</p> +<p class="attribution">—Люси Малори</p> +</div></blockquote> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference internal" href="../../../../../soft-skills/icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Принцип ледокола</span></a>"</p></li> +<li><p>"<a class="reference internal" href="software-design.html#emacsway-agile-software-design"><span class="std std-ref">Role of Software Design in Agile</span></a>"</p></li> +<li><p>"<a class="reference internal" href="patterns.html#emacsway-agile-patterns"><span class="std std-ref">Role of Design Patterns in Agile</span></a>"</p></li> +</ul> +</div> </section> -<section id="id6"> -<h2><a class="toc-backref" href="#id12" role="doc-backlink">Почему Доменные События размещены в директории Агрегата и его Сущностей?</a></h2> -<p>Альтернативным вариантом является размещение Доменных Событий <a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/tree/ce50bb8a2f1fa30e419d9a6863d19eb9999e9ef8/src/Services/Ordering/Ordering.Domain/Events">отдельно от Агрегатов</a>.</p> -<p>Но удобней информация воспринимается тогда, когда следствие расположено ближе к своей причине.</p> -<p>При этом, поскольку Доменные События выражают взаимоотношения между Агрегатами, удобно иметь возможность рассматривать их <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/master/iddd_agilepm/Domain.Model/Products/ProductDiscussionInitiated.cs">не вдаваясь</a> в детали внутреннего устройства Агрегатов.</p> -<p>Точно так же, как Интеграционные (Публичные Доменные) События, выражающие взаимоотношения между Ограниченными Контекстами, расположены в единой директории порождающего их Ограниченного Контекста.</p> -<p>Однако, если Доменные События вынести в отдельную поддиректорию внутри директории Агрегата, то возникает циклический импорт, ведь Доменные События могут содержать Объекты-Значения, объявленные в том же самом пакете, где они инстанционируются. -Чтобы предотвратить циклический импорт, Объекты-Значения так же нужно вынести поддиректорию. -Это было бы логично еще и потому, что Сущности/Агрегаты, Объекты-Значения и Доменные События служат разным целям:</p> -<ol class="arabic simple"> -<li><p>Сущности/Агрегаты - моделируют предметную область.</p></li> -<li><p>Объекты-Значения - описывают характеристики предметов (элементов предметной области), например, возраст - это не предмет.</p></li> -<li><p>Доменные События - фиксируют факт изменения состояния предметов.</p></li> -</ol> -<p>Поддиректории <code class="docutils literal notranslate"><span class="pre">events``и</span> <span class="pre">``values</span></code> имеют множественное число, что позволяет предотвратить коллизии с названиями директорий Сущностей Агрегата, которые именуются в единственном числе.</p> </section> -Sat, 24 Jun 2023 00:00:00 Список литературы для самообучения разработчика программного обеспеченияhttps://dckms.github.io/system-architecture/emacsway/it/self-education/self-education-for-software-engineer.html<span class="target" id="index-0"/><section id="emacsway-self-education-literature"> +Thu, 19 Oct 2023 00:00:00 Список психологических эффектовhttps://dckms.github.io/system-architecture/emacsway/soft-skills/cognitive-biases.html <span id="id1"/> <p><em>Автор раздела: Ivan Zakrevsky</em></p> -<p>Один из частых вопросов, который я наблюдаю регулярно, - это "посоветуйте список литературы в области разработки программного обеспечения". -В этой статье я изложу свое видение самообучения и приведу список тематической литературы, с учетом моего личного опыта.</p> +<blockquote> +<div><p>📝 "Самая главная формула успеха — знание, как обращаться с людьми."</p> +<p class="attribution">—<a class="reference external" href="https://ru.wikiquote.org/wiki/%D0%A2%D0%B5%D0%BE%D0%B4%D0%BE%D1%80_%D0%A0%D1%83%D0%B7%D0%B2%D0%B5%D0%BB%D1%8C%D1%82">Теодор Рузвельт</a></p> +</div></blockquote> +<blockquote> +<div><p>📝 "Вежливость города берет"</p> +<p class="attribution">—Народная пословица</p> +</div></blockquote> +<p>Список психологических эффектов, с которыми приходится сталкиваться в своей деятельности IT-архитектору:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%94%D0%B0%D0%BD%D0%BD%D0%B8%D0%BD%D0%B3%D0%B0_%E2%80%94_%D0%9A%D1%80%D1%8E%D0%B3%D0%B5%D1%80%D0%B0">Эффект Даннинга — Крюгера</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC_%D1%81%D0%B0%D0%BC%D0%BE%D0%B7%D0%B2%D0%B0%D0%BD%D1%86%D0%B0">Синдром самозванца</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%BB%D0%BE%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%BA_%D0%BF%D0%BE%D0%B4%D1%82%D0%B2%D0%B5%D1%80%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D1%8E_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D0%B7%D1%80%D0%B5%D0%BD%D0%B8%D1%8F">Склонность к подтверждению своей точки зрения</a>"</p></li> +<li><p>"<a class="reference internal" href="learning-spiral-phase-mismatch.html#emacsway-learning-spiral-phase-mismatch"><span class="std std-ref">Несовпадение фаз спиралей обучения</span></a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%BE%D0%B5_%D0%B2%D0%BE%D1%81%D0%BF%D1%80%D0%B8%D1%8F%D1%82%D0%B8%D0%B5">Селективное восприятие</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BF%D1%80%D0%B8%D0%B2%D1%8F%D0%B7%D0%BA%D0%B8">Эффект привязки</a>" (Эффект якоря)</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологическая защита</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9E%D1%82%D0%BA%D0%BB%D0%BE%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D1%83_%D1%81%D1%82%D0%B0%D1%82%D1%83%D1%81-%D0%BA%D0%B2%D0%BE">Отклонение в сторону статус-кво</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%BE%D0%B5_%D1%81%D0%BE%D0%BF%D1%80%D0%BE%D1%82%D0%B8%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_(%D0%BF%D1%81%D0%B8%D1%85%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F)">Реактивное сопротивление</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BB%D0%BE%D0%B6%D0%BD%D0%BE%D0%B9_%D1%83%D0%BD%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Эффект ложной уникальности</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%BE%D0%B4%D0%BD%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Эффект неоднозначности</a>" (упоминался <a class="reference external" href="https://t.me/emacsway_log/97">здесь</a> и <a class="reference external" href="https://t.me/emacsway_log/101">здесь</a>)</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%B4%D0%BF%D0%BE%D1%87%D1%82%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D0%BE%D0%B3%D0%BE_%D1%80%D0%B8%D1%81%D0%BA%D0%B0">Предпочтение нулевого риска</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%98%D1%80%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%83%D1%81%D0%B8%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5">Закон иррационального усиления</a>" (упоминался <a class="reference internal" href="learning-spiral-phase-mismatch.html#emacsway-learning-spiral-phase-mismatch-code-review"><span class="std std-ref">здесь</span></a>)</p></li> +<li><p>"<a class="reference external" href="https://en.wikipedia.org/wiki/Sunk_cost">Sunk cost</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%98%D1%81%D0%BA%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_%D0%B2%D0%BE%D1%81%D0%BF%D1%80%D0%B8%D1%8F%D1%82%D0%B8%D0%B8_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B2%D1%8B%D0%B1%D0%BE%D1%80%D0%B0">Искажение в восприятии сделанного выбора</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%9A%D0%BE%D0%B3%D0%BD%D0%B8%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9_%D0%B4%D0%B8%D1%81%D1%81%D0%BE%D0%BD%D0%B0%D0%BD%D1%81">Когнитивный диссонанс</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%BD%D0%BE%D1%81%D1%82%D1%8C">Конформность</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%B2%D0%BB%D0%B0%D0%B4%D0%B5%D0%BD%D0%B8%D1%8F">Эффект владения</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0_%D0%B2%D1%8B%D0%B6%D0%B8%D0%B2%D1%88%D0%B5%D0%B3%D0%BE">Систематическая ошибка выжившего</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D0%BE%D1%80%D0%B8%D1%8F_%D1%80%D0%B0%D0%B7%D0%B1%D0%B8%D1%82%D1%8B%D1%85_%D0%BE%D0%BA%D0%BE%D0%BD">Теория разбитых окон</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%90%D0%BF%D0%B5%D0%BB%D0%BB%D1%8F%D1%86%D0%B8%D1%8F_%D0%BA_%D0%BB%D0%B8%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Апелляция к личности</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%B2%D1%82%D0%BE%D1%80%D0%BE%D0%B9_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B">Эффект второй системы</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/Хоторнский_эффект">Хоторнский эффект новизны</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D1%84%D0%B5%D1%81%D1%81%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%B4%D0%B5%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D1%8F">Профессиональная деформация</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BF%D1%80%D0%BE%D0%B6%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%B0">Эффект прожектора</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%BA%D1%80%D0%B0%D1%81%D1%82%D0%B8%D0%BD%D0%B0%D1%86%D0%B8%D1%8F">Прокрастинация</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D0%BC%D0%BE%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%B2%D1%8B%D0%B3%D0%BE%D1%80%D0%B0%D0%BD%D0%B8%D0%B5">Эмоциональное выгорание</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9E%D1%88%D0%B8%D0%B1%D0%BA%D0%B0_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F">Ошибка планирования</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D1%82%D0%B5%D0%BB%D0%B5%D1%81%D0%BA%D0%BE%D0%BF%D0%B0">Эффект телескопа</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%B4%D0%B0%D0%B2%D0%BD%D0%B5%D0%B3%D0%BE">Эффект недавнего</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BD%D0%BE%D0%B9_%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D0%B8">Каскад доступной информации</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D1%82%D1%80%D0%B8%D0%B2%D0%B8%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Закон тривиальности (эффект велосипедного сарая)</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD%D1%8B_%D0%9F%D0%B0%D1%80%D0%BA%D0%B8%D0%BD%D1%81%D0%BE%D0%BD%D0%B0">Первый закон Паркинсона (Работа заполняет время, отпущенное на неё)</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/Синдром_неприятия_чужой_разработки">Синдром неприятия чужой разработки</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%B0%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D1%82%D0%B5%D1%82%D0%B0">Эффект авторитета</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%93%D1%80%D1%83%D0%BF%D0%BF%D0%BE%D0%B2%D0%BE%D0%B5_%D0%BC%D1%8B%D1%88%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5">Групповое мышление</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B8%D0%B2%D0%B0%D1%8F_%D0%B7%D0%B0%D0%B1%D1%8B%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F">Кривая забывания</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B8%D0%B2%D0%B0%D1%8F_%D0%BE%D0%B1%D1%83%D1%87%D0%B0%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D0%B8">Кривая обучаемости</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BA%D1%80%D0%B0%D1%8F_(%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D1%8C)">Эффект края (память)</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D1%87%D0%B5%D1%82%D1%8B%D1%80%D1%91%D1%85_%D0%BA%D0%B0%D0%BD%D0%B0%D0%BB%D0%BE%D0%B2">Модель четырёх каналов</a>"</p></li> +</ul> +<p>Обзорные (агрегированные) статьи:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9B%D0%BE%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0">Логическая ошибка</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BA%D0%BE%D0%B3%D0%BD%D0%B8%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D1%85_%D0%B8%D1%81%D0%BA%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9">Список когнитивных искажений</a>"</p></li> +<li><p>"<a class="reference external" href="https://en.wikipedia.org/wiki/Decision-making">Decision-making</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.atlassian.com/blog/productivity/cognitive-bias-examples">5 cognitive bias examples and how to avoid them in decision-making</a>" by Ben Crothers</p></li> +</ul> +<p>А вот следующая статья очень интересна. +Научное биологическое обоснование того, почему процесс Knowledge Crunching неизбежен. +Иными словами, почему требуется время на вызревание концептуальных контуров доменного моделирования, что и является основной причиной появления Monolith First:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.hindawi.com/journals/np/2009/482696/">A Plastic Temporal Brain Code for Conscious State Generation</a>"</p></li> +</ul> +<p>На эту тему была неплохая статья на Хабре:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://habr.com/ru/company/web_payment_ru/blog/246081/">О медленном программировании</a>"</p></li> +</ul> +<p>Шпаргалки по теме:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://play.google.com/store/apps/details?id=ru.free_coding.biascs">Шпаргалка по когнитивным искажениям в виде мобильного приложения</a>"</p></li> +</ul> +<p>В виде JSON:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.dropbox.com/s/8l49rx8ig9i4za3/cognitive-bias-cheat-sheet-ru.json">https://www.dropbox.com/s/8l49rx8ig9i4za3/cognitive-bias-cheat-sheet-ru.json</a></p></li> +<li><p><a class="reference external" href="http://ezh.li/cbcs-json">http://ezh.li/cbcs-json</a></p></li> +<li><p><a class="reference external" href="https://github.com/busterbenson/public/blob/master/cognitive-bias-cheat-sheet.json">https://github.com/busterbenson/public/blob/master/cognitive-bias-cheat-sheet.json</a></p></li> +</ul> +<p>Статьи по теме:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://betterhumans.pub/cognitive-bias-cheat-sheet-55a472476b18">Cognitive bias cheat sheet</a>" by Buster Benson</p></li> +<li><p>"<a class="reference external" href="https://medium.com/russian/cognitive-bias-cheat-sheet-5bb0664b67b5">Памятка по когнитивным искажениям</a>" / Alexey Ezhikov</p></li> +<li><p>"<a class="reference external" href="https://www.talent-management.com.ua/3467-shpargalka-po-kognitivnym-iskazheniyam/">Шпаргалка по когнитивным искажениям</a>"</p></li> +</ul> +<p>Простой и доходчивый видеокурс по SoftSkills:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://youtube.com/channel/UCSN7G8syJUaRiXrw1l0qk_g">Soft Skills Pro</a>"</p></li> +</ul> +Wed, 18 Oct 2023 00:00:00 Как пользоватьсяhttps://dckms.github.io/system-architecture/README.html + +<p><a class="reference external" href="https://github.com/emacsway/dckms-template">Distributed Collaborative Knowledge Management System</a></p> <nav class="contents" id="id2"> <p class="topic-title">Содержание</p> <ul class="simple"> -<li><p><a class="reference internal" href="#emacsway-self-education-literature" id="id39">Список литературы для самообучения разработчика программного обеспечения</a></p> -<ul> -<li><p><a class="reference internal" href="#id3" id="id40">Предисловие</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id41">Кандидатский минимум</a></p> -<ul> -<li><p><a class="reference internal" href="#id5" id="id42">Учимся обучению</a></p></li> -<li><p><a class="reference internal" href="#id6" id="id43">Изучаем основную используемую технологию</a></p></li> -<li><p><a class="reference internal" href="#id7" id="id44">Азбука программирования</a></p></li> -<li><p><a class="reference internal" href="#id8" id="id45">Учимся быть эффективным</a></p></li> -<li><p><a class="reference internal" href="#id9" id="id46">Учимся делать команду эффективной</a></p></li> -<li><p><a class="reference internal" href="#id10" id="id47">Изучаем операционную систему</a></p></li> -<li><p><a class="reference internal" href="#id11" id="id48">Изучаем основы алгоритмов и структур данных</a></p></li> -<li><p><a class="reference internal" href="#id12" id="id49">Изучаем математику</a></p></li> -<li><p><a class="reference internal" href="#id13" id="id50">Учимся архитектуре</a></p></li> -<li><p><a class="reference internal" href="#id14" id="id51">Изучаем распределенные системы</a></p></li> -<li><p><a class="reference internal" href="#id15" id="id52">Изучаем распределенные системы. Углубляем навыки.</a></p></li> -<li><p><a class="reference internal" href="#ddd" id="id53">Изучаем DDD</a></p> +<li><p><a class="reference internal" href="#id1" id="id24">Как пользоваться</a></p> <ul> -<li><p><a class="reference internal" href="#id16" id="id54">Статьи на частые вопросы по DDD</a></p> +<li><p><a class="reference internal" href="#id3" id="id25">Почему</a></p> <ul> -<li><p><a class="reference internal" href="#aggregate-domain-modeling" id="id55">Aggregate &amp; Domain Modeling</a></p></li> -<li><p><a class="reference internal" href="#cqrs-event-sourcing" id="id56">CQRS &amp; Event Sourcing</a></p></li> -<li><p><a class="reference internal" href="#bounded-context-and-microservices" id="id57">Bounded Context and Microservices</a></p></li> -<li><p><a class="reference internal" href="#domain-events" id="id58">Domain Events</a></p></li> -<li><p><a class="reference internal" href="#api-design" id="id59">API-Design</a></p></li> -<li><p><a class="reference internal" href="#event-storming" id="id60">Event Storming</a></p></li> -<li><p><a class="reference internal" href="#modelling" id="id61">Modelling</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id26">Коллективность</a></p></li> +<li><p><a class="reference internal" href="#id5" id="id27">Субъектность</a></p></li> +<li><p><a class="reference internal" href="#id6" id="id28">Психология</a></p></li> +<li><p><a class="reference internal" href="#id7" id="id29">Экономия времени</a></p></li> +<li><p><a class="reference internal" href="#id8" id="id30">Навигация</a></p></li> +<li><p><a class="reference internal" href="#id9" id="id31">Интеграция</a></p></li> +<li><p><a class="reference internal" href="#id10" id="id32">Реализация</a></p></li> +<li><p><a class="reference internal" href="#id11" id="id33">Влияние на качество обучения</a></p></li> +<li><p><a class="reference internal" href="#id12" id="id34">Легкость переключения контекста</a></p></li> </ul> </li> +<li><p><a class="reference internal" href="#id13" id="id35">Порядок использования</a></p></li> +<li><p><a class="reference internal" href="#html" id="id36">Как собрать html</a></p></li> +<li><p><a class="reference internal" href="#zettelkasten" id="id37">О Zettelkasten</a></p></li> +<li><p><a class="reference internal" href="#id15" id="id38">Философия</a></p></li> +<li><p><a class="reference internal" href="#id16" id="id39">Близкие по духу системы</a></p> +<ul> +<li><p><a class="reference internal" href="#obsidian" id="id40">Obsidian</a></p></li> +<li><p><a class="reference internal" href="#neuron-zettelkasten" id="id41">Neuron Zettelkasten</a></p></li> +<li><p><a class="reference internal" href="#antora" id="id42">Antora</a></p></li> +<li><p><a class="reference internal" href="#gitjournal" id="id43">GitJournal</a></p></li> +<li><p><a class="reference internal" href="#popular-static-site-generators" id="id44">Статические генераторы сайтов</a></p></li> +<li><p><a class="reference internal" href="#id18" id="id45">Другие интересные проекты</a></p></li> </ul> </li> +<li><p><a class="reference internal" href="#markdown" id="id46">Markdown</a></p></li> +<li><p><a class="reference internal" href="#using-dckms-on-mobile-devices" id="id47">Как работать на мобильных устройствах</a></p> +<ul> +<li><p><a class="reference internal" href="#android" id="id48">Как работать на Android</a></p></li> +<li><p><a class="reference internal" href="#iphone" id="id49">Как работать на iPhone</a></p></li> </ul> </li> -<li><p><a class="reference internal" href="#id17" id="id62">Дополнительная литература (на выбор)</a></p> +<li><p><a class="reference internal" href="#id20" id="id50">Интеграция с другими системами</a></p> <ul> -<li><p><a class="reference internal" href="#sdlc" id="id63">SDLC</a></p> +<li><p><a class="reference internal" href="#id21" id="id51">Интеграция с Obsidian</a></p></li> +<li><p><a class="reference internal" href="#notion" id="id52">Интеграция с Notion</a></p></li> +<li><p><a class="reference internal" href="#evernote" id="id53">Интеграция с Evernote</a></p></li> +<li><p><a class="reference internal" href="#rss" id="id54">RSS</a></p> <ul> -<li><p><a class="reference internal" href="#single-team-agile" id="id64">Single-Team Agile</a></p></li> -<li><p><a class="reference internal" href="#scaled-agile" id="id65">Scaled Agile</a></p></li> -<li><p><a class="reference internal" href="#id18" id="id66">Стандарты</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#id19" id="id67">Менеджмент</a></p></li> -<li><p><a class="reference internal" href="#id20" id="id68">Развитие личностных профессиональных качеств</a></p></li> -<li><p><a class="reference internal" href="#id21" id="id69">Базы данных</a></p></li> -<li><p><a class="reference internal" href="#id22" id="id70">Изучаем распределенные системы. Третий заход.</a></p></li> -<li><p><a class="reference internal" href="#id23" id="id71">API-Design</a></p></li> -<li><p><a class="reference internal" href="#streaming-processing" id="id72">Streaming Processing</a></p></li> -<li><p><a class="reference internal" href="#id24" id="id73">Углубляем DDD</a></p></li> -<li><p><a class="reference internal" href="#id25" id="id74">Изучаем проектирование</a></p></li> -<li><p><a class="reference internal" href="#posa" id="id75">POSA</a></p></li> -<li><p><a class="reference internal" href="#id26" id="id76">Алгоритмы. Второй заход.</a></p></li> -<li><p><a class="reference internal" href="#id27" id="id77">Тестирование</a></p></li> -<li><p><a class="reference internal" href="#id28" id="id78">Компиляторы</a></p></li> -<li><p><a class="reference internal" href="#id29" id="id79">Архитектура</a></p></li> -<li><p><a class="reference internal" href="#id30" id="id80">Аналитика</a></p></li> -<li><p><a class="reference internal" href="#id31" id="id81">Изучаем оценивание задач</a></p></li> -<li><p><a class="reference internal" href="#id32" id="id82">Функциональное программирование</a></p></li> -<li><p><a class="reference internal" href="#id33" id="id83">Справочники</a></p></li> +<li><p><a class="reference internal" href="#rss-mattermost" id="id55">Интегация RSS с Mattermost</a></p></li> +<li><p><a class="reference internal" href="#rss-telegram" id="id56">Интегация RSS с Telegram</a></p></li> </ul> </li> -<li><p><a class="reference internal" href="#id34" id="id84">Справочная информация</a></p> -<ul> -<li><p><a class="reference internal" href="#body-of-knowledge" id="id85">Body of Knowledge</a></p></li> -<li><p><a class="reference internal" href="#id35" id="id86">ГОСТы</a></p></li> -<li><p><a class="reference internal" href="#online" id="id87">Online-каталоги</a></p></li> -<li><p><a class="reference internal" href="#code-smell-catalogs" id="id88">Code Smell catalogs</a></p></li> -<li><p><a class="reference internal" href="#id36" id="id89">Другие подборки литературы</a></p></li> -<li><p><a class="reference internal" href="#id37" id="id90">Почтовые рассылки и сообщества</a></p></li> +<li><p><a class="reference internal" href="#sitemap" id="id57">Sitemap</a></p></li> </ul> </li> -<li><p><a class="reference internal" href="#emacsway-reference-applications" id="id91">Эталонные демонстрационные приложения</a></p></li> +<li><p><a class="reference internal" href="#id22" id="id58">Полезные расширения</a></p></li> +<li><p><a class="reference internal" href="#id23" id="id59">Послесловие</a></p></li> </ul> </li> </ul> </nav> <section id="id3"> -<h2><a class="toc-backref" href="#id40" role="doc-backlink">Предисловие</a></h2> -<p>Классическая ошибка новичков - жажда к знаниям, нетерпеливость. -Обычно это приводит к тому, что, в погоне за количеством, они <a class="reference internal" href="../../soft-skills/planning-in-psychology.html"><span class="doc">надрываются</span></a> (объем знаний, который предстоит освоить, действительно, огромный), осознают невыполнимость желаемого, впадают в депрессию, а затем и в состояние <a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">психологической защиты</a> (мол, "академичность" неуместна на практике), и прекращают развиваться. -Решается эта проблема очень просто - жажда должна быть не к знаниям, а к дисциплине. -А уж дисциплина обязательно приведет к обретению знаний. -Дисциплина - это, своего рода, производная знаний. -Она поддерживает постоянную скорость на пути освоения знаний. -Сперва нужно выработать привычку, а затем привычка будет работать на вас. -Как говорится, сохраняйте порядок, и порядок сохранит вас.</p> -<blockquote> -<div><p>📝 "I'm not a great programmer; I'm just a good programmer with great habits."</p> -<p class="attribution">—Kent Beck at "Refactoring: Improving the Design of Existing Code" 1st edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p> -</div></blockquote> -<p>Достаточно читать по 5 страниц в день. -Тут главное - стабильность. -Пусть будет по чуть-чуть, но постоянно. -Дисциплина - мать победы, говорил А.В. Суворов. -Гнаться за количеством не нужно.</p> -<blockquote> -<div><p>📝 "A little reading goes a long way toward professional advancement. If you read even one -good programming book every two months, roughly 35 pages a week, you'll soon have -a firm grasp on the industry and distinguish yourself from nearly everyone around you."</p> -<p class="attribution">—"Code Complete" by Steve McConnell</p> -</div></blockquote> -<blockquote> -<div><p>📝 "We become authorities and experts in the practical and scientific spheres -by so many separate acts and hours of work. -If a person keeps faithfully busy each hour of the working day, -he can count on waking up some morning to find himself one of the competent -ones of his generation."</p> -<p class="attribution">—William James, cited by Steve McConnell in "Code Complete"</p> -</div></blockquote> -<p>И, желательно, чтобы читаемая книга совпадала с тематикой текущего проекта, чтобы через практику хорошо легла в память. -Я по этой причине часто изменял свой график чтения. -Обычно я читал в параллели 2-3 книги. Одну - планово, другие - по потребностям проекта.</p> -<p>Еще одной ошибкой является неудачный выбор литературы. -Сегодня штампуется много литературы, но далеко не каждая книга достойна внимания. -<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D0%9F%D0%B0%D1%80%D0%B5%D1%82%D0%BE">Закон Парето</a> работает и здесь.</p> -<p>Хорошей вещью для систематизации собственных знаний является написание статей и участие в профессиональных дискуссиях. -Ничто так не систематизирует собственные знания, как попытка объяснить что-то другому человеку. -Вы, конечно, будете периодически ошибаться, но для кристализации знаний это лучше, чем ничего не делать. -К тому же, это хорошо развивает сдержанность в аргументации, что немаловажно.</p> -<p>На первых порах критически важно участвовать в Open Source проектах. -Можно завести свои собственные Open Source проекты. -Можно принимать участие в каких-то существующих проектах с авторитетными комьюнити, которые будут помогать избавляться от ошибок. -В любом случае, не надейтесь на то, что профессиональные проекты предоставят вам достаточную практику для закрепления знаний. -А Open Source проекты - очень даже предоставят. -Я даже считаю, что практика должна предшествовать теории, потому что трудно запомнить какое-то решение, если вам на практике не знакома решаемая проблема.</p> -<blockquote> -<div><p>📝 "Если лечиться по справочнику, то рискуешь умереть от опечатки."</p> -<p class="attribution">—Марк Твен</p> -</div></blockquote> -<p>Потребность в теории должна назреть. -Когда я приступал к теории, то у меня был накоплен уже солидный багаж проблем, решение которых я искал. -Когда я впервые прочитал о мотивации паттерна Bridge, у меня в голове промелькнуло: "так вот, оказывается, как решается та самая проблема". -Когда я читал каталог Code Smells, я частенько вспоминал свой код. -В результате, решения навечно запечатлелись в памяти.</p> -<p>Очень правильно <a class="reference external" href="https://sergeyteplyakov.blogspot.com/2017/02/reading-books-considered-harmful.html">сказал</a> Сергей Тепляков: "Полноценное обучение – это не теория vs. практика. Это комбинация этих вещей, при этом процент одного и другого зависит от человека и изучаемой темы."</p> -<p>Ну и, главное, не впадать в фанатизм. -Засасывает. -Нужно себя уравновешивать другими интересами, семья, спорт, физкультура, шашлыки, друзья, путешествия... -Непредвзятый и свободный взгляд намного важнее изобилия знаний. -Путешествие должно быть на легке, как говорил Кент Бек. -По сути, знания нужны только для того, чтобы избавиться от всего лишнего. -Архитектура - это, на самом деле, наука об ограничениях (т.е. о том, как не надо делать).</p> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +<h2><a class="toc-backref" href="#id25" role="doc-backlink">Почему</a></h2> +<p>Объем информации в современном мире стал достаточно большим, и возникла потребность этим объемом как-то управлять.</p> +<section id="id4"> +<h3><a class="toc-backref" href="#id26" role="doc-backlink">Коллективность</a></h3> +<p>Опыт показал, что высокое качество объемного материала легче достигают <strong>коллективы авторов</strong>, как, например:</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="../../soft-skills/knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">Разрешение конфликтов на почве недостатка знаний</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../soft-skills/planning-in-psychology.html#emacsway-planning-in-psychology"><span class="std std-ref">Психологическое значение планирования</span></a>"</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/">.NET Microservices: Architecture for Containerized .NET Applications</a>" (<a class="reference external" href="https://github.com/dotnet/docs">более 4.5 тыс. форков</a>)</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/">Azure Architecture Center</a> (<a class="reference external" href="https://github.com/MicrosoftDocs/architecture-center">более 1.1 тыс. форков</a>)</p></li> </ul> -</div> +<p>Опыт Microsoft продемонстрировал высокую эффективность распределенных коллективных систем управления знаниями с открытым и неограниченным авторским кругом.</p> +<p>Можно заметить, что некоторые пользователи ведут автономные версии форков, периодически вливая в них главный бранч. +Т.е., пользователи стремятся создавать <strong>собственные пространства знаний</strong>, которые <strong>обогащаются</strong> из других источников и <strong>дистиллируются</strong> от всего лишнего.</p> +<p>Это наводит на мысль - а что, если совместить персональную систему управления знаниями с коллективной? +Вы сами решаете, какими именно своими заметками вы хотите поделиться, а какие вы хотите добавить в свою базу от других авторов.</p> </section> -<section id="id4"> -<h2><a class="toc-backref" href="#id41" role="doc-backlink">Кандидатский минимум</a></h2> <section id="id5"> -<h3><a class="toc-backref" href="#id42" role="doc-backlink">Учимся обучению</a></h3> -<p>Это может показаться немного удивительным, но первая книга будет посвящена не техническим знаниям, а вопросам самоорганизации, управления временем, психологии, методикам работы под стрессом, оцеванию задач по разработке программного обеспечения, вопросам коммуникации и поведению в конфликтных ситуациях, и, самое главное, - науке быть правдивым. -Именно правдивость является важнейшим отличительным признаком настоящего профессионала. -И это не так просто, как может показаться на первый взгляд. -Есть разница между кодером и профессионалом. -И эта книга о том, как стать профессионалом. -Без знаний, изложенных в этой книге, вы просто не сможете изыскать время на самообучение, и список остальных книг вам может просто не понадобиться:</p> -<ul class="simple"> -<li><p>"The Clean Coder" by Robert C. Martin</p></li> -</ul> +<h3><a class="toc-backref" href="#id27" role="doc-backlink">Субъектность</a></h3> +<p>У классических коллективных систем управления знаниями на основе wiki-движков, являющихся единственным носителем инфорации, информация может быть представлена только в единственном виде, а значит, она не может удовлетворять различным потребностям разных пользователей. +Возникает противоречие между между потребностью во множестве представлений информации и единственностью возможного представления информации единичного носителя.</p> +<p>Так же у разных пользователей существует различная потребность в объеме и полноте информации. +Что для одного пользователя представляет ценность, для другого - информационная помеха, затрудняющая навигацию по его подмножеству информации.</p> +<p>Попытка разрешить это противоречие порождает ряд вопросов о модерации, редакционной политике, достижении консенсуса и разрешении противоречий, выработке норм поведения, управлении правами, защите от диверсий в виде уничтожения содержимого или постановки информационных помех. +Все это резко ограничивает возможность применения wiki-движков в качестве персональной системы управления знаниями. +Теряется субъектность пользователя. +Также wiki-движки затруднительно использовать в offline-режиме, особенно с мобильного телефона.</p> +<p>Отдельные попытки решить эти проблемы, и совместить персональную и коллективную системы знаний, осуществляет Notion. +Еще интересней выглядит управление знаниями на основе простых текстовых файлов (чаще всего Markdown или reStructuredText) и системы контроля версий (обычно Git).</p> +<p>Такие средства устраняют противоречие, которое заключается в том, что один экземпляр информации не может соответствовать потребностям множества пользователей. +Каждый пользователь сам устраивает свою базу знаний так, как считает нужным, обогащая её информацией от других пользователей посредством системы контроля версий.</p> +<p>Именно на этой идее и построен данный проект, основная суть которого заключается в том, что <strong>субъектом субъектом знаний в такой моделе является именно пользователь</strong>, в то время, как в большинстве других систем управления знаниями на основе wiki-движков, пользователь является, скорее, объектом системы.</p> +<p>Распределенный подход к хранению знаний избавляет от перечисленных выше проблем - вы сами решаете, чем поделиться, и от кого и что добавить в свою базу знаний. +Можете обогащать статьи других авторов своей собственной информацией, удалять нерелевантную для вас информацию, сохраняя сфокусированность своего внимания, и делиться своими знаниями с другими специалистами, публикуя их в публичных бранчах, закрепив, при этом, свое авторство. +Ваша база знаний не обязана следовать чьим-то чужим точкам зрения. +Все как в реальной жизни.</p> </section> <section id="id6"> -<h3><a class="toc-backref" href="#id43" role="doc-backlink">Изучаем основную используемую технологию</a></h3> -<p>Следующая книга должна быть посвящена основной используемой технологии, т.е. синтаксическим возможностям языка программирования. -Для Python-разработчиков хорошим выбором была бы книга:</p> -<ul class="simple"> -<li><p>"Learning Python" 5th edition by Mark Lutz</p></li> -</ul> -<p>Для Golang интересно выглядят книги:</p> -<ul class="simple"> -<li><p>"Hands-On Software Architecture with Golang. Design and architect highly scalable and robust applications using Go" by Jyotiswarup Raiturkar</p></li> -<li><p>"The Go Programming Language" by Alan A.A. Donovan Google Inc., Brian W. Kernighan Princeton University</p></li> -</ul> -<p>Для Erlang:</p> -<ul class="simple"> -<li><p>"Programming Erlang: Software for a Concurrent World (Pragmatic Programmers)" 2nd edition by Joe Armstrong</p></li> -</ul> -<p>Для frontend-разработчиков, работающих с Angular, имеет смысл обратить внимание на книгу:</p> -<ul class="simple"> -<li><p>"ng-book2. The Complete Book on Angular 6" by Nate Murray, Felipe Coury, Ari Lerner, and Carlos Taborda</p></li> -</ul> +<h3><a class="toc-backref" href="#id28" role="doc-backlink">Психология</a></h3> +<p>Немаловажным является и психологический фактор. +Одно дело, когда человеку нужно представить на суд пользователей информацию, которая будет оцениваться с позиции стандартов коллектива, а другое дело, когда он просто позволяет другим пользователям использовать его персональные заметки. +Снятие психологического барьера ускоряет обмен информацией.</p> </section> <section id="id7"> -<h3><a class="toc-backref" href="#id44" role="doc-backlink">Азбука программирования</a></h3> -<p>Подразумевается что вы уже хорошо знаете синтаксис основного языка программирования. -Но, знание букв еще не делает вас поэтом. -Следующие книги являются азбукой программирования. -Я привожу их в таком порядке, в каком я рекомендую их прочтение:</p> -<ul class="simple"> -<li><p>"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides</p></li> -<li><p>"Patterns of Enterprise Application Architecture" by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford</p></li> -<li><p>"Refactoring: Improving the Design of Existing Code" 1st edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p></li> -<li><p>"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p></li> -<li><p>"Code Complete" 2nd edition by Steve McConnell</p></li> -<li><p>"UML Distilled. A Brief Guide to the Standard Object Modeling Language" 3d edition by Martin Fowler</p></li> -<li><p>"<a class="reference external" href="https://people.apache.org/~fhanik/kiss.html">KISS Principles</a>"</p></li> -</ul> +<h3><a class="toc-backref" href="#id29" role="doc-backlink">Экономия времени</a></h3> +<p>Еще один фактор, который поспособствовал появлению этого проекта, заключается в том, что сегодня человек живет в условиях стесненного времени. +Каждому из нас есть чем поделиться и обогатить коллективные знания, но не у каждого есть время прорабатывать по этой теме статьи. +Именно поэтому короткие заметки стали сегодня так популярны. +В конечном итоге, люди тратят на Telegram (и другие мессенджеры) намного больше времени, чем требуется на написание статей. +Просто в Telegram они делают это короткими интервалами времени.</p> +<p>В Telegram знания хорошо рождаются, но не кристализируются, из-за чего они часто тонут в безорганизованной свалке информации среди океана информационных помех. +Несмотря на факт своего существования, эта информация быстро становится бесполезной в условиях отсутствия навигации. +Возникает потребность комбинировать Telegram с другими формами управления знаниями, и желательно, чтоб эти формы обеспечивали бы как приватный, так и коллективный способ управления знаниями.</p> +<p>Вы, наверное, замечали, как в профессиональных Telegram-чатах молодые ребята регулярно задают один и тот же вопрос. +И если на первый вопрос кто-то из экспертов ответит, то на следующий вопрос "попугайничать" уже никто из экспертов не хочет. +Тогда пытаются отвечать другие малоопытные ребята, и, зачастую, вреда от таких ответов больше, чем пользы. +Через время, отыскать правильный ответ от эксперта становится практически невозможно, так как его становится сложно выявить среди наплодившейся дезинформации.</p> </section> <section id="id8"> -<h3><a class="toc-backref" href="#id45" role="doc-backlink">Учимся быть эффективным</a></h3> -<p>Знаний предыдущих пяти книг достаточно для того, чтобы вы стали работать в разы эффективней. -Но нужно не только знать, а еще и <a class="reference internal" href="../tdd/tdd.html"><span class="doc">уметь быть эффективным на практике</span></a>. -Никто не раскрывает этот вопрос лучше, чем Kent Beck:</p> +<h3><a class="toc-backref" href="#id30" role="doc-backlink">Навигация</a></h3> +<p>Возникло противоречие: там, где можно структурировать, - там не пишут, а там, где пишут, - структурировать нельзя. +Можно ли это противоречие разрешить?</p> +<p>Цель данного проекта заключается в разрешении этого противоречия, путем обеспечения навигации в распределенной коллективной информации коротких сообщений (заметок). +Навигация позволяет повысить реиспользуемость качественных ответов.</p> +<p>Система управления знаниями - это, своего рода, скелет, на который налипают знания. +Без такого скелета знания просто тонут в бесструктурном и распределенном океане информационных помех. +Вы, наверное, слышали о таком антипаттерне как "коллекционер знаний" - это когда информации накапливается много, но найти что-нибудь в этом мессиве становится нереально.</p> +<p>Навигация обеспечивается комплексом средств:</p> <ul class="simple"> -<li><p>"Test-Driven Development By Example" by Kent Beck</p></li> +<li><p>Полнотекстовый offline поиск с морфологией.</p></li> +<li><p>Древовидная структуризация контента. Причем, деревьев может быть множество, и они могут пересекаться между собой. Деревья навигации не обязаны воспроизводить файловую структуру документов.</p></li> +<li><p>Алфавитный указатель (тегирование/индексирование).</p></li> +<li><p>Перекрестные, и даже кросс-проектные, ссылки.</p></li> +<li><p>Навигация по структурированному содержанию страницы.</p></li> </ul> </section> <section id="id9"> -<h3><a class="toc-backref" href="#id46" role="doc-backlink">Учимся делать команду эффективной</a></h3> -<p>Следующий барьер - умение сделать команду эффективной. -Вы не сможете быть эффективным в изоляции, поскольку ваша эффективность определяется качеством кодовой базы, а она разрабатывается всей командой. -Или вы сделаете команду эффективной, или ваша эффективность так и останется мечтательством. -Опять же, лучший наставник в этих вопросах - Kent Beck:</p> -<ul class="simple"> -<li><p>"Extreme Programming Explained" 1st edition by Kent Beck</p></li> -</ul> -<p>На данном этапе, этой книги достаточно. -Обратите внимание, я советую именно первое издание, так как оно лучше раскрывает смысл и назначение <a class="reference internal" href="../sdlc/models/agile/agile.html#emacsway-agile-development-essence"><span class="std std-ref">Agile разработки</span></a>.</p> +<h3><a class="toc-backref" href="#id31" role="doc-backlink">Интеграция</a></h3> +<p>Благодаря RSS-каналу, новые сообщения можно легко отражать в Telegram-channel или в другие мессенджеры, например, в Mattermost, посредством ботов и плагинов к мессенджерам. +Таким образом достигается и цель уведомления о новых сообщениях, и сохраняется навигация по сообщениям.</p> </section> <section id="id10"> -<h3><a class="toc-backref" href="#id47" role="doc-backlink">Изучаем операционную систему</a></h3> -<p>Вот по операционным системам я мало что могу посоветовать, так как низкоуровневым программированием я практически не занимался. -Но вам обязательно нужно получить представление о том, как работают регистры процессора, память, и как управлять операционной системой.</p> -<p>Я в свое время читал эти книги (к сожалению, сегодня они устарели):</p> -<ul class="simple"> -<li><p>"The Linux® Kernel Primer: A Top-Down Approach for x86 and PowerPC Architectures" by Claudia Salzberg Rodriguez, Gordon Fischer, Steven Smolski</p></li> -<li><p>"Digital computers and microprocessors" by Aliyev / "Цифровая вычислительная техника и микропроцессоры" М.М.Алиев</p></li> -</ul> -<p>А вот этот справочник у меня всегда под рукой:</p> -<ul class="simple"> -<li><p>"Unix and Linux System Administration Handbook" 5th edition by Evi Nemeth, Garth Snyder, Trent R. Hein, Ben Whaley, Dan Mackin</p></li> -</ul> +<h3><a class="toc-backref" href="#id32" role="doc-backlink">Реализация</a></h3> +<p>Система представляет собой минималистичный набор принципов и соглашений, реализованный на Open Source системе документирования <a class="reference external" href="https://www.sphinx-doc.org/">Sphinx-doc</a> и использущий reStructuredText и Markdown форматы разметок. +Sphinx-doc предоставляет и тегирование/индексирование (директива "<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#index-generating-markup">index</a>"), и перекрестные ссылки, и Table of Content (ToC, директива "<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#table-of-contents">toctree</a>"), и неограниченную иерархию файлов, и перекрестные связи между иерархиями файлов и иерархиями ToC, и клиентский полнотекстовый поиск (средствами JS браузера), и <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/extensions/todo.html">TODO</a>-листы, и RSS (в виде стороннего расширения), и подсветку синтаксиса языков программирования, и расширяемость с большим количеством готовых к использованию расширений.</p> +<p>Критически важной является <a class="reference internal" href="#using-dckms-on-mobile-devices"><span class="std std-ref">возможность работать offline на мобильном устройстве</span></a> (используя, при этом, полнотекстовый поиск с морфологией).</p> </section> <section id="id11"> -<h3><a class="toc-backref" href="#id48" role="doc-backlink">Изучаем основы алгоритмов и структур данных</a></h3> -<p>Алгоритмы хоть и используются редко в прикладной разработке (если вы только не пишете поисковые системы, системные утилиты, языки программирования и операционные системы, системы маршрутизации, биржевые анализаторы и т.п.), но знать хотя бы базовые основы необходимо. -Существует книга, которая за двести с небольшим страниц может дать эти базовые основы в легкой и популярной форме:</p> -<ul class="simple"> -<li><p>"Algorithms Unlocked" 3d edition by Thomas H. Cormen</p></li> -</ul> -<p>Данная книга не акцентируется на математике, что, с одной стороны, облегчает освоение материала, но, с другой стороны, оставляет невосполненным важный аспект профессиональных знаний. -К счастью, существует книга, которая обеспечивает легкий вход в алгоритмы, включая их математический анализ:</p> -<ul class="simple"> -<li><p>"Introduction to the Design and Analysis of Algorithms" 3d edition by A.Levitin</p></li> -</ul> -<p>При чтении этой книги могут возникать вопросы справочного характера по математике, ответы на которые можно найти в приложении этой книги (Appendix A: Useful Formulas for the Analysis of Algorithms, Appendix B: Short Tutorial on Recurrence Relations), в математических справочниках (например, М.Я. Выгодского, А.А. Гусака) или в справочном разделе по математике "VIII Appendix: Mathematical Background" книги "Introduction to Algorithms" 3d edition by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein.</p> -<p>В качестве минималистичного ликбеза по теоретическим основам может неплохо подойти книга:</p> -<ul class="simple"> -<li><p>"Computer Science Distilled" by Wladston Ferreira Filho</p></li> -</ul> -<p>Она содержит минималистичные основы математики (логика, комбинаторика, вероятность), алгоритмы и структуры данных, основы Баз Данных (RDBMS, NoSQL), описание Парадигм Программирования и основы архитектуры железа.</p> -</section> -<section id="id12"> -<h3><a class="toc-backref" href="#id49" role="doc-backlink">Изучаем математику</a></h3> -<p>Существует монументальная книга, которую стоит упомянуть отдельно (обратите внимание на фамилии авторов, которые в представлении не нуждаются). -Чтобы не тормозить общий процесс обучения, ее лучше читать в параллельно-фоновом режиме. -К тому же математические знания следует всегда поддерживать в актуальном состоянии, и регулярно освежать их в голове в фоновом режиме.</p> -<ul class="simple"> -<li><p>"Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik</p></li> -</ul> -<p>Эта книга дает прекрасную математическую базу для функционального программирования. -И хорошо заходит в сочетании с "The Art Of Computer Programming" Volume 1 3d edition by Donald Knuth, поскольку у них многие темы пересекаются и раскрываются с разных точек зрения, что дает полноту понимания. -Справочник математических нотаций в конце книги нередко оказывается полезным.</p> -<p>Книги по математике и алгоритмам - сложные книги, и я хотел бы поделиться одним советом, который я услышал еще в студенчестве. -Если что-то непонятно - прочитай три раза:</p> +<h3><a class="toc-backref" href="#id33" role="doc-backlink">Влияние на качество обучения</a></h3> +<p>Вот что пишет Евгений Пешков, основатель российского DDD-сообщества, руководитель в ЦИАН:</p> +<blockquote> +<div><p>Летом 2020 я проходил курс по Системному мышлению Левенчука. Анатолий с первых же занятий всячески рекомендует "мышление письмом".</p> +<p>Что это? +Мышление письмом подразумевает создание конспектов занятий, статей, книг. +Но не просто переписывание слов автора, а своё собственное понимание пройденного.</p> +<p>Почему это важно?</p> <ol class="arabic simple"> -<li><p>Первый раз просто прочитай, оставив попытки что-то понять, - нужно просто получить обзорность материала.</p></li> -<li><p>Второй раз прочитай уже пытаясь слегка вникать.</p></li> -<li><p>И третий раз прочитай уже вникая полностью.</p></li> +<li><p>Лучше запоминаем. Это происходит из-за того, что мы прогоняем через себя, через внутренний диалог, через механическую память, через визуальный образ собственных слов.</p></li> +<li><p>Лучше понимаем. Когда мы просто мыслим, наши мысли могут быть недостаточно строго сформулированы, могут обрываться, состоять из полуобразов. Но даже с такими несформировавшимися мыслями у нас может быть ложное ощущение понятности. Когда же мы пишем - мы обязаны четко сформулировать тезисы и сложить их в определенном порядке.</p></li> +<li><p>Можно вернуться и доосмыслить. У нас остается артефакт, пригодный для дальнейшей проработки.</p></li> +<li><p>Наше знание становится отчуждаемым. Мы легко можем запостить наши мысли в телеграм или отправить другу.</p></li> </ol> +<p>Сложно взять и начать записывать, и как одна из рекомендаций в курсе была указана книга "<a class="reference external" href="https://www.goodreads.com/book/show/34507927-how-to-take-smart-notes">How to Take Smart Notes</a>". +И в этой книге есть еще классный поинт: если мы привыкаем делать заметки, то нам становится проще писать в целом. +Тут срабатывает привычка, но кроме этого, как я и указывал ранее, у нас накапливается определенное количество артефактов, которые мы можем легко переиспользовать.</p> +<p>Источник: <a class="reference external" href="https://t.me/dddevotion/176">https://t.me/dddevotion/176</a></p> +</div></blockquote> +<p>На меня, в свое время, произвела сильное впечатление небольшая, и уже не самая молодая, книжечка "Как читать книги" / Поварнин Сергей, которую можно прочесть всего за один день. +Скачать можно <a class="reference external" href="https://royallib.com/book/povarnin_s/kak_chitat_knigi.html">здесь</a> или <a class="reference external" href="https://m.vk.com/wall-56611080_127534">здесь</a>. +Эту книжечку сложно переоценить - она на вес золота.</p> +<p>Также нужно упомянуть про особое значение возможности применять принципы <a class="reference internal" href="#zettelkasten"><span class="std std-ref">Zettelkasten</span></a> для запоминания информации и легкой навигации по ней.</p> +<p>Ну и, раз была затронута тема, не лишне будет упомянуть "A Mind for Numbers: How to Excel at Math and Science" by Barbara Ann Oakley, перевод: "Думай как математик. Как решать любые проблемы быстрее и эффективнее." / Барбара Оакли.</p> +</section> +<section id="id12"> +<h3><a class="toc-backref" href="#id34" role="doc-backlink">Легкость переключения контекста</a></h3> +<p>Специалисты, не работающие с информацией письменно, нередко испытывают затруднения с частым переключением контекста на работе. +Сложность восстанавления в памяти исходного контекста снижает качество решений. +В то же время, у специалистов, работающих с информацией письменно, таких проблем обычно не возникает.</p> +<p>Если выработать привычку записывать все в электронные заметки, прежде чем эта информация отразится в каком-либо еще источнике, то будет единый источник истины, который всегда под рукой, даже offline. +Вначале требуется определенное усилие воли и самодисциплина, чтобы выработать привычку все записывать, но результат проявляется очень быстро, ведь записываем мы один раз, а обращаемся к записанному много раз. +А если к записанному предоставить доступ команде, то это кратно повысит эффективность реиспользования информации и экономию времени.</p> +</section> </section> <section id="id13"> -<h3><a class="toc-backref" href="#id50" role="doc-backlink">Учимся архитектуре</a></h3> -<p>Теперь можно приступить и к архитектуре:</p> -<ul class="simple"> -<li><p>"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p></li> -</ul> +<h2><a class="toc-backref" href="#id35" role="doc-backlink">Порядок использования</a></h2> +<p>Система работает следующим образом:</p> +<ol class="arabic"> +<li><p>Создайте форк <a class="reference external" href="https://github.com/emacsway/dckms-template">репозитария</a>.</p></li> +<li><p>Перейдите в приватный бранч "private".</p></li> +<li><p>Свои приватные заметки ведите в пространстве имен "private" (<code class="docutils literal notranslate"><span class="pre">/private</span></code>, <code class="docutils literal notranslate"><span class="pre">_html_extra/private</span></code>).</p></li> +<li><p>Создайте свой публичный бранч, например, "ivan.ivanov". Приватные директории сразу же внесите в файл ".gitignore" в этом бранче.</p></li> +<li><p>Создайте пространство имен для своих публичных заметок, которыми вы хотите поделиться, например, "ivan.ivanov" (<code class="docutils literal notranslate"><span class="pre">/ivan.ivanov</span></code>, <code class="docutils literal notranslate"><span class="pre">_html_extra/ivan.ivanov</span></code>). Таким образом вы облегчите читателям навигацию по вашим заметкам и сохраните очевидность авторства за собой (можно еще использовать директиву "<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-sectionauthor">sectionauthor</a>"). Создание персонального пространства имен необходимо еще и потому, что древовидное устройство файловой системы сложно унифицировать для всех авторов - у каждого автора есть свое видение на классификацию его материала. Благодаря гибкости директивы "<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#table-of-contents">toctree</a>", вы легко можете включать в дерево своего содержания поддеревья или страницы других авторов.</p></li> +<li><p>Тегируйте свой материал с помощью директивы "<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#index-generating-markup">index</a>"</p></li> +<li><p>С помощью директивы <a class="reference external" href="https://docutils.sourceforge.io/docs/ref/rst/directives.html#include">include</a>, вставляйте одни страницы в другие (полностью или частично, см. options: start-line, start-after, end-line, end-before) для достижения <a class="reference external" href="https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself">DRY</a>. Таким образом вы можете обогащать статьи других авторов, минимзируя исправление оргиниального текста, а также заимствовать текст других авторов в свои статьи.</p></li> +<li><p>Ненужные вам заметки других авторов вы можете удалить в своем приватном бранче. А нужные - добавить, как целиком, так и выборочно, используя <a class="reference external" href="https://git-scm.com/docs/git-cherry-pick">cherry-pick</a>.</p></li> +<li><p>Используя <a class="reference external" href="https://www.uuidgenerator.net/version4">UUID4</a>, создавайте <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#ref-role">перекрестные ссылки</a> между связанными заметками, следуя лучшим практикам <a class="reference internal" href="#zettelkasten"><span class="std std-ref">Zettelkasten</span></a>. Вместо UUID можно использовать префиксирование своих label-names, используя в качестве префикса - пространство имен своих публичных заметок (поскольку заметка может быть перемещена из приватного простанства имен в публичное). Так же можно использовать расширение <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/extensions/autosectionlabel.html">sphinx.ext.autosectionlabel</a> – Allow reference sections using its title (но оно не облегчает изменение локации заметки). И можно даже организовывать ссылки между отдельными проектами, используя директиву <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-seealso">seealso</a> и расширение <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html">sphinx.ext.intersphinx</a>.</p></li> +<li><p>Ведите <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/extensions/todo.html">TODO</a>.</p></li> +<li><p>Создайте Pull Request из своего именного публичного бранча ("ivan.ivanov") в trunk-branch. Может быть множество trunk-бранчей, и, в качестве одного из них, можете использовать <a class="reference external" href="https://github.com/dckms/system-architecture">этот</a>. Trunk-branch можно сравнить с шиной событий в Event Sourcing системе.</p></li> +<li><p>Когда вы делитесь своим контентом в публичном пространстве, важно понимать, что он может оказаться доступным в интернете на других доменах. Чтобы сохранить поисковый траффик за оригинальным адресом предоставляемых страниц, вначале каждой такой страницы используйте <a class="reference external" href="https://www.sphinx-doc.org/en/master/development/theming.html#use-custom-page-metadata-in-html-templates">custom page metadata</a> <code class="docutils literal notranslate"><span class="pre">canonical-url</span></code>:</p> +<blockquote> +<div><div class="highlight-default notranslate"><div class="highlight"><pre><span/><span class="p">:</span><span class="n">canonical</span><span class="o">-</span><span class="n">url</span><span class="p">:</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">my</span><span class="o">-</span><span class="n">domain</span><span class="o">.</span><span class="n">ru</span><span class="o">/</span><span class="n">my</span><span class="o">-</span><span class="n">path</span> +</pre></div> +</div> +<p>или <code class="docutils literal notranslate"><span class="pre">canonical-base-url</span></code> (без закрывающего слэша):</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span/><span class="p">:</span><span class="n">canonical</span><span class="o">-</span><span class="n">base</span><span class="o">-</span><span class="n">url</span><span class="p">:</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">my</span><span class="o">-</span><span class="n">domain</span><span class="o">.</span><span class="n">ru</span> +</pre></div> +</div> +<p>При этом не следует использовать <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_baseurl">html_baseurl</a> или <a class="reference external" href="https://alabaster.readthedocs.io/en/latest/customization.html#theme-options">html_theme_options["canonical_url"]</a>.</p> +</div></blockquote> +</li> +<li><p>Стройте свою распределенную коллективную базу знаний.</p></li> +</ol> +<p>Можно добавить, что GitHub планирует добавить <a class="reference external" href="https://github.com/isaacs/github/issues/629">поддержку cherry-pick в свой web-интерфейс</a>, а в <a class="reference external" href="https://github.blog/2021-03-30-github-desktop-now-supports-cherry-picking/">Desktop-client она уже реализована</a>. +А вот GitLab уже реализовал <a class="reference external" href="https://docs.gitlab.com/ee/user/project/merge_requests/cherry_pick_changes.html">поддержку cherry-pick в web-интерфейсе</a>.</p> </section> -<section id="id14"> -<h3><a class="toc-backref" href="#id51" role="doc-backlink">Изучаем распределенные системы</a></h3> +<section id="html"> +<h2><a class="toc-backref" href="#id36" role="doc-backlink">Как собрать html</a></h2> +<ol class="arabic simple"> +<li><p>Если не установлен Python, то <a class="reference external" href="https://docs.python.org/3/installing/index.html">установите его</a>.</p></li> +<li><p>Установите зависимости. Для этого, из корневой директории проекта выполните команду: <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">-r</span> <span class="pre">requirements.freeze.txt</span></code></p></li> +<li><p>Отредактируйте файл conf.py, подробности смотрите в <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/configuration.html">документации</a>.</p></li> +<li><p>Произведите сборку: <code class="docutils literal notranslate"><span class="pre">make</span> <span class="pre">html</span></code> или <code class="docutils literal notranslate"><span class="pre">sphinx-build</span> <span class="pre">-D</span> <span class="pre">language=ru</span> <span class="pre">-b</span> <span class="pre">html</span> <span class="pre">.</span> <span class="pre">_build</span></code> или <code class="docutils literal notranslate"><span class="pre">docker</span> <span class="pre">build</span> <span class="pre">-t</span> <span class="pre">sphinx_image</span> <span class="pre">.</span> <span class="pre">&amp;&amp;</span> <span class="pre">docker</span> <span class="pre">run</span> <span class="pre">-v</span> <span class="pre">$(pwd):/sphinxtechnicalwriting</span> <span class="pre">sphinx_image</span> <span class="pre">make</span> <span class="pre">html</span></code></p></li> +<li><p>Локальный запуск: <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">http.server</span></code></p></li> +<li><p>Подробнее <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/quickstart.html">здесь</a>.</p></li> +</ol> +<p>Так же существует возможность собрать PDF-файл или электронную книгу EPUB.</p> +</section> +<section id="zettelkasten"> +<span id="id14"/><h2><a class="toc-backref" href="#id37" role="doc-backlink">О Zettelkasten</a></h2> <ul class="simple"> -<li><p>"NoSQL Distilled. A Brief Guide to the Emerging World of Polyglot Persistence." by Pramod J. Sadalage, Martin Fowler</p></li> -<li><p>"Building Microservices. Designing Fine-Grained Systems" 2nd edition by Sam Newman</p></li> -<li><p>"<a class="reference external" href="http://ksat.me/a-plain-english-introduction-to-cap-theorem">A plain english introduction to CAP Theorem</a>" (<a class="reference external" href="https://habr.com/ru/post/130577/">Russian</a>) by Kaushik Sathupadi</p></li> -<li><p>"<a class="reference external" href="http://ksat.me/map-reduce-a-really-simple-introduction-kloudo">Map Reduce: A really simple introduction</a>" by Kaushik Sathupadi</p></li> -<li><p>"<a class="reference external" href="https://www.allthingsdistributed.com/2008/12/eventually_consistent.html">Eventually Consistent - Revisited</a>" by Werner Vogels</p></li> -<li><p>"<a class="reference external" href="http://book.mixu.net/distsys/">Distributed systems: for fun and profit</a>" (2013). An introduction to distributed systems. (<a class="reference external" href="https://github.com/mixu/distsysbook">source code</a>)</p></li> -<li><p>"<a class="reference external" href="https://martin.kleppmann.com/2020/11/18/distributed-systems-and-elliptic-curves.html">Lecture notes (PDF) (including exercises)</a>" by Martin Kleppmann (<a class="reference external" href="https://www.cl.cam.ac.uk/teaching/2021/ConcDisSys/dist-sys-notes.pdf">download</a>, <a class="reference external" href="https://github.com/ept/dist-sys">source code</a>, <a class="reference external" href="https://www.youtube.com/playlist?list=PLeKd45zvjcDFUEv_ohr_HdUFe97RItdiB">video</a>)</p></li> -<li><p>"<a class="reference external" href="https://github.com/ept/ddia-references">Literature references for "Designing Data-Intensive Applications"</a>" by Martin Kleppmann</p></li> -<li><p>"<a class="reference external" href="https://crdt.tech/">Resources and community around CRDT technology - papers, blog posts, code and more.</a>" by Martin Kleppmann (<a class="reference external" href="https://github.com/ept/crdt-website">source code</a>)</p></li> +<li><p><a class="reference external" href="https://zettelkasten.de/posts/overview/">Zettelkasten</a></p></li> +<li><p><a class="reference external" href="https://zettelkasten.de/introduction/">The Introduction to the Zettelkasten Method</a></p></li> +<li><p><a class="reference external" href="https://habr.com/ru/post/509756/">Как я веду Zettelkasten в Notion уже год: стартовый набор и полезные трюки</a></p></li> +<li><p><a class="reference external" href="https://habr.com/ru/post/508672/">Zettelkasten: как один немецкий учёный стал невероятно продуктивным</a></p></li> </ul> +<p>То, что Niklas Luhmann <a class="reference external" href="https://vas3k.club/post/3040/">сделал</a> на простых бумажных карточках, можно сделать и на Sphinx-doc.</p> </section> <section id="id15"> -<h3><a class="toc-backref" href="#id52" role="doc-backlink">Изучаем распределенные системы. Углубляем навыки.</a></h3> -<p>Книг по этой теме предстоит прочитать слишком много. -Вряд-ли ваша работа будет ждать, пока вы прочитаете их все. -К счастью, сообщество .NET разработчиков подготовило краткий справочник, который заменит вам прочтение десятка книг:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/index">.NET Microservices: Architecture for Containerized .NET Applications</a>" edition v2.2.1 (<a class="reference external" href="https://aka.ms/microservicesebook">mirror</a>) by Cesar de la Torre, Bill Wagner, Mike Rousos</p></li> -</ul> -<p>К этой книге существует эталонное приложение, которое наглядно демонстрирует практическое применение изложенной в книге информации:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers">https://github.com/dotnet-architecture/eShopOnContainers</a> (CQRS, DDD, Microservices)</p></li> -</ul> -<p>Еще одно хорошее краткое руководство от Microsoft:</p> +<h2><a class="toc-backref" href="#id38" role="doc-backlink">Философия</a></h2> +<p>Основные принципы системы:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/">Building microservices on Azure</a>"</p></li> +<li><p>минимизация рисков и внешних зависимостей (от конкретного типа текстового редактора, вендора)</p></li> +<li><p>минимализм</p></li> +<li><p>неограниченная расширяемость</p></li> +<li><p>автономность</p></li> +<li><p>субъектность пользователя и полный контроль над информацией</p></li> +<li><p>распределенность и коллективность</p></li> +<li><p>свободное обогащение и дистилляция информации</p></li> </ul> -<p>И можно сюда включить еще и книгу:</p> +</section> +<section id="id16"> +<h2><a class="toc-backref" href="#id39" role="doc-backlink">Близкие по духу системы</a></h2> +<section id="obsidian"> +<h3><a class="toc-backref" href="#id40" role="doc-backlink">Obsidian</a></h3> +<blockquote> +<div><p>In our age when cloud services can shut down, get bought, or change privacy policy any day, the last thing you want is proprietary formats and data lock-in.</p> +<p>With Obsidian, your data sits in a local folder. Never leave your life's work held hostage in the cloud again.</p> +<p>Plain text Markdown also gives you the unparalleled interoperability to use any kind of sync, encryption, or data processing that works with plain text files.</p> +<p class="attribution">—<a class="reference external" href="https://obsidian.md/">https://obsidian.md/</a></p> +</div></blockquote> +</section> +<section id="neuron-zettelkasten"> +<h3><a class="toc-backref" href="#id41" role="doc-backlink">Neuron Zettelkasten</a></h3> +<p><a class="reference external" href="https://github.com/roalyr/zettelkasten">Zettelkasten</a> - a template for a Zettelkasten based on markdown files.</p> +<blockquote> +<div><p>Neuron was designed with these criteria in mind:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-US/previous-versions/msp-n-p/jj554200(v=pandp.10)">CQRS Journey</a>" by Dominic Betts, Julián Domínguez, Grigori Melnik, Fernando Simonazzi, Mani Subramanian</p></li> +<li><p>Future-proof: store notes locally1 as plain-text (Markdown) files</p></li> +<li><p>Not tied2 to a single text editor</p></li> +<li><p>Statically generated web site, for browsing and publishing on the web</p></li> +<li><p>Remain as simple to use as possible, whilst being feature-rich via Plugins</p></li> </ul> -<p>К ней также существует демонстрационное приложение:</p> +<p class="attribution">—<a class="reference external" href="https://neuron.zettel.page/philosophy">https://neuron.zettel.page/philosophy</a></p> +</div></blockquote> +<p>Neuron Zettelkasten может представлять интерес для тех, кто предпочитает минимизацию внешних зависимостей, минимализм и неограниченность:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://github.com/microsoftarchive/cqrs-journey">https://github.com/microsoftarchive/cqrs-journey</a> (Event Sourcing, SAGA transactions)</p></li> +<li><p><a class="reference external" href="https://neuron.zettel.page/philosophy">https://neuron.zettel.page/philosophy</a></p></li> +<li><p><a class="reference external" href="https://neuron.zettel.page/tutorial">https://neuron.zettel.page/tutorial</a></p></li> +<li><p><a class="reference external" href="https://srid.github.io/neuron-template/README">https://srid.github.io/neuron-template/README</a></p></li> +<li><p><a class="reference external" href="https://github.com/srid/neuron">https://github.com/srid/neuron</a></p></li> +<li><p><a class="reference external" href="https://github.com/srid/neuron-template">https://github.com/srid/neuron-template</a></p></li> </ul> -<p>Оригинальная статья "<a class="reference external" href="https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf">SAGAS</a>" by Garcia-Molina, Kenneth Salem (<a class="reference external" href="https://dl.acm.org/doi/10.1145/38713.38742">копия</a>).</p> +<p><a class="reference external" href="https://lobste.rs/s/kydg6q/neuron_0_4_zettelkasten_note_management#c_me2hhh">Сравнение Neuron Zettelkasten и Sphinx-doc</a>.</p> +</section> +<section id="antora"> +<h3><a class="toc-backref" href="#id42" role="doc-backlink">Antora</a></h3> +<p><a class="reference external" href="https://antora.org/">Antora</a> - the multi-repository documentation site generator for tech writers who writing in <a class="reference external" href="https://asciidoc.org/">AsciiDoc</a>.</p> +</section> +<section id="gitjournal"> +<h3><a class="toc-backref" href="#id43" role="doc-backlink">GitJournal</a></h3> +<blockquote> +<div><p>Compatible with your favorite Desktop Apps. GitJournal aims to be extremely configurable and work with your favorite apps. The idea is to not build another silo and instead integrate into your existing workflow.</p> +<p>No two people are the same...</p> +<p>Multiple Editors. All your notes are stored in Markdown. However you can edit the notes in many different ways depending on the task.</p> +<p>100% Open Source. GitJournal will always be completely Open Source. Join the community and help us build your ideal note taking app.</p> +<p class="attribution">—<a class="reference external" href="https://gitjournal.io/">https://gitjournal.io/</a></p> +</div></blockquote> +<blockquote> +<div><p>Why create another Note Taking App? There are many Note taking apps on the desktop, but the mobile space is lacking good note taking apps which give you control over your data and operate with open protocols.</p> +<p class="attribution">—<a class="reference external" href="https://gitjournal.io/support/">https://gitjournal.io/support/</a></p> +</div></blockquote> </section> -<section id="ddd"> -<h3><a class="toc-backref" href="#id53" role="doc-backlink">Изучаем DDD</a></h3> -<p>Начинать я рекомендовал бы с прекрасного краткого руководства:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.oreilly.com/library/view/what-is-domain-driven/9781492057802/">What Is Domain-Driven Design?</a>" by Vladik Khononov</p></li> -</ul> -<p>Или с более новой книги этого же автора:</p> -<ul class="simple"> -<li><p>"Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy" 1st Edition by Vlad Khononov</p></li> -</ul> -<p>Затем приступить к классике:</p> -<ul class="simple"> -<li><p>"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p></li> -<li><p>"<a class="reference external" href="https://kalele.io/books/">Implementing Domain-Driven Design</a>" by Vaughn Vernon</p></li> -</ul> -<p>Существуют краткие изложения этих двух книг по DDD.</p> -<p>Краткие изложения "Domain-Driven Design" by Eric Evans:</p> +<section id="popular-static-site-generators"> +<span id="id17"/><h3><a class="toc-backref" href="#id44" role="doc-backlink">Статические генераторы сайтов</a></h3> +<p>Существует целый класс инструментов, предназначенных для генерации сайта +(блога, документации или информационной страницы) из исходных материалов +в текстовых файлах в markdown, reStructuredText и других аналогичных +форматах. Часто генераторы сайтов поддерживают дополнительную разметку +(shortcodes), которая упрощает вставку диаграмм, формул, сносок, ссылок +на твиты, видео и других элементов.</p> +<p>Наиболее известные из cтатических генераторов сайтов - <a class="reference external" href="https://gohugo.io">Hugo</a> (написан +на Go, распространяется как бинарный исполняемый файл, поддерживает +<a class="reference external" href="https://gohugo.io/content-management/formats/">множество форматов</a> разметки) и <a class="reference external" href="https://github.com/jekyll/jekyll">Jekyll</a> +(требует установки Ruby). Так, например, страницы для представления +markdown файлов на Github Pаges обрабатываются Jekyll.</p> +<p>Есть группа генераторов на JavaScript, как связанная с конкретными +фреймворками (Gastby, Next, Nuxt, VuePress), так и самостоятельных +(Hexo, Eleventy и другие). На Python написаны sphinx, mkdocs, pelican и +другие. +На Ruby можно добавить еще Middleman.</p> +<p>У многих генераторов есть темы оформления, связанные с документацией, +например, очень красивый дизайн у <a class="reference external" href="https://squidfunk.github.io/mkdocs-material/">mkdocs-material</a>, <a class="reference external" href="https://getdoks.org/">doks</a>, <a class="reference external" href="https://github.com/google/docsy">Docsy</a> +для Hugo, а также у <a class="reference external" href="https://github.com/pmarsceill/just-the-docs">just-the-docs</a> и <a class="reference external" href="https://github.com/google/docsy">Docsy Jekyll Theme</a> для Jekyll.</p> +<p>Ряд статических генераторов нацелены преимущественно на "книжный" формат +представления документов c оглавлением слева:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://domainlanguage.com/ddd/reference/">Domain-Driven Design Reference</a>" by Eric Evans</p></li> -<li><p>"<a class="reference external" href="https://www.infoq.com/books/domain-driven-design-quickly/">Domain-Driven Design Quickly</a>"</p></li> +<li><p><a class="reference external" href="https://rust-lang.github.io/mdBook/">mdbook</a> - очень лаконичный и быстрый в развертывании генератор, +используется для документации языка Rust, поставляется бинарным +файлом</p></li> +<li><p><a class="reference external" href="https://jupyterbook.org/intro.html">jupyterbook</a> (Python)</p></li> +<li><p><a class="reference external" href="https://www.bookdown.org/">bookdown</a> (R)</p></li> </ul> -<p>Краткое изложение "Implementing Domain-Driven Design" by Vaughn Vernon:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://kalele.io/books/">Domain-Driven Design Distilled</a>" by V.Vernon</p></li> +<p>Список статических генераторов сайтов по полуярности на Github можно +посмотреть <a class="reference external" href="https://share.streamlit.io/epogrebnyak/ssg-dataset/main">здесь</a> +или <a class="reference external" href="https://jamstack.org/generators/">здесь</a>.</p> +</section> +<section id="id18"> +<h3><a class="toc-backref" href="#id45" role="doc-backlink">Другие интересные проекты</a></h3> +<ul> +<li><p>"<a class="reference external" href="https://github.com/imdone/imdone-core">imdone-core</a>" - Text based kanban processor (<a class="reference external" href="https://github.com/imdone/imdone-core#resources">Why?</a>).</p></li> +<li><p>"<a class="reference external" href="https://github.com/coddx-hq/coddx-alpha">coddx-alpha</a>" - Todo Kanban Board manages tasks and save them as TODO.md - a simple plain text file.</p></li> +<li><p>"<a class="reference external" href="http://www.orgzly.com/">Orgzly</a>" - Outliner for notes and tasks. Notebooks in plain text (<a class="reference external" href="https://github.com/orgzly">Source Code</a>).</p></li> +<li><p>"<a class="reference external" href="https://joplinapp.org/">Joplin</a>" - an open source note taking and to-do application with synchronization capabilities for Windows, macOS, Linux, Android and iOS (<a class="reference external" href="https://github.com/laurent22/joplin/">Source Code</a>).</p></li> +<li><p>"<a class="reference external" href="https://taskjuggler.org/">TaskJuggler</a>" is a modern and powerful, Free and Open Source Software project management tool. Its new approach to project planning and tracking is more flexible and superior to the commonly used Gantt chart editing tools.</p> +<blockquote> +<div><ul> +<li><p><a class="reference external" href="https://github.com/taskjuggler/TaskJuggler">source code</a></p></li> +<li><p><a class="reference external" href="https://github.com/melexis/jira-juggler">импортер из Jira</a></p></li> +<li><p>документация:</p> +<blockquote> +<div><ul class="simple"> +<li><p><a class="reference external" href="https://taskjuggler.org/download/TaskJuggler-Workshop.pdf">https://taskjuggler.org/download/TaskJuggler-Workshop.pdf</a></p></li> +<li><p><a class="reference external" href="https://taskjuggler.org/tj3/manual/index.html">https://taskjuggler.org/tj3/manual/index.html</a></p></li> </ul> -<section id="id16"> -<h4><a class="toc-backref" href="#id54" role="doc-backlink">Статьи на частые вопросы по DDD</a></h4> -<ul class="simple"> -<li><p><a class="reference external" href="https://martinfowler.com/tags/domain%20driven%20design.html">Patterns related to Domain Driven Design</a> by Martin Fowler</p></li> +</div></blockquote> +</li> +<li><p><a class="reference external" href="https://github.com/taskjuggler/TaskJuggler/tree/master/examples">примеры</a></p></li> </ul> -<section id="aggregate-domain-modeling"> -<h5><a class="toc-backref" href="#id55" role="doc-backlink">Aggregate &amp; Domain Modeling</a></h5> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/what-is-domain-logic/">What is domain logic?</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-vs-application-services/">Domain services vs Application services</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-model-isolation/">Domain model isolation</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/email-uniqueness-as-aggregate-invariant/">Email uniqueness as an aggregate invariant</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/how-to-know-if-your-domain-model-is-properly-isolated/">How to know if your Domain model is properly isolated?</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-model-purity-completeness/">Domain model purity vs. domain model completeness</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-model-purity-lazy-loading/">Domain model purity and lazy loading</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-model-purity-current-time/">Domain model purity and the current time</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/immutable-architecture/">Immutable architecture</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/link-to-an-aggregate-reference-or-id/">Link to an aggregate: reference or Id?</a>" by Vladimir Khorikov</p></li> -<li><p>"<a class="reference external" href="https://udidahan.com/2008/02/29/how-to-create-fully-encapsulated-domain-models/">How to create fully encapsulated Domain Models</a>" by Udi Dahan</p></li> -<li><p>"<a class="reference external" href="https://dddcommunity.org/library/vernon_2011/">Effective Aggregate Design</a>" by Vaughn Vernon</p></li> -<li><p>"<a class="reference external" href="https://github.com/ardalis/DDD-NoDuplicates">Designing a Domain Model to enforce No Duplicate Names</a> by Steve Smith</p></li> +</div></blockquote> +</li> </ul> </section> -<section id="cqrs-event-sourcing"> -<h5><a class="toc-backref" href="#id56" role="doc-backlink">CQRS &amp; Event Sourcing</a></h5> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/myth-busting/2020-07-09-overselling-event-sourcing/">Overselling Event Sourcing</a>" by Alexey Zimarev</p></li> -<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/microservices/">Event Sourcing and Microservices</a>" by Alexey Zimarev</p></li> -<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/projections/">Projections in Event Sourcing</a>" by Alexey Zimarev</p></li> -<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/cqrs/">Event Sourcing and CQRS</a>" by Alexey Zimarev</p></li> -<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/entities-as-streams/">Entities as event streams</a>" by Alexey Zimarev</p></li> -<li><p>"<a class="reference external" href="https://zimarev.com/blog/event-sourcing/introduction/">Event Sourcing basics</a>" by Alexey Zimarev</p></li> -<li><p>"<a class="reference external" href="https://eventstore.com/blog/what-is-event-sourcing/">What is Event Sourcing?</a>" by Alexey Zimarev</p></li> -<li><p>"<a class="reference external" href="https://eventstore.com/blog/event-sourcing-and-cqrs/">Event Sourcing and CQRS</a>" by Alexey Zimarev</p></li> -<li><p>"<a class="reference external" href="https://www.eventstore.com/blog/event-immutability-and-dealing-with-change">Event immutability and dealing with change</a>" by Savvas Kleanthous</p></li> -<li><p>"<a class="reference external" href="https://www.eventstore.com/blog/10-problems-that-event-sourcing-can-help-solve-for-you">10 problems that Event Sourcing can help solve for you</a>" by Dennis Doomen</p></li> -<li><p>"<a class="reference external" href="http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/">CQRS, Task Based UIs, Event Sourcing agh!</a>" by Greg Young</p></li> -<li><p>"<a class="reference external" href="https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf">CQRS Documents</a>" by Greg Young</p></li> -<li><p>"<a class="reference external" href="https://leanpub.com/esversioning">Versioning in an Event Sourced System</a>" by Greg Young ("<a class="reference external" href="https://leanpub.com/esversioning/read">читать online</a>", "<a class="reference external" href="https://github.com/luque/Notes--Versioning-Event-Sourced-System">конспект книги</a>")</p></li> -<li><p>"<a class="reference external" href="https://www.researchgate.net/publication/315637858_The_dark_side_of_event_sourcing_Managing_data_conversion">The Dark Side of Event Sourcing: Managing Data Conversion</a>" by Michiel Overeem, Marten Spoor, Slinger Jansen</p></li> -<li><p>"<a class="reference external" href="http://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" by Udi Dahan</p></li> -<li><p>"<a class="reference external" href="https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/">Busting some CQRS myths</a>" by Jimmy Bogard</p></li> -</ul> </section> -<section id="bounded-context-and-microservices"> -<h5><a class="toc-backref" href="#id57" role="doc-backlink">Bounded Context and Microservices</a></h5> +<section id="markdown"> +<h2><a class="toc-backref" href="#id46" role="doc-backlink">Markdown</a></h2> +<p>Markdown - популярный язык разметки. +Приводимые в начале этой страницы архитектурные руководства Microsoft написаны на Markdown.</p> +<p>Вы легко можете использовать Markdown, благодаря расширению <a class="reference external" href="https://myst-parser.readthedocs.io/en/latest/">MyST-Parser</a> (<a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/markdown.html">порядок установки</a>). +Расширение позволяет использовать в Markdown все директивы и роли Sphinx-doc, и является мостом Docutils к <a class="reference external" href="https://github.com/executablebooks/markdown-it-py">markdown-it-py</a>, который поддерживает синтаксис <a class="reference external" href="https://commonmark.org/">CommonMark</a>.</p> +<p>Как вариант, возможна и обычная статическая конвертация Markdown в reStructuredText:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://vladikk.com/2018/01/21/bounded-contexts-vs-microservices/">Bounded Contexts are NOT Microservices</a>" by Vladik Khononov</p></li> -<li><p>"<a class="reference external" href="https://vladikk.com/2018/02/28/microservices/">Tackling Complexity in Microservices</a>" by Vladik Khononov</p></li> -<li><p>"<a class="reference external" href="https://youtu.be/Z0RgR9xIQE4">DDDDD: Bounded Contexts, Microservices, and Everything In Between</a>" by Vladik Khononov</p></li> -<li><p>"<a class="reference external" href="https://kalele.io/reactive-microservices/">Reactive Microservices</a>" by Vaughn Vernon</p></li> -<li><p>"<a class="reference external" href="https://kalele.io/microservices-and-microservices/">Microservices and [Micro]services</a>" by Vaughn Vernon</p></li> -<li><p>"<a class="reference external" href="https://blog.avanscoperta.it/2020/06/11/about-bounded-contexts-and-microservices/">About Bounded Contexts and Microservices</a>" by Alberto Brandolini</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/model/domain-analysis">Using domain analysis to model microservices</a>"</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/model/microservice-boundaries">Identifying microservice boundaries</a>"</p></li> -<li><p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/domains-subdomain-problem-solution-space-in-ddd-clearly-defined-e0b49c7b586c">Domain, Subdomain, Bounded Context, Problem/Solution Space in DDD: Clearly Defined</a>" by Nick Tune</p></li> -<li><p>"<a class="reference external" href="https://medium.com/@kentbeck_7670/monolith-services-theory-practice-617e4546a879">Monolith -&gt; Services: Theory &amp; Practice</a>" by Kent Beck</p></li> -<li><p>"<a class="reference external" href="https://tidyfirst.substack.com/p/tldr-coupling-and-later-cohesion">tl;dr Coupling (&amp; later Cohesion)</a>" by Kent Beck</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/articles/break-monolith-into-microservices.html#GoMacroFirstThenMicro">How to break a Monolith into Microservices :: Go Macro First, then Micro</a>" by Zhamak Dehghani</p></li> +<li><p><a class="reference external" href="https://github.com/miyakogi/m2r">m2r</a> - Markdown to reStructuredText converter</p></li> +<li><p><a class="reference external" href="https://github.com/kata198/mdToRst">mdToRst</a> - tool and library to convert markdown [md] to restructed text [rst] (md to rst).</p></li> </ul> -<p>Tools:</p> +<p>И reStructuredText в Markdown:</p> <ul class="simple"> -<li><p>См. Context Map средствами Archi на диаграмме "Views : Tactical Architecture : Program Level : Context Map" of <a class="reference external" href="https://community.opengroup.org/archimate-user-community/home/-/issues/8">Model</a> used for presentation "Enterprise Architecture Modelling with ArchiMate in an Agile at Scale Programme"</p></li> -<li><p>"<a class="reference external" href="https://github.com/ddd-crew/context-mapping">Context Mapping</a>" by Nick Tune and DDD-Crew</p></li> -<li><p>"<a class="reference external" href="https://github.com/ddd-crew/ddd-starter-modelling-process#organise">Context Map Cheat Sheet</a>" by Nick Tune and DDD-Crew</p></li> -<li><p>"<a class="reference external" href="https://miro.com/app/board/o9J_kqrI8ck=/">Context Map Cheat Sheet (Miro template)</a>" by Nick Tune and DDD-Crew</p></li> -<li><p>"<a class="reference external" href="https://github.com/ddd-crew/context-mapping-quiz">Context Mapping Quiz</a>" by Nick Tune and DDD-Crew</p></li> -<li><p>"<a class="reference external" href="https://miro.com/app/board/o9J_lzWf14U=/">Context Mapping Quiz (Miro template)</a>" by Nick Tune and DDD-Crew</p></li> -<li><p>"<a class="reference external" href="https://contextmapper.org/">ContextMapper - a Modeling Framework for Strategic Domain-driven Design</a>"</p></li> -<li><p>"<a class="reference external" href="https://github.com/ContextMapper">Context Mapper - a Modeling Framework for Strategic Domain-driven Design (DDD) and Service Decomposition (at Github)</a>"</p></li> -<li><p>"<a class="reference external" href="https://github.com/ServiceCutter/ServiceCutter">ServiceCutter - a Structured Way to Service Decomposition</a>"</p></li> -<li><p>"<a class="reference external" href="https://domorobo.to/">DomoRoboto - strategic, rapid, learning for teams using Domain-Driven Design and Architecture modeling</a>" (EventStorming, Bounded Contexts, Context Mapping, Topo Architecture) by Vaughn Vernon</p></li> -<li><p>"<a class="reference external" href="https://speakerdeck.com/mploed/visualizing-sociotechnical-architectures-with-context-maps?slide=56">Visualizing sociotechnical architectures with Context Maps</a>"</p></li> +<li><p><a class="reference external" href="https://rst-to-myst.readthedocs.io/en/latest/">RST-to-MyST</a></p></li> </ul> </section> -<section id="domain-events"> -<h5><a class="toc-backref" href="#id58" role="doc-backlink">Domain Events</a></h5> +<section id="using-dckms-on-mobile-devices"> +<span id="id19"/><h2><a class="toc-backref" href="#id47" role="doc-backlink">Как работать на мобильных устройствах</a></h2> +<section id="android"> +<h3><a class="toc-backref" href="#id48" role="doc-backlink">Как работать на Android</a></h3> <ul class="simple"> -<li><p>"<a class="reference internal" href="../ddd/tactical-design/domain-model/domain-events/domain-events-in-ddd.html"><span class="doc">Domain Events in DDD</span></a>"</p></li> +<li><p>Markor - популярный Markdown-редактор на Android: <a class="reference external" href="https://github.com/gsantner/markor">GitHub</a>, <a class="reference external" href="https://f-droid.org/packages/net.gsantner.markor">F-Droid</a>, <a class="reference external" href="https://play.google.com/store/apps/details?id=net.gsantner.markor">Google Play</a>.</p></li> +<li><p><a class="reference external" href="https://termux.com/">Termux</a> - a unix-like environment for Android, for git and python3.</p></li> +<li><p><a class="reference external" href="https://gitjournal.io/">GitJournal</a> - mobile first Markdown Notes integrated with Git: <a class="reference external" href="https://github.com/GitJournal/GitJournal">GitHub</a>, <a class="reference external" href="https://play.google.com/store/apps/details?id=io.gitjournal.gitjournal&amp;pcampaignid=website">Google Play</a>.</p></li> +<li><p><a class="reference external" href="https://manichord.com/projects/mgit.html">MGit</a> is a Git client Android App: <a class="reference external" href="https://github.com/maks/MGit">GitHub</a>, <a class="reference external" href="https://play.google.com/store/apps/details?id=com.manichord.mgit">Google Play</a>, <a class="reference external" href="https://f-droid.org/packages/com.manichord.mgit">F-Droid</a>.</p></li> </ul> </section> -<section id="api-design"> -<h5><a class="toc-backref" href="#id59" role="doc-backlink">API-Design</a></h5> +<section id="iphone"> +<h3><a class="toc-backref" href="#id49" role="doc-backlink">Как работать на iPhone</a></h3> <ul class="simple"> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/design/api-design">Designing APIs for microservices</a>"</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design">Web API design</a>"</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-implementation">Web API implementation</a>"</p></li> -<li><p>"<a class="reference external" href="https://github.com/Microsoft/api-guidelines">Microsoft REST API Guidelines</a>"</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/graph/query-parameters#filter-parameter">Microsoft Graph API</a>"</p></li> -<li><p>"<a class="reference external" href="https://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part2-url-conventions/odata-v4.0-errata03-os-part2-url-conventions-complete.html#_Toc453752358">OData protocol</a>"</p></li> -<li><p>"<a class="reference external" href="https://google.aip.dev/general">Google REST API Guidelines</a>"</p></li> -<li><p>"<a class="reference external" href="https://cloud.google.com/files/apigee/apigee-web-api-design-the-missing-link-ebook.pdf">Apigee. Web API Design: The Missing Link. Best Practices for Crafting Interfaces that Developers Love.</a>" by Google Cloud</p></li> -<li><p>"<a class="reference external" href="https://microservice-api-patterns.org/">Microservice API Patterns</a>"</p></li> -<li><p>"<a class="reference external" href="https://w3ctag.github.io/capability-urls/">Good Practices for Capability URLs</a>", W3C Draft</p></li> -<li><p>"<a class="reference external" href="https://pages.apigee.com/rs/apigee/images/api-design-ebook-2012-03.pdf">Web API Design - Crafting Interfaces that Developers Love</a>"</p></li> -<li><p>"<a class="reference external" href="https://goodapi.co/blog/rest-vs-graphql">REST vs. GraphQL: A Critical Review</a>"</p></li> -<li><p>"<a class="reference external" href="https://blog.logrocket.com/5-reasons-you-shouldnt-be-using-graphql-61c7846e7ed3/?gi=f67074d77004">5 reasons you shouldn't be using GraphQL</a>" (<a class="reference external" href="https://medium.com/devschacht/esteban-herrera-5-reasons-you-shouldnt-use-graphql-bae94ab105bc">перевод на Русский</a>)</p></li> -<li><p>"<a class="reference external" href="https://www.openapis.org/">OpenAPIs</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.asyncapi.com/">AsyncAPI</a>"</p></li> -<li><p>"<a class="reference external" href="http://www.persvr.org/rql/">Resource Query Language (RQL)</a>"</p></li> -<li><p>"<a class="reference external" href="https://jsonapi.org/">JSON:API</a>"</p></li> -<li><p>"<a class="reference external" href="https://goessner.net/articles/JsonPath/">JSONPath specification - XPath for JSON</a>", "<a class="reference external" href="https://www.baeldung.com/guide-to-jayway-jsonpath">Introduction to JsonPath</a>"</p></li> -<li><p>"<a class="reference external" href="https://netflix.github.io/falcor/starter/what-is-falcor.html">Falcor</a>"</p></li> -<li><p>"<a class="reference external" href="https://microservice-api-patterns.org/cheatsheet">Cheat Sheet a.k.a. API Design Heuristics</a>" - шпаргалка по "Microservices API Patterns"</p></li> -<li><p>"<a class="reference external" href="https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling">REST API Design - Resource Modeling</a>" by Prakash Subramaniam, WhoughtWorks</p></li> -<li><p>"<a class="reference external" href="https://lostechies.com/jimmybogard/2016/06/01/cqrs-and-rest-the-perfect-match/">CQRS and REST: the perfect match</a>" by Jimmy Bogard</p></li> -<li><p>"<a class="reference external" href="https://lostechies.com/jimmybogard/2016/05/12/entities-arent-resources-resources-arent-representations/">Entities aren't resources, resources aren't representations</a>" by Jimmy Bogard</p></li> -<li><p>"<a class="reference external" href="https://blogs.msdn.microsoft.com/maarten_mullender/2004/07/23/crud-only-when-you-can-afford-it-revisited/">CRUD, only when you can afford it (Revisited)</a>" by Maarten Mullender</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/eshoponcontainers-cqrs-ddd-microservice#cqrs-and-ddd-patterns-are-not-top-level-architectures">CQRS and DDD patterns are not top-level architectures</a>"</p></li> -<li><p>"<a class="reference external" href="https://twirl.github.io/The-API-Book/index.ru.html">The API</a>" by Sergey Konstantinov (<a class="reference external" href="https://github.com/twirl/The-API-Book">Source Code</a>, <a class="reference external" href="https://twirl.github.io/The-API-Book/index.html">English</a>)</p></li> +<li><p><a class="reference external" href="https://gitjournal.io/">GitJournal</a> - mobile first Markdown Notes integrated with Git: <a class="reference external" href="https://github.com/GitJournal/GitJournal">GitHub</a>, <a class="reference external" href="https://apps.apple.com/app/gitjournal/id1466519634">App Store</a>.</p></li> +<li><p><a class="reference external" href="https://apps.apple.com/ca/app/working-copy-git-client/id896694807">Working Copy</a> - a Git client.</p></li> +<li><p><a class="reference external" href="https://1writerapp.com/">1Writer</a> - powerful, beautiful Markdown editor for iOS.</p></li> +<li><p><a class="reference external" href="https://ia.net/writer">iA Writer</a> - the simple, award-winning design of iA Writer delivers the essential writing experience.</p></li> +<li><p><a class="reference external" href="https://www.omz-software.com/editorial/">Editorial</a> is a plain text editor for iOS with great Markdown support and powerful automation tools.</p></li> +<li><p><a class="reference external" href="https://tekacs.github.io/editorial-obsidian/">Editorial-obsidian</a> - Editorial scripts for Obsidian (unofficial): <a class="reference external" href="https://github.com/tekacs/editorial-obsidian">GitHub</a>.</p></li> +<li><p><a class="reference external" href="https://brettterpstra.com/ios-text-editors/">iTextEditors</a> - the iOS Text Editor roundup.</p></li> </ul> </section> -<section id="event-storming"> -<h5><a class="toc-backref" href="#id60" role="doc-backlink">Event Storming</a></h5> -<p>By Alberto Brandolini (<a class="reference external" href="https://twitter.com/ziobrando">twitter</a>):</p> -<ul class="simple"> -<li><p>"Domain-Driven Design: The First 15 Years", chapter "Discovering Bounded Contexts with EventStorming" by Alberto Brandolini</p></li> -<li><p>"<a class="reference external" href="http://ziobrando.blogspot.com/2013/11/introducing-event-storming.html">Introducing Event Storming</a>" by Alberto Brandolini</p></li> -<li><p>"<a class="reference external" href="https://blog.avanscoperta.it/2020/03/26/remote-eventstorming/">Remote EventStorming</a>" by Alberto Brandolini</p></li> -<li><p>"<a class="reference external" href="https://blog.avanscoperta.it/2020/03/26/eventstorming-in-covid-19-times/">EventStorming in COVID-19 times</a>" by Alberto Brandolini</p></li> -<li><p>"<a class="reference external" href="https://leanpub.com/introducing_eventstorming">Leanpub: Introducing EventStorming</a>" by Alberto Brandolini</p></li> -<li><p><a class="reference external" href="https://www.eventstorming.com/">EventStorming.com</a></p></li> -</ul> -<p>Others:</p> +</section> +<section id="id20"> +<h2><a class="toc-backref" href="#id50" role="doc-backlink">Интеграция с другими системами</a></h2> +<p>Интеграция с другими системами, сервисами и приложениями возможна в пределах пересекающегося подмножества поддерживаемого Markdown-синтаксиса.</p> +<section id="id21"> +<h3><a class="toc-backref" href="#id51" role="doc-backlink">Интеграция с Obsidian</a></h3> +<p>Идея Obsidian так же построена на локальных Markown-файлах, но с GUI-клиентом (недавно появился и <a class="reference external" href="https://help.obsidian.md/Obsidian/Mobile+app+beta">мобильный клиент</a>). +Теоретически это означает, что вы можете шарить файлы между двумя системами. +На практике я не пробовал это сделать (если попробуете - расскажите, пожалуйста, как получилось).</p> +<p>Зато сообщество Obsidian <a class="reference external" href="https://forum.obsidian.md/t/how-do-i-work-with-obsidian-on-mobile/471">дает много дельных советов</a>, как работать с Markdown-файлами на мобильных устройствах.</p> +<p>А также сообщество Obsidian предоставляет <a class="reference external" href="https://forum.obsidian.md/t/static-site-generators-any-guides/8915">варианты статической генерации</a> помимо помимо <a class="reference external" href="https://obsidian.md/publish">Obsidian Publish</a>.</p> +</section> +<section id="notion"> +<h3><a class="toc-backref" href="#id52" role="doc-backlink">Интеграция с Notion</a></h3> +<p>Notion позволяет экспортировать содержимое в Markdown-файлы. +Теоретически это означает, что вы можете шарить файлы между двумя системами. +На практике я не пробовал это сделать (если попробуете - расскажите, пожалуйста, как получилось). +Массового импорта в Notion я не встречал, но есть варианты, например <a class="reference external" href="https://github.com/Cobertos/md2notion/">Notion.so Markdown Importer</a>.</p> +</section> +<section id="evernote"> +<h3><a class="toc-backref" href="#id53" role="doc-backlink">Интеграция с Evernote</a></h3> +<p>Существуют решения для экспорта заметок из Evernote:</p> <ul class="simple"> -<li><p>"Domain-Driven Design Distilled" by Vaughn Vernon, chapter "Chapter 7 Acceleration and Management Tools :: Event Storming"</p></li> -<li><p>"<a class="reference external" href="https://www.oreilly.com/library/view/what-is-domain-driven/9781492057802/">What is Domain-Driven Design?</a>" by Vladik Khononov, chapter "Chapter 8: Event Storming"</p></li> -<li><p>"<a class="reference external" href="https://ddd-crew.github.io/eventstorming-glossary-cheat-sheet/">EventStorming Glossary &amp; Cheat sheet</a>" by Nick Tune</p></li> -<li><p>"Open Agile Architecture", chapter "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/">19. Event Storming</a>"</p></li> -<li><p>"<a class="reference external" href="http://agilemindset.ru/event-storming-%D0%BD%D0%B0-%D0%BF%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85-%D0%BA%D0%B5%D0%B9%D1%81%D0%B0%D1%85/">Event Storming на практических кейсах</a>", Сергей Баранов (<a class="reference external" href="https://www.youtube.com/watch?v=kJjuTuviZ-E">видео</a>)</p></li> -<li><p>"<a class="reference external" href="https://www.ibm.com/cloud/architecture/architecture/practices/event-storming-methodology-architecture/">Event storming. The workshop focuses on domain events that are generated in the context of a business process or a business application.</a>" by IBM</p></li> -<li><p>"<a class="reference external" href="https://developer.ibm.com/tutorials/reactive-in-practice-1/">Reactive in practice, Unit 1: Event storming the stock trader domain</a>" by Kevin Webber, Dana Harrington</p></li> -<li><p>"<a class="reference external" href="https://www.ibm.com/cloud/architecture/architecture/practices/event-storming-methodology-architecture/">Event storming at ibm.com</a>"</p></li> -<li><p>"<a class="reference external" href="https://developer.ibm.com/tutorials/reactive-in-practice-1/">Event storming &amp; domain-driven design: Reactive in practice — Event storming the stock trader domain — IBM Developer</a>" by Kevin Webber, Dana Harrington</p></li> -<li><p>"<a class="reference external" href="https://ibm-cloud-architecture.github.io/refarch-eda/methodology/event-storming/">Event driven solution implementation methodology</a>"</p></li> -<li><p>"<a class="reference external" href="https://ibm-cloud-architecture.github.io/refarch-kc/implementation/event-storming-analysis/">Container Shipment Analysis</a>" by IBM</p></li> -<li><p>"<a class="reference external" href="https://github.com/ibm-cloud-architecture/refarch-kc">refarch-kc - Implementation solution for container shipment using Event-Driven Architecture</a>" by IBM</p></li> -<li><p>"<a class="reference external" href="https://github.com/mariuszgil/awesome-eventstorming">Awesome EventStorming</a>"</p></li> +<li><p><a class="reference external" href="https://github.com/wormi4ok/evernote2md">evernote2md</a> - convert Evernote .enex files to Markdown.</p></li> +<li><p><a class="reference external" href="https://github.com/claytron/ever2simple">ever2simple</a> - migrate from evernote to simplenote with markdown formatting.</p></li> +<li><p><a class="reference external" href="https://github.com/nicholaskuechler/ever2text">ever2text</a> - convert Evernote exports to text files.</p></li> </ul> -<p>Tools:</p> +</section> +<section id="rss"> +<h3><a class="toc-backref" href="#id54" role="doc-backlink">RSS</a></h3> +<p>Существует несколько коробочных решений RSS-feed для Sphinx:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://domorobo.to/">DomoRoboto - strategic, rapid, learning for teams using Domain-Driven Design and Architecture modeling</a>" (EventStorming, Bounded Contexts, Context Mapping, Topo Architecture) by Vaughn Vernon</p></li> -<li><p><a class="reference external" href="https://github.com/tmorin/plantuml-libs/blob/master/dist/eventstorming/README.md">EventStorming для PlantUML</a></p></li> -<li><p><a class="reference external" href="https://miro.com/">miro.com</a>, см. <a class="reference external" href="https://miro.com/miroverse/category/ideation-and-brainstorming/event-storming">Event Storming template</a></p></li> -<li><dl class="simple"> -<dt>EventStorming для ArchiMate:</dt><dd><ul> -<li><p>C4-Model &amp; Event Storming with ArchiMate, см. "Figure 13: Event Storming Model" of "Agile Architecture Modeling Using the ArchiMate® Language" (см. <a class="reference external" href="https://publications.opengroup.org/g20e">здесь</a>, <a class="reference external" href="https://nicea.nic.in/sites/default/files/Agile_Architecture_Modelling_Using_Archimate.pdf">здесь</a> или <a class="reference external" href="https://nicea.nic.in/download-files.php?nid=247">здесь</a>)</p></li> -<li><p><a class="reference external" href="https://community.opengroup.org/archimate-user-community/home/-/issues/8">Model used by Jean-Baptiste Sarrodie for presentation "Enterprise Architecture Modelling with ArchiMate in an Agile at Scale Programme"</a></p></li> +<li><p><a class="reference external" href="https://github.com/sphinx-contrib/yasfb">https://github.com/sphinx-contrib/yasfb</a></p></li> +<li><p><a class="reference external" href="https://github.com/sphinx-contrib/feed">https://github.com/sphinx-contrib/feed</a></p></li> +<li><p><a class="reference external" href="https://github.com/lsaffre/sphinxfeed">https://github.com/lsaffre/sphinxfeed</a></p></li> +<li><p><a class="reference external" href="https://github.com/prometheusresearch/sphinxcontrib-newsfeed">https://github.com/prometheusresearch/sphinxcontrib-newsfeed</a></p></li> </ul> -</dd> -</dl> -</li> +<p>Смотрите так же <a class="reference external" href="https://github.com/sphinx-doc/sphinx/issues/2">https://github.com/sphinx-doc/sphinx/issues/2</a></p> +<section id="rss-mattermost"> +<h4><a class="toc-backref" href="#id55" role="doc-backlink">Интегация RSS с Mattermost</a></h4> +<ul class="simple"> +<li><p><a class="reference external" href="https://integrations.mattermost.com/rssfeed-plugin/">https://integrations.mattermost.com/rssfeed-plugin/</a></p></li> +<li><p><a class="reference external" href="https://github.com/wbernest/mattermost-plugin-rssfeed">https://github.com/wbernest/mattermost-plugin-rssfeed</a></p></li> </ul> </section> -<section id="modelling"> -<h5><a class="toc-backref" href="#id61" role="doc-backlink">Modelling</a></h5> +<section id="rss-telegram"> +<h4><a class="toc-backref" href="#id56" role="doc-backlink">Интегация RSS с Telegram</a></h4> <ul class="simple"> -<li><p>"<a class="reference external" href="https://github.com/ddd-crew/welcome-to-ddd">Getting started with DDD. Definitions of DDD and fundamental concepts to reduce the learning curve and confusion.</a>" by Nick Tune &amp; DDD-Crew</p></li> -<li><p>"<a class="reference external" href="https://github.com/ddd-crew/ddd-starter-modelling-process">Domain-Driven Design Starter Modelling Process. If you're new to DDD and not sure where to start, this process will guide you step-by-step.</a>" by Nick Tune &amp; DDD-Crew</p></li> -<li><p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/legacy-architecture-modernisation-with-strategic-domain-driven-design-3e7c05bb383f">Legacy Architecture Modernisation With Strategic Domain-Driven Design</a>" by Nick Tune</p></li> +<li><p><a class="reference external" href="https://github.com/BoKKeR/RSS-to-Telegram-Bot">https://github.com/BoKKeR/RSS-to-Telegram-Bot</a></p></li> +<li><p><a class="reference external" href="https://thefeedreaderbot.com/">https://thefeedreaderbot.com/</a> ( <a class="reference external" href="https://telegram.me/TheFeedReaderBot">https://telegram.me/TheFeedReaderBot</a> )</p></li> +<li><p><a class="reference external" href="https://www.integromat.com/en/integrations/rss/telegram">https://www.integromat.com/en/integrations/rss/telegram</a></p></li> +<li><p><a class="reference external" href="https://core.telegram.org/bots/faq">https://core.telegram.org/bots/faq</a></p></li> </ul> -<p>Собственно, этих знаний достаточно для того, чтобы стать зрелым специалистом. -Своего рода - кандидатский минимум. -Далее - порядок чтения может быть произвольным. -Читать весь список необязательно.</p> </section> </section> +<section id="sitemap"> +<h3><a class="toc-backref" href="#id57" role="doc-backlink">Sitemap</a></h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/jdillard/sphinx-sitemap">https://github.com/jdillard/sphinx-sitemap</a></p></li> +</ul> </section> </section> -<section id="id17"> -<h2><a class="toc-backref" href="#id62" role="doc-backlink">Дополнительная литература (на выбор)</a></h2> -<section id="sdlc"> -<h3><a class="toc-backref" href="#id63" role="doc-backlink">SDLC</a></h3> -<section id="single-team-agile"> -<h4><a class="toc-backref" href="#id64" role="doc-backlink">Single-Team Agile</a></h4> +<section id="id22"> +<h2><a class="toc-backref" href="#id58" role="doc-backlink">Полезные расширения</a></h2> <ul class="simple"> -<li><p>"Extreme Programming Explained" 2nd edition by Kent Beck</p></li> -<li><p>"Planning Extreme Programming" by Kent Beck, Martin Fowler</p></li> -<li><p>"More Effective Agile: A Roadmap for Software Leaders" by Steve McConnell</p></li> -<li><p>"Clean Agile: Back to Basics" by Robert C. Martin</p></li> -<li><p>"Agile! The Good, the Hype and the Ugly" by Bertrand Meyer</p></li> -<li><p>"Scrum and XP from the Trenches: How We Do Scrum" 2nd edition by Henrik Kniberg</p></li> -<li><p>"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin</p></li> -<li><p>"Succeeding with Agile: Software Development Using Scrum" by Mike Cohn</p></li> -<li><p>"User Stories Applied: For Agile Software Development" by Mike Cohn</p></li> -<li><p>"Jeff Sutherland's Scrum Handbook" by Jeff Sutherland</p></li> +<li><p><a class="reference external" href="https://sphinxcontrib-needs.readthedocs.io/en/latest/">Sphinx-Needs</a> (<a class="reference external" href="https://github.com/useblocks/sphinxcontrib-needs">source code</a>) - Sphinx-Needs allows the definition, linking and filtering of need-objects, which are by default: requirements, specifications, implementations, test cases.</p></li> +<li><p><a class="reference external" href="https://0x6d64.github.io/sphinx-traceability-example/">Sphinx Traceability plugin</a> (<a class="reference external" href="https://github.com/melexis/sphinx-traceability-extension">source code</a>) - traceability extension for Sphinx documentation generator. Sphinx plugin that allows defining documentation items and relations between those items. Can be used as a requirements management tool for e.g. ISO26262 projects.</p></li> +<li><p><a class="reference external" href="https://github.com/sphinx-contrib/kroki">sphinxcontrib-kroki</a> - Embed PlantUML, DOT, etc. diagrams in your documentation using <a class="reference external" href="https://kroki.io/">Kroki</a>.</p></li> </ul> </section> -<section id="scaled-agile"> -<h4><a class="toc-backref" href="#id65" role="doc-backlink">Scaled Agile</a></h4> +<section id="id23"> +<h2><a class="toc-backref" href="#id59" role="doc-backlink">Послесловие</a></h2> +<p>Проект в состоянии развития. Стабильность пока не гарантируется.</p> +<p>Технически, в отдаленной перспективе можно было бы приспособить под принципы и соглашения системы одно из Open Source приложений для заметок, но у меня такая цель на данный момент не стоит. В таком приложении можно было бы выбирать источники подписок, автоматизировать и облегчить просмотр и принятие коммитов в свою базу знаний, например, если коммит содержит новую заметку, связанную с одной из уже принятых ранее заметок, или является её обновлением, тогда принимать коммит автоматически.</p> +<p>P.S.: Контент проекта представляет собой личную записную книжку и доступен только для учебных и исследовательских целей.</p> +</section> +Wed, 11 Oct 2023 00:00:00 Domain Model Definitionhttps://dckms.github.io/system-architecture/stanislav.bolsun/it/ddd/domain-model/domain-model-definition.html +<span id="stanislav3316-domain-model-definition"/> +<p><em>Автор раздела: Stanislav Bolsun</em></p> +<p>Как показывает моя практика, понимание таких фундаментальных основ как доменная модель, границы доменной модели (ограниченный контекст), могут заметно повысить эффективность (скорость) команды разработки.</p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p>"Scaling Software Agility: Best Practices for Large Enterprises" by Dean Leffingwell</p></li> -<li><p>"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</p></li> -<li><p>"SAFe® 5.0: The World's Leading Framework for Business Agility" by Richard Knaster, Dean Leffingwell</p></li> -<li><p>"Large-Scale Scrum: More with LeSS" by Craig Larman</p></li> -<li><p>"<a class="reference external" href="https://less.works/less/framework/introduction">LeSS</a>" (<a class="reference external" href="https://less.works/ru/less/framework/introduction">перевод на Русский</a>)</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile">Disciplined Agile®</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/">SAFe - Scaled Agile Framework</a>"</p></li> +<li><p><a class="reference internal" href="#domain-model-definition" id="id10">Domain Model Definition</a></p> +<ul> +<li><p><a class="reference internal" href="#id2" id="id11">Доменная модель</a></p> +<ul> +<li><p><a class="reference internal" href="#id3" id="id12">А что если попытаться реализовать единственную всеобъемливающую модель предметной области?</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id13">Важное дополнение: модель по Тарасенко</a></p></li> +<li><p><a class="reference internal" href="#id5" id="id14">Доменная модель, ограниченный контекст и единый язык</a></p></li> +<li><p><a class="reference internal" href="#id7" id="id15">Ограниченный контекст и команды разработки</a></p></li> +<li><p><a class="reference internal" href="#id8" id="id16">Классическая ошибка моделирования ограниченного контекста</a></p></li> +<li><p><a class="reference internal" href="#id9" id="id17">Источники информации</a></p></li> +</ul> +</li> +</ul> +</li> </ul> +</nav> +<section id="id2"> +<h2><a class="toc-backref" href="#id11" role="doc-backlink">Доменная модель</a></h2> +<p>Начнем с канонического определения модели по Эвансу:</p> +<blockquote> +<div><p>💬 "every model represents some aspect of reality or an idea that is of interest. +A model is a simplification. It is an interpretation of reality that abstracts the aspects relevant to solving the problem at hand and ignores extraneous detail..."</p> +<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p> +</div></blockquote> +<blockquote> +<div><p>💬 "Модель - это упрощение; это такая интерпретация реальности, при которой из явления извлекаются существенные для решения задачи аспекты, а лишние детали игнорируются."</p> +<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> +</div></blockquote> +<p>Каждая модель имеет свой контекст применимости, без контекста применимости мы не сможем создать модель, так как не знаем какую проблему решаем (то есть какие свойства и поведение нужны для решения конкретной проблемы).</p> +<figure class="align-center"> +<a class="reference internal image-reference" href="../../../../_images/model_of_earth_processes.png"><img alt="Model of Earth processes" src="../../../../_images/model_of_earth_processes.png" style="width: 100%;"/></a> +</figure> +<p>На изображении выше, мы видим модель процессов Земли, служащую для решения определенных задач.</p> +<p>Ограниченный контекст, являясь границей модели, определяет контекст применимости этой модели. +На это и делают акцент Эванс (см. выше), Вернон и Зимарев в определениях модели:</p> +<blockquote> +<div><p>💬 "So, models represent some artifact of the real world, but with a narrow purpose. +How much space the building will occupy and how high the whole complex will be, for example, +are often just enough for a rough model, during the first review stage of the building project. +Models do not intend to replicate real life. Instead, they represent some particular aspects of real life at a certain level of detail, +depending on the purpose of the model...</p> +<p>Going back to Chapter 1, Why Domain-Driven Design?, if the business domain and the particular problems we have to +solve are in our problem space, the domain model is purely in our solution space. +We will be modeling our solution, and those models will be our domain models."</p> +<p class="attribution">—"Hands-On Domain-Driven Design with .NET Core: Tackling complexity in the heart of software by putting DDD principles into practice" by Alexey Zimarev</p> +</div></blockquote> +<blockquote> +<div><p>💬 "What’s a Domain Model? +It’s a software model of the very specific business domain you are working in. Often it’s implemented as an object model, +where those objects have both data and behavior with literal and accurate business meaning. +Creating a unique, carefully crafted domain model at the heart of a core, strategic application or subsystem is essential to +practicing DDD. With DDD your domain models will tend to be smallish, very focused. +Using DDD, you never try to model the whole business enterprise with a single, large domain model. Phew, that’s good!""</p> +<p class="attribution">—"Implementing Domain-Driven Design" by Vaughn Vernon</p> +</div></blockquote> +<figure class="align-center"> +<a class="reference internal image-reference" href="../../../../_images/real-model-impl.jpg"><img alt="Real object, model and implementation" src="../../../../_images/real-model-impl.jpg" style="width: 100%;"/></a> +</figure> +<p>Важное уточнение: Модель - это абстракция, которая формирует реализацию, но не является реализацией, хотя реализация и может осуществлять (реализовывать) эту модель. +Модель это часть solution space.</p> +<blockquote> +<div><p>💬 "A domain model is not a particular diagram; it is the idea that the diagram is intended to convey. +It is not just the knowledge in a domain expert's head; +it is a rigorously organized and selective abstraction of that knowledge. +A diagram can represent and communicate a model, as can carefully written code, as can an English sentence...</p> +<p>The model and the heart of the design shape each other. +It is the intimate link between the model and the implementation that makes the model relevant and ensures that the analysis that went into it applies to the final product, a running program. +This binding of model and implementation also helps during maintenance and continuing development, because the code can be interpreted based on understanding the model. (See Chapter 3.)"</p> +<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p> +</div></blockquote> +<section id="id3"> +<h3><a class="toc-backref" href="#id12" role="doc-backlink">А что если попытаться реализовать единственную всеобъемливающую модель предметной области?</a></h3> +<p>Если решаемой проблемы не существует или она неизвестена, то у нас есть два возможных пути:</p> +<ol class="arabic"> +<li><p>модель не создавать вообще</p></li> +<li><p>создать модель на все случаи жизни, но тогда придется полностью воспроизвести объект моделирования, что не позволит эффективно решать задачи (например, осуществление навигации судна по точной копии Земли).</p> +<blockquote> +<div><p>💬 "Because the term domain model includes the word domain, we might get the idea that we should create a single, cohesive, all-inclusive model of an organization’s entire business domain—you know, like an enterprise model. +However, when using DDD, that is not our goal. DDD places emphasis on just the opposite. The whole Domain of the organization is composed of Subdomains. +Using DDD, models are developed in Bounded Contexts. In fact, developing a Domain Model is actually one way that we focus on only one specific area of the whole business domain. +Any attempt to define the business of even a moderately complex organization in a single, all-encompassing model will be at best extremely difficult and will usually fail. +As is made clear in this chapter, vigorously separating distinct areas of the whole business domain will help us succeed.</p> +<p>So, if a domain model shouldn’t be all-inclusive of what the organization does and how it does it, what should it be, exactly?</p> +<p>Almost every software Domain has multiple Subdomains. It really doesn’t matter whether the organization is huge and extremely complex or consists of just a few people and the software they use. +There are different functions that make any business successful, so it’s advantageous to think about each of those business functions separately."</p> +<p class="attribution">—"Implementing Domain-Driven Design" by Vaughn Vernon</p> +</div></blockquote> +</li> +</ol> +<p>В качестве иллюстрации того, что модель создается для решения конкретных задач (имеет определенный контекст применимости), рассмотрим примеры из доклада Эрика Эванса (Eric Evans — Tackling Complexity in the Heart of Software, Domain-Driven Design Europe 2016 - Brussels, January 26-29, 2016).</p> +<ol class="arabic simple"> +<li><p>Карта морского ориентирования (цилиндрическая проекция Меркатора)</p></li> +</ol> +<figure class="align-center"> +<a class="reference internal image-reference" href="../../../../_images/mercator_projection.png"><img alt="Mercator projection" src="../../../../_images/mercator_projection.png" style="width: 100%;"/></a> +</figure> +<p>Такие карты используют относительное искажение размеров объектов относительно друг друга, но помогают направлять компас в сторону нужной конечной точки (направление на карте полностью совпадет со стрелкой компаса). +На этой карте Африка и Гренландия выглядят равными по площади, но в действительности, Африка в 14 раз больше Гренландии, то есть у карты есть четкое предназначение, задача для которой она нужна, и только для нее - навигация судов.</p> +<ol class="arabic simple" start="2"> +<li><p>Картографическая проекция земного шара на поверхность многогранника (проекция Димаксион (Фуллера))</p></li> +</ol> +<figure class="align-center"> +<a class="reference internal image-reference" href="../../../../_images/fuller_projection.png"><img alt="Fuller projection" src="../../../../_images/fuller_projection.png" style="width: 100%;"/></a> +</figure> +<p>Данная проекция имеет меньшие искажения относительных размеров объектов, особенно в сравнении с проекцией Меркатора, то есть, она может служить более точным инструментом определения относительных размеров объектов земли.</p> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<blockquote> +<div><p>💬 "We're making an effort with DDD to recognize that there is no practical way to have a canonical, enterprise data model where every single element in the model is representative of how every team in the enterprise would want to use it. +It just doesn't happen. There's always some difference, and many times there are many differences that make it very painful for one team to try to use the model that another team has created. +That's why we're focused on the bounded context with a ubiquitous language."</p> +</div></blockquote> +<p><a class="reference external" href="https://www.infoq.com/articles/modeling-uncertainty-reactive-ddd/">Vaughn Vernon объясняет, почему построение канонической всеобъемлющей модели предприятия и единой предметной области на основе единой модели деятельности - миф</a></p> +</div> </section> -<section id="id18"> -<h4><a class="toc-backref" href="#id66" role="doc-backlink">Стандарты</a></h4> +<section id="id4"> +<h3><a class="toc-backref" href="#id13" role="doc-backlink">Важное дополнение: модель по Тарасенко</a></h3> +<blockquote> +<div><p>💬 "Мы уже сформулировали два определения модели. Первое: модель есть средство осуществления любой деятельности субъекта. Второе: модель есть форма существования знаний. +Можно несколько дополнить каждое из этих определений указанием на то, что модель — тоже система, со всеми описанными в главе 2 общесистемными свойствами. +Отличительная особенность моделей от других систем состоит (в дополнение к тому, что говорят два определения) в их предназначенности отображать моделируемый оригинал, заменять его в определенном отношении, т.е. содержать и представлять информацию об оригинале. +Выразим эту мысль в виде еще одного общего определения: модель есть системное отображение оригинала. +Все три определения носят очень общий, можно сказать, философский характер. Для дальнейшего нам понадобится конкретизация типов моделей и их характерных свойств. +Как мы уже знаем, уточнение описания модели можно сделать с помощью анализа и синтеза."</p> +<p class="attribution">—"Прикладной системный анализ" Ф.П. Тарасенко</p> +</div></blockquote> +<figure class="align-center"> +<a class="reference internal image-reference" href="../../../../_images/tarasenko_model.png"><img alt="Tarasenko model" src="../../../../_images/tarasenko_model.png" style="width: 100%;"/></a> +</figure> +<p>и следует за этим:</p> +<blockquote> +<div><p>💬 "Продолжая рассмотрение отношений между моделью и оригиналом, остановимся на содержании информации в модели. Оригинал и модель — разные вещи. +В оригинале есть много такого, чего нет в модели, по двум причинам: во-первых, не все из того, что известно об оригинале, понадобится включить в модель, предназначенную для достижения конкретной цели (зона А на рис. 3.13 изображает известное, но ненужное, в том числе ошибочно сочтенное ненужным и невключенное в модель); +во-вторых, в оригинале есть всегда нечто непознанное, поэтому не могущее быть включенным в модель (зона В на рис. 3.13).</p> +<p>Зона 2 на рисунке изображает информацию об оригинале, включенную в модель. Это истинная информация, то общее, что имеется у модели и оригинала, благодаря чему модель может служить его (частным, специальным) заменителем, представителем. +Обратим внимание на зону 3. Она отображает тот факт, что у модели всегда есть собственные свойства, не имеющие никакого отношения к оригиналу, т.е. ложное содержание. +Важно подчеркнуть, что это относится к любой модели, как бы ни старался создатель модели включать в нее только истину."</p> +<p class="attribution">—"Прикладной системный анализ" Ф.П. Тарасенко</p> +</div></blockquote> +</section> +<section id="id5"> +<h3><a class="toc-backref" href="#id14" role="doc-backlink">Доменная модель, ограниченный контекст и единый язык</a></h3> +<p>Ограниченный контекст - это рассмотрение объекта моделирования с определенной точки зрения, с определенного ракурса решаемой проблемы (см. пример с огурцом далее). +Основным назначением ограниченного контекста является поиск баланса между простой модели и ее достаточностью для решения проблемы.</p> +<p>Количество слов используемых человеком в лексиконе ограничено, это около 6000 слов (в зависимости от языка), а количство явлений окружающего мира - безгранично. +Это и есть та самая причина того, что если один термин обозначает несколько явлений окружающего мира, либо наоборот, одно явление мы называем различными терминами, - это обозначает лингвистический конфликт.</p> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<p><a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%A1%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D0%BD%D1%8B%D0%B9_%D0%B7%D0%B0%D0%BF%D0%B0%D1%81/">Википедия: Словарный запас</a></p> +</div> +<p>И при поиске ограниченных контекстов мы можем ориентироваться на эти лингвистические конфликты в процессе коммуникации (эти конфликты и являются первыми маркерами/границами ограниченнных контекстов).</p> +<blockquote> +<div><p>💬 "The Language of a team in an explicit Bounded Context expressed as a domain model adds true business value +and gives us certainty that we are implementing the correct software."</p> +<p class="attribution">—"Implementing Domain-Driven Design" by Vaughn Vernon</p> +</div></blockquote> +<p>Если внутри своего ограниченно контекста мы встречаем языковой конфликт, то это может являться симптомом того, что мы решаем сразу несколько задач одновременно. +То есть, если мы называем одно явление разными терминами, то скорее всего это явление используется в разных контекстах, и наш контекст служит нескольким целям. +Это сигнал о том, что наша модель переусложнена и при решении одной задачи мы вынуждены работать с теми деталями модели, которые нерелевантны для нас в момент рассмотрения. Это все отбирает ресурс внимания у команды и может удорожать процесс разработки для бизнеса.</p> +<p>Поэтому, внутри каждого ограниченного контекста существует строгий единый (согласованный) язык. +Единый (согласованный) язык не просто словарь внутри компании, это подразумевает, в первую очередь, согласованный язык внутри границ применимости модели. +Мы, в рамках модели, ограничены ограниченным контекстом, где каждый термин обозначает строго одно явление.</p> +<blockquote> +<div><p>💬 "The model is a set of concepts built up in the heads of people on the project, with terms and relationships that reflect domain insight. +These terms and interrelationships provide the semantics of a language that is tailored to the domain while being precise enough for technical development. +This is a crucial cord that weaves the model into development activity and binds it with the code."</p> +<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p> +</div></blockquote> +<p>В качестве примера можно привести модель обыкновенного огурца, где термин "огурец" в каждом ограниченном контексте имеет строгое и однозначное толкование (но разное): плод, ингредиент, груз ...</p> +<figure class="align-center"> +<a class="reference internal image-reference" href="../../../../_images/cucumber_BC.jpg"><img alt="cucumber in diffent Bounded Contexts" src="../../../../_images/cucumber_BC.jpg" style="width: 100%;"/></a> +</figure> +<p>[Дополнение] Про профессиональные языки от Тарасенко:</p> +<blockquote> +<div><p>💬 "Главная для нас особенность — то, что язык является универсальным средством моделирования: говорить можно о чем угодно. Из многих свойств языка, обеспечивающих ему это свойство, обратим внимание на расплывчатость смысла слов.</p> +<p>Приведем пример словесной модели некоторой ситуации. «В комнату вошел высокий красивый молодой человек, неся тяжелый сверток». Так и видится реальная картина. Но «высокий» — какого именно роста? «Молодой» — а сколько ему лет? +Не говоря уж о том, что такое «красивый». «Тяжелый» — какого веса? Практически ни одно слово естественного языка не имеет точного смысла. Можно привести аналогию: «смысл» конкретной ситуации — точка, «смысл» слова — облако. +Описывая конкретную ситуацию, мы как бы обволакиваем точку облаками, понимая, что истина гдето в середине этого скопления. В большинстве случаев, особенно в быту, такого приблизительного, расплывчатого описания бывает достаточно для действий, часто успешных. +В некоторых видах деятельности такая расплывчатость сознательно используется как важный позитивный фактор: поэзия, юмор, политика, дипломатия, мошенничество…</p> +<p>Однако в случаях, когда необходимо произвести конкретный продукт, достичь конкретного результата, этой конкретности начинает мешать расплывчатость бытового языка. +И тогда те, кто занимается конкретной деятельностью, изживают мешающую неопределенность, вводя в язык более точные термины. +У всякой группы с ее общими целями вырабатывается свой, специфический язык, обеспечивающий нужной точностью эту деятельность. +У скотоводческого африканского племени масаев есть сотни терминов для характеристики коров; у северных народов — множество терминов, определяющих состояние снега; +на своих языках разговаривают физики, медики, юристы; уголовники «ботают по фене»; молодежь говорит на слэнге, не понятном для взрослых; лондонские «низы» разговаривают на «кокни». +Общий вывод: всякая групповая деятельность требует выработки специального, более точного, чем разговорный, языка; условно назовем его профессиональным.</p> +<p>Профессиональные языки более точны, чем разговорный, за счет большей определенности их терминов. Важно осознать, что снятие неопределенности может быть осуществлено только за счет новой, дополнительной информации.</p> +<p>Таким образом, увеличение точности смысла языковых моделей идет за счет добывания и включения в язык все новой и новой информации о предмете интереса.</p> +<p>Есть ли предел этому процессу уточнения? Есть, и это язык математики, в котором термины максимально точны, однозначны. Правда, полностью изжить неопределенность невозможно, иначе было бы невозможно о бесконечности мира говорить конечными фразами. +Есть несколько (и не только вспомогательных, но и базовых) понятий в математике, имеющих расплывчатый смысл: «приблизительно равно», «значительно больше (меньше)», «бесконечно мало (велико)», «неопределенно» и т.д. +И все же математический язык является крайним, самым точным справа в спектре языков описания реальности (рис. 3.7)."</p> +<p class="attribution">—"Прикладной системный анализ" Ф.П. Тарасенко</p> +</div></blockquote> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> <ul class="simple"> -<li><p>"ISO/IEC/IEEE 12207:2017 Systems and software engineering — Software life cycle processes"</p></li> -<li><p>"ISO/IEC/IEEE 15288:2015 Systems and software engineering — System life cycle processes"</p></li> -<li><p>"ISO/IEC/IEEE 29148:2018 Systems and software engineering — Life cycle processes — Requirements engineering"</p></li> -<li><p>"ISO/IEC/IEEE 15289:2019 Systems and software engineering — Content of life-cycle information items (documentation)"</p></li> -<li><p>"ISO/IEC/IEEE 24765:2017 Systems and software engineering — Vocabulary"</p></li> -<li><p>"ISO 9000:2005 Quality management systems — Fundamentals and vocabulary"</p></li> -<li><p>"ISO/IEC 33001:2015 Information technology — Process assessment — Concepts and terminology"</p></li> -<li><p>"ГОСТ Р ИСО/МЭК 12207-2010 Информационная технология. Системная и программная инженерия. Процессы жизненного цикла программных средств."</p></li> -<li><p>"ГОСТ Р 57193-2016 Системная и программная инженерия. Процессы жизненного цикла систем."</p></li> +<li><p>"<a class="reference internal" href="language-context.html#stanislav3316-language-context"><span class="std std-ref">Language Context Definition</span></a>"</p></li> </ul> +</div> </section> -</section> -<section id="id19"> -<h3><a class="toc-backref" href="#id67" role="doc-backlink">Менеджмент</a></h3> +<section id="id7"> +<h3><a class="toc-backref" href="#id15" role="doc-backlink">Ограниченный контекст и команды разработки</a></h3> +<p>Для того чтобы реализовать модель, команда должна ее понимать, соответственно, набольшей эффективностью команда будет обладать тогда, когда граница ответственности команды совпадает с границей модели. +Это и можно назвать границей автономности рабочей команды, что позволяет команде фокусироваться на решении конкретной задачи. +В ограниченном контексте команды модель обладает наибольшей внутренней связанностью (cohesion) и наименьшим сопряжением (coupling) с другими ограниченными контекстами.</p> +<p>В таком случае решается проблема Брукса, а именно, достижение автономности команды, - рост коммуникационных связей внутри команды и уменьшение коммуникационных связей между командами.</p> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> <ul class="simple"> -<li><p>"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr.</p></li> -<li><p>"<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems Thinking</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">перевод на Русский</a>)</p></li> -<li><p>"Art of Project Management" by Scott Berkun</p></li> -<li><p>"Менеджмент: Учебник для вузов." 3-е изд. Глухов В. В.</p></li> -<li><p>"Оргуправленческое мышление. Идеология, методология, технология" / Щедровицкий Георгий Петрович</p></li> -<li><p>"The Leadership Experience" 7th edition by Richard L. Daft</p></li> -<li><p>"Management" 013 edition by Richard L. Daft</p></li> -<li><p>"<a class="reference external" href="https://publications.opengroup.org/g183">Managing Digital Concepts and Practices</a>"</p></li> +<li><p>"<a class="reference internal" href="../../../../emacsway/it/team-topologies/harlan-mills%27-proposal.html#emacsway-team-topologies-at-scale"><span class="std std-ref">Роль архитектуры в масштабировании команд, DDD и микросервисах</span></a>"</p></li> </ul> +</div> +<p>Если же модель поделить неправильно, допустим, разрезать полноценную модель на две разные части, то резко возрастет количество коммуникационных путей между командами (для сохранения и поддержки инвариантов модели), и этим мы ухудшаем параллелизм задач. +Аналогично, если свалим в один ограниченный контекст две модели которые служат двум разным целям, то мы увеличим когнитивную нагрузку команды (путем введения информации нерелеватной в момент рассмотрения, тем самым отнимая когнитивные ресурсы у человека). +И чтобы достичь наибольшего уровня автономности команд, обеспечить их независимость друг от друга нужно правильно определить ограниченные контексты.</p> +<p>Таким образом, можно прийти к выводу, что ограниченный контекст помогает решить две проблемы:</p> +<ol class="arabic simple"> +<li><p>Снижение когнитивной нагрузки на команду (путем исключения из рассмотрения нерелевантных деталей)</p></li> +<li><p>Снижение коммуникативной нагрузки между командами (путем концентрации релевантных деталей)</p></li> +</ol> </section> -<section id="id20"> -<h3><a class="toc-backref" href="#id68" role="doc-backlink">Развитие личностных профессиональных качеств</a></h3> -<ul class="simple"> -<li><p>"The Pragmatic Programmer: From Journeyman to Master" 1st edition by David Thomas, Andrew Hunt</p></li> -<li><p>"The Pragmatic Programmer: your journey to mastery, 20th Anniversary Edition" 2nd edition by David Thomas, Andrew Hunt</p></li> -<li><p>"A Mind for Numbers: How to Excel at Math and Science" by Barbara Ann Oakley</p></li> -<li><p>"Systems Thinking. Quality Software Management. New York: Dorset House." by Gerald M. Weinberg, 1992, ISBN: 0932633226</p></li> -<li><p>"An Introduction to General Systems Thinking" by Gerald M. Weinberg</p></li> -<li><p>"Becoming a Technical Leader" by Gerald M. Weinberg</p></li> -<li><p>"Harvard Business Review on Decision Making" by Harvard Business School Press</p></li> -<li><p>"The Software Architect Elevator: Redefining the Architect's Role in the Digital Enterprise 1st Edition" by Gregor Hohpe</p></li> -<li><p>"Fundamentals of Software Architecture: An Engineering Approach" 1st edition by Mark Richards, Neal Ford</p></li> -<li><p>"Software Architecture: The Hard Parts: Modern Trade-Off Analyses for Distributed Architectures" 1st Edition by Neal Ford, Mark Richards, Pramod Sadalage, Zhamak Dehghani</p></li> -<li><p>"The Book: 37 Things One Architect Knows About IT Transformation" by Gregor Hohpe</p></li> -<li><p>"Eat or Be Eaten!: Jungle Warfare for the Corporate Master Politician" by Phil Porter</p></li> -<li><p>"Presentation patterns: techniques for crafting better presentations" by Neal Ford, Matthew McCullough, Nathaniel Schutta</p></li> -<li><p>"Technology Strategy Patterns: Architecture as Strategy" 1st edition by Eben Hewitt</p></li> -<li><p>"Thinking in Systems: A Primer" by Donella H. Meadows, Diana Wright</p></li> -<li><p>"Social psychology" 13th edition by David G. Myers. Перевод: "Социальная психология" / Майерс Д. Пер. с англ. З. Замчук; Зав. ред. кол. Л. Винокуров. — 7-е изд. — СПб.: Питер, 2006.</p></li> -<li><p>"Never split the difference: negotiating as if life depended on it" by Chris Voss. Перевод: "Договориться не проблема. Как добиваться своего без конфликтов и ненужных уступок." / Крис Восс</p></li> -<li><p>"Искусство спора. О теории и практике спора." / Поварнин С.И.</p></li> -<li><p>"Эристика, или Искусство побеждать в спорах" / Шопенгауэр Артур. English: "The Art of Being Right: 38 Ways to Win an Argument" by Arthur Schopenhauer</p></li> -<li><p>"Как читать книги" / Поварнин С.И.</p></li> -<li><p>"<a class="reference external" href="https://ruxpert.ru/%D0%98%D1%81%D0%BA%D1%83%D1%81%D1%81%D1%82%D0%B2%D0%BE_%D1%81%D0%BF%D0%BE%D1%80%D0%B0_(%D0%BE%D0%B1%D1%83%D1%87%D0%B0%D1%8E%D1%89%D0%B8%D0%B5_%D0%BC%D0%B0%D1%82%D0%B5%D1%80%D0%B8%D0%B0%D0%BB%D1%8B)">Искусство спора (обучающие материалы)</a>"</p></li> -<li><p>"<a class="reference external" href="https://m.vk.com/wall-56611080_127534">Книги по риторике</a>"</p></li> -</ul> -<p>Простой и доходчивый видеокурс по SoftSkills:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://youtube.com/channel/UCSN7G8syJUaRiXrw1l0qk_g">Soft Skills Pro</a>"</p></li> -</ul> +<section id="id8"> +<h3><a class="toc-backref" href="#id16" role="doc-backlink">Классическая ошибка моделирования ограниченного контекста</a></h3> +<p>Классическая ошибка при моделировании ограниченного контекста заключается в том, что при неправильном понимании модели возникает желание "запихнуть" модель объекта моделирования в какой-то один ограниченный контекст. +Существует два самых неправильных вопроса - в какой ограниченный контекст поместить сущность и как мне получить из другого ограниченного контекста нужную сущность.</p> +<p>Моделирование ограниченного контекста - это не кройка. Плод, груз, ингредиент, блюдо - это все модели одного и того же объекта моделирования - огурца, только в разных ограниченных контекстах. +Можно рассмотреть ограниченный контекст как одну из плоскостей додека‌эдра (когда один и тот же элемент виден под разными ракурсами), а не как фрагмент пазла (когда один элемент может принадлежать только одному фрагменту полотна).</p> +<p>Задача не в том, в какой ограниченный контекст "запихнуть", и не в том, как разрезать, а в том, какие именно аспекты поведения объекта моделирования релевантны в контексте решаемой проблемы текущего ограниченного контекста. +Посетитель, пользователь, клиент, покупатель, плательщик, получатель, адресат - это все тоже модели одного и того же объекта моделирования.</p> +<figure class="align-center"> +<a class="reference internal image-reference" href="../../../../_images/bc_perspective.png"><img alt="Different pespectives are matter" src="../../../../_images/bc_perspective.png" style="width: 60%;"/></a> +</figure> +<p>Владик отлично выводит противоречие, как опытный диалектик:</p> +<blockquote> +<div><p>💬 "However, it is more difficult to represent such a divergent model of the business domain in software. Source code doesn’t cope well with ambiguity. If we were to bring the sales department’s complicated model into marketing, +it would introduce complexity where it’s not needed— far more detail and behavior than marketing people need for optimizing advertising campaigns. But if we were to try to simplify the sales model according to the marketing world view, +it wouldn’t fit the sales subdomain’s needs, because it’s too simplistic for managing and optimizing the sales process. +We’d have an overengineered solution in the first case and an under-engineered one in the second."</p> +</div></blockquote> </section> -<section id="id21"> -<h3><a class="toc-backref" href="#id69" role="doc-backlink">Базы данных</a></h3> -<ul class="simple"> -<li><p>"Mastering PostgreSQL In Application Development" by Dimitri Fontaine</p></li> -<li><p>"The Art of PostgreSQL" 2nd edition by Dimitri Fontaine - is the new title of "Mastering PostgreSQL in Application Development"</p></li> -<li><p>"SQL Antipatterns. Avoiding the Pitfalls of Database Programming." by Bill Karwin</p></li> -<li><p>"Refactoring Databases. Evolutionary Database Design" by Scott J Ambler and Pramod J. Sadalage</p></li> -<li><p>"An Introduction to Database Systems" by C.J. Date</p></li> -<li><p>"PostgreSQL 10 High Performance" by Ibrar Ahmed, Gregory Smith, Enrico Pirozzi</p></li> -</ul> -<p>PostgresPro представил <a class="reference external" href="https://postgrespro.ru/education/books">четыре книги</a> для разных уровней подготовленности читателей, от совершенно неосведомленного человека до разработчика баз данных. -Книги дают комплексные знания в лаконичной форме. -Все книги доступны для скачивания в свободном доступе:</p> +<section id="id9"> +<h3><a class="toc-backref" href="#id17" role="doc-backlink">Источники информации</a></h3> <ol class="arabic simple"> -<li><p>"<a class="reference external" href="https://postgrespro.ru/education/books/introbook">Postgres: первое знакомство</a>" / П.В. Лузанов, Е.В. Рогов, И.В. Лёвшин</p></li> -<li><p>"<a class="reference external" href="https://postgrespro.ru/education/books/internals">PostgreSQL изнутри</a>" / Е.В. Рогов — М.: ДМК Пресс, 2022. — 660 с.</p></li> -<li><p>"<a class="reference external" href="https://postgrespro.ru/education/books/sqlprimer">PostgreSQL. Основы языка SQL: учеб. пособие</a>" / Е.П. Моргунов; под ред. Е.В. Рогова, П.В. Лузанова.</p></li> -<li><p>"<a class="reference external" href="https://postgrespro.ru/education/books/dbtech">Основы технологий баз данных: учеб. пособие</a>" / Б.А. Новиков, Е.А. Горшкова, Н.Г. Графеева; под ред. Е.В. Рогова.</p></li> +<li><p>Ivan Zakrevskii</p></li> +<li><p>Группа тг-канала объединения ИТ-архитекторов (@ru_arc)</p></li> +<li><p>DDDevotion chat (tg <a class="reference external" href="https://t.me/iDDDqd">https://t.me/iDDDqd</a>)</p></li> +<li><p>Группа тг-канала (@emacsway_log) о Software Design/Architecture, DDD, Microservice Architecture, Distributed Systems, SDLC, Agile, Team Topology etc.</p></li> +<li><p>рефлексия собственного опыта</p></li> </ol> -<p>Так же доступны <a class="reference external" href="https://postgrespro.ru/education/courses">учебные материалы курсов</a>: слайды, видео, руководства. Скачать можно все материалы каждого курса одним архивом.</p> -<p><a class="reference external" href="https://postgrespro.ru/education/where">Видеозаписи курсов</a>.</p> -<p>Превосходная подборка статей с фундаментальной информацией простым языком о внутреннем устройстве PostgreSQL, от разработчиков PostgresPro:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://m.habr.com/ru/company/postgrespro/blog/442804/">MVCC-1. Изоляция</a></p></li> -<li><p><a class="reference external" href="https://m.habr.com/ru/company/postgrespro/blog/458186/">WAL в PostgreSQL: 1. Буферный кеш</a></p></li> -</ul> -<p>Шпаргалка по выбору типа хранилища данных:</p> +</section> +</section> +Wed, 11 Oct 2023 00:00:00 Language Context Definitionhttps://dckms.github.io/system-architecture/stanislav.bolsun/it/ddd/domain-model/language-context.html +<span id="stanislav3316-language-context"/> +<p><em>Автор раздела: Stanislav Bolsun</em></p> +<section id="id1"> +<h2>Определение языкового контекста</h2> +<blockquote> +<div><p>💬 ЯЗЫКОВОЙ КОНТЕКСТ. — +1. Фрагмент текста или речи, содержащий избранное для анализа языковое выражение или единицу языка; +2. Ситуация употребления анализируемого выражения.</p> +<p>Языковой контекст во многом определяют семантические характеристики выражений языка. Прежде всего, это состоит в том, что контекст уменьшает или вовсе элиминирует многозначность выражения. Благодаря наличию контекста, оно часто интерпретируется как однозначное. Предельным случаем такого уточнения смысла при помощи контекста можно считать контекстуальные определения, т.е. такие определения, одна из частей которых является контекстом, включающим определяемый термин.</p> +<p>Контексты часто влияют на семантические отношения. Напр., одни и те же выражения могут в разных контекстах выступать и как синонимы, и как антонимы. С отношением к синонимии, кроме того, связано различение двух типов контекстов: экстенсиональных и интенсиональных. Это различение определяется возможностью замены в данном контексте одного выражения на синонимичное (по экстенсионалу) без изменения семантических характеристик контекста в целом. Напр., высказывание «Диагонали ромба перпендикулярны друг другу» представляет собой экстенсиональный контекст для выражения «ромб». При замене его на синонимичное по экстенсионалу выражение «параллелограмм, две смежные стороны которого равны между собой» мы получим семантически эквивалентное высказывание. Важнейшей семантической характеристикой, которая сохраняется при указанной замене, является истинность. Интенсиональный контекст не допускает такой замены. Примером интенсионального контекста является высказывание: «Требуется доказать, что параллелограмм, две смежные стороны которого равны между собой, является ромбом». Если приведенное высказывание истинно, то после замены оно может оказаться ложным. Различение двух типов контекстов имеет важный эпистемологический смысл, поскольку в них по-разному отражено состояние знания о предмете. Экстенсиональный контекст предполагает указание на предмет в целом. Его использование подразумевает, что классы объектов, описываемых двумя взаимозаменимыми выражениями, являются полностью обозримыми и что эта обозримость позволяет обнаружить совпадение классов. Поэтому заменимость выражений в экстенсиональном контексте вытекает из тождества обозначаемых ими объектов. Интенсиональный контекст указывает не на предмет, а лишь на определенное свойство (в приведенном примере — на свойство какого-то предмета быть ромбом). Знание о предмете предполагается еще не полным, а совпадение экстенсионалов двух выражений — не установленным. Можно указать на связь между понятиями интенсионального контекста и интенциональности. Использование интенсионального контекста подразумевает описание не самого предмета, а его ноэматического образа, т.е. смысла, установленного в сознании, или интенционального объекта. Поэтому интенсиональные контексты нельзя сводить (как это делал Г. Фреге) к пропозициональным установкам, т.е. к высказываниям типа: «N знает, что...», или «N думает, что...». Они возникают при упоминании любого интенционального акта, т.е. акта сознания, направленного на предмет (см. также Семантика, Синонимия).</p> +<p>Значительная часть описаний, фигурирующих как в науке, так и в обыденной речи носят интенсиональный и, соответственно, интенциональный характер. Они не могут претендовать на полноту понятия о предмете, но, скорее, выражают лишь некоторый спектр его характеристик. Поэтому для более точного определения некоторых понятий часто требуются более широкие контексты или даже совокупность контекстов, содержащих обозначающий это понятие термин. В естествознании или математике этого удается избежать с помощью формализации языков описания. В рамках формальной теории, как правило, возможно обойтись без интенсиональных контекстов, хотя применимость таких теорий всегда ограничена областью идеальных объектов. В гуманитарной сфере, где едва ли осуществима формализация, полнота знания так или иначе связана с широтой контекстов. Такая ситуация, напр., весьма характерна при определении важнейших философских категорий, а также вообще при рассмотрении ключевых или предельных понятий той или иной дисциплины. Напр., смысл понятия «материя» в философии Аристотеля невозможно передать при помощи краткого определения. Его понимание требует привлечения весьма широкого контекста, включающего сопоставление этого понятия с рядом др. (напр., возможность, лишенность), противопоставление его понятию «форма» (и действительность), а кроме того — множество примеров, аналогий, рассуждений, использующих это понятие и т.д.</p> +<p>Контекстуальный характер понимания находит отражение в идее сократического диалога (см. Диалог). Согласно этой идее, определить (и, соответственно, понять) нечто невозможно с помощью какой-либо краткой словесной формулировки. Полное определение требует включения исследуемого понятия во множество контекстов, приведения различных примеров его употребления, сопоставления разных определений и т.д. Сам диалог оказывается при этом попыткой раскрытия (или создания) полного контекста существования исследуемого понятия. При этом, говоря о контексте, уже невозможно ограничиться представлением о нем, как о явно присутствующем фрагменте текста (пусть даже достаточно длинном). Он подразумевает также совокупность коммуникативных ситуаций употребления выражения.</p> +<p>Для характеристики роли Я. к. в коммуникации важны используемые в лингвистике понятия об экстралингвистическом и имплицитном контексте. Первый (противопоставляемый собственно лингвистическому контексту) представляет собой неязыковой фон коммуникации. Он включает время и место общения, обстановку, в которой оно происходит, психическое и физическое состояние участников коммуникации, их социальный статус, их отношение друг к другу и т.д. Имплицитный контекст (противопоставляемый эксплицитному — т.е. непосредственно наблюдаемому +лингвистическому и экстралингвистическому контексту) составляет совокупность фоновых знаний участников коммуникации. Он включает, напр., все лингвистические пресуппозиции, существенные для данной коммуникативной ситуации (см. Пресуппозиция в лингвистике). Кроме того, он включает знания участников коммуникации друг о друге, память о прошлых коммуникациях, представление о настоящей ситуации и т.д. Очевидно, что все указанные обстоятельства влияют на характер понимания используемых языковых выражений и на правила их употребления. См. также Дискурс.</p> +<p>Г.Б. Гутнер</p> +<p class="attribution">—"Энциклопедия эпистемологии и философии науки. М.: «Канон+», РООИ «Реабилитация». И.Т. Касавин. 2009"</p> +</div></blockquote> +</section> +Wed, 11 Oct 2023 00:00:00 Agile Requirementshttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.html +<span id="emacsway-agile-requirements"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/guide/technology-choices/data-store-comparison">Understand data store models</a>"</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/guide/technology-choices/data-store-decision-tree">Select an Azure data store for your application</a>"</p></li> +<li><p><a class="reference internal" href="#agile-requirements" id="id4">Agile Requirements</a></p> +<ul> +<li><p><a class="reference internal" href="#id2" id="id5">Что такое требование</a></p></li> +<li><p><a class="reference internal" href="#product-backlog-item-requirements" id="id6">Product Backlog Item и Requirements</a></p></li> +<li><p><a class="reference internal" href="#user-story-requirements" id="id7">Почему User Story, а не Requirements</a></p></li> +<li><p><a class="reference internal" href="#emacsway-agile-requirements-literature" id="id8">Литература про Agile-requirements</a></p></li> </ul> -<p>Jepsen's analysis over two dozen databases, coordination services, and queues—and we've found replica divergence, data loss, stale reads, read skew, lock conflicts, and much more:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://jepsen.io/analyses">Analyses</a>"</p></li> -<li><p>"<a class="reference external" href="https://aphyr.com/tags/jepsen">Everything Tagged "Jepsen"</a>"</p></li> +</li> </ul> -<p>Рейтинг хранилищ данных:</p> +</nav> +<section id="id2"> +<h2><a class="toc-backref" href="#id5" role="doc-backlink">Что такое требование</a></h2> +<p>Следует различать значения терминов <strong>needs</strong>, <strong>requirements</strong> и <strong>specification</strong>. +Вопросы возникают, как правило, там, где их не различают, и под требованиями зачастую понимают System Requirements Specification (SyRS), на который распространяется стандарт "ISO/IEC/IEEE 29148:2018 Systems and software engineering - Life cycle processes - Requirements engineering".</p> +<p>Однако, на сами требования распространяются стандарты SDLC:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://db-engines.com/en/ranking">DB-Engines Ranking</a>"</p></li> +<li><p>"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p></li> +<li><p>"ISO/IEC/IEEE 15288:2015 Systems and software engineering - System life cycle processes"</p></li> </ul> +<p>Итак, что такое требование:</p> +<blockquote> +<div><p>📝 "<strong>requirement</strong> - statement that translates or expresses a need and its associated constraints and conditions. +[SOURCE: ISO/IEC/IEEE 29148:2011, modified, NOTE has been removed.]"</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> +</div></blockquote> +<p>Это все. Ни больше, ни меньше.</p> </section> -<section id="id22"> -<h3><a class="toc-backref" href="#id70" role="doc-backlink">Изучаем распределенные системы. Третий заход.</a></h3> -<ul class="simple"> -<li><p>"Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions" by Gregor Hohpe, Bobby Woolf</p></li> -<li><p>"Service Design Patterns: Fundamental Design Solutions for SOAP/WSDL and RESTful Web Services" by Robert Daigneau</p></li> -<li><p>"Microsoft .NET: Architecting Applications for the Enterprise" 2nd edition by Dino Esposito, Andrea Saltarello</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/">Cloud Design Patterns</a>"</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn568099(v=pandp.10)">Cloud Design Patterns. Prescriptive architecture guidance for cloud applications</a>" by Alex Homer, John Sharp, Larry Brader, Masashi Narumoto, Trent Swanson. (<a class="reference external" href="http://aka.ms/cloud-design-patterns-sample">Code Samples</a>)</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices">Build Microservices on Azure</a>" by Microsoft Corporation and community</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/best-practices/">Cloud Best Practices</a>" by Microsoft Corporation and community</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/antipatterns">Performance Antipatterns</a>" by Microsoft Corporation and community</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/guide/">Azure Application Architecture Guide</a>" by Microsoft Corporation and community</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/data-guide/">Azure Data Architecture Guide</a>" by Microsoft Corporation and community</p></li> -<li><p>"Release It! Design and Deploy Production-Ready Software" 2nd edition by Michael Nygard</p></li> -<li><p>"<a class="reference external" href="https://www.manning.com/books/microservice-patterns">Microservices Patterns: With examples in Java</a>" 1st edition by Chris Richardson (<a class="reference external" href="https://microservices.io/book">more info</a>)</p></li> -<li><p>"Monolith to Microservices Evolutionary Patterns to Transform Your Monolith" by Sam Newman</p></li> -<li><p>"Microservices AntiPatterns and Pitfalls" by Mark Richards</p></li> -<li><p>"Microservices vs. Service-Oriented Architecture" by Mark Richards</p></li> -<li><p>"<a class="reference external" href="https://landing.google.com/sre/books/">Site Reliability Engineering: How Google runs production systems</a>" edited by Betsy Beyer, Chris Jones, Jennifer Petoff &amp; Niall Richard Murphy</p></li> -<li><p>"<a class="reference external" href="https://landing.google.com/sre/books/">The Site Reliability Workbook: Practical Ways to Implement SRE.</a>" by Betsy Beyer, Niall Richard Murphy, David K. Rensin, Kent Kawahara &amp; Stephen Thorne</p></li> -<li><p>"<a class="reference external" href="https://landing.google.com/sre/books/">Building Secure &amp; Reliable Systems: Best Practices for Designing, Implementing and Maintaining Systems.</a>" by Heather Adkins, Betsy Beyer, Paul Blankinship, Ana Oprea, Piotr Lewandowski, Adam Stubblefield</p></li> -<li><p>"Database Reliability Engineering. Designing and Operating Resilient Database Systems." by Laine Campbell and Charity Majors</p></li> -<li><p>"Designing Data-Intensive Applications. The Big Ideas Behind Reliable, Scalable, and Maintainable Systems" by Martin Kleppmann</p></li> -<li><p>"Database Internals: A Deep Dive into How Distributed Data Systems Work" by Alex Petrov</p></li> -<li><p>"<a class="reference external" href="https://www.distributed-systems.net/index.php/books/ds3/">Distributed systems: principles and paradigms</a>" 3d edition by Andrew S. Tanenbaum, Maarten Van Steen</p></li> -<li><p>"<a class="reference external" href="http://books.ifmo.ru/file/pdf/1551.pdf">Введение в распределенные вычисления</a>" / Косяков М. С. — СПб: НИУ ИТМО, 2014. — С. 75-82. — 155 с.</p></li> -<li><p>"Service-Oriented Architecture Analysis and Design for Services and Microservices" by Thomas Erl</p></li> -<li><p>"Workflow patterns: the definitive guide" by Aalst, Wil van der, Russell, Nick, Ter Hofstede, Arthur</p></li> -<li><p>"Real-Life BPMN (4th edition): Includes an introduction to DMN" by Jakob Freund, Bernd Rücker</p></li> -<li><p>"Practical Process Automation" by Bernd Ruecker</p></li> -</ul> +<section id="product-backlog-item-requirements"> +<span id="emacsway-product-backlog-item"/><h2><a class="toc-backref" href="#id6" role="doc-backlink">Product Backlog Item и Requirements</a></h2> +<p>Какая связь между Product Backlog Item и Requirements?</p> +<blockquote> +<div><p>📝 "In the Scrum framework a <strong>product backlog</strong> lists all of the <strong>requirements</strong> for a solution, including both <strong>customer and technical requirements</strong>."</p> +<p class="attribution">—Agile Extension to the BABOK® Guide version 1 (obsolete, на момент написания статьи)</p> +</div></blockquote> +<blockquote> +<div><p>📝 "<strong>Backlog Item</strong> - An item on the backlog which represents one or more <strong>requirements</strong>.</p> +<p>&lt;...&gt;</p> +<p><strong>User Stories</strong> are used to convey a customer <strong>requirement</strong> for the delivery team."</p> +<p class="attribution">—Agile Extension to the BABOK® Guide version 2 (actual, на момент написания статьи)</p> +</div></blockquote> +<p>Актуальная версия Agile-расширения BABoK (на момент написания статьи) - вторая, хотя актуальная версия самого BABoK - третья.</p> +<blockquote> +<div><p>💬 "The unit of requirements gathering is the "user story," user-visible functionality that can be developed within one iteration."</p> +<p class="attribution">—"Agile Software Development" by Alistair Cockburn</p> +</div></blockquote> +<blockquote> +<div><p>📝 "The <strong>Product Backlog</strong> is a list of <strong>functional and nonfunctional requirements</strong> that, when turned into functionality, will deliver this vision."</p> +<p class="attribution">—"Agile Project Management with Scrum" by Ken Schwaber</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Agile projects generally maintain <strong>requirements</strong> in the form of user stories in a <strong>product backlog</strong>."</p> +<p class="attribution">—"Software Requirements (Developer Best Practices)" 3rd Edition by Karl Wiegers</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Instead of compiling a large inventory of detailed <strong>requirements</strong> up front, we create placeholders for the <strong>requirements</strong>, called <strong>product backlog items (PBIs)</strong>"</p> +<p class="attribution">—"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin</p> +</div></blockquote> +<blockquote> +<div><p>📝 "XP- originated "<strong>user story</strong>" as the primary currency for expressing application <strong>requirements</strong>."</p> +<p>📝 "<strong>User stories</strong> are the agile replacement for most of what has been traditionally expressed as software <strong>requirements</strong> statements (or use cases in RUP and UML), and they are the workhorses of agile development."</p> +<p class="attribution">—"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</p> +</div></blockquote> +<p>И есть у него еще такой <a class="reference external" href="https://scalingsoftwareagility.files.wordpress.com/2007/03/a-lean-and-scalable-requirements-information-model-for-agile-enterprises-pdf.pdf">документ</a>, который прекрасно раскрывает связь между требованиями и PBI.</p> +<blockquote> +<div><p>📝 "<strong>User Story</strong>: agile software development practice from Extreme Programming to express <strong>requirements</strong> from an end user perspective, emphasizing verbal communication. +In Scrum, it is often used to express functional items on the Product Backlog."</p> +<p class="attribution">—Официальный сайт Ken Schwaber, <a class="reference external" href="https://www.scrum.org/resources/professional-scrum-developer-glossary">glossary</a></p> +</div></blockquote> +<blockquote> +<div><p>📝 "The agile approach to <strong>requirements</strong> is based on <strong>user stories</strong>: units of functionality corresponding to interactions of users with the system."</p> +<p class="attribution">—"Agile! The Good, the Hype and the Ugly" by Bertrand Meyer</p> +</div></blockquote> +<p>У Mike Cohn есть прекрасная статья на тему, чем отличается User Story от других способов документирования требований, и начинается она со слов:</p> +<blockquote> +<div><p>📝 "Extreme programming (XP) introduced the practice of expressing <strong>requirements</strong> in the form of <strong>user stories</strong>"</p> +<p class="attribution">—"<a class="reference external" href="https://www.mountaingoatsoftware.com/articles/advantages-of-user-stories-for-requirements">Advantages of User Stories for Requirements</a>" by Mike Cohn</p> +</div></blockquote> </section> -<section id="id23"> -<h3><a class="toc-backref" href="#id71" role="doc-backlink">API-Design</a></h3> +<section id="user-story-requirements"> +<span id="emacsway-user-story"/><h2><a class="toc-backref" href="#id7" role="doc-backlink">Почему User Story, а не Requirements</a></h2> +<p>Kent Beck разъясняет, почему он использовал термин Story вместо Requirements. +Ключевым аргументом здесь выступает семантическое различие - требования переменны, а не константны. +А так же то, что полнота требований недостижима.</p> +<blockquote> +<div><p>📝 "Software development has been steered wrong by the word "requirement", defined in the dictionary as "something mandatory or obligatory." +The word carries a connotation of absolutism and permanence, inhibitors to embracing change. +And the word "requirement" is just plain wrong. +Out of one thousand pages of "requirements", if you deploy a system with the right 20% or 10% or even 5%, you will likely realize all of the business benefit envisioned for the whole system. +So what were the other 80%? Not "requirements"; they weren't really mandatory or obligatory.</p> +<p><strong>Early estimation is a key difference between stories and other requirements practices.</strong> +Estimation gives the business and technical perspectives a chance to interact, which creates value early, when an idea has the most potential. +When the team knows the cost of features it can split, combine, or extend scope based on what it knows about the features' value."</p> +<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck</p> +</div></blockquote> +<p>Bertrand Meyer о том, в чем отличия между User Story и Requirements. +Обратите внимание, Bertrand Meyer, как и Kent Beck, так же делает акцент на недостижимость полноты требований, и указывает на семантическое отличие термина Requirements по своему смыслу, хотя по стандарту итеративная разработка освобождается от полноты требований (и даже предназначается для её разрешения).</p> +<blockquote> +<div><p>📝 "Agile development accepts change. +In software projects, full requirements cannot be determined at the beginning; needs emerge as the project develops, and evolve as customers and others try intermediate releases. +Such change is considered a normal part of the development process.</p> +<p>&lt;...&gt;</p> +<p>The last principle gives us the second part of the replacement for requirements: use scenarios to define functionality. +A scenario is a description of a particular interaction of a user with the system, for example (if we are building mobile phone software) a phone conversation from the time the caller dials the number to the time the two parties get disconnected. +"Scenario" is not a common agile term, but covers variants such as use cases and user stories which differ by their level of granularity (a use case is a complete interaction, a user story an application of a smaller unit of functionality). +Scenarios are obtained from customers and indicate the fundamental properties of the system's functionality as seen from the user perspective. +Collecting scenarios, usually in the form of user stories, is the principal agile technique for requirements; it differs from traditional requirements elicitation in two fundamental ways:</p> <ul class="simple"> -<li><p>"REST in Practice: Hypermedia and Systems Architecture" by Savas Parastatidis, Jim Webber, Ian Robinson</p></li> -<li><p>"RESTful Web APIs: Services for a Changing World" by Leonard Richardson, Sam Ruby, Mike Amundsen</p></li> -<li><p>"Web API Design Crafting Interfaces that Developers Love" by Brian Mulloy</p></li> -<li><p>"REST API Design Rulebook" by Mark Massé</p></li> -<li><p>"Principles of Web API Design: Delivering Value with APIs and Microservices" by James Higginbotham</p></li> -<li><p>"Continuous API Management" 2nd edition by Mehdi Medjaoui, Erik Wilde, Ronnie Mitra, Mike Amundsen</p></li> +<li><p>A scenario is just one example; unlike requirements, it cannot lay claim to completeness. A set of scenarios, however large, cannot come even close to achieving this goal, in the same way that no number of tests of a program can replace a specification.</p></li> +<li><p>In agile development, requirements are not collected at the beginning of the project but throughout, as development progresses. Note, however, that this difference is not as absolute as the agile literature suggests when it blasts "waterfall approaches": while the traditional software engineering view presents requirements as a specific lifecycle step, coming early in the process, it does not rule out — except in the imagination of agile authors — a scheme in which the requirements are constantly updated in the rest of the lifecycle.</p></li> </ul> +<p>&lt;...&gt;</p> +<p>The agile approach to requirements is based on user stories: units of functionality corresponding to interactions of users with the system.</p> +<p>&lt;...&gt;</p> +<p>We note once again the confusion inherent in such agile criticism as Beck's comment that "Requirements gathering isn't a phase that produces a static document", as if having a requirements phase implied that the resulting requirements document will be static. +The two matters are separate."</p> +<p class="attribution">—"Agile! The Good, the Hype and the Ugly" by Bertrand Meyer</p> +</div></blockquote> +<p>Подведем итог: требование в условиях недостаточной полноты требований, которое может быть изменено по мере снижения уровня неопределенности, традиционно называется User Story или PBI. +В таком случае требования уточняются по мере снижения уровня неопределенности, что является базовым принципом <a class="reference internal" href="../../../iterative.html#emacsway-iterative-development"><span class="std std-ref">итеративной модели</span></a> разработки.</p> </section> -<section id="streaming-processing"> -<h3><a class="toc-backref" href="#id72" role="doc-backlink">Streaming Processing</a></h3> +<section id="emacsway-agile-requirements-literature"> +<span id="id3"/><h2><a class="toc-backref" href="#id8" role="doc-backlink">Литература про Agile-requirements</a></h2> <ul class="simple"> -<li><p>"Streaming Data: Understanding the real-time pipeline" 1st edition by Andrew Psaltis</p></li> -<li><p>"Big Data: Principles and best practices of scalable realtime data systems" 1st edition by Nathan Marz, James Warren</p></li> -<li><p>"Kafka Streams in Action: Real-time apps and microservices with the Kafka Streams API" 1st edition by Bill Bejeck</p></li> -<li><p>"The Enterprise Big Data Lake: Delivering the Promise of Big Data and Data Science" 1st edition by Alex Gorelik</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/22-cpre-advanced-level-re-agile-handbook/handbook_cpre_al_re%40agile_en_v1.0.2.pdf">Handbook of RE@Agile According to the IREB Standard Education and Training for IREB Certified Professional for Requirements Engineering Advanced Level RE@Agile</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute, 2017</p></li> +<li><p>"Agile Extension to the BABOK® Guide" version 2 (actual, на момент написания статьи)</p></li> +<li><p>"<a class="reference external" href="https://www.amazon.com/Agile-Software-Requirements-Enterprise-Development/dp/0321635841">Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise</a>" by Dean Leffingwell.</p></li> +<li><p>"Software Requirements (Developer Best Practices)" 3rd Edition by Karl Wiegers</p></li> +<li><p>"<a class="reference external" href="https://scalingsoftwareagility.wordpress.com/2010/03/05/an-agile-architectural-epic-kanban-system-part-2-%E2%80%93-the-model/">An Agile Architectural Epic Kanban System: Part 2 – The Model</a>" by Dean Leffingwell</p></li> +<li><p>"<a class="reference external" href="https://scalingsoftwareagility.files.wordpress.com/2007/03/a-lean-and-scalable-requirements-information-model-for-agile-enterprises-pdf.pdf">A Lean and Scalable Requirements Information Model for the Agile Enterprise</a>" by Dean Leffingwell with Juha‐Markus Aalto</p></li> </ul> -</section> -<section id="id24"> -<h3><a class="toc-backref" href="#id73" role="doc-backlink">Углубляем DDD</a></h3> +<p>См. также:</p> <ul class="simple"> -<li><p>"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon</p></li> -<li><p>"Patterns, Principles, and Practices of Domain-Driven Design" by Scott Millett, Nick Tune</p></li> -<li><p>"Hands-On Domain-Driven Design with .NET Core: Tackling complexity in the heart of software by putting DDD principles into practice" by Alexey Zimarev</p></li> -<li><p>"Balancing Coupling in Software Design: Successful Software Architecture in General and Distributed Systems" by Vladislav Khononov</p></li> -<li><p>"<a class="reference external" href="https://www.informit.com/imprint/series_detail.aspx?ser=7937178">The Addison-Wesley Signature Series: Vaughn Vernon</a>"</p></li> -<li><p>"<a class="reference external" href="https://leanpub.com/dddwithpython">Event Sourced Building Blocks for Domain-Driven Design with Python</a>" by John Bywater</p></li> +<li><p>"<a class="reference external" href="http://agilemodeling.com/artifacts/#Requirements">Agile Modeling :: Requirements-Analysis Models</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/safe-requirements-model/">SAFe Requirements Model</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/en/downloads/tag:handbook">Library of IREB artifacts</a>"</p></li> </ul> -</section> -<section id="id25"> -<h3><a class="toc-backref" href="#id74" role="doc-backlink">Изучаем проектирование</a></h3> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> <ul class="simple"> -<li><p>"Agile Software Development. Principles, Patterns, and Practices." by Robert C. Martin, James W. Newkirk, Robert S. Koss</p></li> -<li><p>"Analysis Patterns. Reusable Object Models" by Martin Fowler</p></li> -<li><p>"Implementation Patterns" by Kent Beck</p></li> -<li><p>"Smalltalk Best Practice Patterns" by Kent Beck</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/eaaDev/">Development of Further Patterns of Enterprise Application Architecture</a>" by Martin Fowler</p></li> -<li><p>"Domain Specific Languages" by Martin Fowler (with Rebecca Parsons)</p></li> -<li><p>"Pattern Hatching: Design Patterns Applied" by John Vlissides</p></li> -<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ff650706(v=pandp.10)?redirectedfrom=MSDN">Microsoft Application Architecture Guide</a>" 2nd edition (Patterns &amp; Practices) by Microsoft Corporation (J.D. Meier, David Hill, Alex Homer, Jason Taylor, Prashant Bansode, Lonnie Wall, Rob Boucher Jr., Akshay Bogawat)</p></li> -<li><p>"Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development" by Craig Larman</p></li> -<li><p>"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer</p></li> -<li><p>"Working Effectively with Legacy Code" by Michael C. Feathers</p></li> -<li><p>"Refactoring To Patterns" by Joshua Kerievsky</p></li> -<li><p>"Structure and Interpretation of Computer Programs" (aka SICP) 2nd edition (MIT Electrical Engineering and Computer Science) by Harold Abelson, Gerald Jay Sussman, Julie Sussman</p></li> -<li><p>"How to Design Programs, second edition: An Introduction to Programming and Computing" 2d edition by Matthias Felleisen, Robert Bruce Findler, Matthew Flatt, Shriram Krishnamurthi</p></li> -<li><p>"Object Oriented Software Engineering: A Use Case Driven Approach" by Ivar Jacobson</p></li> -<li><p>"Object-Oriented Analysis and Design with Applications" 3rd edition by Grady Booch, Robert A. Maksimchuk, Michael W. Engle, Bobbi J. Young Ph.D., Jim Conallen, Kelli A. Houston</p></li> +<li><p>"<a class="reference internal" href="../../../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> </ul> +</div> </section> -<section id="posa"> -<h3><a class="toc-backref" href="#id75" role="doc-backlink">POSA</a></h3> +Sat, 07 Oct 2023 00:00:00 Роль архитектуры в масштабировании команд, DDD и микросервисахhttps://dckms.github.io/system-architecture/emacsway/it/team-topologies/harlan-mills'-proposal.html +<span id="emacsway-team-topologies-at-scale"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p>"Pattern-Oriented Software Architecture: A System of Patterns, Volume 1" by Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, Michael Stal</p></li> -<li><p>"Pattern-Oriented Software Architecture: Patterns for Concurrent and Networked Objects, Volume 2" by Douglas C. Schmidt, Michael Stal, Hans Rohnert, Frank Buschmann</p></li> -<li><p>"Pattern-Oriented Software Architecture: Patterns for Resource Management, Volume 3" by Michael Kircher, Prashant Jain</p></li> -<li><p>"Pattern-Oriented Software Architecture: A Pattern Language for Distributed Computing, Volume 4" by Frank Buschmann, Kevin Henney, Douglas C. Schmidt</p></li> -<li><p>"Pattern-Oriented Software Architecture: On Patterns and Pattern Languages, Volume 5" by Frank Buschmann, Kevin Henney, Douglas C. Schmidt</p></li> +<li><p><a class="reference internal" href="#ddd" id="id16">Роль архитектуры в масштабировании команд, DDD и микросервисах</a></p> +<ul> +<li><p><a class="reference internal" href="#id2" id="id17">Закон Брукса и роль автономности команд</a></p> +<ul> +<li><p><a class="reference internal" href="#emacsway-brooks-s-law" id="id18">Закон Брукса</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id19">Противоречие между эффективностью и производительностью</a></p></li> +<li><p><a class="reference internal" href="#emacsway-harlan-mills-proposal" id="id20">Предложение Харлана Миллза</a></p></li> </ul> -</section> -<section id="id26"> -<h3><a class="toc-backref" href="#id76" role="doc-backlink">Алгоритмы. Второй заход.</a></h3> -<ul class="simple"> -<li><p>"Introduction to Algorithms" 3d edition by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein</p></li> -<li><p>"Algorithms and Data Structures" (Oberon version: August 2004) by N.Wirth</p></li> +</li> +<li><p><a class="reference internal" href="#program-management" id="id21">Program Management</a></p> +<ul> +<li><p><a class="reference internal" href="#spotify" id="id22">Spotify</a></p></li> +<li><p><a class="reference internal" href="#agile-software-requirements-lean-requirements-practices-for-teams-programs-and-the-enterprise" id="id23">Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise</a></p></li> +<li><p><a class="reference internal" href="#scaled-agile-framework-safe" id="id24">Scaled Agile Framework (SAFe)</a></p></li> +<li><p><a class="reference internal" href="#agile-practice-guide-by-pmi" id="id25">"Agile Practice Guide" by PMI</a></p></li> +<li><p><a class="reference internal" href="#disciplined-agile-delivery-dad" id="id26">Disciplined agile delivery (DAD)</a></p></li> +<li><p><a class="reference internal" href="#iso-iec-ieee-12207-2017" id="id27">ISO/IEC/IEEE 12207:2017</a></p></li> +<li><p><a class="reference internal" href="#nexus" id="id28">Nexus</a></p></li> +<li><p><a class="reference internal" href="#extreme-programming" id="id29">Extreme Programming</a></p></li> +<li><p><a class="reference internal" href="#scrum-of-scrums" id="id30">Scrum of Scrums</a></p></li> +<li><p><a class="reference internal" href="#early-scrum" id="id31">Early Scrum</a></p></li> +<li><p><a class="reference internal" href="#id6" id="id32">Другие</a></p></li> </ul> -<p>Donald E. Knuth:</p> -<ul class="simple"> -<li><p>"The Art of Computer Programming, Volume 1: Fundamental Algorithms" 3d edition by Donald Knuth</p></li> -<li><p>"The Art of Computer Programming, Volume 1, Fascicle 1: MMIX; A RISC Computer for the New Millennium" 1st edition by Donald Knuth</p></li> -<li><p>"The Art of Computer Programming, Volume 2, Seminumerical Algorithms" 3rd edition by Donald E. Knuth</p></li> -<li><p>"The Art of Computer Programming, Volume 3, Sorting and Searching" 2nd edition by Donald E. Knuth</p></li> -<li><p>"The Art of Computer Programming, Volume 4, Fascicle 0: Introduction to Combinatorial Algorithms and Boolean Functions" 1st edition by Donald E. Knuth</p></li> -<li><p>"The Art of Computer Programming, Volume 4, Fascicle 1: Bitwise Tricks &amp; Techniques; Binary Decision Diagrams" 1st edition by Donald E. Knuth</p></li> -<li><p>"The Art of Computer Programming, Volume 4, Fascicle 2: Generating All Tuples and Permutations" 1st edition by Donald E. Knuth</p></li> -<li><p>"The Art of Computer Programming, Volume 4, Fascicle 3: Generating All Combinations and Partitions Paperback" 1st edition by Donald E. Knuth</p></li> -<li><p>"Art of Computer Programming, Volume 4, Fascicle 4: Generating All Trees; History of Combinatorial Generation 1st edition by Donald E. Knuth</p></li> -<li><p>"The Art of Computer Programming" Volume 4, Fascicle 5: Mathematical Preliminaries Redux; Introduction to Backtracking; Dancing Links" 1st edition by Donald E. Knuth</p></li> -<li><p>"The Art of Computer Programming, Volume 4, Fascicle 6: Satisfiability" 1st edition by Donald E. Knuth</p></li> -<li><p>"The Art of Computer Programming, Volume 4A, Combinatorial Algorithms, Part 1" 1st edition by Donald E. Knuth</p></li> +</li> +<li><p><a class="reference internal" href="#emacsway-fractal-team" id="id33">Фрактальная структура</a></p></li> +<li><p><a class="reference internal" href="#id8" id="id34">Социальная роль архитектуры</a></p></li> +<li><p><a class="reference internal" href="#emacsway-team-topologies-at-scale-literature" id="id35">Литература</a></p></li> +<li><p><a class="reference internal" href="#id10" id="id36">Ссылки по теме</a></p></li> </ul> -<p>Хорошая подборка книг по алгоритмам: <a class="reference external" href="http://e-maxx.ru/bookz/">http://e-maxx.ru/bookz/</a></p> +</li> +</ul> +</nav> +<section id="id2"> +<h2><a class="toc-backref" href="#id17" role="doc-backlink">Закон Брукса и роль автономности команд</a></h2> +<section id="emacsway-brooks-s-law"> +<span id="id3"/><h3><a class="toc-backref" href="#id18" role="doc-backlink">Закон Брукса</a></h3> +<p>Сегодня, наверное, каждый знает Закон Брукса:</p> +<blockquote> +<div><p>📝 "Если проект не укладывается в сроки, то добавление рабочей силы задержит его ещё больше.</p> +<p>Adding manpower to a late software project makes it later."</p> +<p class="attribution">—The Brooks's Law</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Brooks' law is based on the idea that communications overhead is a significant factor on software projects, and that work on a software project is not easily partitioned into isolated, independent tasks. Ten people can pick cotton ten times as fast as one person because the work is almost perfectly partitionable, requiring little communication or coordination. But nine women can't have a baby any faster than one woman can because the work is not partitionable. Brooks argues that work on a software project is more like having a baby than picking cotton. When new staff are brought into a late project, they aren't immediately productive, and they must be trained. The staff who must train them are already productive, but they lose productivity while they're training new staff. Brooks argues that, on balance, more effort is lost to training and additional coordination and communications overhead than is gained when the new staff eventually becomes productive."</p> +<p class="attribution">—"<a class="reference external" href="https://stevemcconnell.com/articles/brooks-law-repealed/">Brooks' Law Repealed?</a>" by Steve McConnell</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Число занятых [специалистов] и число месяцев [в термине человеко-месяц] являются взаимозаменяемыми величинами лишь тогда, когда задачу можно распределить среди ряда работников, которые не имеют между собой взаимосвязи (рис. 2.1).</p> +<p>Men and months [in term man-month] are interchangeable commodities only when a task can be partitioned among many workers with no communication among them (Fig. 2.1)."</p> +<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Сравните это с</p> +<blockquote> +<div><p>📝 "Microservices' main benefit, in my view, is enabling parallel development by establishing a hard-to-cross boundary between different parts of your system."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/dont-start-monolith.html">Don't start with a monolith</a>" by Stefan Tilkov, a co-founder and principal consultant at innoQ</p> +</div></blockquote> +</section> +<section id="id4"> +<h3><a class="toc-backref" href="#id19" role="doc-backlink">Противоречие между эффективностью и производительностью</a></h3> +<p>Frederick Brooks формулирует противоречие. С одной стороны:</p> +<blockquote> +<div><p>📝 "Выше я доказал, что само число разработчиков, действия которых нужно согласовывать, оказывает влияние на стоимость проекта, поскольку значительная часть издержек вызвана необходимостью общения и устранения отрицательных последствий разобщенности (системная отладка). Это также наводит на мысль, что <strong>желательно разрабатывать системы возможно меньшим числом людей</strong>. Действительно, опыт разработки больших программных систем, как правило, показывает, что подход с позиций грубой силы влечет удорожание, замедленность, неэффективность, а создаваемые в результате системы не являются концептуально целостными. Список, иллюстрирующий это, бесконечен: OS/360, Exec 8, Scop 6600, Multics, TSS, SAGE и другие.</p> +<p>I have earlier argued that the sheer number of minds to be coordinated affects the cost of the effort, for a major part of the cost is communication and correcting the ill effects of miscommunication (system debugging). This, too, suggests that one wants the system to be built by <strong>as few minds as possible</strong>. Indeed, most experience with large programming systems shows that the brute-force approach is costly, slow, inefficient, and produces systems that are not conceptually integrated. OS/360, Exec 8, Scope 6600, Multics, TSS, SAGE, etc.—the list goes on and on."</p> +<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Таким же наблюдением делится и Sam Newman:</p> +<blockquote> +<div><p>📝 "... небольшие команды, работающие с небольшим объемом исходного кода, как правило, показывают более высокую продуктивность.</p> +<p>... smaller teams working on smaller codebases tend to be more productive!"</p> +<p class="attribution">—"Building Microservices. Designing Fine-Grained Systems" by Sam Newman, перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Но, с другой стороны:</p> +<blockquote> +<div><p>📝 "В этом и состоит <strong>изъян идеи маленькой активной команды: для создания по-настоящему крупных систем ей потребуется слишком много времени</strong>. Посмотрим, как разработка OS/360 осуществлялась бы маленькой активной командой, допустим, из 10 человек. Положим, что они в семь раз более продуктивны средних программистов (что далеко от истины). Допустим, что уменьшение объема общения благодаря малочисленности команды позволило еще в семь раз повысить производительность. Допустим, что на протяжении всего проекта работает одна и та же команда. Таким образом, 5000/(10*7*7)=10, т.е. работу в 5000 человеко-лет они выполнят за 10 лет. Будет ли продукт представлять интерес через 10 лет после начала разработки или устареет благодаря стремительному развитию программных технологий?</p> +<p>This then is <strong>the problem with the small, sharp team concept: it is too slow for really big systems. Consider the OS/360 job as it might be tackled with a small, sharp team</strong>. Postulate a 10-man team. As a bound, let them be seven times as productive as mediocre programmers in both programming and documentation, because they are sharp. Assume OS/360 was built only by mediocre programmers (which is far from the truth). As a bound, assume that another productivity improvement factor of seven comes from reduced communication on the part of the smaller team. Assume the same team stays on the entire job. Well, 5000/(10 X 7 X 7 ) = 10; they can do the 5000 man-year job in 10 years. Will the product be interesting 10 years after its initial design? Or will it have been made obsolete by the rapidly developing software technology?"</p> +<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Возникает противоречие:</p> +<blockquote> +<div><p>📝 "Дилемма представляется жестокой. Для эффективности и концептуальной целостности предпочтительнее, чтобы проектирование и создание системы осуществили <strong>несколько светлых голов</strong>. Однако для больших систем желательно поставить под ружье <strong>значительный контингент</strong>, чтобы продукт мог увидеть свет вовремя. <strong>Как можно примирить эти два желания?</strong></p> +<p>The dilemma is a cruel one. For efficiency and conceptual integrity, one prefers <strong>a few good minds</strong> doing design and construction. Yet for large systems one wants a way to bring <strong>considerable manpower to bear</strong>, so that the product can make a timely appearance. <strong>How can these two needs be reconciled?</strong>"</p> +<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Добавим немного контекста:</p> +<blockquote> +<div><p>📝 "Вторая ошибка рассуждений заключена в самой единице измерения, используемой при оценивании и планировании: человеко-месяц. Стоимость действительно измеряется как произведения числа занятых на количество затраченных месяцев. Но не достигнутый результат. Поэтому использование человеко-месяца как единицы измерения объема работы является опасным заблуждением.</p> +<p>Число занятых и число месяцев являются взаимозаменяемыми величинами лишь тогда, когда задачу можно распределить среди ряда работников, которые не имеют между собой взаимосвязи (рис. 2.1). Это верно, когда жнут пшеницу или собирают хлопок, но в системном программировании это далеко не так.</p> +<figure class="align-left" id="id11"> +<a class="reference internal image-reference" href="../../../_images/fig-2.1-perfectly-partitionable-task.png"><img alt="Рис. 2.1 Зависимость времени от числа занятых — полностью разделимая задача. Fig. 2.1 Time versus number of workers—perfectly partitionable task. The image source is &quot;The Mythical Man-Month Essays on Software Engineering Anniversary Edition&quot; by Frederick P. Brooks, Jr., &quot;Chapter 2 The Mythical Man-Month&quot;, перевод ООО Издательство &quot;Питер&quot;." src="../../../_images/fig-2.1-perfectly-partitionable-task.png" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">Рис. 2.1 Зависимость времени от числа занятых — полностью разделимая задача. Fig. 2.1 Time versus number of workers—perfectly partitionable task. The image source is "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., "Chapter 2 The Mythical Man-Month", перевод ООО Издательство "Питер".</span></p> +</figcaption> +</figure> +<p>Если задачу нельзя разбить на части, поскольку существуют ограничения на последовательность выполнения этапов, то увеличение затрат не оказывает влияния на график (рис. 2.2). Чтобы родить ребенка требуется девять месяцев независимо от того, сколько женщин привлечено к решению данной задачи. Многие задачи программирования относятся к этому типу, поскольку отладка по своей сути носит последовательный характер.</p> +<figure class="align-left" id="id12"> +<a class="reference internal image-reference" href="../../../_images/fig-2.2-unpartitionable-task.png"><img alt="Рис. 2.2 Зависимость времени от числа занятых — неразделимая задача. Fig. 2.2 Time versus number of workers—unpartitionable task. The image source is &quot;The Mythical Man-Month Essays on Software Engineering Anniversary Edition&quot; by Frederick P. Brooks, Jr., &quot;Chapter 2 The Mythical Man-Month&quot;, перевод ООО Издательство &quot;Питер&quot;." src="../../../_images/fig-2.2-unpartitionable-task.png" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">Рис. 2.2 Зависимость времени от числа занятых — неразделимая задача. Fig. 2.2 Time versus number of workers—unpartitionable task. The image source is "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., "Chapter 2 The Mythical Man-Month", перевод ООО Издательство "Питер".</span></p> +</figcaption> +</figure> +<p>Для задач, которые могут быть разбиты на части, но требуют обмена данными между подзадачами, затраты на обмен данными должны быть добавлены к общему объему необходимых работ. Поэтому достижимый наилучший результат оказывается несколько хуже, чем простое соответствие числа занятых и количества месяцев (рис. 2.3).</p> +<figure class="align-left" id="id13"> +<a class="reference internal image-reference" href="../../../_images/fig-2.3-partitionable-task-requiring-communication.png"><img alt="Рис. 2.3 Зависимость времени от числа занятых — разделимая задача, требующая обмена данными. Fig. 2.3 Time versus number of workers—partitionable task requiring communication. The image source is &quot;The Mythical Man-Month Essays on Software Engineering Anniversary Edition&quot; by Frederick P. Brooks, Jr., &quot;Chapter 2 The Mythical Man-Month&quot;, перевод ООО Издательство &quot;Питер&quot;." src="../../../_images/fig-2.3-partitionable-task-requiring-communication.png" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">Рис. 2.3 Зависимость времени от числа занятых — разделимая задача, требующая обмена данными. Fig. 2.3 Time versus number of workers—partitionable task requiring communication. The image source is "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., "Chapter 2 The Mythical Man-Month", перевод ООО Издательство "Питер".</span></p> +</figcaption> +</figure> +<p>Дополнительная нагрузка состоит из двух частей — обучения и обмена данными. Каждого работника нужно обучить технологии, целям проекта, общей стратегии и плану работы. Это обучение нельзя разбить на части, поэтому данная часть затрат изменяется линейно в зависимости от числа занятых.</p> +<p><strong>С обменом данными дело обстоит хуже. Если все части задания должны быть отдельно скоординированы между собой, то затраты возрастают как n(n-1)/2. Для трех работников требуется втрое больше попарного общения, чем для двух, для четырех — вшестеро. Если помимо этого возникает необходимость в совещаниях трех, четырех и т.д. работников для совместного решения вопросов, положение становится еще хуже. Дополнительные затраты на обмен данными могут полностью обесценить результат дробления исходной задачи и привести к положению, описываемому рисунком 2.4.</strong></p> +<figure class="align-left" id="id14"> +<a class="reference internal image-reference" href="../../../_images/fig-2.4-task-with-complex-interrelationships.png"><img alt="Рис. 2.4 Зависимость времени от числа занятых — задача со сложными взаимосвязями. Fig. 2.4 Time versus number of workers—task with complex interrelationships. The image source is &quot;The Mythical Man-Month Essays on Software Engineering Anniversary Edition&quot; by Frederick P. Brooks, Jr., &quot;Chapter 2 The Mythical Man-Month&quot;, перевод ООО Издательство &quot;Питер&quot;." src="../../../_images/fig-2.4-task-with-complex-interrelationships.png" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">Рис. 2.4 Зависимость времени от числа занятых — задача со сложными взаимосвязями. Fig. 2.4 Time versus number of workers—task with complex interrelationships. The image source is "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., "Chapter 2 The Mythical Man-Month", перевод ООО Издательство "Питер".</span></p> +</figcaption> +</figure> +<p>Поскольку создание программного продукта является по сути системным проектом — практикой сложных взаимосвязей, затраты на обмен данными велики и быстро начинают преобладать над сокращением сроков, достигаемым в результате разбиения задачи на более мелкие подзадачи. В этом случае привлечение дополнительных работников не сокращает, а удлиняет график работ.</p> +<p>The second fallacious thought mode is expressed in the very unit of effort used in estimating and scheduling: the man-month. Cost does indeed vary as the product of the number of men and the number of months. Progress does not. Hence the man-month as a unit for measuring the size of a job is a dangerous and deceptive myth. It implies that men and months are interchangeable.</p> +<p>Men and months are interchangeable commodities only when a task can be partitioned among many workers with no communication among them (Fig. 2.1). This is true of reaping wheat or picking cotton; it is not even approximately true of systems programming.</p> +<p>When a task cannot be partitioned because of sequential constraints, the application of more effort has no effect on the schedule (Fig. 2.2). The bearing of a child takes nine months, no matter how many women are assigned. Many software tasks have this characteristic because of the sequential nature of debugging.</p> +<p>In tasks that can be partitioned but which require communication among the subtasks, the effort of communication must be added to the amount of work to be done. Therefore the best that can be done is somewhat poorer than an even trade of men for months (Fig. 2.3).</p> +<p>The added burden of communication is made up of two parts, training and intercommunication. Each worker must be trained in the technology, the goals of the effort, the overall strategy, and the plan of work. This training cannot be partitioned, so this part of the added effort varies linearly with the number of workers.</p> +<p><strong>Intercommunication is worse. If each part of the task must be separately coordinated with each other part/ the effort increases as n(n-1)/2. Three workers require three times as much pairwise intercommunication as two; four require six times as much as two. If, moreover, there need to be conferences among three, four, etc., workers to resolve things jointly, matters get worse yet. The added effort of communicating may fully counteract the division of the original task and bring us to the situation of Fig. 2.4.</strong></p> +<p>Since software construction is inherently a systems effort—an exercise in complex interrelationships—communication effort is great, and it quickly dominates the decrease in individual task time brought about by partitioning. Adding more men then lengthens, not shortens, the schedule."</p> +<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Мы остановились на дилемме: с одной стороны, чем меньше численность людей, принимающих проектные решения, тем выше их продуктивность. +С другой стороны, чем больше людей задействовано в разработке, тем скорее продукт сможет выйти на рынок. +Проанализируем о том, как эту дилемму можно решить.</p> +<p>Решение этой дилеммы становится возможным с качественным отделением архитектуры от реализации (с чем отлично справляются сетевые границы Bounded Contexts):</p> +<blockquote> +<div><p>📝 "<strong>Архитектура и разработка должны быть тщательно разделены.</strong> Как сказал Блау (Blaauw), "архитектура говорит, что должно произойти, а разработка - как сделать, чтобы это произошло". В качестве простого примера он приводит часы, архитектура которых состоит из циферблата, стрелок и заводной головки. Ребенок, освоивший это архитектуру, с одинаковой легкостью может узнать время и по ручным часам, и по часам на колокольне. Исполнение же и его реализация описывают, что происходит внутри: передача усилий и управление точностью каждым из многих механизмов.</p> +<p><strong>Architecture must be carefully distinguished from implementation.</strong> As Blaauw has said, "Where architecture tells what happens, implementation tells how it is made to happen." He gives as a simple example a clock, whose architecture consists of the face, the hands, and the winding knob. When a child has learned this architecture, he can tell time as easily from a wristwatch as from a church tower. The implementation, however, and its realization, describe what goes on inside the case—powering by any of many mechanisms and accuracy control by any of many."</p> +<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +</div></blockquote> </section> -<section id="id27"> -<h3><a class="toc-backref" href="#id77" role="doc-backlink">Тестирование</a></h3> +<section id="emacsway-harlan-mills-proposal"> +<span id="id5"/><h3><a class="toc-backref" href="#id20" role="doc-backlink">Предложение Харлана Миллза</a></h3> +<p>Harlan Mills' Proposal (Предложение Харлана Миллза) было опубликовано в:</p> <ul class="simple"> -<li><p>"xUnit Test Patterns. Refactoring Test Code." by Gerard Meszaros</p></li> -<li><p>"Unit Testing Principles, Practices, and Patterns: Effective testing styles, patterns, and reliable automation for unit testing, mocking, and integration testing with examples in C#" 1st Edition by Vladimir Khorikov</p></li> -<li><p>"Growing Object-Oriented Software, Guided by Tests" by Steve Freeman, Nat Pryce</p></li> -<li><p>"Agile Testing: A Practical Guide for Testers and Agile Teams" by Lisa Crispin, Janet Gregory</p></li> -<li><p>"More Agile Testing: Learning Journeys for the Whole Team" by Lisa Crispin, Janet Gregory</p></li> -<li><p>"ATDD by Example: A Practical Guide to Acceptance Test-Driven Development" by Markus Gärtner</p></li> -<li><p>"Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation" by Jez Humble, David Farley</p></li> -<li><p>"Continuous Integration: Improving Software Quality and Reducing Risk" by Paul M. Duvall, Steve Matyas, Andrew Glover</p></li> -<li><p>"<a class="reference external" href="https://www.istqb.org/references/books/istqb-related-books.html">ISTQB® Related Books</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.istqb.org/references/books/referenced-books-in-istqb-syllabi.html">Referenced Books in ISTQB® Syllabi</a>"</p></li> +<li><p>Mills, H., "Chief programmer teams, principles, and procedures," IBM Federal Systems Division Report FSC 71-5108, Gaithersburg, Md., 1971.</p></li> +<li><p>Baker, F. T., "Chief programmer team management of production programming," IBM Sys. J., 11, 1 (1972).</p></li> </ul> +<blockquote> +<div><p>📝 "Предложение Харлана Миллза дает свежее и творческое решение. Миллз предложил, чтобы на каждом участке работы была <strong>команда разработчиков, организованная наподобие бригады хирургов, а не мясников</strong>. Имеется в виду, что не каждый участник группы будет врезаться в задачу, но резать будет один, а остальные оказывать ему всевозможную поддержку, повышая его производительность и плодотворность.</p> +<p>При некотором размышлении ясно, что <strong>эта идея приведет к желаемому, если ее удастся осуществить</strong>. Лишь несколько голов занято проектированием и разработкой, и в то же время много работников находится на подхвате. Будет ли такая организация работать? Кто играет роль анестезиологов и операционных сестер в группе программистов, а как осуществляется разделение труда? Чтобы нарисовать картину работы такой команды с включением всех мыслимых видов поддержки, я позволю себе вольное обращение к метафорам.</p> +<p>A proposal by Harlan Mills offers a fresh and creative solution. Mills proposes that each segment of a large job be tackled by a team, but that <strong>the team be organized like a surgical team rather than a hog-butchering team</strong>. That is, instead of each member cutting away on the problem, one does the cutting and the others give him every support that will enhance his effectiveness and productivity.</p> +<p>A little thought shows that <strong>this concept meets the desiderata, if it can be made to work</strong>. Few minds are involved in design and construction, yet many hands are brought to bear. Can it work? Who are the anesthesiologists and nurses on a programming team, and how is the work divided? Let me freely mix metaphors to suggest how such a team might work if enlarged to include all conceivable support."</p> +<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Обратите внимание на слова "эта идея приведет к желаемому, если ее удастся осуществить". +Именно эту задачу успешно решает концепция <a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard-single/#_solution_space">Bounded Context</a>, позволяя совместить большой размер коллектива и продуктивность, т.е., осуществить масштабирование команд без ущерба производительности.</p> +<blockquote> +<div><p>📝 "... мы стремимся к тому, чтобы сервисы создавались в результате разбиения системы на такие части, при которых <strong>темпы развития внутри сервисов были намного выше темпов развития между сервисами</strong>.</p> +<p>... we aim to ensure our services are decomposed such that the <strong>pace of change inside a service is much higher than the pace of change between services</strong>."</p> +<p class="attribution">—"Building Microservices. Designing Fine-Grained Systems" by Sam Newman, перевод ООО Издательство "Питер"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "One case study was particularly interesting. The team had made the wrong choice, using microservices on a system that wasn't complex enough to cover the Microservice Premium. The project got in trouble and needed to be rescued, so lots more people were thrown onto the project. At this point the microservice architecture became helpful, because <strong>the system was able to absorb the rapid influx of developers and the team was able to leverage the larger team numbers much more easily than is typical with a monolith</strong>. As a result the project accelerated to a productivity greater than would have been expected with a monolith, enabling the team to catch up. The result was still a net negative, in that the software cost more staff-hours than it would have done if they had gone with a monolith, but the <strong>microservices architecture did support ramp up</strong>."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/microservice-trade-offs.html">Microservice Trade-Offs</a>" by Martin Fowler</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Netflix и Amazon</p> +<p>Наверное, идея обязательной согласованности организации и архитектуры может быть неплохо проиллюстрирована на примере Amazon и Netflix. В Amazon довольно рано начали понимать преимущества владения командами полным жизненным циклом управляемых ими систем. Там решили, что команды должны всецело распоряжаться теми системами, за которые они отвечают, управляя всем жизненным циклом этих систем. Но в Amazon также знали, что <strong>небольшие команды могут работать быстрее больших</strong>. Это привело к созданию команд, которые можно было бы накормить двумя пиццами. Это стремление к созданию небольших команд, владеющих полным жизненным циклом своих сервисов, и стало основной причиной того, что в Amazon была разработана платформа Amazon Web Services. Для обеспечения самодостаточности своих команд компании понадобилось создать соответствующий инструментарий. Этот пример был взят на вооружение компанией Netflix и с самого начала определил формирование ее структуры вокруг небольших независимых команд, образуемых с прицелом на то, что создаваемые ими сервисы также будут независимы друг от друга. Тем самым обеспечивалась оптимизация скорости изменения архитектуры систем. Фактически в Netflix разработали организационную структуру для желаемой архитектуры создаваемых систем.</p> +<p>Netflix and Amazon</p> +<p>Probably the two poster children for the idea that organizations and architecture should be aligned are Amazon and Netflix. Early on, Amazon started to understand the benefits of teams owning the whole lifecycle of the systems they managed. It wanted teams to own and operate the systems they looked after, managing the entire lifecycle. But Amazon also knew that <strong>small teams can work faster than large teams</strong>. This led famously to its two-pizza teams, where no team should be so big that it could not be fed with two pizzas. This driver for small teams owning the whole lifecycle of their services is a major reason why Amazon developed Amazon Web Services. It needed to create the tooling to allow its teams to be self-sufficient. Netflix learned from this example, and ensured that from the beginning it structured itself around small, independent teams, so that the services they created would also be independent from each other. This ensured that the architecture of the system was optimized for speed of change. Effectively, Netflix designed the organizational structure for the system architecture it wanted."</p> +<p class="attribution">—"Building Microservices. Designing Fine-Grained Systems" by Sam Newman, перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>я хотел бы добавить еще одно высказывание от разработчиков популярного микросервисного фреймворка go-kit:</p> +<blockquote> +<div><p>📝 "Почему микросервисы? Практически вся современная разработка программного обеспечения ориентирована на единственную цель - улучшить время выхода на рынок. Микросервисы представляют собой эволюцию модели сервис-ориентированной архитектуры, которая элегантно устраняет организационные противоречия, <strong>предоставляя вашим инженерам и командам автономию</strong>, необходимую им для непрерывной доставки, итерации и улучшения.</p> +<p>Why microservices? Almost all of contemporary software engineering is focused on the singular goal of improving time-to-market. Microservices are an evolution of the service-oriented architecture pattern that elegantly eliminate organizational friction, <strong>giving your engineers and teams the autonomy</strong> they need to continuously ship, iterate, and improve."</p> +<p class="attribution">—"<a class="reference external" href="https://gokit.io/">Go kit. A toolkit for microservices.</a>"</p> +</div></blockquote> +<p>На самом деле, если у вас армейская дисциплина среди разработчиков, то нет необходимости укреплять сетевыми границами пределы автономности команд, поскольку границами автономности команды является Bounded Context, который не обязательно должен быть выражен микорсервисом(-ами).</p> +<blockquote> +<div><p>📝 "In theory, you don't need microservices for this if you simply have the discipline to follow clear rules and establish clear boundaries within your monolithic application; in practice, I've found this to be the case only very rarely.)"</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/dont-start-monolith.html">Don't start with a monolith</a>" by Stefan Tilkov</p> +</div></blockquote> +<p>Сетевые границы решают проблему, известную как creeping coupling или abstraction leak. А это позволяет снизить квалификационные требования к разработчикам, тем более, что Microservices First обычно имеет экономическую целесообразность только при задействовании большого количества разработчиков.</p> +<blockquote> +<div><p>📝 "Обмен данными между самими сервисами ведется через сетевые вызовы, чтобы <strong>упрочить обособленность сервисов</strong> и избежать рисков, сопряженных с тесными связями.</p> +<p>All communication between the services themselves are via network calls, <strong>to enforce separation between the services</strong> and avoid the perils of tight coupling."</p> +<p class="attribution">—"Building Microservices. Designing Fine-Grained Systems" by Sam Newman, перевод ООО Издательство "Питер"</p> +</div></blockquote> </section> -<section id="id28"> -<h3><a class="toc-backref" href="#id78" role="doc-backlink">Компиляторы</a></h3> -<ul class="simple"> -<li><p>"<cite>Crafting Interpreters &lt;https://craftinginterpreters.com/&gt;</cite>" by Robert Nystrom</p></li> -<li><p>"Compiler Construction" by N.Wirth</p></li> -<li><p>"Compilers: Principles, Techniques, and Tools" 2nd edition by Alfred V. Aho, Monica S. Lam, Ravi Sethi, Jeffrey D. Ullman</p></li> -</ul> </section> -<section id="id29"> -<h3><a class="toc-backref" href="#id79" role="doc-backlink">Архитектура</a></h3> -<ul class="simple"> -<li><p>"Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman</p></li> -<li><p>"Documenting Software Architectures: Views and Beyond" 2nd edition by Paul Clements, Felix Bachmann, Len Bass, David Garlan, James Ivers, Reed Little, Paulo Merson, Robert Nord, Judith Stafford</p></li> -<li><p>"Software Systems Architecture: Working With Stakeholders Using Viewpoints and Perspectives" 2nd edition by Nick Rozanski, Eóin Woods</p></li> -<li><p>"Designing Software Architectures: A Practical Approach (SEI Series in Software Engineering)" 1st edition by Humberto Cervantes, Rick Kazman</p></li> -<li><p>"Fundamentals of Software Architecture: An Engineering Approach" 1st edition by Mark Richards, Neal Ford</p></li> -<li><p>"Introduction to Solution Architecture Paperback" by Alan McSweeney</p></li> -<li><p>"Systems Analysis and Design" 7th edition by Alan Dennis, Barbara Haley Wixom, Roberta M. Roth</p></li> -<li><p>"The Design of Design: Essays from a Computer Scientist" by Frederick P. Brooks</p></li> -<li><p>"Living Documentation: Continuous Knowledge Sharing by Design" by Cyrille Martraire</p></li> -<li><p>"Just Enough Software Architecture: A Risk-Driven Approach" by George H. Fairbanks</p></li> -<li><p>"The Book: 37 Things One Architect Knows About IT Transformation" by Gregor Hohpe</p></li> -<li><p>"The Software Architect Elevator: Redefining the Architect's Role in the Digital Enterprise 1st Edition" by Gregor Hohpe</p></li> -<li><p>"Cloud Strategy: A Decision-based Approach to Successful Cloud Migration" by Gregor Hohpe, Michele Danieli, Jean-Francois Landreau, Tahir Hashmi</p></li> -<li><p>"Architecting for Scale" 2nd Edition by Lee Atchison</p></li> -<li><p>"Software Engineering: A Practitioner's Approach" 9th edition by Roger S. Pressman, Bruce Maxim</p></li> -<li><p>"Presentation patterns: techniques for crafting better presentations" by Neal Ford, Matthew McCullough, Nathaniel Schutta</p></li> -<li><p>"Team Topologies: Organizing Business and Technology Teams for Fast Flow" by Matthew Skelton, Manuel Pais</p></li> -<li><p>"Technology Strategy Patterns: Architecture as Strategy" 1st edition by Eben Hewitt</p></li> -</ul> -<p>Архитектура в Agile:</p> -<ul class="simple"> -<li><p>"Building Evolutionary Architectures: Support Constant Change" 1st Edition by Neal Ford, Rebecca Parsons, Patrick Kua</p></li> -<li><p>"Agile Software Architecture: Aligning Agile Processes and Software Architectures" by Muhammad Ali Babar, Alan W. Brown, Kai Koskimies, Ivan Mistrík</p></li> -<li><p>"Continuous Architecture: Sustainable Architecture in an Agile and Cloud-Centric World" by Murat Erder, Pierre Pureur</p></li> -<li><p>"<a class="reference external" href="https://www.amazon.com/Balancing-Agility-Discipline-Guide-Perplexed/dp/0321186125">Balancing Agility and Discipline: A Guide for the Perplexed</a>" by Barry Boehm, Richard Turner</p></li> -<li><p>"<a class="reference external" href="https://www.researchgate.net/publication/228701141_Architected_Agile_Solutions_for_Software-Reliant_Systems">Architected Agile Solutions for Software-Reliant Systems</a>" by Barry Boehm, Jo Ann Lane, Richard Turner</p></li> -<li><p>"<a class="reference external" href="https://www.researchgate.net/publication/224579114_The_ROI_of_Systems_Engineering_Some_Quantitative_Results">The ROI of Systems Engineering: Some Quantitative Results</a>" by Barry Boehm, Ricardo Valerdi</p></li> -<li><p>"Lean Architecture: for Agile Software Development" 1st edition by James O. Coplien, Gertrud Bjørnvig</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute (PMI), 2017</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile/process/enterprise-architecture">Enterprise Architecture in Disciplined Agile</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/enterprise-architect/">Enterprise Architect in SAFe</a>"</p></li> -</ul> -<p>Стандарты:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/">Open Agile Architecture: A Standard of The Open Group</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.iso.org/standard/50508.html">ISO/IEC/IEEE 42010:2011(en) Systems and software engineering — Architecture description</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.iso.org/standard/68982.html">ISO/IEC/IEEE 42020:2019 Software, systems and enterprise — Architecture processes</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.iso.org/standard/73436.html">ISO/IEC/IEEE 42030:2019 Software, systems and enterprise — Architecture evaluation framework</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.iso.org/standard/35733.html">ISO/IEC 25010:2011 Systems and software engineering — Systems and software Quality Requirements and Evaluation (SQuaRE) — System and software quality models</a>"</p></li> -<li><p><a class="reference external" href="https://allgosts.ru/35/080/gost_r_57100-2016">ГОСТ Р 57100-2016 Системная и программная инженерия. Описание архитектуры</a></p></li> -</ul> -<p>Рейтинг инструментов для упраления требованиями/архитектурой/SDLC/etc. от Gartner по категориям: "<a class="reference external" href="https://www.gartner.com/reviews/markets">Reviews Organized by Markets</a>".</p> +<section id="program-management"> +<span id="emacsway-program-management"/><h2><a class="toc-backref" href="#id21" role="doc-backlink">Program Management</a></h2> +<p>Знаете, почему не бывает больших червяков? +Любое беспозвоночное животное не может быть бесконечно большим, поскольку на определенном пороге сила его тяжести превысит предел его прочности. +Рост силы тяжести опережает рост прочности. +Чтобы увеличение массы организма стало возможным, в нем должен появиться скелет, который выполняет опорную функцию.</p> +<p>По этой же причине бумажный кораблик хорошо держит форму, но если его пропорционально увеличить в несколько раз, то он рухнет под собственной тяжестью без фермы жесткости.</p> +<p>По этой же причине невозможно фрактально увеличить село до размеров крупного города, не обеспечив в нем транспортные магистрали и узлы связи.</p> +<p>Эту проблему хорошо сформулировал Galileo Galilei в теории theory of Beam Bending:</p> +<blockquote> +<div><figure class="align-left" id="id15"> +<a class="reference internal image-reference" href="../../../_images/galileo-beam-bending.jpg"><img alt="Discorsi e dimostrazioni matematiche, intorno à due nuoue scienze. Leiden: appresso gli Elsevirii, 1638. The image source is &quot;Galileo's Beam Experiment&quot; https://civil.lindahall.org/strength.shtml" src="../../../_images/galileo-beam-bending.jpg" style="width: 200px;"/></a> +<figcaption> +<p><span class="caption-text">Discorsi e dimostrazioni matematiche, intorno à due nuoue scienze. Leiden: appresso gli Elsevirii, 1638. The image source is "<a class="reference external" href="https://civil.lindahall.org/strength.shtml">Galileo's Beam Experiment</a>"</span></p> +</figcaption> +</figure> +</div></blockquote> +<blockquote> +<div><p>📝 "Many mathematicians before Galileo had dealt with the problem of statics – how forces are transmitted by structural members. +Galileo proposed a new science, the study of the strength of materials, that considered how the size and shape of structural members affects their ability to carry and transmit loads. +He discovered that as the length of a beam increases, its strength decreases, unless you increase the thickness and breadth at an even greater rate. +You cannot, therefore, simply double or triple the dimensions of a beam, and expect it to carry double or triple the load. +This led Galileo to recognize what we now call <strong>the scaling problem – there are limits to how big nature can make a tree, or an animal, for beyond a certain limit, the branches of the tree or the limbs of the animal, will break under their own weight.</strong></p> +<p>The illustration of a cantilever beam demonstrates Galileo’s discovery that the breaking force on a beam increases as the square of its length."</p> +<p class="attribution">—"<a class="reference external" href="https://civil.lindahall.org/strength.shtml">Galileo's Beam Experiment</a>"</p> +</div></blockquote> +<p>Масса балки зависит от ее объема (кубатура), а прочность - от сечения (квадратура). Т.е. масса возрастает на одно изменение больше прочности.</p> +<p>Попытка фрактально увеличивать численность Scrum/Nexus-команд равносильна попытке создать беспозвоночное животное с массой динозавра. +Основная тяжесть, под которой рушится прочность коллектива, формируется коммуникативной нагрузкой (з-н Брукса: n(n-1)/2).</p> +<p>Если предыдущий пример показался вам неубедительным, то давайте попробуем представить себе управление воздушным движением без диспетчеров. +Ну, такие... самоорганизующиеся экипажи. +Чтобы пилоты во время полета сами между собой договаривались о том, как они будут расходиться, какие эшелоны они будут занимать, в какой очередности они будут производить посадку и взлет... +Причем, гипотетически это еще было бы осуществимо где-то в районе малозагруженных аэропортов. +Но при этом возрастет когнитивная нагрузка на пилота. +Ни один из пилотов, в условиях управления воздушным судном, не обладает ресурсами внимания достаточными для достижения целостного понимания картины воздушного движения. +Эту когнитивную нагрузку с него снимает диспетчер управления воздушным движением. +А теперь попробуйте представьте себе что-то подобное в Шереметьево. +А если какое-то одно воздушное судно терпит бедствие и нуждается в аварийной посадке?</p> +<section id="spotify"> +<h3><a class="toc-backref" href="#id22" role="doc-backlink">Spotify</a></h3> +<p>Даже в Spotify существует такой "опорный скелет":</p> +<blockquote> +<div><p>📝 "At Spotify there is a separate operations team, but their job is not to make releases for the squads -­ their job is to give the squads the support they need to release code themselves; support in the form of infrastructure, scripts, and routines. +They are, in a sense, "building the road to production".</p> +<p>&lt;...&gt;</p> +<p>We also have a chief architect role, a person who coordinates work on high-­level architectural issues that cut across multiple systems. +He reviews development of new systems to make sure they avoid common mistakes, and that they are aligned with our architectural vision. +The feedback is always just suggestions and input -­ the decision for the final design of the system still lies with the squad building it."</p> +<p class="attribution">—"<a class="reference external" href="https://www.scrumatscale.com/wp-content/uploads/2020/09/S@S_Spotify_Scaling.pdf">Scaling Agile @ Spotify with Tribes, Squads, Chapters &amp; Guilds</a>" by Henrik Kniberg &amp; Anders Ivarsson, Oct 2012</p> +</div></blockquote> +<p>Но более отчетливо этот скелет сформирован в виде Program Management в <a class="reference external" href="https://www.scaledagileframework.com/">Scaled Agile Framework (SAFe)</a> и в <a class="reference external" href="https://www.pmi.org/disciplined-agile/process/introduction-to-dad">Disciplined agile delivery (DAD)</a>.</p> +<p>SAFe создан известным автором по аналитике Dean Leffingwell, и, наверное, поэтому SAFe хорошо регламентирует процессы, предшествующие этапу реализации ПО в условиях масштабируемой Agile-разработки.</p> </section> -<section id="id30"> -<h3><a class="toc-backref" href="#id80" role="doc-backlink">Аналитика</a></h3> -<ul class="simple"> -<li><p>"Software Requirements (Developer Best Practices)" 3rd Edition by Karl Wiegers</p></li> -<li><p>"<a class="reference external" href="https://bertrandmeyer.com/2022/10/28/new-book-requirements-handbook/">Handbook of Requirements and Business Analysis</a>" by Bertrand Meyer</p></li> -<li><p>"INCOSE Guide for Writing Requirements" by INCOSE</p></li> -<li><p>"<a class="reference external" href="https://www.incose.org/products-and-publications/se-handbook">Systems engineering handbook. A guide for System Life Cycle Processes and activities.</a>" by INCOSE</p></li> -<li><p>"Managing Software Requirements: A Unified Approach" 1st edition by Dean Leffingwell, Don Widrig</p></li> -<li><p>"Managing Software Requirements (paperback): A Use Case Approach" 2d Edition by Dean Leffingwell, Don Widrig</p></li> -<li><p>"Requirements Engineering Fundamentals: A Study Guide for the Certified Professional for Requirements Engineering Exam - Foundation Level - IREB compliant" 2nd Edition by Klaus Pohl, Chris Rupp</p></li> -<li><p>"Прикладной системный анализ" / Ф.П. Тарасенко</p></li> -<li><p>"<a class="reference external" href="https://www.iiba.org/career-resources/a-business-analysis-professionals-foundation-for-success/babok/">A Guide to the Business Analysis Body of Knowledge (BABOK®)</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.sebokwiki.org/wiki/Download_SEBoK_PDF">Guide to the Systems Engineering Body of Knowledge (SEBoK)</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/en/downloads/tag:handbook">Library of IREB artifacts</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/5-cpre-foundation-level-handbook/cpre_foundationlevel_handbook_en_v1.0.pdf">Handbook for the CPRE Foundation Level according to the IREB Standard Education and Training for Certified Professional for Requirements Engineering (CPRE) Foundation Level</a>" Version 1.0.0</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/13-cpre-advanced-level-elicitation-handbook/advanced_level_elicitation_handbook_en.pdf">Handbook of Advanced Level Elicitation according to the IREB Standard Education and Training for IREB Certified Professional for Requirements Engineering Advanced Level Advanced Level Elicitation</a>" Version 1.0.3</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/16-cpre-advanced-level-requirements-management-handbook/ireb-cpre-handbook-for-requirements-management-advanced-level-en-v1.1.pdf">Requirements Management according to the IREB Standard Education and Training for the IREB Certified Professional for Requirements Engineering Qualification Advanced Level Requirements Management</a>" Version 1.1.0</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/19-handbook-cpre-advanced-level-requirements-modeling/ireb_cpre_handbook_requirements-modeling_advanced-level-v1.3.pdf">Handbook of Requirements Modeling According to the IREB Standard Education and Training for IREB Certified Professional for Requirements Engineering Advanced Level Requirements Modeling</a>" Version 1.3</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/1-cpre-glossary/ireb_cpre_glossary_17.pdf">A Glossary of Requirements Engineering Terminology</a>" Version 1.7</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/2-cpre-glossary-2-0/ireb_cpre_glossary_en_2.0.pdf">A Glossary of Requirements Engineering Terminology Caution: This glossary is aligned to the CPRE Foundation Level syllabus 3.0 only!</a>" Version 2.0.0</p></li> -</ul> -<p>Аналитика в Agile:</p> -<ul class="simple"> -<li><p>"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</p></li> -<li><p>Whitepaper "<a class="reference external" href="https://scalingsoftwareagility.files.wordpress.com/2007/03/a-lean-and-scalable-requirements-information-model-for-agile-enterprises-pdf.pdf">A Lean and Scalable Requirements Information Model for the Agile Enterprise</a>" by Dean Leffingwell with Juha‐Markus Aalto</p></li> -<li><p>"<a class="reference external" href="https://scalingsoftwareagility.wordpress.com/2010/03/05/an-agile-architectural-epic-kanban-system-part-2-%E2%80%93-the-model/">An Agile Architectural Epic Kanban System: Part 2 – The Model</a>" by Dean Leffingwell</p></li> -<li><p>"<a class="reference external" href="https://www.iiba.org/career-resources/business-analysis-resources/iiba-bookstore/">Agile Extension to the BABOK® Guide</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/23-cpre-advanced-level-re-agile-handbook/handbook_cpre_al_re%40agile_en_v2.0.pdf">Handbook of RE@Agile According to the IREB Standard Education and Training for IREB Certified Professional for Requirements Engineering Advanced Level RE@Agile</a>" Version 2.0</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/36-re-agile-glossary/ireb_cpre_re%40agile_glossary_v1.0.5.pdf">IREB Certified Professional for Requirements Engineering RE@Agile Glossary</a>"</p></li> -</ul> -<p>Другие подборки литературы по аналитике:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://systems.education/books">Литература по аналитике на сайте Systems.Education</a></p></li> -<li><p><a class="reference external" href="https://www.volere.org/resources/books/">Литература по аналитике на сайте Volere Requirements Resources</a>.</p></li> -</ul> -<p>Смотрите также список инструментов для управления требованиями:</p> +<section id="agile-software-requirements-lean-requirements-practices-for-teams-programs-and-the-enterprise"> +<h3><a class="toc-backref" href="#id23" role="doc-backlink">Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise</a></h3> +<p>В книге "Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell, которая вышла в печать в том же году, в котором он выпустил первый релиз SAFe, Dean Leffingwell убедительно обосновывает, что аналитики и архитекторы должны быть частью системной команды.</p> +<blockquote> +<div><p>📝 "Architects: Many agile teams do not contain people with titles containing the word architect [The best architectures, requirements, and designs emerge from self-organizing teams.], and yet architecture does matter to agile teams. +In these cases, the local architecture (that of the component, service, or feature that the team is accountable for) is most often determined by the local teams in a collaborative model. +In this way, it can be said that "architecture emerges" from the activities of those teams.</p> +<p>At the system level, however, <strong>architecture is often coordinated among system architects and business analysts who are responsible for determining the overall structure (components and services) of the system</strong>, as well as the system-level use cases and performance criteria that are to be imposed on the system as a whole. +For this reason, it is likely that the <strong>agile team has a key interface to one or more architects who may live outside the team</strong>. +(We'll discuss this in depth in Chapter 20.)</p> +<p>&lt;...&gt;</p> +<p>Some of these QA personnel will live outside the team, while others (primarily testers) will have likely been dispatched to live with the product team. +There, they work daily with developers to test new code and thereby help assure new code quality on a real-time basis.</p> +<p>In addition, as we'll see later, QA personnel are involved with the development of the system-level testing required to assure overall system quality and conformance to nonfunctional, as well as functional, requirements.</p> +<p>&lt;...&gt;</p> +<p>Other specialists and supporting personnel: Other supporting roles may include user-experience designers, documentation specialists, database designers and administrators, configuration management, build and deployment specialists, and whomever else is necessary to develop and deploy a whole product solution.</p> +<p class="attribution">—Agile Software Requirements Lean Requirements Practices for Teams, Programs, and the Enterprise (Agile Software Development Series) by Dean Leffingwell</p> +</div></blockquote> +<p>Для такого решения есть несколько причин:</p> +<ol class="arabic"> +<li><p>В спринте возникают две цели (текущая и посторонняя):</p> +<ol class="arabic simple"> +<li><p>Реализация текущего системного инкремента.</p></li> +<li><p>Анализ и проектирование (т.е. <a class="reference internal" href="../sdlc/uncertainty-management/prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Prediction-активности</span></a> в виде PBR, Spike и Planning) будущего системного инкремента.</p></li> +</ol> +<p>Источником работы аналитиков являются стейкхолдеры, а результатом работы - требования (под руководством Product Owner, разумеется), т.е. <a class="reference internal" href="../sdlc/models/agile/analysis/requirements/requirements.html#emacsway-product-backlog-item"><span class="std std-ref">PBI</span></a>. +В то время как для команды разработки источником работы являются PBI (в состоянии DOR), а результатом работы - Системный Инкремент.</p> +<p>Получается, что две команды работают несинхронно, над разными целями, и производят разные артефакты. +Аналитики работают вне цикла реализации Системного Инкремента, опережая его в среднем на пару спринтов.</p> +<p>PBI, не производящий Системного Инкремента, но производящий артефакты, необходимые для доведения другого PBI до состояния DOR, традиционно называется Spike. +Spike нацелен на достижение цели будущих спринтов, поэтому его присутствие в текущем спринте отвлекает от цели текущего спринта, повышает когнитивную нагрузку и затрудняет управление Team Backlog. +Говоря архитектурным языком, налицо все признаки падения Cohesion, который восстанавливается, как известно, путем декомпозиции. +Для малочисленного коллектива (тем более, для Single Team Agile) эта нагрузка не превышает накладные расходы на содержание отдельного Program Backlog. +Но, по мере роста численности коллектива, накладные расходы на содержание отдельного Program Backlog начинают уже окупаться.</p> +</li> +<li><p>По мере роста численности коллектива растет коммуникативная нагрузка, и требуется <a class="reference internal" href="#emacsway-harlan-mills-proposal"><span class="std std-ref">повышение уровня автономности команд</span></a>.</p></li> +<li><p>Системные инкременты, производимы командами, нуждаются в интеграции. Было бы неэффективно каждой команде погружаться в подробности целостной картины потребностей интеграции, при этом дублируя друг друга.</p></li> +<li><p>Стоимость <a class="reference internal" href="../sdlc/uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">адаптации</span></a> Продукта возрастает стремительней роста численность коллектива, что создает экономическую целесообразность для смещения <a class="reference internal" href="../sdlc/uncertainty-management/balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">баланса Pridiction/Adaptation</span></a> в сторону <a class="reference internal" href="../sdlc/uncertainty-management/prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Prediction</span></a>.</p></li> +</ol> +<p>Поэтому, аналитику, архитектуру и UX/UI Design, в таком случае, выводят в отдельный цикл производства, известный сегодня как Program Management (который следует отличать от Program Management в PMBoK). +Получается два каскадных цикла, при этом, первый цикл (Program Backlog) создает артефакты, необходимые для достижения DOR для второго цикла (Team Backlogs), который, в свою очередь, уже производит системный инкремент.</p> +<p>Говоря о проблемах масштабирования Agile-команд, мне очень интересной показалась ещё одна его книга, которая вышла 4-мя годами ранее:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://www.volere.org/tools/">Tools</a> on Volere Requirements Resources</p></li> -<li><p><a class="reference external" href="https://www.volere.org/requirements-tools/">Requirements Tools</a> on Volere Requirements Resources</p></li> +<li><p>"Scaling Software Agility: Best Practices for Large Enterprises" by Dean Leffingwell</p></li> </ul> </section> -<section id="id31"> -<h3><a class="toc-backref" href="#id81" role="doc-backlink">Изучаем оценивание задач</a></h3> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/framework/practice-standard-scheduling-3rdedition">Practice Standard for Scheduling</a>" 3d edition by Project Management Institute</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/framework/practice-standard-for-estimating">Practice Standard for Project Estimating</a>" 2d edition Project Management Institute</p></li> -<li><p>"Software Estimation: Demystifying the Black Art (Developer Best Practices)" by Steve McConnell (я встречал в интернете <a class="reference external" href="http://igorshevchenko.ru/blog/entries/software-estimation">краткий конспект</a>)</p></li> -<li><p>"Agile Estimating and Planning" by Mike Cohn</p></li> -</ul> -<p>Очень кратко (всего 3 страницы) о методике оценивания PERT:</p> -<ul class="simple"> -<li><p>"The Clean Coder" by Robert C. Martin, "Chapter 10 Estimation :: PERT"</p></li> -</ul> -<p>Статья, отвечающая на очень частый вопрос:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.mountaingoatsoftware.com/blog/how-do-story-points-relate-to-hours">How Do Story Points Relate to Hours?</a>" by Mike Cohn</p></li> +<section id="scaled-agile-framework-safe"> +<h3><a class="toc-backref" href="#id24" role="doc-backlink">Scaled Agile Framework (SAFe)</a></h3> +<ul> +<li><p>"<a class="reference external" href="https://www.amazon.com/dp/B08F5HC37Z">SAFe® 5.0 Distilled: Achieving Business Agility with the Scaled Agile Framework®</a>" by Richard Knaster, Dean Leffingwell</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/program-and-solution-backlogs/">Program and Solution Backlogs</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/system-architect-engineering/">System Architect/Engineering</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/agile-teams/">Agile Teams</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/organizing-agile-teams-and-arts-team-topologies-at-scale/">Organizing Agile Teams and ARTs: Team Topologies at Scale</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/shared-services/">Shared Services</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/architectural-runway/">Architectural Runway</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/agile-architecture/">Agile Architecture in SAFe</a>"</p> +<blockquote> +<div><p>📝 "The second dimension of the team and technical agility competency is teams of Agile teams. +Even with good, local execution, building enterprise-class solutions typically requires more scope and breadth of skills than a single Agile team can provide. +Therefore, Agile teams operate in the context of an ART, which is a long-lived team of Agile teams. +The ART incrementally develops, delivers, and (where applicable) operates one or more solutions (Figure 6-5)."</p> +<p>📝 "System Architect/Engineering is an individual or team that defines the overall architecture of the system. +They work at a level of abstraction above the teams and components and define Non-Functional Requirements (NFRs), major system elements, subsystems, and interfaces."</p> +<p>📝 "System Teams typically assist in building and supporting DevOps infrastructure for development, continuous integration, automated testing, and deployment into the staging environment. +In larger systems they may do end-to-end testing, which cannot be readily accomplished by individual Agile teams."</p> +<p>📝 "Shared Services are specialists—for example, data security, information architects, Database Administrators (DBAs)—who are necessary for the success of an ART but cannot be dedicated to a specific train."</p> +<p>📝 "With the right architecture, elements of the system may be released independently. +Figure 8-8 illustrates an autonomous delivery system that was architected to enable system elements to be released independently."</p> +<p>📝 "Figure 8-8. Architecture impacts the ability to release system elements independently"</p> +<p class="attribution">—"SAFe® 5.0: The World's Leading Framework for Business Agility" by Richard Knaster, Dean Leffingwell</p> +</div></blockquote> +</li> </ul> </section> -<section id="id32"> -<h3><a class="toc-backref" href="#id82" role="doc-backlink">Функциональное программирование</a></h3> -<ul class="simple"> -<li><p><a class="reference external" href="http://se.ethz.ch/~meyer/publications/functional/meyer_functional_oo.pdf">"Software architecture: object-oriented vs functional</a>" by Bertrand Meyer</p></li> -<li><p>"<a class="reference external" href="https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/">Category Theory for Programmers</a>" by Bartosz Milewski (<a class="reference external" href="https://github.com/hmemcpy/milewski-ctfp-pdf">unofficial PDF and LaTeX source</a>)</p></li> -<li><p>"<a class="reference external" href="https://fsharpforfunandprofit.com/books/">Domain Modeling Made Functional. Tackle Software Complexity with Domain-Driven Design and F#</a>" by Scott Wlaschin</p></li> -<li><p>"<a class="reference external" href="https://fsharpforfunandprofit.com/">F# for Fun and Profit</a>" by Scott Wlaschin</p></li> -<li><p>"Functional Programming for the Object-Oriented Programmer" by Brian Marick</p></li> -<li><p>"Functional Thinking" by Neal Ford</p></li> -<li><p>"<a class="reference external" href="https://en.wikibooks.org/wiki/Haskell">Haskell</a>"</p></li> -<li><p>"<a class="reference external" href="https://github.com/winitzki/sofp/blob/master/sofp-src/sofp.pdf">The Science of Functional Programming. A Tutorial, with Examples in Scala.</a>" by Sergei Winitzki, Ph.D.</p></li> -<li><p>"Microservices with Clojure. Develop event-driven, scalable, and reactive microservices with real-time monitoring" by Anuj Kumar</p></li> -</ul> -<p>Для Golang-разработчиков:</p> +<section id="agile-practice-guide-by-pmi"> +<h3><a class="toc-backref" href="#id25" role="doc-backlink">"Agile Practice Guide" by PMI</a></h3> +<p>Отдельно стоит выделить книгу "<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute, 2017, поскольку эта книга является мощным оружием в руках аналитиков и архитекторов в вопросах организации качественных процессов. +Автором книги является Project Management Institute (PMI), обладающий неоспоримым авторитетом в глазах менеджмента. +Книга достаточно грамотная, и затрагивает острые вопросы интеграции аналитической и архитектурной активности в Agile-разработку. +В общем, если вы где-то услышите фразу "Architecture vs. Agile", то самое время вспомнить об этой книге.</p> <ul class="simple"> -<li><p>"Learning Functional Programming in Go: Change the way you approach your applications using functional programming in Go" by Lex Sheehan</p></li> +<li><p>"<a class="reference external" href="https://scalingsoftwareagility.files.wordpress.com/2007/03/a-lean-and-scalable-requirements-information-model-for-agile-enterprises-pdf.pdf">A Lean and Scalable Requirements Information Model for the Agile Enterprise</a>" by Dean Leffingwell with Juha‐Markus Aalto</p></li> </ul> </section> -<section id="id33"> -<h3><a class="toc-backref" href="#id83" role="doc-backlink">Справочники</a></h3> +<section id="disciplined-agile-delivery-dad"> +<h3><a class="toc-backref" href="#id26" role="doc-backlink">Disciplined agile delivery (DAD)</a></h3> +<p>И еще один официальный способ о том, как интегрировать работу аналитиков и архитекторов в Scrum:</p> <ul class="simple"> -<li><p>"Computing Handbook. Computer Science and Software Engineering." 3d edition by Allen Tucker, Teofilo Gonzalez, Jorge Diaz-Herrera</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile/lifecycle/program">DAD Life Cycle – Program (Team of Teams)</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile/process/program-management">Program Management</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile/agility-at-scale/tactical-agility-at-scale/large-agile-teams">Large Agile Teams</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile/agility-at-scale/tactical-agility-at-scale/large-agile-teams/organizing-agile-teams#Large">Organizing Agile Teams : Large Teams/Programs</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/foundational/program-management">The Standard for Program Management – Fourth Edition</a>"</p></li> </ul> -</section> -</section> -<section id="id34"> -<h2><a class="toc-backref" href="#id84" role="doc-backlink">Справочная информация</a></h2> -<section id="body-of-knowledge"> -<h3><a class="toc-backref" href="#id85" role="doc-backlink">Body of Knowledge</a></h3> +<p>Учитывая, что Disciplined agile delivery (DAD) сопровождается и развивается by Project Management Institute (PMI), интеграция его практик вызвает, как правило, меньше всего возражений со стороны менеджмента.</p> +<p>См. также:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://www.sebokwiki.org/wiki/Download_SEBoK_PDF">Guide to the Systems Engineering Body of Knowledge (SEBoK)</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.computer.org/education/bodies-of-knowledge/software-engineering">Software Engineering Body of Knowledge (SWEBOK) v.3</a>" (<a class="reference external" href="https://github.com/ligurio/swebok-2004-in-russian">на русском</a>)</p></li> -<li><p>"<a class="reference external" href="https://waseda.app.box.com/v/ieee-cs-swebok">Software Engineering Body of Knowledge (SWEBOK) v.4 (draft)</a>"</p></li> -<li><p>"<a class="reference external" href="https://itabok.iasaglobal.org/">The Information Technology Architecture Body of Knowledge (ITABoK)</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.mitre.org/publications/technical-papers/guide-to-the-evolving-enterprise-architecture-body-of-knowledge">The Enterprise Architecture Body of Knowledge (EABoK)</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.mitre.org/publications/technical-papers/the-mitre-systems-engineering-guide">MITRE Systems Engineering Guide</a></p></li> -<li><p>"<a class="reference external" href="https://www.businessarchitectureguild.org/page/BIZBOK">A Guide to the Business Architecture Body of Knowledge(R) (BIZBOK(R) Guide)</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.iiba.org/career-resources/a-business-analysis-professionals-foundation-for-success/babok/">A Guide to the Business Analysis Body of Knowledge (BABOK®)</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.iiba.org/career-resources/business-analysis-resources/iiba-bookstore/">Agile Extension to the BABOK® Guide</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.dama.org/content/what-data-management">DAMA-DMBOK: Data Management Body of Knowledge</a>" 2nd edition by DAMA International</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/foundational/pmbok">The Project Management Body of Knowledge (PMBoK)</a>" by Project Management Institute (PMI)</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute (PMI), 2017</p></li> -<li><p>"<a class="reference external" href="https://book4cio.ru/">Учебник 4CIO. Настольная книга ИТ-Директора</a>"</p></li> -<li><p>"<a class="reference external" href="https://4cio.ru/pages/570">Учебник 4CDTO. Настольная книга руководителя цифровой трансформации</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.incose.org/products-and-publications/se-handbook">Systems engineering handbook. A guide for System Life Cycle Processes and activities.</a>" by INCOSE</p></li> -<li><p>"<a class="reference external" href="https://sfia-online.org/en">The global skills and competency framework for a digital world</a>" by SFIA Foundation</p></li> -<li><p>"<a class="reference external" href="https://sfia-online.org/en/tools-and-resources/bodies-of-knowledge/list-of-bodies-of-knowledge">List of Bodies of Knowledge</a>" by SFIA Foundation</p></li> -<li><p>"<a class="reference external" href="https://mellarius.ru/">mellarius.ru</a>" - превосходный минималистичный и самодостаточный справочник по архитектуре, анализу, организации процессов, тестированию и т.п.</p></li> +<li><p>"<a class="reference external" href="http://agilemodeling.com/essays/agileArchitecture.htm">Agile Architecture: Strategies for Scaling Agile Development</a>"</p></li> </ul> </section> -<section id="id35"> -<h3><a class="toc-backref" href="#id86" role="doc-backlink">ГОСТы</a></h3> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://allgosts.ru/35/">База ГОСТов allgosts.ru - 35. ИНФОРМАЦИОННЫЕ ТЕХНОЛОГИИ. МАШИНЫ КОНТОРСКИЕ</a>"</p></li> -<li><p>"<a class="reference external" href="https://standartgost.ru/0/753-informatsionnye_tehnologii_mashiny_kontorskie">StandartGOST.ru - бесплатные ГОСТы и магазин документов. Информационные технологии. Машины конторские</a>"</p></li> -</ul> +<section id="iso-iec-ieee-12207-2017"> +<h3><a class="toc-backref" href="#id27" role="doc-backlink">ISO/IEC/IEEE 12207:2017</a></h3> +<blockquote> +<div><p>📝 "Agile projects for complex systems attempt to manage cost by prioritizing the most important capabilities for early realization. +If an organization manages the development and maintenance of its entire portfolio of software systems as a single system, managed by spend rate rather than total spending, then the organization can, in principle, manage that portfolio of systems as a continuing agile development, analogous to managing a highly iterative "Kanban" maintenance effort."</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> +</div></blockquote> </section> -<section id="online"> -<h3><a class="toc-backref" href="#id87" role="doc-backlink">Online-каталоги</a></h3> +<section id="nexus"> +<h3><a class="toc-backref" href="#id28" role="doc-backlink">Nexus</a></h3> +<p>На scrum.org есть интересная статья, сравнивающая Nexus и SAFe:</p> <ul class="simple"> -<li><p><a class="reference external" href="http://www.refactoring.com/catalog/">Catalog of Refactorings</a></p></li> -<li><p><a class="reference external" href="http://c2.com/cgi/wiki?CodeSmell">Code Smell</a></p></li> -<li><p><a class="reference external" href="http://c2.com/cgi/wiki?AntiPatternsCatalog">Anti Patterns Catalog</a></p></li> -<li><p><a class="reference external" href="https://martinfowler.com/eaaCatalog/">Catalog of Patterns of Enterprise Application Architecture</a></p></li> -<li><p><a class="reference external" href="https://www.martinfowler.com/dslCatalog/">List of DSL Patterns</a></p></li> -<li><p><a class="reference external" href="http://www.enterpriseintegrationpatterns.com/">Enterprise Integration Patterns</a> (<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/download/EIPTutorialReferenceChart.pdf">шпаргалка по EIP</a>)</p></li> -<li><p><a class="reference external" href="https://verraes.net/2019/05/ddd-msg-arch/">DDD and Messaging Architectures</a> - an overview of different series on patterns in distributed systems by Mathias Verraes.</p></li> -<li><p><a class="reference external" href="http://servicedesignpatterns.com/">Service Design Patterns</a></p></li> -<li><p><a class="reference external" href="https://patterns.arcitura.com/soa-patterns">SOAPatterns.org</a></p></li> -<li><p><a class="reference external" href="https://patterns.arcitura.com/cloud-computing-patterns">CloudPatterns.org</a></p></li> -<li><p><a class="reference external" href="https://patterns.arcitura.com/big-data-patterns">BigDataPatterns.org</a></p></li> -<li><p><a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/">Cloud Design Patterns | Microsoft Docs</a></p></li> -<li><p><a class="reference external" href="http://workflowpatterns.com/patterns/">Workflow Patterns</a></p></li> -<li><p><a class="reference external" href="https://microservices.io/patterns/">Microservices Patterns</a></p></li> -<li><p><a class="reference external" href="https://www.manning.com/books/microservice-patterns">Microservices Patterns (book)</a></p></li> -<li><p><a class="reference external" href="https://samnewman.io/patterns/">Microservices Patterns from Sam Newman</a></p></li> -<li><p><a class="reference external" href="http://ddd.fed.wiki.org/">About DDD on the site of Ward Cunningham</a></p></li> -<li><p><a class="reference external" href="http://www.databaserefactoring.com/">Refactoring Databases</a></p></li> -<li><p><a class="reference external" href="http://xunitpatterns.com/">XUnit Test Patterns</a></p></li> -<li><p><a class="reference external" href="https://databaserefactoring.com/">Refactoring Databases</a></p></li> -<li><p><a class="reference external" href="http://www.agiledata.org/essays/databaseRefactoringCatalog.html">Catalog of Database Refactorings</a></p></li> -<li><p><a class="reference external" href="http://www.extremeprogramming.org/rules.html">Extreme Programming Rules</a></p></li> -<li><p><a class="reference external" href="https://jepsen.io/consistency">Consistency Models - a clickable map</a></p></li> -<li><p><a class="reference external" href="https://www.agilealliance.org/agile101/subway-map-to-agile-practices/">Subway Map to Agile Practices - a clickable map</a></p></li> -<li><p><a class="reference external" href="https://patterns.arcitura.com/">The Arcitura Education Patterns, Mechanisms and Metrics Master Catalog</a></p></li> -<li><p><a class="reference external" href="https://microservice-api-patterns.org/">Microservice API Patterns</a></p></li> -<li><p><a class="reference external" href="https://www.openapis.org/">OpenAPIs</a></p></li> -<li><p><a class="reference external" href="https://www.asyncapi.com/">AsyncAPI</a></p></li> -<li><p><a class="reference external" href="https://nocomplexity.com/documents/arplaybook/">Architecture Playbook</a> (<a class="reference external" href="https://github.com/nocomplexity/ArchitecturePlaybook">source</a>)</p></li> -<li><p><a class="reference external" href="https://www.viewpoints-and-perspectives.info/">Software Systems Architecture</a> - This web site contains a selection of supporting material for the book ("Software Systems Architecture: Working With Stakeholders Using Viewpoints and Perspectives" 2nd edition by Nick Rozanski, Eóin Woods), including sample chapters, references and white papers.</p></li> +<li><p>"<a class="reference external" href="https://www.scrum.org/resources/blog/comparing-nexus-and-safe-similarities-differences-potential-synergies">Comparing Nexus and SAFe - Similarities, Differences, potential synergies</a>" by Yuval Yeret</p></li> </ul> -</section> -<section id="code-smell-catalogs"> -<h3><a class="toc-backref" href="#id88" role="doc-backlink">Code Smell catalogs</a></h3> +<p>Интересна она, прежде всего, тем, что открыто говорит о проблемах Nexus, которые можно решить путем заимствования практик у SAFe.</p> +<p>Одним из наиболее узких мест Nexus является отсутствие масштабирования аналитической работы (сбор требований) в problem space. +Команды масштабируются, а бизнес-анализ, в лице единственного Product Owner, - нет. +Scrum, как известно, оставляет Product Owner с этой проблемой наедине, предлагая ему самостоятельно решать эту проблему путем делегации полномочий в случаях, когда аналитическая работа становится узким горлышком.</p> +<blockquote> +<div><p>📝 "it's hard for one Product Owner to deal with too many teams... +In real life, these Product Owners are typically accountable for the value delivered by these multiple teams and rely upon a lot of assistance from the Development Teams in order to deal with the challenge of scale."</p> +<p class="attribution">—"<a class="reference external" href="https://www.scrum.org/resources/blog/comparing-nexus-and-safe-similarities-differences-potential-synergies">Comparing Nexus and SAFe - Similarities, Differences, potential synergies</a>" by Yuval Yeret</p> +</div></blockquote> +<blockquote> +<div><p>📝 "A Nexus has a single Product Owner who manages a single Product Backlog from which the Scrum Teams work."</p> +<p class="attribution">—"<a class="reference external" href="https://www.scrum.org/resources/online-nexus-guide">The 2021 Nexus™ Guide</a></p> +</div></blockquote> +<blockquote> +<div><p>📝 "The Product Owner may do the above work or may delegate the responsibility to others. Regardless, the Product Owner remains accountable."</p> +<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "In multi-team programs, this one Product Owner may delegate the work to Product Owners that represent him or her on subordinate teams, but all decisions and direction come from the top-level, single Product Owner.</p> +<p class="attribution">—"Jeff Sutherland's Scrum Handbook" by Jeff Sutherland</p> +</div></blockquote> +<p>Статья подчеркивает ограниченность масштабирования Nexus по этой причине и предлагает к рассмотрению SAFe-практики:</p> +<blockquote> +<div><p>📝 "As Nexus is designed to be a lightweight framework, with a more limited scope than SAFe, its not surprising that there are a lot more elements in SAFe that Nexus doesn't say anything about. +Some of these can be useful in your context, some not necessarily. +Think Architectural Runway, Innovation and Planning iteration, Team-level Kanbans, DevOps, Continuous Delivery pipeline, System Architect, Business Owner, Features/Enablers, Epics."</p> +<p class="attribution">—"<a class="reference external" href="https://www.scrum.org/resources/blog/comparing-nexus-and-safe-similarities-differences-potential-synergies">Comparing Nexus and SAFe - Similarities, Differences, potential synergies</a>" by Yuval Yeret</p> +</div></blockquote> +<p>В числе прочего, упоминается и выделенная роль системного архитектора, поскольку в масштабируемом Agile возникают вопросы одновременного достижения как интеграции инкремента продукта, так и автономности команд.</p> +<p>В статье много лестных отзывов о Program Kanban:</p> +<blockquote> +<div><p>📝 "Program Kanban. +SAFe includes one of the most powerful techniques to help improve flow and collaboration across a team of teams - a Kanban Board that takes a cross-team perspective. +I started using this technique back in 2009 and it's one I "don't leave home without". +Nexus doesn't include a Nexus-level Kanban board but it's a very nice complementary practice to consider. +<a class="reference external" href="https://www.scrum.org/resources/blog/scaling-scrum-nexus-and-kanban">Read more here</a>"</p> +<p class="attribution">—"<a class="reference external" href="https://www.scrum.org/resources/blog/comparing-nexus-and-safe-similarities-differences-potential-synergies">Comparing Nexus and SAFe - Similarities, Differences, potential synergies</a>" by Yuval Yeret</p> +</div></blockquote> +<p>Здесь автор ссылается на другую свою статью "<a class="reference external" href="https://www.scrum.org/resources/blog/scaling-scrum-nexus-and-kanban">Scaling Scrum with Nexus and Kanban</a>" by Yuval Yeret, где предлагает интегрировать Program Management в самую легковесную scaled Scrum модель разработки Nexus, подобно тому, как это сделано в SAFe.</p> +<blockquote> +<div><p>📝 "This will include all stages of work in the Nexus - ranging from Value discovery..."</p> +<p class="attribution">—"<a class="reference external" href="https://www.scrum.org/resources/blog/scaling-scrum-nexus-and-kanban">Scaling Scrum with Nexus and Kanban</a>" by Yuval Yeret</p> +</div></blockquote> +<p>Хотя в Scrum и можно выстроить хорошо отлаженные процессы, но это требует настолько деликатной работы, что я бы предпочел рассматривать сразу SAFe даже для маленьких команд (минимальную его конфигурацию - Essential Safe):</p> <ul class="simple"> -<li><p>Chapter 17: "Smells and Heuristics" of the book "Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p></li> -<li><p>Chapter 3. "Bad Smells in Code" of the book "Refactoring: Improving the Design of Existing Code" by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p></li> -<li><p><a class="reference external" href="http://c2.com/cgi/wiki?CodeSmell">Code Smell</a> catalog on the site of Ward Cunningham</p></li> -<li><p>"Refactoring To Patterns" by Joshua Kerievsky</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/guidance-six-safe-practices-for-s-sized-teams/">Six SAFe Practices for S-Sized Teams</a>" by Juha-Markus Aalto, Director Product Development, Qentinel Group</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/essential-safe/">Essential SAFe</a>"</p></li> </ul> </section> -<section id="id36"> -<h3><a class="toc-backref" href="#id89" role="doc-backlink">Другие подборки литературы</a></h3> -<ul class="simple"> -<li><p><a class="reference external" href="https://github.com/sindresorhus/awesome">Awesome lists</a></p></li> -<li><p><a class="reference external" href="https://github.com/heynickc/awesome-ddd">Awesome Domain-Driven Design</a></p></li> -<li><p><a class="reference external" href="https://mehdihadeli.github.io/awesome-go-education/ddd/">Awesome Go Education: DDD</a></p></li> -<li><p><a class="reference external" href="https://mehdihadeli.github.io/awesome-go-education/cqrs/">Awesome Go Education: CQRS</a></p></li> -<li><p><a class="reference external" href="https://mehdihadeli.github.io/awesome-go-education/event-sourcing/">Awesome Go Education: Event Sourcing</a></p></li> -<li><p><a class="reference external" href="https://mehdihadeli.github.io/awesome-go-education/clean-architecture/">Awesome Go Education: Clean Architecture</a></p></li> -<li><p><a class="reference external" href="https://github.com/valignatev/ddd-dynamic">Domain Driven Design in Python, Ruby and other dynamic languages resources</a></p></li> -<li><p><a class="reference external" href="https://github.com/mfornos/awesome-microservices">Awesome Microservices</a></p></li> -<li><p><a class="reference external" href="https://github.com/unlight/solution-architecture">Solution Architecture links, articles, books, video lessons, etc.</a></p></li> -<li><p><a class="reference external" href="https://github.com/tayllan/awesome-algorithms">Awesome Algorithms</a></p></li> -<li><p><a class="reference external" href="https://github.com/gaerae/awesome-algorithms-education">Awesome Algorithms Education</a></p></li> -<li><p><a class="reference external" href="https://github.com/donnemartin/system-design-primer">The System Design Primer</a> - Learn how to design large-scale systems. Prep for the system design interview.</p></li> -<li><p><a class="reference external" href="https://github.com/prakhar1989/awesome-courses">List of awesome university courses for learning Computer Science</a></p></li> -<li><p><a class="reference external" href="http://e-maxx.ru/bookz/">MAXimal :: bookz - электронные версии различных книг по алгоритмам</a></p></li> -<li><p><a class="reference external" href="http://www.kamilgrzybek.com/programming-and-design-resources/">Programming and design learning resources by Kamil Grzybek</a></p></li> -<li><p><a class="reference external" href="https://sergeyteplyakov.blogspot.com/2013/08/blog-post.html">Список книг от Сергея Теплякова</a></p></li> -<li><p><a class="reference external" href="https://handbookofsoftwarearchitecture.com/books/">Список книг от Grady Booch</a></p></li> -<li><p><a class="reference external" href="https://www.luxoft-training.ru/about/experts/answers/302/30945/">Книги по направлению Архитектура и проектирование ПО от эксперта luxoft</a></p></li> -<li><p><a class="reference external" href="https://architectelevator.com/architecture/architect-path/">The Architect's Path (Part 1 - Model)</a> by Gregor Hohpe</p></li> -<li><p><a class="reference external" href="https://architectelevator.com/architecture/architect-bookshelf/">The Architect's Path (Part 2 - Implementation)</a> by Gregor Hohpe</p></li> -<li><p><a class="reference external" href="https://www.developertoarchitect.com/books.html">Software Architecture Book References</a> by Mark Richards</p></li> -<li><p><a class="reference external" href="https://ruxpert.ru/%D0%98%D1%81%D0%BA%D1%83%D1%81%D1%81%D1%82%D0%B2%D0%BE_%D1%81%D0%BF%D0%BE%D1%80%D0%B0_(%D0%BE%D0%B1%D1%83%D1%87%D0%B0%D1%8E%D1%89%D0%B8%D0%B5_%D0%BC%D0%B0%D1%82%D0%B5%D1%80%D0%B8%D0%B0%D0%BB%D1%8B)">Искусство спора (обучающие материалы)</a></p></li> -<li><p><a class="reference external" href="https://m.vk.com/wall-56611080_127534">Книги по риторике</a></p></li> -</ul> +<section id="extreme-programming"> +<h3><a class="toc-backref" href="#id29" role="doc-backlink">Extreme Programming</a></h3> +<blockquote> +<div><p>📝 "With awareness and appropriate adaptations, <strong>XP does scale</strong>. +Some problems can be simplified to be easily handled by a small XP team. +For others, XP must be augmented. +The basic values and principles apply at all scales. +The practices can be modified to suit your situation."</p> +<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Chapter 15. Scaling XP :: Conclusion"</p> +</div></blockquote> +<p>Во втором издании "Extreme Programming Explained", Kent Beck предлагает механизм масштабирования команд, который в точности реализует Program Management на основе <a class="reference internal" href="#emacsway-harlan-mills-proposal"><span class="std std-ref">Harlan Mills' Proposal</span></a>.</p> +<blockquote> +<div><p>📝 "Creating and maintaining a community of one hundred is a much different job than creating and maintaining a community of twelve, but it is done all the time."</p> +<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Chapter 15. Scaling XP"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "If just using a smaller team doesn't work, turn the big programming problem into several smaller problems, each solvable by a small team. +First solve a small part of the problem with a small team. +Then divide the system along its natural fracture lines and begin working on it with a few teams. +<strong>Partitioning introduces the risk that the pieces won't fit on integration, so integrate frequently to reconcile differing assumptions between teams.</strong> +This is a conquer-and-divide strategy instead of a divide-and-conquer strategy. +Sabre Airline Solutions, profiled in the next chapter, uses this strategy extensively.</p> +<p>The goal of conquer-and-divide is <strong>to have teams that can each be managed as if they are the only team to limit coordination costs</strong>. +Even so, the whole <strong>system needs to be integrated frequently</strong>. +The occasional exceptions to this illusion of independence are managed as exceptions. +<strong>If the exceptions become the norm and the teams have to spend too much time coordinating, look to the system to see if there are ways of restructuring it to return the teams to independence.</strong> +<strong>Only if this fails is the overhead of large-project management appropriate.</strong></p> +<p>In summary, faced with the apparent need for a large team, first ask if a small team can solve the problem. +If that doesn't work, <strong>begin the project with a small team, then split the work among autonomous teams.</strong>"</p> +<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Chapter 15. Scaling XP :: Number of People"</p> +</div></blockquote> </section> -<section id="id37"> -<h3><a class="toc-backref" href="#id90" role="doc-backlink">Почтовые рассылки и сообщества</a></h3> -<ul class="simple"> -<li><p><a class="reference external" href="http://dddcommunity.org/">Domain Driven Design Community</a></p></li> -<li><p><a class="reference external" href="http://dddweekly.com/">Domain Driven Design Weekly</a></p></li> -<li><p><a class="reference external" href="https://microserviceweekly.com/">Microservice Weekly</a></p></li> +<section id="scrum-of-scrums"> +<h3><a class="toc-backref" href="#id30" role="doc-backlink">Scrum of Scrums</a></h3> +<blockquote> +<div><ul class="simple"> +<li><p>Each team had an architecture representative on <strong>a Scrum of Scrum architecture team led by the Business Unit Lead Architect</strong></p></li> +<li><p>The <strong>enterprise architecture team had Business Unit Lead Architects led by the CTO</strong> who had senior management commitment to 10% of all points in every sprint dedicated to architectural improvement (technical debt remediation, integration, branding, etc.)</p></li> </ul> +<p class="attribution">—"<a class="reference external" href="https://www.scruminc.com/wp-content/uploads/2014/06/agile-architecture.pdf">Agile Architecture Fast, Cheap, Out of Control</a>" Jeff Sutherland</p> +</div></blockquote> +<p>См. также структуру "Scrum of Scrum Team (SoS) a Core Team" на странице 5 "<a class="reference external" href="https://www.scrumatscale.com/wp-content/uploads/2020/09/Scrum_At_Scale_Case_Study_Air_Transport_Amogh.pdf">The Scrum Software Factory</a>" by Amogh Joshi.</p> </section> -</section> -<section id="emacsway-reference-applications"> -<span id="id38"/><h2><a class="toc-backref" href="#id91" role="doc-backlink">Эталонные демонстрационные приложения</a></h2> -<ul class="simple"> -<li><p><a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers">eShopOnContainers</a> (CQRS, DDD, Microservices)</p></li> -<li><p><a class="reference external" href="https://github.com/microsoftarchive/cqrs-journey">Microsoft patterns &amp; pratices CQRS Journey sample application</a> (CQRS, DDD, Event Sourcing, SAGA transactions)</p></li> -</ul> +<section id="early-scrum"> +<h3><a class="toc-backref" href="#id31" role="doc-backlink">Early Scrum</a></h3> <blockquote> -<div><p>"A perfect example of this [you can see] if you go look at the CQRS and Event Sourcing by Microsoft Patterns and Practices, which is heavily focused on doing this inside of Azure using their toolkits."</p> -<p>- Greg Young, "<a class="reference external" href="https://youtu.be/LDW0QWie21s?t=1092">A Decade of DDD, CQRS, Event Sourcing</a>" at 18:15</p> +<div><p>The first keynote speaker was Ken Schwaber. Ken and Jeff Sutherland are the authors and founders of the Scrum agile methodology. Ken started by describing his experiences working with Scrum on large projects and several techniques he had successfully used in the early stages of the project life cycle.</p> +<p>Ken explained on one project how the team was very concerned with getting the overall architecture of the system proven in the early stages of development. Early project iterations (sprints in Scrum terminology) contained stories focused on proving the system architecture peppered with several real business cases. After several iterations, during which the architecture was continuously refined and tested, the team had a good sense of whether the architecture was sufficient for the demands of the business.</p> +<p>Scaling was then achieved by starting new teams with the founders of the original architecture team. With most of the architectural issues addressed, the new teams could focus on implementing business logic on top of the then stable architecture.</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/canScaling.html">Canadian Workshop on Scaling XP/Agile Methods</a>" by Jonathan Rasmusson, Jim McDonald</p> </div></blockquote> -<ul class="simple"> -<li><p><a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd">Full Modular Monolith application with Domain-Driven Design approach</a> by Kamil Grzybek</p></li> -<li><p><a class="reference external" href="https://github.com/kgrzybek/sample-dotnet-core-cqrs-api">Sample .NET Core REST API CQRS implementation with raw SQL and DDD using Clean Architecture</a> by Kamil Grzybek</p></li> -<li><p><a class="reference external" href="https://github.com/kgrzybek/refactoring-from-anemic-to-rich-domain-model-example">Refactoring from anemic to rich Domain Model example</a> by Kamil Grzybek</p></li> -<li><p><a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET">Sample Bounded Contexts for C#.NET from the book "Implementing Domain-Driven Design"</a> by Vaughn Vernon</p></li> -<li><p><a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples">Sample Bounded Contexts from the book "Implementing Domain-Driven Design"</a> by Vaughn Vernon</p></li> -<li><p><a class="reference external" href="https://github.com/vlingo/xoom-examples">xoom-examples</a> - the VLINGO XOOM examples demonstrating features and functionality available in the reactive components.</p></li> -<li><p>Implementation of samples from the book "Domain-Driven Design" by Eric Evans in <a class="reference external" href="https://github.com/citerus/dddsample-core">Java</a>, <a class="reference external" href="https://github.com/SzymonPobiega/DDDSample.Net">C#</a>, <a class="reference external" href="https://github.com/paulrayner/ddd_sample_app_ruby">Ruby</a>, <a class="reference external" href="https://github.com/marcusolsson/goddd">Golang</a> (<a class="reference external" href="https://github.com/go-kit/kit/tree/master/examples/shipping">yet another Golang</a>). See also <a class="reference external" href="https://www.citerus.se/go-ddd">the article</a>.</p></li> -<li><p><a class="reference external" href="https://goa.design/">Goa</a> provides a holistic approach for developing remote APIs and microservices in Go.</p></li> -<li><p><a class="reference external" href="https://github.com/gregoryyoung/m-r">Simple CQRS example</a> by Greg Young (приложение так же реализует Event Sourcing)</p></li> -<li><p><a class="reference external" href="https://github.com/thinkbeforecoding/m-r">Greg Young's Simple CQRS in F#</a> by Jérémie Chassaing</p></li> -<li><p><a class="reference external" href="https://github.com/EventStore/training-advanced-go">Golang DDD ES/CQRS Reference Application</a> by EventStore contributors</p></li> -<li><p><a class="reference external" href="https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example">Complete serverless application to show how to apply DDD, Clean Architecture, and CQRS by practical refactoring of a Go project</a> (<a class="reference external" href="https://threedots.tech/post/serverless-cloud-run-firebase-modern-go-application/">more info</a>) by Robert Laszczak</p></li> -<li><p><a class="reference external" href="https://github.com/ThreeDotsLabs/monolith-microservice-shop">Clean Monolith Shop</a> by Robert Laszczak - Source code for article "<a class="reference external" href="https://threedots.tech/post/microservices-or-monolith-its-detail/">Why using Microservices or Monolith can be just a detail?</a>"</p></li> -<li><p><a class="reference external" href="https://github.com/AntonStoeckl/go-iddd">go-iddd - showcase project for implementing DDD in Go</a> by Anton Stöckl (see more info <a class="reference external" href="https://medium.com/@TonyBologni/implementing-domain-driven-design-and-hexagonal-architecture-with-go-1-292938c0a4d4">here</a> and <a class="reference external" href="https://medium.com/@TonyBologni/implementing-domain-driven-design-and-hexagonal-architecture-with-go-2-efd432505554">here</a>).</p></li> -<li><p><a class="reference external" href="https://github.com/agiledragon/transfer-money-go">transfer-money-go</a> by Zhang Xiaolong - A sample of DDD and DCI in Go.</p></li> -<li><p><a class="reference external" href="https://github.com/agiledragon/ddd-sample-in-golang">ddd-sample-in-golang</a> by Zhang Xiaolong.</p></li> -<li><p><a class="reference external" href="https://github.com/shijuvar/go-distributed-sys">go-distributed-sys</a> - Guidance for building distributed systems and Microservices in Go. "<a class="reference external" href="https://shijuvar.medium.com/building-event-driven-distributed-systems-in-go-with-grpc-nats-jetstream-and-cockroachdb-c4b899c8636d">Building Event-Driven Distributed Systems in Go with gRPC, NATS JetStream and CockroachDB</a>" by Shiju Varghese</p></li> -<li><p><a class="reference external" href="https://github.com/asynkron/realtimemap-go">Real-time Map</a> displays real-time positions of public transport vehicles in Helsinki. It's a showcase for <a class="reference external" href="https://proto.actor/">Proto.Actor</a> - an ultra-fast distributed actors solution for Go, C#, and Java/Kotlin. See also <a class="reference external" href="https://github.com/asynkron/realtimemap-dotnet">realtimemap-dotnet</a> implementation in .NET.</p></li> -<li><p><a class="reference external" href="https://github.com/johnbywater/es-example-taxi-demo">Demo taxi system, using eventsourcing library</a> by John Bywater</p></li> -<li><p><a class="reference external" href="https://github.com/johnbywater/es-example-bank-accounts">Example "bank accounts" application using the Python eventsourcing library</a> by John Bywater</p></li> -<li><p><a class="reference external" href="https://github.com/johnbywater/es-example-cargo-shipping">Example "cargo shipping" application using the Python eventsourcing library</a> by John Bywater</p></li> -<li><p><a class="reference external" href="https://github.com/johnbywater/eventsourcing/tree/main/eventsourcing/examples">Examples of using eventsourcing library</a> by John Bywater</p></li> -<li><p><a class="reference external" href="https://github.com/microservices-patterns/ftgo-application">FTGO example application. Example code for the book Microservice patterns</a> by Chris Richardson</p></li> -<li><p><a class="reference external" href="https://github.com/eventuate-tram/eventuate-tram-examples-customers-and-orders/">Eventuate Tram Customers and Orders</a> by Chris Richardson</p></li> -<li><p><a class="reference external" href="https://github.com/eventuate-examples/eventuate-tram-core-dotnet-examples-customers-and-orders">Eventuate Tram Customers and Orders - .NET version</a> by Chris Richardson</p></li> -<li><p><a class="reference external" href="https://github.com/eventuate-examples">eventuate-examples</a> by Chris Richardson</p></li> -<li><p><a class="reference external" href="https://github.com/elbandit/PPPDDD">Sample code for the book Principles, Practices and Patterns of Domain-Driven Design</a> by Scott Millett, Nick Tune</p></li> -<li><p><a class="reference external" href="https://github.com/PacktPublishing/Hands-On-Domain-Driven-Design-with-.NET-Core">Hands-On Domain-Driven Design with .NET Core, published by Packt</a> by Alexey Zimarev</p></li> -<li><p>"<a class="reference external" href="https://github.com/Eventuous/dotnet-sample">dotnet-sample</a>" - Sample application using Eventuous .NET by Alexey Zimarev</p></li> -<li><p><a class="reference external" href="https://github.com/swlaschin/DomainModelingMadeFunctional">Extended code samples related to the book "Domain Modeling Made Functional"</a> by Scott Wlaschin</p></li> -<li><p><a class="reference external" href="https://github.com/swlaschin/Railway-Oriented-Programming-Example">Railway-Oriented-Programming-Example</a> by Scott Wlaschin</p></li> -<li><p><a class="reference external" href="https://github.com/andorp/order-taking">Order Taking Service</a> - Idris version of Domain Modeling Made Functional Book.</p></li> -<li><p><a class="reference external" href="https://github.com/VaughnVernon/DDDwithActors">DDD with Actors</a> by Vaughn Vernon</p></li> -<li><p><a class="reference external" href="https://github.com/VaughnVernon/ReactiveMessagingPatterns_ActorModel">The examples for the book "Reactive Messaging Patterns with the Actor Model"</a> by Vaughn Vernon</p></li> -<li><p><a class="reference external" href="https://github.com/VaughnVernon/reactive-stock-trader">A Stock Trader system to demonstrate reactive systems development</a> (<a class="reference external" href="https://github.com/RedElastic/reactive-stock-trader">source</a> by RedElastic)</p></li> -<li><p><a class="reference external" href="https://github.com/jbogard/ContosoUniversityDotNetCore-Pages">ContosoUniversityDotNetCore-Pages</a> by Jimmy Bogard</p></li> -<li><p><a class="reference external" href="https://github.com/RedElastic/reactive-stock-trader">RedElastic: reactive-stock-trader</a> - A reference architecture for stock trading to demonstrate the concepts of reactive systems development. Based on the original Stock Trader by IBM and implemented with Lagom by Lightbend. "<a class="reference external" href="https://developer.ibm.com/series/reactive-in-practice/">Reactive in practice: A complete guide to event-driven systems development in Java.</a>"</p></li> -<li><p><a class="reference external" href="https://github.com/IBMStockTrader">IBM Stock Trader</a> - Org containing a repository per microservice in the IBM Stock Trader cloud-native sample application. "<a class="reference external" href="https://developer.ibm.com/blogs/introducing-stocktrader/">Introduction to the IBM Stock Trader sample.</a>"</p></li> -<li><p><a class="reference external" href="https://github.com/vkhorikov/AnemicDomainModel">Refactoring from Anemic Domain Model Towards a Rich One</a> by Vladimir Khorikov</p></li> -<li><p><a class="reference external" href="https://github.com/vkhorikov/DddInAction">DDD in Practice</a> by Vladimir Khorikov</p></li> -<li><p><a class="reference external" href="https://github.com/vkhorikov/DddAndEFCore">DDD and EF Core</a> by Vladimir Khorikov</p></li> -<li><p><a class="reference external" href="https://github.com/vkhorikov/CqrsInPractice">CQRS in Practice</a> by Vladimir Khorikov</p></li> -<li><p><a class="reference external" href="https://github.com/vkhorikov/FuntionalPrinciplesCsharp">Applying Functional Principles in C#</a> by Vladimir Khorikov</p></li> -<li><p><a class="reference external" href="https://github.com/vkhorikov/SpecPattern">Specification Pattern in C#</a> by Vladimir Khorikov</p></li> -<li><p><a class="reference external" href="https://github.com/vkhorikov/SpecificationPattern">Specification pattern implementation in C#</a> by Vladimir Khorikov</p></li> -<li><p><a class="reference external" href="https://github.com/vkhorikov/ValidationInDDD">Validation in DDD course</a> by Vladimir Khorikov</p></li> -</ul> -<p>Варианты реализации OO/Functional Aggregates на примере Reference Applications by Chris Richardson:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://github.com/cer/event-sourcing-examples/tree/master/java-spring">Traditional OO mutable Domain Objects</a></p></li> -<li><p><a class="reference external" href="https://github.com/cer/event-sourcing-using-scala-typeclasses">Functional Scala witn immutable Domain Objects</a></p></li> -<li><p><a class="reference external" href="https://github.com/cer/event-sourcing-examples/tree/master/scala-spring">Hybrid OO/Functional Scala with immutable Domain Objects</a></p></li> -</ul> -<p>Others:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://github.com/heynickc/awesome-ddd#sample-projects">DDD Sample Projects</a></p></li> -</ul> </section> -</section> -Sat, 24 Jun 2023 00:00:00 Поиск границ Агрегатовhttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/aggregate-boundaries.html -<span id="id1"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id2"> -<p class="topic-title">Содержание</p> +<section id="id6"> +<h3><a class="toc-backref" href="#id32" role="doc-backlink">Другие</a></h3> +<p>Program Management также присутствует в MSF и в FDD. +В RAD тоже аналитика является "upstream development activities". +RUP реализует <a class="reference internal" href="../sdlc/models/spiral.html#emacsway-spiral-development"><span class="std std-ref">спиральную</span></a> модель.</p> +<p>В книге "Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman особый интерес представляют собою главы:</p> <ul class="simple"> -<li><p><a class="reference internal" href="#emacsway-golang-aggregate" id="id14">Поиск границ Агрегатов</a></p> -<ul> -<li><p><a class="reference internal" href="#id3" id="id15">Бизнес-требования</a></p></li> -<li><p><a class="reference internal" href="#strong-consistency-rdbms" id="id16">Strong Consistency (RDBMS)</a></p></li> -<li><p><a class="reference internal" href="#eventual-consistency" id="id17">Eventual Consistency</a></p> -<ul> -<li><p><a class="reference internal" href="#id4" id="id18">Первоначальная модель</a></p> -<ul> -<li><p><a class="reference internal" href="#id5" id="id19">Упрощенная реализация первоначальной модели</a></p></li> -<li><p><a class="reference internal" href="#id6" id="id20">Реализация требований</a></p></li> -<li><p><a class="reference internal" href="#id7" id="id21">Проблемы данной модели</a></p> -<ul> -<li><p><a class="reference internal" href="#id8" id="id22">Вероятность утраты согласованности</a></p></li> -<li><p><a class="reference internal" href="#id9" id="id23">Уникальность артефакта</a></p></li> -<li><p><a class="reference internal" href="#endorsement" id="id24">Преобразование Endorsement в Сущность</a></p></li> -<li><p><a class="reference internal" href="#id10" id="id25">Достижение согласованности</a></p> +<li><p>20.6 More on ADD Step 7: Perform Analysis of the Current Design and Review the Iteration Goal and Achievement of the Design Purpose</p> <ul> -<li><p><a class="reference internal" href="#data-context-and-interaction-dci" id="id26">Data, context, and interaction (DCI)</a></p></li> -<li><p><a class="reference internal" href="#process-manager-pattern" id="id27">Process Manager Pattern</a></p></li> -<li><p><a class="reference internal" href="#pessimistic-offline-lock" id="id28">Pessimistic Offline Lock</a></p></li> -<li><p><a class="reference internal" href="#id11" id="id29">Резервирование</a></p></li> -</ul> -</li> -</ul> -</li> -</ul> -</li> -<li><p><a class="reference internal" href="#id12" id="id30">Упрощенная реализация итоговой модели</a></p></li> +<li><p>Use of an Architectural Backlog</p></li> +<li><p>Use of a Design Kanban Board</p></li> </ul> </li> -<li><p><a class="reference internal" href="#missing-chapter" id="id31">Missing chapter</a></p></li> </ul> -</li> +<p>Интерес они вызыват прежде всего потому, что:</p> +<blockquote> +<div><p>📝 "The drivers become part of an <strong>architectural design backlog</strong> that you should use to perform the different design iterations. +When you have made design decisions that account for all of the items in the backlog, you’ve completed this round."</p> +<p class="attribution">—"Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman</p> +</div></blockquote> +<blockquote> +<div><p>📝 "The output of ADD is not an architecture complete in every detail, but an architecture in which the main design approaches have been selected and vetted. +<strong>It produces a "workable" architecture early and quickly, one that can be given to other project teams so they can begin their work while the architect or architecture team continues to elaborate and refine.</strong>"</p> +<p class="attribution">—"Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman</p> +</div></blockquote> +<p>Humberto Cervantes и Rick Kazman, в книге "Designing Software Architectures: A Practical Approach", которая была посвящена ADD 3.0, предлагают заводить "architectural design backlog" даже в Scrum:</p> +<blockquote> +<div><p>📝 "For example, when using Scrum, the sprint backlog and the design backlog are not independent: +Some features in the sprint backlog may require architecture design to be performed, so they will generate items that go into the architectural design backlog. +These two backlogs can be managed separately, however. +The design backlog may even be managed internally, as it contains several items that are typically not discussed or prioritized by the customer (or product owner).</p> +<p>Also, additional architectural concerns may arise as decisions are made. +For example, if you choose a reference architecture, you will probably need to add specific architectural concerns, or quality attribute scenarios derived from them, to the architectural design backlog. +An example of such a concern is the management of sessions for a web application reference architecture."</p> +<p class="attribution">—"Designing Software Architectures: A Practical Approach" by Humberto Cervantes, Rick Kazman</p> +</div></blockquote> +<p>Т.е. речь идет опять же, об отдельном Backlog для активностей, предшествующих фазе реализации Системного Инкремента.</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.atlassian.com/blog/jira-align/tools-for-agile-program-management">4 tools you need to build an agile program management powerhouse</a>" by Kyle Foreman</p></li> </ul> -</nav> -<section id="id3"> -<h2><a class="toc-backref" href="#id15" role="doc-backlink">Бизнес-требования</a></h2> -<p>Бизнес-требования к Reference Application описаны в разделе "<a class="reference external" href="https://github.com/ru-arc/charter/blob/main/charter.md#46-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0-%D0%BA%D0%B2%D0%B0%D0%BB%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%BE%D0%B9-%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%B8-%D1%87%D0%BB%D0%B5%D0%BD%D0%BE%D0%B2-%D0%BE%D1%80%D0%B3%D0%B0%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8">4.6. Система квалификационной классификации членов Организации</a>" Устава региональной общественной организации "Объединение ИТ-Архитекторов".</p> -<p>Выделим основные из них:</p> -<ol class="arabic simple"> -<li><p>Каждый член Организации может отдать 20 рекомендаций (признаний) в год в пользу других членов.</p></li> -<li><p>Одна рекомендация от члена Организации претендуемого (или более высокого) квалификационного класса равноценна двум рекомендациям от членов Организации текущего квалификационного класса (излишки не переносятся).</p></li> -<li><p>Рекомендации от членов Организации более низкого квалификационного класса не допускаются.</p></li> -<li><p>Допускается одна рекомендация рекомендующего за один конкретный артефакт рекомендуемого.</p></li> -<li><p>Требуемые количества рекомендаций по квалификационным классам:</p> +</section> +</section> +<section id="emacsway-fractal-team"> +<span id="id7"/><h2><a class="toc-backref" href="#id33" role="doc-backlink">Фрактальная структура</a></h2> +<p>Хотя Program Management и выполняет роль опорного хребта коммуникативной нагрузки коллектива, момент его внедрения в процессы разработки должен быть своевременным и оправданным, т.е. издержки на его содержание должны покрываться выгодами от его внедрения. +Кроме того, концентрация всех архитектурных задач на уровне Program Management может привести к образованию узкого горлышка. +Одним из способов решения этой задачи является децентрализация архитектурных решений об интеграции ограниченных контекстов. +Карта ограниченных контекстов (<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard-single/#context-map">Context Map</a>) позволяет сократить количество возможных коммуникационных путей в коллективе и снизить коммуникативную нагрузку. +Например, если подмножество какого-то публичного интерфейса Ограниченного Контекста используется как Customer/Supplier только одним другим Ограниченным Контекстом, то команде не нужно общаться с командами остальных Ограниченных Контекстов по поводу изменения этого подмножества. +Построение топологии команд по Ограниченным Контекстам позволяет сфокусировать полезную коммуникативную нагрузку внутри команды и уменьшить контрпродуктивную коммуникативную нагрузку по интеграции между командами, тем самым повышая уровень автономности команд.</p> +<p>Более лучшего эффекта можно достигнуть используя CDC-Tests:</p> +<blockquote> +<div><p>📝 "About consumer-driven contract testing, we identified two reasons:</p> <ol class="arabic simple"> -<li><p>Эксперт - 20 рекомендаций Экспертов или 40 рекомендаций Кандидатов в эксперты;</p></li> -<li><p>Кандидат в эксперты - 10 рекомендаций Кандидатов в эксперты или 20 рекомендаций 1-го класса;</p></li> -<li><p>1 класс - 7 рекомендаций 1-го класса или 14 рекомендаций 2-го класса;</p></li> -<li><p>2 класс - 5 рекомендаций 2-го класса или 10 рекомендаций 3-го класса;</p></li> -<li><p>3 класс - 3 рекомендации 3-го класса или 6 рекомендаций без класса;</p></li> -<li><p>без класса - по умолчанию.</p></li> -</ol> -</li> +<li><p>development teams have communication obstacles when several people working on one microservice (e.g., over 8 people, see Figure 6 (Right)) and</p></li> +<li><p>microservices systems extensively use third party resources [118]."</p></li> </ol> -<p>Остальные требования в настоящий момент рассмотрения пока не сильно релевантны.</p> -</section> -<section id="strong-consistency-rdbms"> -<h2><a class="toc-backref" href="#id16" role="doc-backlink">Strong Consistency (RDBMS)</a></h2> -<p>Этот вариант реализации хорошо был расcмотрен в статье "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/modeling-relationships-in-ddd-way/">Modeling Relationships in a DDD Way</a>" by Vladimir Khorikov, поэтому подробно рассматривать мы его не будем. -Приведу только заключительный фрагмент его статьи:</p> -<div class="literal-block-wrapper docutils container" id="id13"> -<div class="code-block-caption"><span class="caption-text"><a class="reference external" href="https://stackoverflow.com/questions/24921227/save-and-load-objects-without-breaking-encapsulation">Example from Stackoverflow</a></span></div> -<div class="highlight-csharp notranslate"><div class="highlight"><pre><span/><span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="nc">Student</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">Entity</span><span class="w"/> -<span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="n">Name</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="n">Email</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">readonly</span><span class="w"> </span><span class="n">IList</span><span class="p">&lt;</span><span class="n">StudentInstructor</span><span class="p">&gt;</span><span class="w"> </span><span class="n">_studentInstructors</span><span class="p">;</span><span class="w"/> -<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">IReadOnlyList</span><span class="p">&lt;</span><span class="n">Instructor</span><span class="p">&gt;</span><span class="w"> </span><span class="n">Instructors</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">_studentInstructors</span><span class="w"/> -<span class="w"> </span><span class="p">.</span><span class="n">Select</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">Instructor</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">.</span><span class="n">OrderBy</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">DateAdded</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">.</span><span class="n">ToList</span><span class="p">();</span><span class="w"/> - -<span class="w"> </span><span class="k">internal</span><span class="w"> </span><span class="k">void</span><span class="w"> </span><span class="nf">AddInstructor</span><span class="p">(</span><span class="n">StudentInstructor</span><span class="w"> </span><span class="n">instructor</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="n">_studentInstructors</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="n">instructor</span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="nc">Instructor</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">Entity</span><span class="w"/> -<span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="n">Name</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">readonly</span><span class="w"> </span><span class="n">IList</span><span class="p">&lt;</span><span class="n">StudentInstructor</span><span class="p">&gt;</span><span class="w"> </span><span class="n">_studentInstructors</span><span class="p">;</span><span class="w"/> -<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">IReadOnlyList</span><span class="p">&lt;</span><span class="n">Student</span><span class="p">&gt;</span><span class="w"> </span><span class="n">Students</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">_studentInstructors</span><span class="w"/> -<span class="w"> </span><span class="p">.</span><span class="n">Select</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">Student</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">.</span><span class="n">OrderBy</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">DateAdded</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">.</span><span class="n">ToList</span><span class="p">();</span><span class="w"/> - -<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="k">void</span><span class="w"> </span><span class="nf">AddStudent</span><span class="p">(</span><span class="n">Student</span><span class="w"> </span><span class="n">student</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="kt">var</span><span class="w"> </span><span class="n">studentInstructor</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">StudentInstructor</span><span class="p">(</span><span class="n">student</span><span class="p">,</span><span class="w"> </span><span class="k">this</span><span class="p">,</span><span class="w"> </span><span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="n">_studentInstructors</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="n">studentInstructor</span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="n">student</span><span class="p">.</span><span class="n">AddInstructor</span><span class="p">(</span><span class="n">studentInstructor</span><span class="p">);</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="nc">StudentInstructor</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">Entity</span><span class="w"/> -<span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">Student</span><span class="w"> </span><span class="n">Student</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">Instructor</span><span class="w"> </span><span class="n">Instructor</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">DateTime</span><span class="w"> </span><span class="n">DateAdded</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> - -<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="nf">StudentInstructor</span><span class="p">(</span><span class="n">Student</span><span class="w"> </span><span class="n">student</span><span class="p">,</span><span class="w"> </span><span class="n">Instructor</span><span class="w"> </span><span class="n">instructor</span><span class="p">,</span><span class="w"> </span><span class="n">DateTime</span><span class="w"> </span><span class="n">dateAdded</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="n">Student</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">student</span><span class="p">;</span><span class="w"/> -<span class="w"> </span><span class="n">Instructor</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">instructor</span><span class="p">;</span><span class="w"/> -<span class="w"> </span><span class="n">DateAdded</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">dateAdded</span><span class="p">;</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="p">}</span><span class="w"/> -</pre></div> -</div> -</div> +<p class="attribution">—"<a class="reference external" href="https://www.researchgate.net/publication/337326691_Consumer-Driven_Contract_Tests_for_Microservices_A_Case_Study">Consumer-Driven Contract Tests for Microservices: A Case Study</a>" by Jyri Lehvä, Niko Mäkitalo, Tommi Mikkonen</p> +</div></blockquote> +<blockquote> +<div><p>📝 "We use some techniques from DDD, particularly event storming, to understand and model the domains in our business context. +At a more technical level, we use Pact for contract testing services and inter-team communication. +Pact has really helped us to adopt a clear, defined approach to testing services, setting expectations across all teams about how to test and interact with other teams."</p> +<p class="attribution">—"Team Topologies: Organizing Business and Technology Teams for Fast Flow" by Matthew Skelton, Manuel Pais</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Contract tests are a big win when it comes to enabling teams to work and deploy independently, but they also require some level of coordination. +Consumer contract tests are of very little value unless they're verified against the provider, and a provider can't write contract tests for their system without working with the consumer team to get the tests added to the consumer project.</p> +<p>Contracts are not a replacement for good communication between or within teams. +In fact, contracts require collaboration and communication. +One could make the argument that this is one of the main reasons to leverage Pact and enforce communication pathways in large internal and external development organizations.</p> +<p>Contracts are not a magical silver bullet that will allow you to hide in your developer caves and toss built artifacts at each other until everything passes. +It is important for all teams to be invested in the process. +One of the most common reasons that Pact fails to be successfully adopted in an organisation is a lack of buy in from all parties.</p> +<p>Collaborate about the problems, collaborate over the design, and keep the communication channels open."</p> +<p class="attribution">—"<a class="reference external" href="https://docs.pact.io/pact_nirvana/step_2">CI/CD Setup Guide :: Talk</a>"</p> +</div></blockquote> +<p>Таким образом, независимо от того, существует ли у команд Program Management, или же команды имеет фрактальную структуру, CDC-Tests позволяют в значительной мере управлять коммуникативной нагрузкой на команды и минизировать Проблему Брукса.</p> </section> -<section id="eventual-consistency"> -<h2><a class="toc-backref" href="#id17" role="doc-backlink">Eventual Consistency</a></h2> -<section id="id4"> -<h3><a class="toc-backref" href="#id18" role="doc-backlink">Первоначальная модель</a></h3> -<p>Хотя предполагается использование RDBMS, но была предпринята попытка найти такие контуры Агрегатов, которые без существенной переработки могли бы функционировать и в условиях отсутствия транзакционной согласованности.</p> -<p>Самый первый вариант модели практически полностью воспроизводил структуру (online) excel-таблиц, использовавшихся на тот момент. -Упрощенная реализация модели выглядела примерно так:</p> -<section id="id5"> -<h4><a class="toc-backref" href="#id19" role="doc-backlink">Упрощенная реализация первоначальной модели</a></h4> -<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kn">package</span><span class="w"> </span><span class="nx">grade_1</span><span class="w"/> - -<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"errors"</span><span class="w"/> -<span class="w"> </span><span class="s">"time"</span><span class="w"/> -<span class="p">)</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="kt">uint64</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">AvailableEndorsementCount</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">ReceivedEndorsementCount</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">EndorsementId</span><span class="w"> </span><span class="kt">uint64</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="w"> </span><span class="kt">string</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Weight</span><span class="w"> </span><span class="kt">uint8</span><span class="w"/> - -<span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="nx">PeerWeight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> -<span class="w"> </span><span class="nx">HigherWeight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">2</span><span class="w"/> -<span class="p">)</span><span class="w"/> - -<span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="nx">Expert</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">Candidate</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">Grade1</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">Grade2</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">Grade3</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">WithoutGrade</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"/> -<span class="p">)</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Specialist</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">grade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="nx">ReceivedEndorsementCount</span><span class="w"/> -<span class="w"> </span><span class="nx">assignments</span><span class="w"> </span><span class="p">[]</span><span class="nx">Assignment</span><span class="w"/> -<span class="w"> </span><span class="nx">version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">GetId</span><span class="p">()</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">GetGrade</span><span class="p">()</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">GetVersion</span><span class="p">()</span><span class="w"> </span><span class="kt">uint</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">IncreaseReceivedEndorsementCount</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">Weight</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nx">ReceivedEndorsementCount</span><span class="p">(</span><span class="nx">w</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">WithoutGrade</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">6</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade3</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade3</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade2</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade2</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade1</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade1</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Candidate</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Candidate</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">40</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Expert</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">g</span><span class="w"> </span><span class="nx">Grade</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">assignments</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">assignments</span><span class="p">,</span><span class="w"> </span><span class="nx">Assignment</span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="p">,</span><span class="w"> </span><span class="nx">g</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">})</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">g</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">IncreaseVersion</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Assignment</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">assignedGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Endorser</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">grade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="nx">AvailableEndorsementCount</span><span class="w"/> -<span class="w"> </span><span class="nx">version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">Endorse</span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">Specialist</span><span class="p">,</span><span class="w"> </span><span class="nx">aDesc</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">Endorsement</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">{},</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"it is allowed to endorse only members with equal or lower grade"</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">{},</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"you have reached the limit of available recommendations this year"</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nb">uint64</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">uint64</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">GetId</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">{},</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"endorser can't endorse himself"</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">grade</span><span class="p">,</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">GetVersion</span><span class="p">(),</span><span class="w"/> -<span class="w"> </span><span class="nx">aDesc</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="kc">nil</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">DecreaseAvailableEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"no endorsement is available"</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">IncreaseVersion</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Endorsement</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">endorserId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">endorserGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">endorserVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">artifactDescription</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> +<section id="id8"> +<h2><a class="toc-backref" href="#id34" role="doc-backlink">Социальная роль архитектуры</a></h2> +<p>📝 "By keeping things team sized, we help to achieve what MacCormack and colleagues call "an '<strong>architecture for participation</strong>' that promotes ease of understanding by limiting module size, and ease of contribution by minimizing the propagation of design changes."[MacCormack et al., "Exploring the Structure of Complex Software Designs."] In other words, we need <strong>a team-first software architecture that maximizes people's ability to work with it</strong>.</p> +<p>&lt;...&gt;</p> +<p>More than ever I believe that someone who claims to be an <strong>Architect needs both technical and social skills, they need to understand people and work within the social framework</strong>. They also need a remit that is broader than pure technology—they need to have a say in <strong>organizational structures and personnel issues, i.e. they need to be a manager too</strong>.[Kelly, "Return to Conway's Law."]"</p> +<p>— "Team Topologies: Organizing Business and Technology Teams for Fast Flow" by Matthew Skelton</p> +</section> +<section id="emacsway-team-topologies-at-scale-literature"> +<span id="id9"/><h2><a class="toc-backref" href="#id35" role="doc-backlink">Литература</a></h2> +<ul class="simple"> +<li><p>"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr.</p></li> +<li><p>"Team Topologies: Organizing Business and Technology Teams for Fast Flow" by Matthew Skelton</p></li> +<li><p>"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</p></li> +<li><p>"Scaling Software Agility: Best Practices for Large Enterprises" by Dean Leffingwell</p></li> +<li><p>"SAFe® 5.0: The World's Leading Framework for Business Agility" by Richard Knaster, Dean Leffingwell</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute, 2017</p></li> +<li><p>"<a class="reference external" href="https://leanpub.com/arch-modernization-ddd">Architecture Modernization with Strategic Domain-Driven Design. A Guide for Technology Leaders.</a>" by Nick Tune</p></li> +<li><p>"<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/">Open Agile Architecture. A Standard of The Open Group</a>"</p></li> +</ul> +</section> +<section id="id10"> +<h2><a class="toc-backref" href="#id36" role="doc-backlink">Ссылки по теме</a></h2> +<ol class="arabic simple"> +<li><p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/team-responsibility-ownership-patterns-part-1-a-business-architecture-model-63597c4e60e1">Architecture Ownership Patterns For Team Topologies. Part 1: A Business Architecture Model</a>" by Nick Tune</p></li> +<li><p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/architecture-ownership-patterns-for-team-topologies-part-2-single-team-patterns-943d31854285">Architecture Ownership Patterns for Team Topologies. Part 2: Single Team Patterns</a>" by Nick Tune</p></li> +<li><p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/architecture-ownership-patterns-for-team-topologies-part-3-multi-team-patterns-eecc146ddb28">Architecture Ownership Patterns for Team Topologies. Part 3: Multi-Team Patterns</a>" by Nick Tune</p></li> +</ol> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://blog.avanscoperta.it/2021/04/22/about-team-topologies-and-context-mapping/">About Team Topologies and Context Mapping</a>" by Alberto Brandolini</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/articles/strong-weak-arch.html">The strong and weak forces of architecture</a>" by Evan Bottcher</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/articles/devops-compliance.html">Compliance in a DevOps Culture. Integrating Compliance Controls and Audit into CI/CD Processes</a> by Carl Nygard</p></li> +<li><p>"<a class="reference external" href="https://event-driven.io/en/how_using_events_help_in_teams_autonomy/">How using events helps in a teams' autonomy</a>" by Oskar Dudycz</p></li> +</ul> +</section> +Thu, 05 Oct 2023 00:00:00 Specification in Golanghttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/specification.html +<span id="emacsway-specification-in-golang"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/specification-pattern-c-implementation/">Specification pattern: C# implementation</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/specification-pattern-always-valid-domain-model/">Specification Pattern vs Always-Valid Domain Model</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://khorikov.org/posts/2021-08-02-purity-specification-pattern/">Specification Pattern in DDD trilemma</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://github.com/vkhorikov/SpecificationPattern">Implementation of the Specification Pattern in C#</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://github.com/vkhorikov/SpecPattern">Implementation of the Specification Pattern in C#</a>" by Vladimir Khorikov</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/apsupp/spec.pdf">Specification</a>" by Martin Fowler</p></li> +</ul> +Wed, 23 Aug 2023 00:00:00 Technical Debt и сложный процентhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/compound-interest.html +<span id="emacsway-compound-interest"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#technical-debt" id="id2">Technical Debt и сложный процент</a></p></li> +</ul> +</nav> +<p>"<a class="reference internal" href="common-planning-errors.html#emacsway-planning-error-false-commutativity"><span class="std std-ref">Ложная Коммутативность</span></a>" в управленческих решениях - это когда совокупная стоимость реализации нескольких задач зависит от последовательности их выполнения. +Особенно это касается платформенных (технических) задач, которые иногда нужно уметь "продать" бизнесу, если только у вас нет выделенной <a class="reference external" href="https://www.scaledagileframework.com/agile-teams/">платформенной команды</a>.</p> +<p>И, зачастую, представителям бизнеса, находящимся в контексте бизнес-проблем, а не технических проблем, сложно понять, почему первой должна выполняться задача "А", если задача "Б" более востребована бизнесом. +Это называется <a class="reference internal" href="../balancing-business-technical-concerns.html#emacsway-agile-balancing-business-technical-concerns"><span class="std std-ref">поиском баланса между бизнес-интересами и техническими интересами</span></a>. +Острота этого вопроса в Agile даже привела к тому, что Quality, изначально бывшее 4-ой переменной управления разработкой (наряду с Cost, Time, Scope), очень быстро было <a class="reference internal" href="../balancing-business-technical-concerns.html#emacsway-xp2-balancing-business-technical-concerns"><span class="std std-ref">преобразовано в константу</span></a>.</p> +<p>Выявлением причинно-следственных циклов занимается "Системное Мышление", и вам сильно повезло, если ваши представители бизнеса знакомы с этой наукой. +В противном случае, как пишет Craig Larman, проблемы могут возникать даже в таких компаниях, как Microsoft, являющихся "колыбелью архитектуры" (откуда вышли такие авторы, как Steve McConnell), см. "<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems Thinking</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">на русском</a>).</p> +<p>Наверное, наилучшим образом помочь донести представителям бизнеса проблему "Ложной Коммутативности" может "<a class="reference external" href="https://quote.rbc.ru/news/training/5e280d059a7947eb63f54970">Сложный Процент</a>".</p> +<p>Основная проблема термина "Technical Debt" в русском менталитете заключается в том, что зачастую его влияние на стоимость разработки воспринимается представителями бизнеса как константная величина - сколько сегодня позаимствовали, столько завтра и вернем.</p> +<p>На самом же деле, основная суть термина "<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebt.html">Technical Debt</a>", вложенная в этот термин by Ward Cunningham, заключается в "interest on the debt":</p> +<blockquote> +<div><p>📝 "Thinking of this as paying interest versus paying of principal can help decide which cruft to tackle."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebt.html">Technical Debt</a>" by Martin Fowler</p> +</div></blockquote> +<blockquote> +<div><p>📝 "...that would slow us down which is like paying interest on a loan."</p> +<p class="attribution">—"<a class="reference external" href="https://youtu.be/pqeJFYwnkjE?t=90">Debt Metaphor</a>" by Ward Cunningham</p> +</div></blockquote> +<blockquote> +<div><p>💬 Burden</p> +<p>I think that there were plenty of cases where people would rush software out the door and learn things but never put that learning back into the program, and that by analogy was borrowing money thinking that you never had to pay it back.</p> +<p>Of course, if you do that, you know, say with your credit card, <strong>eventually all your income goes to interest and your purchasing power goes to zero</strong>.</p> +<p>By the same token, if you develop a program for a long period of time by only adding features and never reorganizing it to reflect your understanding of those features, then eventually that program simply does not contain any understanding and all efforts to work on it take longer and longer. In other words, the interest is total — you'll make zero progress.</p> +<p class="attribution">—"<a class="reference external" href="http://wiki.c2.com/?WardExplainsDebtMetaphor">Ward Explains Debt Metaphor</a>" by Ward Cunningham</p> +</div></blockquote> +<blockquote> +<div><p>💬 Debt</p> +<p>I coined the debt metaphor to explain the refactoring that we were doing on the WyCash product. This was an early product done in Digitalk Smalltalk, and it was important to me that we accumulate the learnings we did about the application over time by modifying the program to look as if we had known what we were doing all along and to look as if it had been easy to do in Smalltalk.</p> +<p>The explanation I gave to my boss, and this was financial software, was a financial analogy I called "the debt metaphor". And that said that if we failed to make our program align with what we then understood to be the proper way to think about our financial objects, then we were gonna continually stumble over that disagreement and that would slow us down which was like paying interest on a loan.</p> +<p class="attribution">—"<a class="reference external" href="http://wiki.c2.com/?WardExplainsDebtMetaphor">Ward Explains Debt Metaphor</a>" by Ward Cunningham</p> +</div></blockquote> +<p>А он рассчитывается по правилу "сложного процента". +Вся суть в том, чтобы перенести внимание бизнеса с тела долга на геометрическую прогрессию роста его процента:</p> +<blockquote> +<div><div class="highlight-default notranslate"><div class="highlight"><pre><span/><span class="n">S</span> <span class="o">=</span> <span class="n">P</span><span class="o">*</span><span class="p">(</span><span class="mi">1</span><span class="o">+</span> <span class="n">i</span><span class="p">)</span><span class="o">^</span><span class="n">n</span> <span class="p">(</span><span class="n">в</span> <span class="n">степени</span> <span class="n">n</span><span class="p">),</span> </pre></div> </div> -<p>Метод <code class="docutils literal notranslate"><span class="pre">Endorser.Endorse(Specialist,</span> <span class="pre">ArtifactDescription,</span> <span class="pre">time.Time)</span></code> является фабричным методом Агрегата <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>. -При сохранении Агрегата <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> в Хранилище, из него извлекаются Доменные События, и отправляются подписчикам через некий механизм доставки. -Мы предполагаем, что они могут быть обработаны как синхронно в той же транзакции (Mediator/Observer Design Pattern), так и асинхронно в другой транзакции (<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/MessageBroker.html">Message Broker</a>).</p> -<p>На Доменное Событие <code class="docutils literal notranslate"><span class="pre">EndorsementCreated</span></code> подписаны:</p> -<ol class="arabic simple"> -<li><p><code class="docutils literal notranslate"><span class="pre">Endorser</span></code>, у которого вызывается метод <code class="docutils literal notranslate"><span class="pre">Endorser.DecreaseAvailableEndorsementCount()</span></code> для вычитания использованной рекомендации из счетчика доступных в этом году рекомендаций;</p></li> -<li><p><code class="docutils literal notranslate"><span class="pre">Endorse</span></code>, у которого вызывается метод <code class="docutils literal notranslate"><span class="pre">Specialist.IncreaseReceivedEndorsementCount(Weight)</span></code> с указанием веса рекомендации, зависящего от отношения квалификационного класса рекомендующего к квалификационному классу рекомендуемого.</p></li> +<p>где S – получаемая сумма, P – цена облигации при покупке, i – процент в сотых долях, а n – число выплат.</p> +<p class="attribution">—"<a class="reference external" href="https://bankiros.ru/wiki/term/kak-rasscitat-dohodnost-obligacij">Как рассчитать доходность облигаций</a>" / Редакция Bankiros.ru</p> +</div></blockquote> +<p>По утверждению ряда авторитетных авторов (Kent Beck, Martin Fowler, Robert C. Martin и др.), рост стоимости разработки при накоплении техдолга может обретать характер, близкий именно к геометрической прогрессии (или к экспоненте). +Статистику конкретного проекта смотрите в "Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin.</p> +<p>Термин "TechnicalDebt" у нас воспринимается несколько по-иному, безобиднее, еще и потому, что он ассоциируется в нашем менталитете с "академической задолженностью" в ВУЗе, где в центре внимания лежит тело долга (paying of principal), а не геометрический характер роста процентов (paying interest). +А так же находит отражение традиция безпроцентного долга в виде взаимовыручки "до зарплаты", который является распространенным явлением в дружеской среде. +Поэтому, термин "TechnicalDebt" не несет своего изначального смысла в нашем менталитете, и не выполняет своей функции, как метафоры, надлежащим образом, что приводит к росту напряженности и недопонимания между представителями бизнеса и техническими специалистами. +Для разработчика техдолг означает экспоненциальный рост стоимости изменения кода, в то время, как для представителя бизнеса, - это просто отложенное выполнение задачи.</p> +<blockquote> +<div><p>📝 "Asking "is something technical debt" is usually uninteresting. The metaphor's value is comparing paying interest vs principal. We judge debt of $1K differently if we are paying $1/month to service it vs $100/month"</p> +<p class="attribution">—<a class="reference external" href="https://twitter.com/martinfowler/status/1517152168775614473?t=BMpST8vXSLBnY36k9o-lUg&amp;s=19">Martin Fowler</a></p> +</div></blockquote> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference internal" href="architecture-options.html#emacsway-architecture-options"><span class="std std-ref">Architecture: Selling Options</span></a>"</p></li> +</ul> +</div> +Wed, 23 Aug 2023 00:00:00 Repository in Golanghttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/infrastructure/repository.html +<span id="emacsway-repository-in-golang"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +Sat, 19 Aug 2023 00:00:00 Balancing Prediction/Adaptationhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/balancing-prediction-adaptation.html +<span id="emacsway-balancing-prediction-adaptation"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#balancing-prediction-adaptation" id="id4">Balancing Prediction/Adaptation</a></p> +<ul> +<li><p><a class="reference internal" href="#id2" id="id5">Стоимость гибкости</a></p></li> +<li><p><a class="reference internal" href="#open-agile-architecture-standard-by-the-open-group" id="id6">Open Agile Architecture™ Standard by The Open Group</a></p></li> +<li><p><a class="reference internal" href="#prediction-adaptation" id="id7">Эволюционный маятник баланса Prediction/Adaptation</a></p> +<ul> +<li><p><a class="reference internal" href="#prediction-adaptation-adaptation" id="id8">Занос маятника Prediction/Adaptation в сторону Adaptation</a></p></li> +<li><p><a class="reference internal" href="#prediction-adaptation-prediction" id="id9">Отскок маятника Prediction/Adaptation назад к Prediction</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#alberto-brandolini-about-prediction-adaptation" id="id10">Alberto Brandolini about Prediction/Adaptation</a></p></li> +</ul> +</li> +</ul> +</nav> +<blockquote> +<div><p>💬 "Scrum projects do not have an up-front analysis or design phase; all work occurs within the repeated cycle of sprints. +This does not mean, however, that design on a Scrum project is not intentional. +An intentional design process is one in which the design is guided through deliberate, conscious decision making. +The difference on a Scrum project is not that intentional design is thrown out, but that it is done (like everything else on a Scrum project) incrementally. +Scrum teams acknowledge that as nice as it might be to make all design decisions up front, doing so is impossible. +This means that on a Scrum project, design is both intentional and emergent.</p> +<p>A big part of an organization's becoming agile is finding the appropriate balance between anticipation and adaptation (Highsmith 2002). +Figure 9.2 shows this balance along with activities and artifacts that influence the balance. +When doing up-front analysis or design, we are attempting to anticipate users' needs. +Because we cannot perfectly anticipate these, we will make some mistakes; some work will need to be redone. +When we forgo analysis and design and jump immediately into coding and testing with no forethought at all, we are trying to adapt to users' needs. +All projects of interest will be positioned somewhere between anticipation and adaptation based on their own unique characteristics; no application will be all the way to either extreme. +A life-critical, medical safety application may be far to the anticipation side. +A three-person startup company building a website of information on kayak racing may be far toward the side of adaptation.</p> +<p>Foretelling the agile preference for simplicity, in 1990, was speaker and author Do-While Jones.</p> +<blockquote> +<div><p>I'm not against planning for the future. +Some thought should be given to future expansion of capability. +But when the entire design process gets bogged down in an attempt to satisfy future requirements that may never materialize, then it is time to stop and see if there isn't a simpler way to solve the immediate problem.</p> +<p class="attribution">—Jones' 1990 article, "The Breakfast Food Cooker," remains a classic parable of what can go wrong when software developers over-design a solution. I highly recommended reading it at <a class="reference external" href="http://www.ridgecrest.ca.us/~do_while/toaster.htm">http://www.ridgecrest.ca.us/~do_while/toaster.htm</a></p> +</div></blockquote> +<p>Scrum teams avoid this "bogging down" by realizing that not all future needs are worth worrying about today. Many future needs may be best handled by planning to adapt as they arise."</p> +<p class="attribution">—"Succeeding with Agile: Software Development Using Scrum" by Mike Cohn</p> +</div></blockquote> +<figure class="align-left" id="id3"> +<a class="reference internal image-reference" href="../../../../_images/fig-9.2-balancing-anticipation-adaptation.png"><img alt="FIGURE 9.2 Achieving a balance between anticipation and adaptation involves balancing the influence of the activities and artifacts on each side. The image source is &quot;Succeeding with Agile: Software Development Using Scrum&quot; by Mike Cohn" src="../../../../_images/fig-9.2-balancing-anticipation-adaptation.png" style="width: 90%;"/></a> +<figcaption> +<p><span class="caption-text">FIGURE 9.2 Achieving a balance between anticipation and adaptation involves balancing the influence of the activities and artifacts on each side. The image source is "Succeeding with Agile: Software Development Using Scrum" by Mike Cohn</span></p> +</figcaption> +</figure> +<blockquote> +<div><p>💬 McConnell writes, "In ten years the pendulum has swung from 'design everything' to 'design nothing.' +But the alternative to BDUF [Big Design Up Front] isn't no design up front, it's a Little Design Up Front (LDUF) or Enough Design Up Front (ENUF)." +This is a strawman argument. +The alternative to designing before implementing is designing after implementing. +Some design up-front is necessary, but just enough to get the initial implementation. +Further design takes place once the implementation is in place and the real constraints on the design are obvious. +Far from "design nothing," the XP strategy is "design always."</p> +<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck</p> +</div></blockquote> +<blockquote> +<div><p>💬 "From the very earliest days of agile methods, people have asked what role there is for architectural or design thinking. +A common misconception is that since agile methods drop the notion of a detailed up-front design artifact, that there is no room for architecture in an agile project. +In my keynote at the first-ever agile conference, I pointed out that design was every bit as important for agile projects, but it manifests itself differently, becoming an evolutionary approach."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/agile.html">Agile Software Development</a>" by Martin Fowler</p> +</div></blockquote> +<blockquote> +<div><p>💬 "Though BDUF is an Agile anti-pattern, does it mean architecture should solely be a product from emergence? As James Coplien argues [Coplien 2010], some intentional architecture saves waste and accelerates the decision process.</p> +<p>Agile Architecture shall seek a balance between intentional and emerging. Intentional architecture provides value if it is done differently. Intentional architecture represents a set of assumptions that must be verified. It should not slow down the integration of new requirements.</p> +<p>[Coplien 2010] Lean Architecture, by James Coplien and Gertrud Bjørnvig, July 2010, published by Wiley"</p> +<p class="attribution">—"Open Agile Architecture™" by The Open Group, Chapter "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard-single/#_axiom_14_bias_for_change">9.14. Axiom 14. Bias for Change</a>"</p> +</div></blockquote> +<blockquote> +<div><p>💬 "The incremental and iterative nature of Agile development can facilitate efficient technical and management processes and practices to reduce the cost associated with change. +In comparison, projects managed at the waterfall end of the continuum seek to reduce total rework cost by minimizing the number of changes, limiting the number of control points, and baselining detailed specifications which are reviewed and traced throughout the project."</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> +</div></blockquote> +<blockquote> +<div><p>💬 "Agile" methods actually can be applied within a variety of models. +While Agile methods are common in executing an evolutionary lifecycle model, they can be used in other lifecycle models at various stages. +What the methods have in common is an emphasis on continuous inspection and collaboration in the rapid production of working software in an environment where changes, including changes to requirements, are expected.</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> +</div></blockquote> +<blockquote> +<div><p>💬 Waterfalls and iterations may nest inside each other. +A six year project might consist of two 3 year projects, where each of the two projects are structured in a waterfall style, but the second project adds additional features. +You can think of this as a two-iteration project at the top level with each iteration as a waterfall. Due to the large size and small number of iterations, I'd regard that as primarily a waterfall projecta +In contrast you might see a project with 16 iterations of one month each, where each iteration is planned in a waterfall style. +That I'd see as primarily iterative. +While in theory there's potential for a middle ground projects that are hard to classify, in practice it's usually easy to tell that one style predominates.</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/WaterfallProcess.html">Waterfall Process</a>" by Martin Fowler</p> +</div></blockquote> +<section id="id2"> +<h2><a class="toc-backref" href="#id5" role="doc-backlink">Стоимость гибкости</a></h2> +<p>Изменяемость тоже имеет свою стоимость. Нельзя создавать бесконечно гибкое решение. Важен баланс.</p> +<blockquote> +<div><p>💬 "One trade-off that's often overlooked is between the number of options you have and the resulting complexity. More options are desirable, but wanting to have all options all the time will result in unnecessary complexity, as is often the case with overly elaborate abstraction layers or massive configuration frameworks. I captured this effect into Gregor's Law:</p> +<blockquote> +<div><p>Excessive complexity is nature's punishment for organizations that are unable to make decisions."</p> +</div></blockquote> +<p class="attribution">—"<a class="reference external" href="https://architectelevator.com/gregors-law/">Gregor's Law. Excessive complexity is nature's punishment for organizations that are unable to make decisions</a>" by Gregor Hohpe</p> +</div></blockquote> +<blockquote> +<div><p>💬 "If you pick any one aspect of software then you can make it easy to change, but we don't know how to make everything easy to change. Making something easy to change makes the overall system a little more complex, and making everything easy to change makes the entire system very complex. Complexity is what makes software hard to change. That, and duplication."</p> +<p class="attribution">—Ralf Johnson at "<a class="reference external" href="https://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf">Who Needs an Architect?</a>" by Martin Fowler</p> +</div></blockquote> +</section> +<section id="open-agile-architecture-standard-by-the-open-group"> +<h2><a class="toc-backref" href="#id6" role="doc-backlink">Open Agile Architecture™ Standard by The Open Group</a></h2> +<p>Глава "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/architecture-development.html#_architecture_development_styles">4.5. Architecture Development Styles</a>" стандарта посвящена поиску баланса между "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/architecture-development.html#_intentional_architecture_2">4.5.2. Intentional Architecture</a>" и "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/architecture-development.html#emergence">4.5.1. Emergence Architecture</a>".</p> +</section> +<section id="prediction-adaptation"> +<span id="emacsway-balancing-prediction-adaptation-pendulum-swinging"/><h2><a class="toc-backref" href="#id7" role="doc-backlink">Эволюционный маятник баланса Prediction/Adaptation</a></h2> +<p>В 2021 году большую популярность обрела статья, освещавшая назревшие в индустрии вопросы относительно поиска баланса Prediction/Adaptation:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://threedots.tech/post/software-dark-ages/">Software Dark Ages</a>" by Robert Laszczak</p></li> +<li><p>"<a class="reference external" href="https://habr.com/ru/company/cian/blog/569940/">Темные века разработки программного обеспечения</a>" by Robert Laszczak, перевод Евгения Пешкова</p></li> +</ul> +<p>Simon Brown тоже обратил внимание на тот факт, что на современном рынке маятник Prediction/Adaptation качнулся в сторону Prediction (анализ и проектирование) от Adaptation (преобладающий принцип Single-Team Agile):</p> +<blockquote> +<div><p>💬 "Even just a few years ago, "software architecture" was not a topic that people were interested in ... "because agile". Times are changing?"</p> +<p class="attribution">—2021-12-23, <a class="reference external" href="https://t.co/ipu5HpS1C4">https://t.co/ipu5HpS1C4</a></p> +</div></blockquote> +<p>В 2000-м Tom DeMarco и Camden, Maine писали:</p> +<blockquote> +<div><p>💬 "In On War, Carl von Clausewitz tells us that military history is a pendulum swinging back and forth between the relative advantages of armor and of mobility. +The knights in shining armor were able to dominate any knight without, but they were no match for the quick, nearly naked pony warriors that swept across the plains with Genghis Kahn and his Mongols. +Light cavalry itself was doomed as soon as there were tanks, and tanks were no match for fleet-footed Palestinian teenagers with Sagger missiles. +With the Maginot Line, the French were gambling that the pendulum had swung again toward armor, but it hadn't, and the Germans simply went around it.</p> +<p>In the field of IT, we are just emerging from a time in which armor (process) has been king. +And now we are moving into a time when only mobility matters. +Building a product the right way still sounds like a laudable goal, but—let's face it—what really matters today is building it fast. +Because we are process-obsessed in our field, we have tended to react to this new imperative as we reacted to the imperatives thrust upon us in the 1980s and 1990s. +We have asked, "What shall we add to our process to deal with this new situation?"</p> +<p class="attribution">—Foreword of "Planning Extreme Programming" by Kent Beck, Martin Fowler</p> +</div></blockquote> +<section id="prediction-adaptation-adaptation"> +<h3><a class="toc-backref" href="#id8" role="doc-backlink">Занос маятника Prediction/Adaptation в сторону Adaptation</a></h3> +<p>Можно заметить, что на рубеже 2000 года, <a class="reference internal" href="../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">маятник Prediction/Adaptation максимально отклонился в сторону Adaptation</span></a>, зачастую минимизируя долю Prediction до минималистичного набора практик - PBR, Spike, Planning. +Этому способствовало радикальное снижение стоимости Adaptation в те годы, благодаря росту популярности OOP, <a class="reference internal" href="adaptation/software-design/patterns.html#emacsway-agile-patterns"><span class="std std-ref">шаблонов</span></a> проектирования и принципов проектирования, методик управления сложностью (ROM, POSA, GOF, OOAD, <a class="reference internal" href="adaptation/software-design/solid.html#emacsway-agile-solid"><span class="std std-ref">SOLID</span></a>, Use Case Driven Approach, Object-Oriented Software Construction etc.), <a class="reference internal" href="../../tdd/tdd.html#emacsway-tdd"><span class="std std-ref">TDD</span></a>, Refactoring и т.д.</p> +<p>В конце 90-х — в начале 2000-х, когда ведущим умам архитектуры своего времени удалось достигнуть <a class="reference internal" href="../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">пологого графика роста стоимости изменения (адаптации) кода, максимально приближенного к горизонтальной асимтоте</span></a>, что открыло широкие возможности по удешевлению разработки путем <a class="reference internal" href="adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">эмпирического (т.е. опытным путем) разрешения неопределенности</span></a> (т.е. итеративно). +Это означало, что стоимость реализации решения больше не зависело от момента его принятия, что позволило отказаться от заблаговременного проектирования и откладывать принятие решения до момента наибольшей полноты информированности, даже после частичной реализации продукта.</p> +<p>Основной фокус архитектуры сместился с</p> +<blockquote> +<div><p>💬 "Architecture is the decisions that you wish you could get right early in a project, but that you are not necessarily more likely to get them right than any other." — Ralph Johnson</p> +</div></blockquote> +<p>на</p> +<blockquote> +<div><p>💬 "A good architect pretends that the decision has not been made, and shapes the system such that those decisions can still be deferred or changed for as long as possible.</p> +<p>A good architect maximizes the number of decisions not made."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +</div></blockquote> +<blockquote> +<div><p>💬️ "Ah, interesting! +Both architecture and agile methods thrive under high levels of uncertainty! +And isn't that exactly the environment we mostly face today with rapid changes in technology and short-lived business models? +So, agile and architecture are addressing the same problem from different angles: <strong>architecture gives you the options to sustain velocity when the unexpected happens</strong>. +And agile gives you the attitude to always be learning and to quickly adapt to changing circumstances."</p> +<p class="attribution">—"<a class="reference external" href="https://architectelevator.com/transformation/agile_architecture/">Agile and Architecture: Friend, not Foe</a>" by Gregor Hohpe</p> +</div></blockquote> +<blockquote> +<div><p>💬️ "Grady Booch has also provided a set of guidelines for an agile architecture (which in turn imply some duties for the agile architect). +Booch claims that all good software-intensive architectures are agile. +What does he mean by this? He means that a successful architecture is resilient and loosely coupled. +It is composed of a core set of well-reasoned design decisions but still contains some "wiggle room" that allows modifications to be made and refactorings to be done, without ruining the original structure.</p> +<p>Booch also notes that an effective agile process will allow the architecture to grow incrementally as the system is developed and matures. +The key to success is to have decomposability, separation of concerns, and near-independence of the parts. +(Sound familiar? These are all modifiability tactics.)</p> +<p>Finally, Booch notes that to be agile, the architecture should be visible and self-evident in the code; this means making the design patterns, cross-cutting concerns, and other important decisions obvious, well communicated, and defended. +This may, in turn, require documentation. +But whatever architectural decisions are made, the architect must make an effort to "socialize" the architecture."</p> +<p class="attribution">—"Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman</p> +</div></blockquote> +<blockquote> +<div><p>💬 Agile methodologies are based on the notion of embracing change over following detailed plans; to quote the Agile Manifesto: working software over comprehensive documentation. +The future is uncertain. +Customer needs change and so do external conditions; +any plans you draw up will need to be <strong>altered</strong> anyway. +This means that the <strong>role of architecture in an Agile context is different from the “waterfall” approach</strong>, where you first draw up plans and then execute them. +In an Agile context the plans themselves, and hence <strong>the architecture, are constantly being adapted</strong> to match changing circumstances and requirements. +This does not mean that architecture is no longer relevant in Agile. +On the contrary, architecture captures the shared vision needed by Agile teams.</p> +<p class="attribution">—"<a class="reference external" href="https://pubs.opengroup.org/architecture/guides/agile-modeling/">The Open Group Guide: Agile Architecture Modeling Using the ArchiMate® Language :: Chapter 2.1 Agile and Architecture in General</a>"</p> +</div></blockquote> +<p>Маятник отклонился от Prediction к Adaptation с большим заносом. +Хотя в то время уже были модели разработки того, что мы сегодня называем моделями масштабируемого Agile (RUP, MSF, RAD, FDD, Crystal Clear etc.), но они не занимали значительной части рынка.</p> +<p>Так же, как во времена роста популярности OOP, "Switch-Case Statement" считался Code Smell, дабы стимулировать продвижение OOP в массы (об этом признается M.Fowler во втором издании книги Refactoring), в начале 2000-х значение заблаговременного анализа и проектирования (Prediction) нередко принебрегалось, дабы подчеркнуть превосходство эмпирического способа разрешения неопределенности (Adaptation) и стимулировать продвижение этой идеи в массы.</p> +<blockquote> +<div><p>💬️ "We decided to call it a manifesto since it was a call to arms and a statement of our beliefs."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/agileStory.html">Writing The Agile Manifesto</a>" by Martin Fowler</p> +</div></blockquote> +<blockquote> +<div><p>💬️ "The Agile movement is not anti-methodology, in fact, many of us want to restore credibility to the word methodology. +We want to restore a balance. We embrace modeling, but not in order to file some diagram in a dusty corporate repository. +We embrace documentation, but not hundreds of pages of never-maintained and rarely-used tomes. +We plan, but recognize the limits of planning in a turbulent environment. +Those who would brand proponents of XP or SCRUM or any of the other Agile Methodologies as "hackers" are ignorant of both the methodologies and the original definition of the term hacker."</p> +<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/history.html">History: The Agile Manifesto</a>"</p> +</div></blockquote> +</section> +<section id="prediction-adaptation-prediction"> +<h3><a class="toc-backref" href="#id9" role="doc-backlink">Отскок маятника Prediction/Adaptation назад к Prediction</a></h3> +<p>Однако, в статье мы наблюдаем, что маятник пошел в обратном направлении:</p> +<blockquote> +<div><p>💬 "пять дней кодинга может сэкономить день планирования</p> +<p>With 5 days of coding, you can save 1 day of planning"</p> +<p class="attribution">—"<a class="reference external" href="https://threedots.tech/post/software-dark-ages/">Software Dark Ages</a>" by Robert Laszczak, перевод Евгения Пешкова</p> +</div></blockquote> +<p>При этом, в статье очень вяло и вскользь говорится о снижении стоимости Adaptation:</p> +<blockquote> +<div><p>💬 "Если вам нужно реализовать что-то "на будущее", потому что позже будет сложнее добавить это, – это очень плохой знак. +Вам следует подумать о том, как упростить позднее добавление.</p> +<p>If you need to implement something "for the future" because it will be harder to add it later – that's a very bad sign. +You should think about how to make it easy to add it later."</p> +<p class="attribution">—"<a class="reference external" href="https://threedots.tech/post/software-dark-ages/">Software Dark Ages</a>" by Robert Laszczak, перевод Евгения Пешкова</p> +</div></blockquote> +<p>Что это? Бунт против Agile? Против заветов Eric Evans?</p> +<p>Причин здесь две.</p> +<ol class="arabic"> +<li><p>Проекты стали сложнее, а команды стали больше, нежели они были 20 лет назад. +Cредний проект стал слишком большим для Single-Team Agile, а стоимость Adaptation нарастает со значительным опережением роста численности коллектива.</p> +<p>Это вынуждает <a class="reference internal" href="../../team-topologies/harlan-mills%27-proposal.html#emacsway-harlan-mills-proposal"><span class="std std-ref">сместить баланс Prediction/Adaptation назад, в сторону Prediction</span></a>. +Интерес к Prediction-методам обработки неопределенности начал возвращаться. +На первое место вышли вопросы достижения автономности команд и интеграции производимых ими системных инкрементов. +Архитектура стала обретать социальное значение.</p> +<p>И здесь мы наблюдаем воскрешение старых принципов, которые были хорошо известны в RUP, MSF, RAD, FDD, Crystal Clear etc. +На базе старых моделей масштабируемой итеративной разработки появились новые (SAFe, DAD, LESS etc.). +Дело в том, что в старые времена Scaled Agile хоть и был не таким частым явлением, как сегодня, да и не назывался вовсе Agile, но он все-таки существовал в немногочисленных крупных корпорациях, т.к. они уже тогда столкнулись с теми проблемами, которые обрели массовость примерно к 2010 году. +Например, многие идеи популярной книги "Team Topologies", которые сегодня создают "вау-эффект", были описаны, еще в RAD.</p> +<p>Обратите внимание на тот факт, что это совпало хронологически со взрывным ростом интереса к микросервисной архитектурой и DDD, поскольку они также отвечали на главный вызов своего времени - стремительной рост размера среднего проекта и среднего коллектива.</p> +</li> +<li><p>Начали появляться новые, более легковесные и экономичные методики анализа и проектирования (Event Storming/Modeling, Domain Storytelling, Impact Mapping, Example Mapping, Design Thinking etc.). +Prediction стал дешевле, что позволило увеличить его долю, оставаясь в прежних пределах его экономической целесообразности.</p></li> </ol> -<p>Обратите внимание, <code class="docutils literal notranslate"><span class="pre">Assignment</span></code>, как и <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>, имеет значение для бизнес-правил, и он не может быть усечен снэпшотом event sourced log. -Например, он может устанавливать правила минимального, либо максимального периода времени между присваиваниями классности, например, не чаще одного раза в полгода. -Или, например, требовать подтверждения текущей классности в случае отсутствия присваиваний в течении года. -Поэтому, он выполнен в виде самостоятельного Объекта-Значения. -В ином случае он мог бы быть перемещен в ReadModel.</p> -<p><code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>, в свою очередь, отвечает за то, чтобы <code class="docutils literal notranslate"><span class="pre">Endorser</span></code> не смог порекомендовать один и тот же <code class="docutils literal notranslate"><span class="pre">Artifact</span></code> одного и того же <code class="docutils literal notranslate"><span class="pre">Specialist</span></code> дважды.</p> +<p>Изменился контекст разработки, и сегодня в индустрии принципы Single-Team Agile зачастую стали не ускорять, а замедлять разработку. +Это качнуло маятник назад, в сторону Prediction.</p> +<p>Многие старые идеи Scaled Agile реинкарнировали в современные итеративные модели разработки, такие как DAD и SAFe.</p> +<p>Начали появляться способы интеграции <a class="reference internal" href="../../team-topologies/harlan-mills%27-proposal.html#emacsway-program-management"><span class="std std-ref">Program Management</span></a> (т.е. организации процессов Prediction) в даже самые легковесные Scaled Agile Frameworks, такие как Nexus by Ken Schwaber.</p> +<p>А в основе лежит все та же идея "<a class="reference internal" href="../../team-topologies/harlan-mills%27-proposal.html#emacsway-harlan-mills-proposal"><span class="std std-ref">Метода Хирурга</span></a>" Харлана Миллза, который младше Закона Конвея всего на три года.</p> +<p>Разные реализации разных SDLC-моделей отличаются прежде всего различным горизонтом видения Prediction и его долей в балансе Prediction/Adaptation, например, в SAFe доля Prediction больше, чем в Nexus, а в RUP - еще больше. Важно уметь грамотно выбирать модель под потребности конкретного проекта. +Grady Booch даже назвал <a class="reference internal" href="../sdlc-reference.html#emacsway-sdlc-literature"><span class="std std-ref">качество управления моделью жизненного цикла разработки критическим условием успешности проекта</span></a>. +А поскольку модель SDLC призвана решать проблему управления неопределенностью требований, то <a class="reference external" href="https://itabok.iasaglobal.org/itabok3_0/architecture-methodologies-and-frameworks/">выбор модели становится архитектурной задачей</a>.</p> +<p>Здесь Prediction сфокусирован, главным образом, на разрешении неопределенности в problem-space (т.е. требований), что влияет на выбор SDLC-модели. +За разрешение неопределенности в solution-space на уровне Implementation и Software Design отвечает принцип <a class="reference internal" href="adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>, целью которого является само снижение стоимости Adaptation.</p> +<p>О том, как интегрировать активности по анализу и проектированию в Agile-модель разработки, см. также в разделе <a class="reference internal" href="../../team-topologies/harlan-mills%27-proposal.html#emacsway-program-management"><span class="std std-ref">Program Management</span></a>.</p> +<p>Новый исторический контекст выдвинул новые проблемы и новые способы их решения. +Agile модель разработки изменилась.</p> +<blockquote> +<div><p>💬 "Despite discussions over whether the Manifesto itself should be amended, many of the original signers see the document as a historical—not a living—document. +"It's like a Declaration of Independence in U.S. history," says Cockburn. +"You don't go back and rewrite that.""</p> +<p class="attribution">—"<a class="reference external" href="https://www.theatlantic.com/technology/archive/2017/12/agile-manifesto-a-history/547715/">The Winter Getaway That Turned the Software World Upside Down</a>" by Caroline Mimbs Nyce</p> +</div></blockquote> +<p>В своем докладе "<a class="reference external" href="https://youtu.be/d4qldY0g_dI?t=16m57s">Kent Beck talks beyond Agile Programming @ Startup Lessons Learned Conference 2010</a>" Kent Beck говорит, что по прошествии 10 лет принципа "Individuals and interactions over processes and tools" of "Agile Manifesto" уже недостаточно, и он добавил бы к нему еще и "Team vision and discipline".</p> +<p>Ценность "Individuals and interactions over processes and tools" of "Agile Manifesto" нередко воспринимается в отрасли как противопоставление проектным практикам и всей Prediction-активности.</p> +<blockquote> +<div><p>💬 "I see some teams that use the word "agile" when they really mean "chaotic""</p> +<p class="attribution">—"<a class="reference external" href="https://pragdave.me/blog/2007/02/24/some-agile-history.html">Some Agile History</a>" by Dave Thomas</p> +</div></blockquote> +<p>На самом деле, у этого пункта были конкретные причины, и они не ставили цели "исключить" Prediction-активности из процессов разработки.</p> +<blockquote> +<div><p>💬 "For example, I think that ultimately, Extreme Programming has mushroomed in use and interest, not because of pair-programming or refactoring, but because, taken as a whole, the practices define a developer community freed from the baggage of Dilbertesque corporations. +Kent Beck tells the story of an early job in which he estimated a programming effort of six weeks for two people. +After his manager reassigned the other programmer at the beginning of the project, he completed the project in twelve weeks—and felt terrible about himself! +The boss—of course—harangued Kent about how slow he was throughout the second six weeks. +<strong>Kent, somewhat despondent because he was such a "failure" as a programmer, finally realized that his original estimate of 6 weeks was extremely accurate—for 2 people—and that his "failure" was really the manager's failure, indeed, the failure of the standard "fixed" process mindset that so frequently plagues our industry.</strong></p> +<p><strong>This type of situation goes on every day—marketing, or management, or external customers, internal customers, and, yes, even developers — don't want to make hard trade-off decisions, so they impose irrational demands through the imposition of corporate power structures.</strong> +This isn't merely a software development problem, it runs throughout Dilbertesque organizations.</p> +<p><strong>In order to succeed in the new economy, to move aggressively into the era of e-business, e-commerce, and the web, companies have to rid themselves of their Dilbert manifestations of make-work and arcane policies.</strong> +This freedom from the inanities of corporate life attracts proponents of Agile Methodologies, and scares the begeebers (you can't use the word 'shit' in a professional paper) out of traditionalists. +Quite frankly, the Agile approaches scare corporate bureaucrats — at least those that are happy pushing process for process' sake versus trying to do the best for the "customer" and deliver something timely and tangible and "as promised" — because they run out of places to hide.</p> +<p><strong>The Agile movement is not anti-methodology, in fact, many of us want to restore credibility to the word methodology.</strong> +<strong>We want to restore a balance.</strong> +<strong>We embrace modeling, but not in order to file some diagram in a dusty corporate repository.</strong> +<strong>We embrace documentation, but not hundreds of pages of never-maintained and rarely-used tomes.</strong> +<strong>We plan, but recognize the limits of planning in a turbulent environment.</strong> +Those who would brand proponents of XP or SCRUM or any of the other Agile Methodologies as "hackers" are ignorant of both the methodologies and the original definition of the term hacker."</p> +<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/history.html">History: The Agile Manifesto</a>"</p> +</div></blockquote> +<blockquote> +<div><p>💬 ...people and how they work together is the primary factor in software development, and that processes are a secondary factor. +This is reflected in the first value of the agile manifesto "Individuals and interactions over processes and tools"...</p> +<p>&lt;...&gt;</p> +<p>An important consequence of these values and principles is that a team should choose its own process - one that suits the people and context in which they work. +<strong>Imposing an agile process from the outside strips the team of the self-determination which is at the heart of agile thinking.</strong></p> +<p>&lt;...&gt;</p> +<p>This notion of a process made to fit the team (and not the other way around) is a necessary condition for agile methods, but clearly isn't sufficient. +A team may choose a totally waterfall, un-agile process. +In that case, clearly the process is no more agile than apples taste of strawberries. +But <strong>agile methods aren't the best for all situations</strong>, and personally I'd rather have a team work in a non-agile manner they chose themselves than have my favorite agile practices imposed upon them.</p> +<p>&lt;...&gt;</p> +<p>imposition isn't as clear cut as it can sound, but the fundamental point remains - <strong>imposing agile methods introduces a conflict with the values and principles that underlie agile methods</strong>.</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/AgileImposition.html">Agile Imposition</a>" by Martin Fowler</p> +</div></blockquote> </section> -<section id="id6"> -<h4><a class="toc-backref" href="#id20" role="doc-backlink">Реализация требований</a></h4> -<p>Пройдемся по требованиям:</p> -<dl class="simple"> -<dt>Каждый член Организации может отдать 20 рекомендаций (признаний) в год в пользу других членов.</dt><dd><p>Это требование реализуется счетчиком <code class="docutils literal notranslate"><span class="pre">Endorser.availableEndorsementCount</span></code> и инвариантом <code class="docutils literal notranslate"><span class="pre">Объекта-Значения</span> <span class="pre">AvailableEndorsementCount</span></code>, который не может превышать установленное ограничение.</p> -</dd> -<dt>Одна рекомендация от члена Организации претендуемого (или более высокого) квалификационного класса равноценна двум рекомендациям от членов Организации текущего квалификационного класса (излишки не переносятся).</dt><dd><p>Это требование реализуется обработчиком Доменного События <code class="docutils literal notranslate"><span class="pre">EndorsementCreated</span></code> перед вызовом метода <code class="docutils literal notranslate"><span class="pre">Specialist.IncreaseReceivedEndorsementCount(Weight)</span></code>.</p> -</dd> -<dt>Рекомендации от членов Организации более низкого квалификационного класса не допускаются.</dt><dd><p>Реализуется фабричным методом <code class="docutils literal notranslate"><span class="pre">Endorser.Endorse(...)</span></code>.</p> -</dd> -<dt>Допускается одна рекомендация рекомендующего за один конкретный артефакт рекомендуемого.</dt><dd><p>Это требование обсудим отдельно.</p> -</dd> -<dt>Требуемые количества рекомендаций по квалификационным классам...</dt><dd><p>Реализуется фабричным методом <code class="docutils literal notranslate"><span class="pre">Endorser.Endorse(...)</span></code>.</p> -</dd> -</dl> </section> -<section id="id7"> -<h4><a class="toc-backref" href="#id21" role="doc-backlink">Проблемы данной модели</a></h4> -<p>В существующей модели прослеживается ряд проблем. Рассмотрим их по порядку.</p> -<section id="id8"> -<h5><a class="toc-backref" href="#id22" role="doc-backlink">Вероятность утраты согласованности</a></h5> -<p>Давайте представим, что <code class="docutils literal notranslate"><span class="pre">endorserA</span></code> 2-го класса дает рекомендацию в пользу <code class="docutils literal notranslate"><span class="pre">specialistA</span></code> 2-го класса, у которого уже существует 13 рекомендаций, т.е. для присвоения нового квалификационного класса не хватает всего одной рекомендации. -В период времени с момента проверки инварианта методом <code class="docutils literal notranslate"><span class="pre">Endorser.Endorse(...)</span></code> и до декрементирования счетчика доступных рекомендаций рекомендующего методом <code class="docutils literal notranslate"><span class="pre">Endorser.DecreaseAvailableEndorsementCount()</span></code>, а также до вызова метода <code class="docutils literal notranslate"><span class="pre">Specialist.IncreaseReceivedEndorsementCount(Weight)</span></code>, другой участник <code class="docutils literal notranslate"><span class="pre">endorserB</span></code> 2-го класса может также успеть дать рекомендацию в пользу <code class="docutils literal notranslate"><span class="pre">specialistA</span></code>.</p> -<p>В результате рекомендация <code class="docutils literal notranslate"><span class="pre">endorserB</span></code> будет зачтена в пользу <code class="docutils literal notranslate"><span class="pre">specialistA</span></code> уже фактически 1-го класса, что нарушает требование о запрете на рекомендацию участников более высокого квалификационного класса.</p> -<p>Для упреждения такой ситуации достаточно наложить покрывающий (композитный) уникальный индекс на поля <code class="docutils literal notranslate"><span class="pre">Endorsement.specialistId</span></code> и <code class="docutils literal notranslate"><span class="pre">Endorsement.specialistVersion</span></code>.</p> -<p>Или рассмотрим другую ситуацию. -Участник <code class="docutils literal notranslate"><span class="pre">endorserA</span></code>, у которого оставалась всего одна доступная рекомендация в текущем году, дает рекомендацию в пользу <code class="docutils literal notranslate"><span class="pre">specialistA</span></code>, -но произошла техническая задержка доставки сообщения <code class="docutils literal notranslate"><span class="pre">EndorsementCreated</span></code> рекомендующему по техническим причинам, например, очередь "встала" (или подписчик затупил, чек-поинт в БД запустился, сеть упала...), и тогда рекомендующий может успеть раздать рекомендаций больше, чем располагает. -Упреждается такая ситуация таким же образом - покрывающим уникальным индексом на поля <code class="docutils literal notranslate"><span class="pre">Endorsement.endorserId</span></code> и <code class="docutils literal notranslate"><span class="pre">Endorsement.endorserGrade</span></code>.</p> -<p>Но это выдвигает новый вопрос - каким образом партиционировать таблицу <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>, чтобы реализовать оба уникальных индекса? -Кто хоть раз занимался партиционированием, тот знает, что уникальный индекс возможен только в пределах партиции. -Можно, конечно, партиционировать <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> по автоинкрементальному первичному ключу (или по дате создания), но тут самое время перейти к следующему требованию, которое гласит: "Допускается одна рекомендация рекомендующего за один конкретный артефакт рекомендуемого".</p> +<section id="alberto-brandolini-about-prediction-adaptation"> +<h2><a class="toc-backref" href="#id10" role="doc-backlink">Alberto Brandolini about Prediction/Adaptation</a></h2> +<p><em>Автор раздела: Андрей Ганичев</em></p> +<p>Андрей Ганичев, contributor of "<a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd">Full Modular Monolith application with Domain-Driven Design approach</a>", на тему поиска баланса Prediction/Adaptation:</p> +<p>Когда читал книгу Брандолини про "<a class="reference external" href="https://leanpub.com/introducing_eventstorming">Introducing EventStorming: An act of Deliberate Collective Learning</a>" by Alberto Brandolini (та которая недописанная), обратил внимание что и он вскользь проходит по этой теме.</p> +<p>Глава Pretending to solve the problem writing software, раздел Embrace Change:</p> +<blockquote> +<div><p>💬 "...iterative development is expensive. It is the best approach for developing software in very complex, and lean-demanding domains. However, the initial starting point matters, a lot. A big refactoring will cost a lot more than iterative fine tuning (think splitting a database, vs renaming a variable). So I'll do everything possible to start iterating from the most reasonable starting point."</p> +<p class="attribution">—"<a class="reference external" href="https://leanpub.com/introducing_eventstorming">Introducing EventStorming: An act of Deliberate Collective Learning</a>" by Alberto Brandolini</p> +</div></blockquote> +<blockquote> +<div><p>💬 "Upfront is a terrible word in the agile jargon. It recalls memories the old times analysis phase in the worst corporate waterfall. Given this infamous legacy, the word has been banned from agile environments like blasphemy. But unfortunately ...there's always something upfront. Even the worst developer thinks before typing the firs line of code."</p> +<p class="attribution">—"<a class="reference external" href="https://leanpub.com/introducing_eventstorming">Introducing EventStorming: An act of Deliberate Collective Learning</a>" by Alberto Brandolini</p> +</div></blockquote> +<p>Cм. также:</p> +<ul class="simple"> +<li><p>"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin</p> +<ul> +<li><p>"Chapter 3 Agile Principles :: Prediction and Adaptation"</p></li> +<li><p>"Chapter 3 Agile Principles :: Balance Predictive Up-Front Work with Adaptive Just-in-Time Work"</p></li> +</ul> +</li> +<li><p>"Succeeding with Agile: Software Development Using Scrum" by Mike Cohn, "Chapter 9 Technical Practices :: Design: intentional yet Emergent"</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/architecture/">Software Architecture Guide</a>" by Martin Fowler</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/agile.html">Agile Software Guide</a>" by Martin Fowler</p></li> +<li><p>"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html#PredictiveVersusAdaptive">The New Methodology :: Predictive versus Adaptive</a>" by Martin Fowler</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/WaterfallProcess.html">Waterfall Process</a>" by Martin Fowler</p></li> +</ul> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference internal" href="adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> +<li><p>"<a class="reference internal" href="prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Что такое Prediction</span></a>"</p></li> +<li><p>"<a class="reference internal" href="adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>"</p></li> +<li><p>"<a class="reference internal" href="adaptation/software-construction/borrowing-trouble.html#emacsway-borrowing-trouble"><span class="std std-ref">Borrowing trouble</span></a>"</p></li> +</ul> +</div> +</section> +Sat, 19 Aug 2023 00:00:00 Как осуществлять изменения в коллективеhttps://dckms.github.io/system-architecture/emacsway/soft-skills/change-making.html<span class="target" id="index-0"/><section id="emacsway-change-making-in-psychology"> +<span id="id1"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id2"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#emacsway-change-making-in-psychology" id="id5">Как осуществлять изменения в коллективе</a></p> +<ul> +<li><p><a class="reference internal" href="#id3" id="id6">Один из реальных примеров</a></p></li> +<li><p><a class="reference internal" href="#emacsway-change-making-literature" id="id7">Литература по теме осуществления изменений</a></p></li> +</ul> +</li> +</ul> +</nav> +<p>На протяжении своей практики я регулярно наблюдал одну и ту же картину: кто-то из сотрудников узнал что-то новое, или же был принят на работу сотрудник с новыми знаниями (например, DDD, архитектурные, методологические, процессные подходы и т.п.), но, странное дело, новая идея получает не поддержку, а сопротивление коллектива, хотя и могла бы облегчить жизнь многим.</p> +<p>Далее одно из двух - либо напряженность нарастает, и наступает разрыв отношений, либо человек смиряется, проявив "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%BD%D0%BE%D1%81%D1%82%D1%8C">Внешний конформизм</a>".</p> +<p>Последний вариант опасен тем, что для человека намного проще согласиться с существующим положением дел, и, чтобы подавить "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%B3%D0%BD%D0%B8%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9_%D0%B4%D0%B8%D1%81%D1%81%D0%BE%D0%BD%D0%B0%D0%BD%D1%81">Когнитивный диссонанс</a>", человек старается всеми силами преувеличить существенность принятого им решения, одновременно приуменьшая важность отвергнутого. +Вследствие этого альтернатива теряет всякую привлекательность в его глазах.</p> +<p>Далее наступает "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%98%D1%81%D0%BA%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_%D0%B2%D0%BE%D1%81%D0%BF%D1%80%D0%B8%D1%8F%D1%82%D0%B8%D0%B8_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B2%D1%8B%D0%B1%D0%BE%D1%80%D0%B0">Искажение в восприятии сделанного выбора</a>" и "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%98%D1%80%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%83%D1%81%D0%B8%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5">Закон иррационального усиления</a>", и, из сторонника изменений, человек превращается в реакциониста, находя в этом "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологическую защиту</a>".</p> +<p>Наверняка вы слышали в своей практике такие фразы, как "я тоже был таким когда-то...", "юношеский максимализм" и т.п.</p> +<p>Но бывает и третий вариант - человеку удается изменить среду. +В конце концов, существующая среда была кем-то создана. +Почему одним это удается, а другим нет?</p> +<blockquote> +<div><p>📝 "Исторический фатализм существует для трусов. +Смелость и счастливый случай не раз меняли ход событий. +Этому учит нас история. +Бывают моменты, когда воля нескольких человек сокрушает все препятствия и открывает новые дороги".</p> +<p class="attribution">—<a class="reference external" href="https://topwar.ru/28631-general-sharl-de-goll.html">Шарль де Голль</a></p> +</div></blockquote> +<p>По моим наблюдениям, условием снижения напряженности является <a class="reference internal" href="knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">выравнивание уровня знаний</span></a>. +Вероятность разрыва отношений выше в ригидных коллективах с низкой обучаемостью. +Поэтому, первая задача, которую предстоит решить, - это изменить систему ценностей коллектива, и возвести знания в элемент престижа.</p> +<p>Никогда не предлагайте внедрения какого-либо нового подхода, например, DDD. +Для коллектива это - еще одна неопределенность, которая может превратиться в еще одну проблему на их шее. +В силу "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%BE%D0%B4%D0%BD%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Эффекта неоднозначности</a>" предлагаемые изменения будут отвергнуты.</p> +<p>Не пытайтесь доказать собеседнику его неправоту, потому что:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%BE%D0%B5_%D0%B2%D0%BE%D1%81%D0%BF%D1%80%D0%B8%D1%8F%D1%82%D0%B8%D0%B5">Селективное восприятие</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%BB%D0%BE%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%BA_%D0%BF%D0%BE%D0%B4%D1%82%D0%B2%D0%B5%D1%80%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D1%8E_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D0%B7%D1%80%D0%B5%D0%BD%D0%B8%D1%8F">Склонность к подтверждению своей точки зрения</a>"</p></li> +<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%94%D0%B0%D0%BD%D0%BD%D0%B8%D0%BD%D0%B3%D0%B0_%E2%80%94_%D0%9A%D1%80%D1%8E%D0%B3%D0%B5%D1%80%D0%B0">Эффект Даннинга — Крюгера</a>"</p></li> +<li><p><a class="reference external" href="https://architectelevator.com/strategy/always-be-right/">Вы и сами можете ошибаться.</a></p></li> +</ul> +<p>Мне известен только один действенный способ провести изменения, это - <a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">идентифицировать проблемы</a>, и в ответ на <strong>конкретные проблемы</strong> предлагать <strong>конкретные решения</strong>. +Например, если проблему решает один из тактических паттернов DDD, то не нужно настаивать на переходе на DDD полностью. +Если проблему решает "<a class="reference external" href="https://www.pmi.org/disciplined-agile/lifecycle/program">Program Management</a>", то <a class="reference external" href="https://www.scrum.org/resources/blog/scaling-scrum-nexus-and-kanban">не нужно настаивать на переходе на SAFe или DAD полностью</a>.</p> +<p>Также учтите, что <a class="reference external" href="https://www.hindawi.com/journals/np/2009/482696/">мозгу нужно время</a>, чтобы осознать решение и рассеять неопределенность. +Поэтому, не спешите. +Вернитесь к вопросу несколько раз через время. +<a class="reference internal" href="icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Вода камень точит</span></a>. +Видели как море режет скалы? +Обязательно посмотрите - вдохновляет. +Стекающие капельки воды прорезают в камне бороздки и углубляют их до тех пор, пока глыба не обрушится. +Капля против скалы! +А вы - больше, чем капля. +Терпенье и труд, как говорится...</p> +<p>Этот пример учит еще одному - <a class="reference internal" href="icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">чем меньше гранулярность изменений, тем выше вероятность их принятия</span></a>. +Это важно, ибо силовое превосходство не на вашей стороне. +Чтобы повысить удельное давление, нужно уменьшить площадь воздействия. +Побеждает не тот, кто сильнее, а тот, кто способен создать силовое превосходство в нужное время в нужном месте.</p> +<p>В крайнем случае, сработает "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BD%D0%BE%D0%B9_%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D0%B8">Каскад доступной информации</a>".</p> +<p>Как говорил Генри Форд, <em>"качество — это делать что-либо правильно, даже когда никто не смотрит"</em>. +Единственный способ этого достигнуть - это единое понимание и полнота информированности коллектива. +Достигается это проливанием света на недостающие связи между причиной и следствием. +Изменения должны происходить снизу, от самоорганизующегося коллектива, а не спускаться директивно сверху. +Важно уметь не внедрить изменения, а инициировать и подпитывать их. +Больше слушать, спрашивать, меньше говорить. +Mike Cohn в статье "<a class="reference external" href="https://www.mountaingoatsoftware.com/blog/my-favorite-hard-questions-to-ask-when-making-a-decision">My Favorite Hard Questions to Ask When Making a Decision</a>" разделяет эту тактику, и даже конкретизирует список вопросов, которые нужно задавать для осуществления влияния.</p> +<section id="id3"> +<h2><a class="toc-backref" href="#id6" role="doc-backlink">Один из реальных примеров</a></h2> +<p>Nick Tune поделился <a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/carefully-forming-teams-to-begin-technology-modernization-f4aa3e776e1f">историей конфликта с одним из ведущих разработчиков</a>. +Его статья напомнила мне <a class="reference external" href="https://ain.ua/ru/2017/10/17/we-fired-our-rick/">другую нашумевшую статью</a>.</p> +<p>Подобных историй я уже слышал предостаточно. +Коротко описать ситуацию можно так: в старом коллективе есть некий синьор, на котором много лет держалась кодовая база. +Пришел новый специалист с новыми процессами и с новой архитектурой. +Старый специалист начинает саботировать изменения вплоть до раскола коллектива.</p> +<p>По всей видимости, старый специалист рассчитывал на признание со стороны руководства за многолетний вклад, а вместо этого получил демонстрацию недоверия в виде делегации полномочий нанятому со стороны специалисту, способного (в отличии от него) решить проблему, и которому он теперь должен подчиняться. +<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологическая защита</a> была вполне ожидаемой.</p> +<p>Катализатором конфликта выступил <a class="reference internal" href="knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">разный уровень знаний</span></a>:</p> +<blockquote> +<div><p>"People in the first modernization teams must be especially open to learning"</p> +<p class="attribution">—"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/carefully-forming-teams-to-begin-technology-modernization-f4aa3e776e1f">Carefully Forming Teams to Begin Technology Modernization</a>" by Nick Tune.</p> +</div></blockquote> +<p>Так как стороной конфликта выступил Nick Tune, известный автор в области архитектуры ПО, то можно предположить, что синьор заметно уступал ему. +<a class="reference internal" href="knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">Выравнивание уровня знаний</span></a> - основной способ устранения причин сопротивления.</p> +<p>Но сама по себе <strong>разница в уровне знаний</strong> была не причиной конфликта, а только его почвой. +Причиной стало <a class="reference internal" href="knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">принуждение коллектива к изменениям в условиях недостаточной информированности</span></a>.</p> +<p>Сила внешнего принуждения в данном случае оказалась сильней сил консолидации коллектива - коллектив распался.</p> +<p>Как можно было предотвратить эту ситуацию?</p> +<p>Один из вариантов - просто не принуждать коллектив к изменениям в условиях недостаточной информированности. +Тем более, что еще Kent Beck писал ряд предостережений по поводу деликатности внедрения парного программирования. +Это предотвратило бы раскол, но не устранило бы сопротивления.</p> +<p>У сопротивления было две причины:</p> +<ol class="arabic simple"> +<li><p>Недооцененность давнего сотрудника.</p></li> +<li><p>Чувство ущербности старого сотрудника на фоне знаний нового сотрудника.</p></li> +</ol> +<p>Первая причина решается очень легко - на недооценненного сотрудника возлагается самая ответственная задача по внедрению изменений (или любая другая ответственная задача). +Это позволило бы ему сохранить свои позиции в коллективе и почувствовать оказание ему доверия, что выбило бы почву для психологической защиты.</p> +<p>Вторая причина решается возведением знаний в элемент престижа коллектива и постоянным выравниванием уровня знаний. +Вот тут уже все зависит от обучаемости конкретного специалиста, и гарантий никто дать не может. +Однако, из статьи следует, что он - парень, в общем-то, способный, и его ценили, несмотря на его замкнутость.</p> +<p>Но был в этой ситуации и политический момент. +На самом деле, Nick Tune уволил его не из-за того, что тот саботировал изменения, а из-за того, что он подрывал авторитет Ника в коллективе, и, обладая сильной позицией в коллективе, настраивал коллектив против изменений. +Т.е. он выступал в роли очага консолидации сил сопротивления всего коллектива. +В этом заключается главная причина. +Шла борьба за влияние на коллектив.</p> +<p>Проблема этой ситуации в том, что Nick Tune выбрал слишком широкий фронт изменений, на котором не смог <a class="reference internal" href="icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">обеспечить превосходство сил изменения над силами сопротивления</span></a>. +В конечном итоге он это осознал, и повысил удельную силу изменений путем сокращения численности коллектива, чем ослабил силу сопротивления. +Правда, для этого ему пришлось уволить из компании основные очаги сопротивления.</p> +<p>Этот шаг был вынужденным, так как оставшаяся часть коллектива не оказывала достаточной поддержки изменениям, но и не выражала сильного сопротивления:</p> +<blockquote> +<div><p>"afraid to speak in meetings"</p> +<p class="attribution">—"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/carefully-forming-teams-to-begin-technology-modernization-f4aa3e776e1f">Carefully Forming Teams to Begin Technology Modernization</a>" by Nick Tune.</p> +</div></blockquote> +<p>Можно было бы попытаться сохранить коллектив, если внедрять изменения инкрементально. +Это позволило бы Нику сформировать плацдарм (в виде обученной части коллектива), который оказал бы ему поддержку в дальнейшем распространении изменений. +И тогда расстановка сил в коллективе была бы уже совсем иной. +Из риска остаться изгоем, такой синьор уже воздержался бы от попыток саботажа.</p> +<p>А вот выносить конфликт в публичную плоскость было, пожалуй, опрометчиво - люди объединяются по принципу отождествления общих угроз, что может уменьшить базу его поддержки.</p> </section> -<section id="id9"> -<h5><a class="toc-backref" href="#id23" role="doc-backlink">Уникальность артефакта</a></h5> -<p>Суть в том, что дубликаты описаний артефактов могут быть нечеткими. -Требуется вводить пре-модерацию рекомендаций. -Но это значит, что оптимистическая блокировка с помощью уникального индекса может длиться часами и днями. -Вряд ли пользователи системы будут в восторге от этого.</p> -<p>А что если выделить <code class="docutils literal notranslate"><span class="pre">Endorsement.artifactDescription</span></code> в отдельный Агрегат и сделать пре-модерацию для него? -Кажется, это предотвратит длительные блокировки по уже одобренным артефактам, а рекомендация неодобренных артефактов в принципе невозможна. -Более того, артефакты можно категоризировать, и тогда система сможет информировать не только о квалификационной классности члена Организации, но и об областях знаний его экспертности.</p> -<p>Вносим правки:</p> -<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kd">type</span><span class="w"> </span><span class="nx">Endorsement</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">endorserId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">endorserGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">endorserVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">artifactId</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Artifact</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="w"/> -<span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="nx">ArtifactStatus</span><span class="w"/> -<span class="w"> </span><span class="nx">description</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="w"/> -<span class="w"> </span><span class="nx">competenceIds</span><span class="w"> </span><span class="p">[]</span><span class="nx">CompetenceId</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Competence</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">CompetenceId</span><span class="w"/> -<span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="nx">CompetenceName</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> -<span class="p">}</span><span class="w"/> -</pre></div> +<section id="emacsway-change-making-literature"> +<span id="id4"/><h2><a class="toc-backref" href="#id7" role="doc-backlink">Литература по теме осуществления изменений</a></h2> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://architectelevator.com/transformation/reversing-disablement-cycle/">Reversing the disablement cycle: Everyone does the right thing, yet nothing much gets done. How to break self-reinforcing bad habits.</a>" by Gregor Hohpe</p></li> +<li><p>"<a class="reference external" href="https://craiglarman.com/wiki/index.php?title=Larman%27s_Laws_of_Organizational_Behavior">Larman's Laws of Organizational Behavior</a>" by Craig Larman (<a class="reference external" href="https://habr.com/ru/companies/scrumtrek/articles/320832/">на русском</a>)</p></li> +<li><p>"<a class="reference external" href="https://less.works/less/structure">Structure</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/structure">на русском</a>)</p></li> +<li><p>"Social psychology" 13th edition by David G. Myers. Перевод: "Социальная психология" / Майерс Д. Пер. с англ. З. Замчук; Зав. ред. кол. Л. Винокуров. — 7-е изд. — СПб.: Питер, 2006.</p></li> +<li><p>"Leading Change, With a New Preface by the Author" by John P. Kotter, November 6, 2012</p></li> +<li><p>"The Dance of Change: The challenges to sustaining momentum in a learning organization" by Peter M. Senge, George Roth, March 16, 1999</p></li> +<li><p>"Lean Change Management: Innovative practices for managing organizational change" by Jason Little</p></li> +<li><p>"The Leadership Experience" 7th edition by Richard L. Daft</p></li> +<li><p>"Management" 013 edition by Richard L. Daft</p></li> +<li><p>"Вызов лидеров" / Карлоф Б., Седерберг С.</p></li> +<li><p>"Organizational development and change." by Huse E., L., 1975.</p></li> +<li><p>"The change masters." by Kanter R., N.Y., 1985.</p></li> +<li><p>"Choosing strategies for change" by Kotter J., Schlesinger L. //Harvard business review. March. 1979.</p></li> +<li><p>"Transformational leadership and organizational change during agile and devops initiatives." by Mayner, Stephen, ProQuest, 2017.</p></li> +<li><p>"The effects of transformational and change leadership on employees' commitment to change: a multi-level study." by Herold, David M., Donald B. Fedor, Steven Caldwell, and Yi Liu, Journal of Applied Psychology, Volume 93, 2008.</p></li> +<li><p>"Leading Change, With a New Preface by the Author." by Kotter, John P, Harvard Business Review Press, 2012.</p></li> +<li><p>"Switch: How to Change Things When Change Is Hard." by Heath, Chip, and Dan Heath, The Crown Publishing Group, 2010.</p></li> +<li><p>"A More Beautiful Question: The Power of Inquiry to Spark Breakthrough Ideas" by Warren Berger</p></li> +<li><p>"Just Listen: Discover the Secret to Getting Through to Absolutely Anyone" by Mark Goulston</p></li> +<li><p>Бражников М.А. Управление изменениями: базовый курс: учеб. пособие / М.А. Бражников, И.В. Хорина. – Самара: Самар. гос. техн. ун-т, 2015. – 238 с.</p></li> +<li><p>Данилюк. УПРАВЛЕНИЕ ИЗМЕНЕНИЯМИ: учебное пособие. Тюмень: Издательство Тюменского государственного университета, 2014. 288 с.</p></li> +<li><p>Иванова Е.А. Управление изменениями: Учебное пособие. - М: МГУПС (МИИТ), 2014. – 167 с..</p></li> +<li><p>Кужева С.Н. Управление изменениями: учебное пособие/ С.Н. Кужева.– Омск: Изд-во Ом. гос. ун-та, 2011. – 140 с.</p></li> +<li><p>Медведева Н.В. Управление изменениями в организации: Учебное пособие. – Саратов: СГУ, 2016. – 119 с.</p></li> +<li><p>Колеман Д., Фармер А. Управление изменениями. Жуковский, 1992.</p></li> +<li><p>Тичи Н., Деванна М. Лидеры реорганизаций. М., 1990.</p></li> +<li><p>"<a class="reference external" href="http://ibcm.biz/%d1%87%d1%82%d0%be-%d1%82%d0%b0%d0%ba%d0%be%d0%b5-%d1%81%d0%be%d0%bf%d1%80%d0%be%d1%82%d0%b8%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b8%d0%b7%d0%bc%d0%b5%d0%bd%d0%b5%d0%bd%d0%b8%d1%8f%d0%bc-%d0%b8/">Что такое сопротивление изменениям и как с ним работать?</a>"</p></li> +<li><p>"<a class="reference external" href="http://ibcm.biz/wp-content/uploads/2016/06/%D0%A2%D0%B5%D0%BA%D1%81%D1%82-%D0%9E%D1%81%D0%BE%D0%B1%D0%B5%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8-%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8-%D0%B2-%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D0%B8.pdf">Особенности управления изменениями в России</a>" / Демьяненко Василий и др.</p></li> +<li><p>"<a class="reference external" href="https://membership.neuroleadership.com/material/scarf-a-brain-based-model-for-collaborating-with-and-influencing-others-vol-1/">SCARF®: A Brain-Based Model for Collaborating with and Influencing Others (Vol. 1)</a>" by David Rock</p></li> +<li><p>"<a class="reference external" href="http://ibcm.biz/%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C-%D1%81%D0%BE%D1%86%D0%B8%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE-%D0%BF%D0%BE%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D1%8F-scarf-%D0%B4%D1%8D%D0%B2%D0%B8%D0%B4/">Как управлять поведением сотрудников с помощью модели социального поведения SCARF (Дэвид Рок)</a>"</p></li> +<li><p>"<a class="reference external" href="https://theoryandpractice.ru/posts/20482-chto-takoe-model-scarf-ili-kak-nash-mozg-ispolzuet-knut-i-pryanik">Что такое модель SCARF, или Как наш мозг использует кнут и пряник</a>" / Александра Смаракова</p></li> +</ul> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference internal" href="icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Принцип ледокола</span></a>"</p></li> +<li><p>"<a class="reference internal" href="knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">Разрешение конфликтов на почве недостатка знаний</span></a>"</p></li> +</ul> </div> -<p>Задача упрощается. -В момент создания Агрегата <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> мы можем удостовериться, что такой артефакт такого рекомендуемого еще пока не был рекомендован таким рекомендующим, с помощью стратегии-валидатора, передаваемой аргументом в фабричный метод, ответственный за создание этого Агрегата.</p> -<p>Но вот в чем дело. -После выделения артефакта в отдельный Агрегат, нам корневой доступ к Агрегату <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> особо-то и не нужен. -Это значит, что его можно преобразовать в Сущность.</p> -</section> -<section id="endorsement"> -<h5><a class="toc-backref" href="#id24" role="doc-backlink">Преобразование Endorsement в Сущность</a></h5> -<p>С точки зрения <a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-model-purity-completeness/">DDD Trilemma</a>, учитывая относительно небольшое количество возможных рекомендаций в процессе жизни Агрегата <code class="docutils literal notranslate"><span class="pre">Specialist</span></code>, имеет смысл отдать предпочтение в пользу "Domain model purity" и "Domain model completeness".</p> -<p>Вопрос в том, в каком именно Агрегате разместить Сущность <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>? -Ответ на этот вопрос подскажет нам, по какому ключу лучше партиционировать таблицу <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>. -Сейчас становится уже очевидно, что партиционирование по автоинкрементальному первичному ключу (или по дате создания) будет приводить к просмотру всех партиций, что нас не устраивает.</p> -<p>У кого хранится в реальном мире наградной лист, почетная грамота, сертификат и т.д. - у награждаемого или у награждающего? -Для кого он имеет ценность?</p> -<p>Это наводит на мысль о том, что Сущность <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> должна принадлежать Агрегату <code class="docutils literal notranslate"><span class="pre">Specialist</span></code>. -Что подтвержается также ответом на вопрос о том, должен ли рекомендующий, т.е. Агрегат <code class="docutils literal notranslate"><span class="pre">Endorser</span></code>, хранить рекомендации удаленных из системы рекомендуемых? -Вроде бы рекомендации должны удаляться вместе с рекомендуемым (это отвечает и на вопрос о том, по какому ключу партиционировать таблицу <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>). -А вот если из системы удаляется рекомендующий, то его рекомендации продолжают иметь значение как способ подтверждения достоверности квалификационной классности рекомендуемого. -Иными словами, квалификационная классность рекомендуемого является <a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%91%D1%80%D1%82%D0%BA%D0%B0_%D1%81%D0%BF%D0%B8%D1%81%D0%BA%D0%B0">сверткой (left fold)</a> этих рекомендаций, по-другому говоря - их проекцией.</p> -<p>Таким образом, между рекомендуемым и рекомендациями образуется строгая согласованность. -Все, что теперь требуется Агрегату <code class="docutils literal notranslate"><span class="pre">Specialist</span></code> для того, чтобы установить возможность создания рекомендации - это квалификационный класс рекомендующего и достоверность того, что он пока еще не исчерпал доступные ему рекомендации.</p> -<p>Но это так же значит, что мы не можем создать покрывающий уникальный индекс на поля <code class="docutils literal notranslate"><span class="pre">Endorsement.endorserId</span></code> и <code class="docutils literal notranslate"><span class="pre">Endorsement.endorserGrade</span></code>.</p> -<p>Иными словами, существует незначительная вероятность того, что <code class="docutils literal notranslate"><span class="pre">Endorser</span></code> успеет раздать рекомендаций больше, чем ему доступно. -Существует несколько способов решить эту проблему.</p> -</section> -<section id="id10"> -<h5><a class="toc-backref" href="#id25" role="doc-backlink">Достижение согласованности</a></h5> -<section id="data-context-and-interaction-dci"> -<h6><a class="toc-backref" href="#id26" role="doc-backlink">Data, context, and interaction (DCI)</a></h6> -<p>Первый из них - это "<a class="reference external" href="https://en.m.wikipedia.org/wiki/Data,_context_and_interaction">Data, context, and interaction (DCI)</a>". -Подробно он описан в главе "Chapter 9. Coding it Up: The DCI Architecture" книги "Lean Architecture: for Agile Software Development" 1st edition by James O. Coplien, Gertrud Bjørnvig. -Можно посмотреть на <a class="reference external" href="https://github.com/agiledragon/transfer-money-go">примере реализации перевода денежных средств</a> с одного счета на другой счет (который, в определенной мере, похож на перенос рекомендации от одного члена Организации к другому члену Организации).</p> </section> -<section id="process-manager-pattern"> -<h6><a class="toc-backref" href="#id27" role="doc-backlink">Process Manager Pattern</a></h6> -<p>Второй способ описывает Vaughn Vernon в интервью "<a class="reference external" href="https://www.infoq.com/articles/modeling-uncertainty-reactive-ddd/">Modeling Uncertainty with Reactive DDD</a>" by Vaughn Vernon reviewed by Thomas Betts - путем применения <a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/ProcessManager.html">Process Manager Pattern</a>.</p> -<p>Сюда же можно отнести <a class="reference external" href="https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf">SAGA pattern</a> и <a class="reference external" href="https://github.com/meirwah/awesome-workflow-engines">workflow engines</a>.</p> </section> -<section id="pessimistic-offline-lock"> -<h6><a class="toc-backref" href="#id28" role="doc-backlink">Pessimistic Offline Lock</a></h6> -<p>Еще одним решением может быть <a class="reference external" href="https://martinfowler.com/eaaCatalog/pessimisticOfflineLock.html">пессимистическая блокировка</a> Агрегата <code class="docutils literal notranslate"><span class="pre">Endorser</span></code>. -Сценарий будет состоять из следующих этапов:</p> +Tue, 08 Aug 2023 00:00:00 Как сохранить Агрегат в БД не разрушая инкапсуляции?https://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/aggregate-encapsulation.html +<span id="id1"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<p>Инварианты лишены смысла своего существования в условиях дырявой, как решето, инкапсуляции. +Вопрос в том, как сохранить инкапсуляцию Агрегатов в Golang, когда нам требуется его внутреннее состояние для формирования SQL-запроса, или, наоборот, требуется установить состояние Агрегата в результате выполнения SQL-запроса.</p> +<nav class="contents" id="id2"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p>блокировка Агрегата <code class="docutils literal notranslate"><span class="pre">Endorser</span></code>;</p></li> -<li><p>проверка возможности осуществления рекомендации;</p> -<ul> -<li><p>в случае неудачи - блокировка отпускается;</p></li> -<li><p>в случае успеха - порождается Доменное Событие;</p> -<ul> -<li><p>обработчик Доменного События вызывает <code class="docutils literal notranslate"><span class="pre">Specialist.ReceiveEndorsement(Endorser,</span> <span class="pre">ArtifactId,</span> <span class="pre">time.Time)</span> <span class="pre">error</span></code>;</p> -<ul> -<li><p>в случае успеха порождается Доменное Событие об успехе;</p> +<li><p><a class="reference internal" href="#emacsway-golang-encapsulation" id="id4">Как сохранить Агрегат в БД не разрушая инкапсуляции?</a></p> <ul> -<li><p>обработчик Доменного События осуществит декрементирование счетчика доступных рекомендаций рекомендующего методом <code class="docutils literal notranslate"><span class="pre">Endorser.DecreaseAvailableEndorsementCount()</span></code> и отпустит блокировку;</p></li> -</ul> -</li> -<li><p>в случае неудачи порождается Доменное Событие о неудаче;</p> +<li><p><a class="reference internal" href="#memento-pattern" id="id5">Memento pattern</a></p></li> +<li><p><a class="reference internal" href="#walker" id="id6">Walker</a></p></li> +<li><p><a class="reference internal" href="#valuer-scanner" id="id7">Valuer &amp; Scanner</a></p></li> +<li><p><a class="reference internal" href="#reflection" id="id8">Reflection</a></p></li> +<li><p><a class="reference internal" href="#exporter" id="id9">Exporter</a></p> <ul> -<li><p>обработчик Доменного События отпустит блокировку.</p></li> -</ul> -</li> -</ul> -</li> +<li><p><a class="reference internal" href="#accepting-interface-mediator" id="id10">1. Accepting interface (Mediator)</a></p></li> +<li><p><a class="reference internal" href="#returning-structure" id="id11">2. Returning structure</a></p></li> </ul> </li> </ul> </li> </ul> -<p>Блокировка не позволит рекомендующему осуществить другую рекомендацию, пока не завершится первая.</p> +</nav> +<section id="memento-pattern"> +<h2><a class="toc-backref" href="#id5" role="doc-backlink">Memento pattern</a></h2> +<p>Memento оказался близко, но не по назначению. Суть Memento в том, что он не должен раскрывать свое состояние никому, кроме своего создателя:</p> +<blockquote> +<div><ol class="arabic simple"> +<li><p>Preserving encapsulation boundaries. Memento avoids exposing information that only an originator should manage but that must be stored nevertheless outside the originator. +The pattern shields other objects from potentially complex Originator internals, thereby preserving encapsulation boundaries.</p></li> +</ol> +<p class="attribution">—"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides</p> +</div></blockquote> +<p>Тем не менее, этот подход используется некоторыми авторитетными источниками, см. <a class="reference external" href="https://github.com/microsoftarchive/cqrs-journey/blob/6ffd9a8c8e865a9f8209552c52fa793fbd496d1f/source/Conference/Registration/SeatsAvailability.cs#L237">здесь</a> и <a class="reference external" href="https://github.com/microsoftarchive/cqrs-journey/blob/6ffd9a8c8e865a9f8209552c52fa793fbd496d1f/source/Infrastructure/Azure/Infrastructure.Azure/EventSourcing/AzureEventSourcedRepository.cs#L31">здесь</a>.</p> +<blockquote> +<div><p>💬 The event is stored using some form of serialization, for the rest of this discussion the mechanism will assumed to be built in serialization although the use of the memento pattern can be highly advantageous.</p> +<p>&lt;...&gt;</p> +<p>Many use the default serialization package available with their platform with good results though the Memento pattern is quite useful when dealing with snapshots. The Memento pattern (or custom serialization) better insulates the domain over time as the structure of the domain objects change. The default serializer has versioning problems when the new structure is released (the existing snapshots must either deleted and recreated or updated to match the new schema). The use of the Memento pattern allows the separated versioning of the snapshot schema from the domain object itself.</p> +<p class="attribution">—"<a class="reference external" href="https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf">CQRS Documents by Greg Young</a>"</p> +</div></blockquote> </section> -<section id="id11"> -<h6><a class="toc-backref" href="#id29" role="doc-backlink">Резервирование</a></h6> -<p>Повысить параллелизм можно, если заменить блокировку на резервирование рекомендации, используя счетчик <code class="docutils literal notranslate"><span class="pre">Endorser.pendingEndorsementCount</span></code>, значение которого не должно превышать значение <code class="docutils literal notranslate"><span class="pre">Endorser.availableEndorsementCount</span></code>. -Сценарий будет состоять из следующих этапов:</p> +<section id="walker"> +<h2><a class="toc-backref" href="#id6" role="doc-backlink">Walker</a></h2> +<p>Walker представляет собою модификацию паттерна Visitor с целью сохранить инкапсуляцию Агрегатов. К числу недостатков паттерна паттерна Visitor относится:</p> +<blockquote> +<div><p>6. Breaking encapsulation. Visitor's approach assumes that the ConcreteElement interface is powerful enough to let visitors do their job. +As a result, the pattern often forces you to provide public operations that access an element's internal state, which may compromise its encapsulation.</p> +<p class="attribution">—"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides</p> +</div></blockquote> +<p>Что будет создавать Walker в случае обхода иерархической структуры Агрегата с несколькими вложенными Сущностями? +Вероятно, это будет будет несколько SQL-запросов с параметрами, т.е. некий композитный объект, выраженный некой структурой данных. +Это лишает смысла использование Visitor, если можно сразу возвратить структуру данных, причем, абстрагированную от SQL.</p> +<p>Технически, можно сделать так:</p> +<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kd">type</span><span class="w"> </span><span class="nx">Walkable</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">Accept</span><span class="p">(</span><span class="nx">Walker</span><span class="p">)</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Walker</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">SetField</span><span class="p">(</span><span class="kt">string</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">WalkWalkable</span><span class="p">(</span><span class="nx">Walkable</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">WalkUint8</span><span class="p">(</span><span class="kt">uint8</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">WalkUint64</span><span class="p">(</span><span class="kt">uint64</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">WalkUint</span><span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">WalkTime</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"/> +<span class="p">}</span><span class="w"/> +</pre></div> +</div> +<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">)</span><span class="w"> </span><span class="nx">Accept</span><span class="p">(</span><span class="nx">walker</span><span class="w"> </span><span class="nx">interfaces</span><span class="p">.</span><span class="nx">Walker</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">walker</span><span class="p">.</span><span class="nx">SetField</span><span class="p">(</span><span class="s">"endorserId"</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">walker</span><span class="p">.</span><span class="nx">WalkWalkable</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">endorserId</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">walker</span><span class="p">.</span><span class="nx">SetField</span><span class="p">(</span><span class="s">"endorserGrade"</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">walker</span><span class="p">.</span><span class="nx">WalkWalkable</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">endorserGrade</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="c1">// ...</span><span class="w"/> +<span class="p">}</span><span class="w"/> +</pre></div> +</div> +<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">id</span><span class="w"> </span><span class="nx">EndorserId</span><span class="p">)</span><span class="w"> </span><span class="nx">Accept</span><span class="p">(</span><span class="nx">walker</span><span class="w"> </span><span class="nx">interfaces</span><span class="p">.</span><span class="nx">Walker</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">walker</span><span class="p">.</span><span class="nx">WalkUint64</span><span class="p">(</span><span class="nx">id</span><span class="p">.</span><span class="nx">Value</span><span class="p">())</span><span class="w"/> +<span class="p">}</span><span class="w"/> +</pre></div> +</div> +<p>Проблема в том, что на этапе создания SQL-запроса нам пока еще могут быть неизвестны первичные ключи Агрегатов, чтобы их можно было бы проставить в SQL-запросы их Сущностей.</p> +<p>Кроме того, осведомленность о способах образования SQL-запросов размазывается между Walkers и Repositories, что вызывает "Разлет Дроби" (Code Smell) в случае изменения существующего способа построения SQL (например, в случае изменения диалекта БД или в случае внедрения какого-либо QueryBuilder). +Walker начинает быть слишком осведомленным о деталях реализации Repository.</p> +<p>В целях достижения DRY возникает целесообразность возложить на Walker генерирование только части SQL, и освободить его от осведомленности знания таблиц в БД, что будет разрывать обязанность за построение SQL на несколько объектов и подрывать Cohesion.</p> +</section> +<section id="valuer-scanner"> +<h2><a class="toc-backref" href="#id7" role="doc-backlink">Valuer &amp; Scanner</a></h2> <ul class="simple"> -<li><p>резервирование рекомендации инкрементированием счетчика <code class="docutils literal notranslate"><span class="pre">Endorser.pendingEndorsementCount</span></code>;</p></li> -<li><p>проверка возможности осуществления рекомендации;</p> -<ul> -<li><p>в случае неудачи - декрементирование счетчика <code class="docutils literal notranslate"><span class="pre">Endorser.pendingEndorsementCount</span></code>;</p></li> -<li><p>в случае успеха - порождается Доменное Событие;</p> -<ul> -<li><p>обработчик Доменного События вызывает <code class="docutils literal notranslate"><span class="pre">Specialist.ReceiveEndorsement(Endorser,</span> <span class="pre">ArtifactId,</span> <span class="pre">time.Time)</span> <span class="pre">error</span></code>;</p> -<ul> -<li><p>в случае успеха порождается Доменное Событие об успехе;</p> -<ul> -<li><p>обработчик Доменного События осуществит декрементирование счетчика доступных рекомендаций рекомендующего <code class="docutils literal notranslate"><span class="pre">Endorser.availableEndorsementCount</span></code> и отпустит резервирование декрементированием счетчика <code class="docutils literal notranslate"><span class="pre">Endorser.pendingEndorsementCount</span></code>;</p></li> -</ul> -</li> -<li><p>в случае неудачи порождается Доменное Событие о неудаче;</p> -<ul> -<li><p>обработчик Доменного События отпустит резервирование декрементированием счетчика <code class="docutils literal notranslate"><span class="pre">Endorser.pendingEndorsementCount</span></code>.</p></li> -</ul> -</li> -</ul> -</li> -</ul> -</li> +<li><p><a class="reference external" href="https://pkg.go.dev/database/sql/driver#Valuer">Valuer</a></p></li> +<li><p><a class="reference external" href="https://pkg.go.dev/database/sql#Scanner">Scanner</a></p></li> </ul> -</li> +<p>Интерфейс Scanner открывает дверь к изменяемости ValueObject, что противоречит основной его сути. +А так же открывает брешь в инкапсуляции Агрегата. +Справедливости ради, стоит отметить, что можно его реализовать таким образом, чтобы он был только однократно мутируемым, предварительно проверяя, не установлено ли уже значение.</p> +<p>Но есть еще один момент - метод <code class="docutils literal notranslate"><span class="pre">Scan(src</span> <span class="pre">any)</span> <span class="pre">error</span></code> вызывается у конкретного типа, что препятствует использованию паттерна, известного как <a class="reference external" href="https://martinfowler.com/eaaCatalog/specialCase.html">Special Case</a> или <a class="reference external" href="https://refactoring.com/catalog/introduceSpecialCase.html">Null Object</a>. +Кроме того, в некоторых случаях может потребоваться преобразовать неизменяемые исторические данные для новой версии модели. +Вопрос затрагивался в разделе "4. Validating historical data" статьи "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/always-valid-domain-model/">Always-Valid Domain Model</a>" by Vladimir Khorikov и в разделе "6. The use of ORMs within and outside of the always-valid boundary" статьи "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/database-always-valid-domain-model/">Database and Always-Valid Domain Model</a>" by Vladimir Khorikov.</p> +<p>С другой стороны, Valuer может возвращать только примитивные типы, а значит, он не пригоден для экспорта иерархической структуры состояния Агрегата:</p> +<blockquote> +<div><p>It is either nil, a type handled by a database driver's NamedValueChecker interface, or an instance of one of these types:</p> +<ul class="simple"> +<li><p>int64</p></li> +<li><p>float64</p></li> +<li><p>bool</p></li> +<li><p>[]byte</p></li> +<li><p>string</p></li> +<li><p>time.Time</p></li> </ul> -<p>Этот вариант выглядит наиболее простым, поэтому, на нем и остановимся. -Не исключено, что в будущем появятся альтернативные реализации с использованием описанных подходов.</p> -</section> -</section> -</section> +<p class="attribution">—<a class="reference external" href="https://pkg.go.dev/database/sql/driver#Value">Источник</a></p> +</div></blockquote> </section> -<section id="id12"> -<h3><a class="toc-backref" href="#id30" role="doc-backlink">Упрощенная реализация итоговой модели</a></h3> -<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kn">package</span><span class="w"> </span><span class="nx">grade_2</span><span class="w"/> +<section id="reflection"> +<h2><a class="toc-backref" href="#id8" role="doc-backlink">Reflection</a></h2> +<p>В документации <a class="reference external" href="https://pkg.go.dev/reflect#Value.FieldByName">отсутствуют</a> какие-либо упоминания об ограничении доступа к защищенным атрибутам структуры данных посредством рефлекции.</p> +<p>Может быть через рефлексию и заработало бы - я не пробовал. +Но использовать рефлексию в production для таких целей как-то не сильно хочется, в т.ч. и по соображениям производительности. +К тому же этот метод является, по сути, еще одним способом пробить брешь в инкапсуляции.</p> +<p>Похожий трюк используется <a class="reference external" href="https://stackoverflow.com/a/25405485">здесь</a>:</p> +<div class="literal-block-wrapper docutils container" id="id3"> +<div class="code-block-caption"><span class="caption-text"><a class="reference external" href="https://stackoverflow.com/a/25405485">How to marshal struct when some members are protected/inner/hidden</a></span></div> +<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"/> <span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"errors"</span><span class="w"/> -<span class="w"> </span><span class="s">"time"</span><span class="w"/> -<span class="p">)</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="kt">uint64</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="w"> </span><span class="kt">uint64</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="w"> </span><span class="kt">string</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">ArtifactStatus</span><span class="w"> </span><span class="kt">uint8</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">CompetenceId</span><span class="w"> </span><span class="kt">uint64</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">CompetenceName</span><span class="w"> </span><span class="kt">string</span><span class="w"/> - -<span class="kd">type</span><span class="w"> </span><span class="nx">Weight</span><span class="w"> </span><span class="kt">uint8</span><span class="w"/> - -<span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="nx">LowerWeight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> -<span class="w"> </span><span class="nx">PeerWeight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> -<span class="w"> </span><span class="nx">HigherWeight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">2</span><span class="w"/> - -<span class="w"> </span><span class="nx">Expert</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">Candidate</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">Grade1</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">Grade2</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">Grade3</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">WithoutGrade</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="s">"fmt"</span><span class="w"/> +<span class="w"> </span><span class="s">"reflect"</span><span class="w"/> -<span class="w"> </span><span class="nx">Proposed</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">ArtifactStatus</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="nx">Accepted</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">ArtifactStatus</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="s">"github.com/bitly/go-simplejson"</span><span class="w"/> <span class="p">)</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">Specialist</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">grade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">receivedEndorsements</span><span class="w"> </span><span class="p">[]</span><span class="nx">Endorsement</span><span class="w"/> -<span class="w"> </span><span class="nx">assignments</span><span class="w"> </span><span class="p">[]</span><span class="nx">Assignment</span><span class="w"/> -<span class="w"> </span><span class="nx">version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">A</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:"name"`</span><span class="w"/> +<span class="w"> </span><span class="nx">code</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:"code"`</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">ReceiveEndorsement</span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">,</span><span class="w"> </span><span class="nx">aId</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">GetGrade</span><span class="p">()</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"it is allowed to receive endorsements only from members with equal or higher grade"</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">!</span><span class="nx">e</span><span class="p">.</span><span class="nx">CanCompleteEndorsement</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"endorser is not able to complete endorsement"</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nb">uint64</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">GetId</span><span class="p">())</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">uint64</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> -<span class="w"> </span><span class="s">"endorser can't endorse himself"</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsements</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">v</span><span class="p">.</span><span class="nx">IsEndorsedBy</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">GetId</span><span class="p">(),</span><span class="w"> </span><span class="nx">aId</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"this artifact has already been endorsed by the recogniser"</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="nx">marshal</span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="nx">A</span><span class="p">)</span><span class="w"> </span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">simplejson</span><span class="p">.</span><span class="nx">New</span><span class="p">()</span><span class="w"/> +<span class="w"> </span><span class="nx">va</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">a</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">vt</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">va</span><span class="p">.</span><span class="nx">Elem</span><span class="p">()</span><span class="w"/> +<span class="w"> </span><span class="nx">types</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">vt</span><span class="p">.</span><span class="nx">NumField</span><span class="p">();</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">j</span><span class="p">.</span><span class="nx">Set</span><span class="p">(</span><span class="nx">types</span><span class="p">.</span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">Tag</span><span class="p">.</span><span class="nx">Get</span><span class="p">(</span><span class="s">"json"</span><span class="p">),</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Sprintf</span><span class="p">(</span><span class="s">"%v"</span><span class="p">,</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">Indirect</span><span class="p">(</span><span class="nx">va</span><span class="p">).</span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="p">)))</span><span class="w"/> <span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsements</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsements</span><span class="p">,</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">GetId</span><span class="p">(),</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">GetGrade</span><span class="p">(),</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">GetVersion</span><span class="p">(),</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="nx">aId</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">})</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">actualizeGrade</span><span class="p">(</span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">j</span><span class="p">.</span><span class="nx">MarshalJSON</span><span class="p">()</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">actualizeGrade</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">WithoutGrade</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">6</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade3</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade3</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade2</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade2</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade1</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade1</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Candidate</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Candidate</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">40</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Expert</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">A</span><span class="p">{</span><span class="nx">name</span><span class="p">:</span><span class="w"> </span><span class="s">"jessonchan"</span><span class="p">,</span><span class="w"> </span><span class="nx">code</span><span class="p">:</span><span class="w"> </span><span class="s">"abc"</span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="nx">b</span><span class="p">,</span><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">marshal</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nb">string</span><span class="p">(</span><span class="nx">b</span><span class="p">))</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="kt">uint</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">counter</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsements</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">v</span><span class="p">.</span><span class="nx">GetSpecialistGrade</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">counter</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nb">uint</span><span class="p">(</span><span class="nx">v</span><span class="p">.</span><span class="nx">GetWeight</span><span class="p">())</span><span class="w"/> +</pre></div> +</div> +</div> +</section> +<section id="exporter"> +<h2><a class="toc-backref" href="#id9" role="doc-backlink">Exporter</a></h2> +<section id="accepting-interface-mediator"> +<h3><a class="toc-backref" href="#id10" role="doc-backlink">1. Accepting interface (Mediator)</a></h3> +<p>Такой вариант рассматривается в книге "<a class="reference external" href="https://kalele.io/books/">Implementing Domain-Driven Design</a>" by Vaughn Vernon:</p> +<blockquote> +<div><p>Use a Mediator to Publish Aggregate Internal State</p> +<p>To work around the problem of tight coupling between the model and its clients, you may choose to design Mediator +[Gamma et al.] (aka Double-Dispatch and Callback) interfaces to which the Aggregate publishes its internal state. +Clients would implement the Mediator interface, passing the implementer’s object reference to the Aggregate as a method argument. +The Aggregate would then double-dispatch to that Mediator to publish the requested state, all without revealing its shape or structure. +The trick is to not wed the Mediator’s interface to any sort of view specification, but to keep it focused on rendering +Aggregate states of interest:</p> +<div class="highlight-java notranslate"><div class="highlight"><pre><span/><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">BacklogItem</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="p">...</span><span class="w"/> +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">provideBacklogItemInterest</span><span class="p">(</span><span class="n">BacklogItemInterest</span><span class="w"> </span><span class="n">anInterest</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informTenantId</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">tenantId</span><span class="p">().</span><span class="na">id</span><span class="p">());</span><span class="w"/> +<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informProductId</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">productId</span><span class="p">().</span><span class="na">id</span><span class="p">());</span><span class="w"/> +<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informBacklogItemId</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">backlogItemId</span><span class="p">().</span><span class="na">id</span><span class="p">());</span><span class="w"/> +<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informStory</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">story</span><span class="p">());</span><span class="w"/> +<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informSummary</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">summary</span><span class="p">());</span><span class="w"/> +<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informType</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">type</span><span class="p">().</span><span class="na">toString</span><span class="p">());</span><span class="w"/> +<span class="w"> </span><span class="p">...</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">provideTasksInterest</span><span class="p">(</span><span class="n">TasksInterest</span><span class="w"> </span><span class="n">anInterest</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="n">Set</span><span class="o">&lt;</span><span class="n">Task</span><span class="o">&gt;</span><span class="w"> </span><span class="n">tasks</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">allTasks</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="n">anInterest</span><span class="p">.</span><span class="na">informTaskCount</span><span class="p">(</span><span class="n">tasks</span><span class="p">.</span><span class="na">size</span><span class="p">());</span><span class="w"/> +<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">Task</span><span class="w"> </span><span class="n">task</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">tasks</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="p">...</span><span class="w"/> <span class="w"> </span><span class="p">}</span><span class="w"/> <span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">counter</span><span class="w"/> +<span class="w"> </span><span class="p">...</span><span class="w"/> <span class="p">}</span><span class="w"/> +</pre></div> +</div> +<p>The various interest providers may be implemented by other classes, much the same way that Entities (5) describe the way +validation is delegated to separate validator classes.</p> +<p>Be aware that some will consider this approach completely outside the responsibility of an Aggregate. Others will consider +it a completely natural extension of a well-designed domain model. +As always, such trade-offs must be discussed by your technical team members.</p> +</div></blockquote> +<p>Ссылки по теме:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.infoworld.com/article/2072302/more-on-getters-and-setters.html">More on getters and setters</a>" by Allen Holub</p></li> +<li><p>"<a class="reference external" href="https://stackoverflow.com/questions/24921227/save-and-load-objects-without-breaking-encapsulation">Save and load objects without breaking encapsulation</a>" at Stackoverflow</p></li> +</ul> +<p>Идею также можно посмотреть на примере:</p> +<div class="literal-block-wrapper docutils container" id="emacsway-code-exporter-example-1"> +<div class="code-block-caption"><span class="caption-text"><a class="reference external" href="https://www.infoworld.com/article/2072302/more-on-getters-and-setters.html">Example by Allen Holub</a></span></div> +<div class="highlight-java notranslate"><div class="highlight"><pre><span/><span class="w"> </span><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.Locale</span><span class="p">;</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">g</span><span class="w"> </span><span class="nx">Grade</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">assignments</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">assignments</span><span class="p">,</span><span class="w"> </span><span class="nx">Assignment</span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="p">,</span><span class="w"> </span><span class="nx">g</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">,</span><span class="w"/> -<span class="w"> </span><span class="p">})</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">g</span><span class="w"/> -<span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">Employee</span><span class="w"/> +<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">Name</span><span class="w"> </span><span class="n">name</span><span class="p">;</span><span class="w"/> +<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">EmployeeId</span><span class="w"> </span><span class="n">id</span><span class="p">;</span><span class="w"/> +<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">Money</span><span class="w"> </span><span class="n">salary</span><span class="p">;</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">IncreaseVersion</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">interface</span> <span class="nc">Exporter</span><span class="w"/> +<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">addName</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">addID</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">addSalary</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">salary</span><span class="w"> </span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">interface</span> <span class="nc">Importer</span><span class="w"/> +<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">provideName</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">provideID</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">provideSalary</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">open</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">close</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="nf">Employee</span><span class="p">(</span><span class="w"> </span><span class="n">Importer</span><span class="w"> </span><span class="n">builder</span><span class="w"> </span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">open</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Name</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">provideName</span><span class="p">()</span><span class="w"> </span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">EmployeeId</span><span class="p">(</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">provideID</span><span class="p">()</span><span class="w"> </span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">salary</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Money</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">provideSalary</span><span class="p">(),</span><span class="w"/> +<span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Locale</span><span class="p">(</span><span class="s">"en"</span><span class="p">,</span><span class="w"> </span><span class="s">"US"</span><span class="p">)</span><span class="w"> </span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">close</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">export</span><span class="p">(</span><span class="w"> </span><span class="n">Exporter</span><span class="w"> </span><span class="n">builder</span><span class="w"> </span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">addName</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">name</span><span class="p">.</span><span class="na">toString</span><span class="p">()</span><span class="w"> </span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">addID</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">id</span><span class="p">.</span><span class="na">toString</span><span class="p">()</span><span class="w"> </span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="na">addSalary</span><span class="p">(</span><span class="w"> </span><span class="n">salary</span><span class="p">.</span><span class="na">toString</span><span class="p">()</span><span class="w"> </span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="c1">//...</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +</pre></div> +</div> +</div> +<p>Пример реализации:</p> +<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kn">package</span><span class="w"> </span><span class="nx">grade_1</span><span class="w"/> + +<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="s">"time"</span><span class="w"/> +<span class="p">)</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Exporter</span><span class="p">[</span><span class="nx">T</span><span class="w"> </span><span class="kt">any</span><span class="p">]</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">SetState</span><span class="p">(</span><span class="nx">T</span><span class="p">)</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">Endorsement</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">endorserId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">endorserGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">endorserVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">artifactId</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">Exportable</span><span class="p">[</span><span class="nx">T</span><span class="w"> </span><span class="kt">any</span><span class="p">]</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">ExportTo</span><span class="p">(</span><span class="nx">Exporter</span><span class="p">[</span><span class="nx">T</span><span class="p">])</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">)</span><span class="w"> </span><span class="nx">IsEndorsedBy</span><span class="p">(</span><span class="nx">rId</span><span class="w"> </span><span class="nx">MemberId</span><span class="p">,</span><span class="w"> </span><span class="nx">aId</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">endorserId</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">rId</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">artifactId</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">aId</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="p">)</span><span class="w"> </span><span class="nx">Export</span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="nx">Exporter</span><span class="p">[</span><span class="kt">uint</span><span class="p">])</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetState</span><span class="p">(</span><span class="nb">uint</span><span class="p">(</span><span class="nx">e</span><span class="p">))</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">)</span><span class="w"> </span><span class="nx">GetSpecialistGrade</span><span class="p">()</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">specialistGrade</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">EndorserExporterSetter</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">SetId</span><span class="p">(</span><span class="nx">MemberId</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">SetGrade</span><span class="p">(</span><span class="nx">Grade</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">SetAvailableEndorsementCount</span><span class="p">(</span><span class="nx">EndorsementCount</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">SetPendingEndorsementCount</span><span class="p">(</span><span class="nx">EndorsementCount</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">SetVersion</span><span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">SetCreatedAt</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">)</span><span class="w"> </span><span class="nx">GetWeight</span><span class="p">()</span><span class="w"> </span><span class="nx">Weight</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">endorserGrade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">specialistGrade</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">PeerWeight</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">endorserGrade</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">specialistGrade</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">HigherWeight</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">LowerWeight</span><span class="w"/> -<span class="p">}</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">UintExporter</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">Assignment</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> -<span class="w"> </span><span class="nx">specialistVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> -<span class="w"> </span><span class="nx">assignedGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">UintExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetState</span><span class="p">(</span><span class="nx">value</span><span class="w"> </span><span class="kt">uint</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="o">*</span><span class="nx">e</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">UintExporter</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span><span class="w"/> <span class="p">}</span><span class="w"/> <span class="kd">type</span><span class="w"> </span><span class="nx">Endorser</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> @@ -6450,3743 +4937,5251 @@ ones of his generation."</p> <span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">GetId</span><span class="p">()</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">id</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">Export</span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="nx">EndorserExporterSetter</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetId</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetGrade</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">grade</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetAvailableEndorsementCount</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetPendingEndorsementCount</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetVersion</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">SetCreatedAt</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">createdAt</span><span class="p">)</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">GetGrade</span><span class="p">()</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">grade</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">EndorserExporter</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">Id</span><span class="w"> </span><span class="nx">UintExporter</span><span class="w"/> +<span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="nx">UintExporter</span><span class="w"/> +<span class="w"> </span><span class="nx">AvailableEndorsementCount</span><span class="w"> </span><span class="nx">UintExporter</span><span class="w"/> +<span class="w"> </span><span class="nx">PendingEndorsementCount</span><span class="w"> </span><span class="nx">UintExporter</span><span class="w"/> +<span class="w"> </span><span class="nx">Version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">CreatedAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">GetVersion</span><span class="p">()</span><span class="w"> </span><span class="kt">uint</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetId</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="nx">MemberId</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">val</span><span class="p">.</span><span class="nx">Export</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ex</span><span class="p">.</span><span class="nx">Id</span><span class="p">)</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">canReserveEndorsement</span><span class="p">()</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetGrade</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="nx">Grade</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">val</span><span class="p">.</span><span class="nx">Export</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ex</span><span class="p">.</span><span class="nx">Grade</span><span class="p">)</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">CanCompleteEndorsement</span><span class="p">()</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetAvailableEndorsementCount</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">val</span><span class="p">.</span><span class="nx">Export</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ex</span><span class="p">.</span><span class="nx">AvailableEndorsementCount</span><span class="p">)</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">ReserveEndorsement</span><span class="p">()</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">!</span><span class="nx">e</span><span class="p">.</span><span class="nx">canReserveEndorsement</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"no endorsement can be reserved"</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetPendingEndorsementCount</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">val</span><span class="p">.</span><span class="nx">Export</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ex</span><span class="p">.</span><span class="nx">PendingEndorsementCount</span><span class="p">)</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">ReleaseEndorsementReservation</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetVersion</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="kt">uint</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">Version</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">val</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">CompleteEndorsement</span><span class="p">()</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"no endorsement is available"</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"there is no endorsement reservation"</span><span class="p">)</span><span class="w"/> -<span class="w"> </span><span class="p">}</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> -<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ex</span><span class="w"> </span><span class="o">*</span><span class="nx">EndorserExporter</span><span class="p">)</span><span class="w"> </span><span class="nx">SetCreatedAt</span><span class="p">(</span><span class="nx">val</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">ex</span><span class="p">.</span><span class="nx">CreatedAt</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">val</span><span class="w"/> <span class="p">}</span><span class="w"/> +</pre></div> +</div> +<p>Или на более лаконичном примере:</p> +<div class="literal-block-wrapper docutils container" id="emacsway-code-exporter-example-2"> +<div class="code-block-caption"><span class="caption-text"><a class="reference external" href="https://stackoverflow.com/questions/24921227/save-and-load-objects-without-breaking-encapsulation">Example from Stackoverflow</a></span></div> +<div class="highlight-java notranslate"><div class="highlight"><pre><span/><span class="w"> </span><span class="kd">interface</span> <span class="nc">PersonImporter</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">IncreaseVersion</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="nf">getAge</span><span class="p">();</span><span class="w"/> + +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">getId</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="kd">interface</span> <span class="nc">PersonExporter</span><span class="w"> </span><span class="p">{</span><span class="w"/> + +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">setDetails</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">age</span><span class="p">);</span><span class="w"/> + +<span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="kd">class</span> <span class="nc">Person</span><span class="w"> </span><span class="p">{</span><span class="w"/> + +<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">age</span><span class="p">;</span><span class="w"/> +<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">id</span><span class="p">;</span><span class="w"/> + +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="nf">Person</span><span class="p">(</span><span class="n">PersonImporter</span><span class="w"> </span><span class="n">importer</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="n">age</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">importer</span><span class="p">.</span><span class="na">getAge</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">importer</span><span class="p">.</span><span class="na">getId</span><span class="p">();</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">export</span><span class="p">(</span><span class="n">PersonExporter</span><span class="w"> </span><span class="n">exporter</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="n">exporter</span><span class="p">.</span><span class="na">setDetails</span><span class="p">(</span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">age</span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="p">}</span><span class="w"/> +</pre></div> +</div> +</div> +<p>Замечательный вариант, но проблема в том, что он использует интерефейсы, и это получается слишком многословно - требуется декларировать сам тип (структуру), интерфейс, сеттеры. +Вряд ли кто-то будет этим заниматься, когда можно просто обязать Агрегат вернуть простую структуру.</p> +<blockquote> +<div><p>💬️ "Цель архитектуры программного обеспечения — уменьшить человеческие трудозатраты на создание и сопровождение системы.</p> +<p>The goal of software architecture is to minimize the human resources required to build and maintain the required system."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin, перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p><a class="reference internal" href="#emacsway-code-exporter-example-2"><span class="std std-ref">Второй</span></a> из приведенных примеров содержит пакетированный сеттер, что делает его несколько менее многословным. +Этот вариант уступает первому варианту тем, что в случае одноименного метода <code class="docutils literal notranslate"><span class="pre">setDetails</span></code> нельзя обойти одним экспортером сразу несколько вложенных объектов, например, агрегат и его композитный первичный ключ, что может быть удобным для составления списка параметров SQL-запроса. +В таком случае придется жертвовать консистентностью именования, что лишает второй вариант превосходств перед первым вариантом. +Также второй вариант обладает несколько большей хрупкостью при добавлении новых полей, либо их удалении.</p> +<p>Немного смущает смешивание парадигм FP и OOP для ValueObject. +Хотя ValueObject и остается неизменяемым, но сам факт того, что функционально чистый объект вызывает мутирующие методы другого объекта, вызывает небольшое смущение. +Возникает вопрос - почему функционально чистый объект не может просто взять и вернуть другой функционально чистый объект? +Если бы Golang поддерживать Generics для методов, тогда могло бы получиться что-то похожее на <code class="docutils literal notranslate"><span class="pre">Endorser.Export[T](exporterFactory</span> <span class="pre">function(attr1,</span> <span class="pre">attr2,</span> <span class="pre">attr3)</span> <span class="pre">T)</span> <span class="pre">T</span></code>. +Однако, если продолжить развивать эту мысль, то мы обнаружим, что таким образом пытаемся решить проблему обхода инкапсуляции, которая вызвана именно применением OOP.</p> +<p>Как говорил Michael Feathers:</p> +<blockquote> +<div><p>💬️ "OO makes code understandable by encapsulating moving parts. +FP makes code understandable by minimizing moving parts." +— <a class="reference external" href="https://twitter.com/mfeathers/status/29581296216">Michael Feathers</a></p> +</div></blockquote> +<p>Использование такого подхода в тестовых кейсах делает их несколько более многословными.</p> +<p>Можно было бы сказать, что тестировать нужно по принципам <a class="reference internal" href="../../../tdd/tdd.html#emacsway-tdd-black-box"><span class="std std-ref">черного ящика</span></a>, т.е. только внешнее поведение. +Совершенно верно, но только нам требуется не только внешнее поведение, но и достоверность сохранения введенной в конструктор Агрегата информации в БД.</p> +<blockquote> +<div><p>💬️ "Давно известно, что простота тестирования является характерным признаком хорошей архитектуры. +Шаблон «Скромный объект» — хороший пример, потому что раздел между легко и тяжело тестируемыми частями часто совпадает с архитектурными границами. +Раздел между Презентаторами и Представлениями — одна из таких границ, но существует много других.</p> +<p>It has long been known that testability is an attribute of good architectures. +The Humble Object pattern is a good example, because the separation of the behaviors into testable and non-testable parts often defines an architectural boundary. +The Presenter/View boundary is one of these boundaries, but there are many others."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin, перевод ООО Издательство "Питер"</p> +</div></blockquote> +</section> +<section id="returning-structure"> +<h3><a class="toc-backref" href="#id11" role="doc-backlink">2. Returning structure</a></h3> +<p>Возникает целесообразность облегчить метод экспортирования, придав ему сигнатуру <code class="docutils literal notranslate"><span class="pre">Endorser.Export()</span> <span class="pre">EndorserState</span></code> вместо <code class="docutils literal notranslate"><span class="pre">Endorser.ExportTo(ex</span> <span class="pre">EndorserExporter)</span></code>. +Получится что-то типа DTO с тем лишь отличием, что он пересекает не сетевые границы, а границы инкапсуляции Агрегата. +В Golang этот вариант выглядит чуть более привлекательным, хотя и менее OOP, но зато не контрастирует с FP принципами Value Object.</p> +<p>О таком же принципе этом писал Robert C. Martin:</p> +<blockquote> +<div><p>💬️ "Презентаторы являются разновидностью шаблона проектирования «Скромный объект» (Humble Object), помогающего выявлять и защищать архитектурные границы.</p> +<p>Presenters are a form of the Humble Object pattern, which helps us identify and protect architectural boundaries."</p> +<p>💬️ "Обычно через границы данные передаются в виде простых структур. +При желании можно использовать простейшие структуры или объекты передачи данных (Data Transfer Objects; DTO). +Данные можно также передавать в вызовы функций через аргументы. +Или упаковывать их в ассоциативные массивы или объекты. +Важно, чтобы через границы передавались простые, изолированные структуры данных. +Не нужно хитрить и передавать объекты сущностей или записи из базы данных. +Структуры данных не должны нарушать правило зависимостей.</p> +<p>Например, многие фреймворки для работы с базами данных возвращают ответы на запросы в удобном формате. +Их можно назвать «представлением записей». +Такие представления записей не должны передаваться через границы внутрь. +Это нарушает правило зависимостей, потому что заставляет внутренний круг знать что-то о внешнем круге. +Итак, при передаче через границу данные всегда должны принимать форму, наиболее удобную для внутреннего круга.</p> +<p>Typically the data that crosses the boundaries consists of <strong>simple data structures</strong>. +You can use <strong>basic structs or simple data transfer objects</strong> if you like. +Or the data can simply be arguments in function calls. +Or you can pack it into a hashmap, or construct it into an object. +The important thing is that isolated, <strong>simple data structures</strong> are passed across the boundaries. +We don't want to cheat and pass Entity objects or database rows. +We don't want the data structures to have any kind of dependency that violates the Dependency Rule.</p> +<p>For example, many database frameworks return a convenient data format in response to a query. +We might call this a "row structure." +We don't want to pass that row structure inward across a boundary. +Doing so would violate the Dependency Rule because it would force an inner circle to know something about an outer circle.</p> +<p>Thus, when we pass data across a boundary, it is always in the form that is most convenient for the inner circle."</p> +<p>💬️ "Он также переносит данные из базы данных Database в память сущностей Entities через интерфейс DataAccessInterface. +По завершении UseCaseInteractor забирает данные из сущностей Entities и конструирует из них другой простой Java-объект OutputData. +Затем объект OutputData передается через интерфейс OutputBoundary презентатору Presenter.</p> +<p>It also uses the DataAccessInterface to bring the data used by those Entities into memory from the Database. +Upon completion, the UseCaseInteractor gathers data from the Entities and constructs the OutputData as another <strong>plain old Java object</strong>. +The OutputData is then passed through the OutputBoundary interface to the Presenter."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin, перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Этот подход демонстрируется в <a class="reference external" href="https://github.com/EventStore/training-advanced-go/blob/9cc2b5a4f3484dc643757c88480c4b6e371149fd/domain/doctorday/day.go#L225">Golang DDD ES/CQRS Reference Application</a> от контрибьюторов EventStore.</p> +<p>И такой же подход демонстрирует Nick Tune в <a class="reference external" href="https://github.com/elbandit/PPPDDD/blob/4d9d864fa6d9dfc0bad323ae21e949be1808b460/21%20-%20Repositories/DDDPPP.Chap21.EFExample/DDDPPP.Chap21.EFExample.Application/Model/Auction/Auction.cs#L48">демонстрационном коде</a> к своей книге. +Причем, применяет он его даже <a class="reference external" href="https://github.com/elbandit/PPPDDD/blob/4d9d864fa6d9dfc0bad323ae21e949be1808b460/21%20-%20Repositories/DDDPPP.Chap21.EFExample/DDDPPP.Chap21.EFExample.Application/Model/Auction/Money.cs#L58">для Value Object</a>.</p> +<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kn">package</span><span class="w"> </span><span class="nx">grade_2</span><span class="w"/> + +<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="s">"time"</span><span class="w"/> +<span class="p">)</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Exportable</span><span class="p">[</span><span class="nx">T</span><span class="w"> </span><span class="kt">any</span><span class="p">]</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">Export</span><span class="p">()</span><span class="w"> </span><span class="nx">T</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">Artifact</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="w"/> -<span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="nx">ArtifactStatus</span><span class="w"/> -<span class="w"> </span><span class="nx">description</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="w"/> -<span class="w"> </span><span class="nx">competenceIds</span><span class="w"> </span><span class="p">[]</span><span class="nx">CompetenceId</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="p">)</span><span class="w"> </span><span class="nx">Export</span><span class="p">()</span><span class="w"> </span><span class="kt">uint</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">uint</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span><span class="w"/> <span class="p">}</span><span class="w"/> -<span class="kd">type</span><span class="w"> </span><span class="nx">Competence</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> -<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">CompetenceId</span><span class="w"/> -<span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="nx">CompetenceName</span><span class="w"/> -<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"> </span><span class="nx">ExportableUint</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">EndorserState</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">Id</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">AvailableEndorsementCount</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">PendingEndorsementCount</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">Version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">CreatedAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Endorser</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">grade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"/> +<span class="w"> </span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"/> +<span class="w"> </span><span class="nx">version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">Export</span><span class="p">()</span><span class="w"> </span><span class="nx">EndorserState</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">EndorserState</span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">id</span><span class="p">.</span><span class="nx">Export</span><span class="p">(),</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">grade</span><span class="p">.</span><span class="nx">Export</span><span class="p">(),</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="p">.</span><span class="nx">Export</span><span class="p">(),</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="p">.</span><span class="nx">Export</span><span class="p">(),</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="p">,</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">createdAt</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> <span class="p">}</span><span class="w"/> </pre></div> </div> -<p>Ссылка на полную модель:</p> +<p>Недостатком такого решения, который я успел обнаружить, является то, что клиент не имеет возможности контролировать структуру экспортируемого объекта, в отличии от варианта с интерфейсом. +Это затрудняет создание обобщенных классов, например, <a class="reference external" href="https://martinfowler.com/eaaCatalog/identityField.html">обобщенного композитного первичного ключа</a>. +В результате плодятся промежуточные структуры, которые затем нужно преобразовывать к нужному виду.</p> +<p>Знание о возвращаемом типе подталкивает к применению generics там, где этого несложно избежать.</p> +<p>Возвращаемая структура и ее типизация является избыточным знанием, которое может препятствовать обобщению (абстрагированию) клиента этого метода, например, препятствовать выделению абстрактного класса паттерна Repository. +Гораздо удобней в таком случае был бы массив/срез объектов с типом <a class="reference external" href="https://pkg.go.dev/database/sql/driver#Value">driver.Value</a>. +Это еще один аргумент в пользу первого варианта с отдельными сеттерами для каждого атрибута Агрегата.</p> +<p>Попробовав оба варианта, я остановился, все-таки, на первом, каноническом, даже несмотря на его многословность.</p> +</section> +</section> +Sun, 30 Jul 2023 00:00:00 Event Storming with Archihttps://dckms.github.io/system-architecture/emacsway/it/ddd/ddd-in-practice/event-storming/archi.html +<span id="emacsway-event-storming-archi"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p><a class="reference external" href="https://github.com/emacsway/grade/tree/main/grade/internal/domain">https://github.com/emacsway/grade/tree/main/grade/internal/domain</a></p></li> +<li><p><a class="reference internal" href="#event-storming-with-archi" id="id11">Event Storming with Archi</a></p> +<ul> +<li><p><a class="reference internal" href="#id2" id="id12">Обзор инструментов</a></p></li> +<li><p><a class="reference internal" href="#archi" id="id13">Archi</a></p></li> +<li><p><a class="reference internal" href="#archi-event-storming" id="id14">Достоинства Archi для Event Storming</a></p></li> +<li><p><a class="reference internal" href="#id3" id="id15">Недостатки</a></p> +<ul> +<li><p><a class="reference internal" href="#git" id="id16">Средствами Git</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id17">Штатный механизм слияния модели</a></p></li> +<li><p><a class="reference internal" href="#id5" id="id18">Избегание конфликтов</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#id6" id="id19">Установка</a></p></li> +<li><p><a class="reference internal" href="#id7" id="id20">Определение границ микросервисов</a></p></li> +<li><p><a class="reference internal" href="#id8" id="id21">Интеграция</a></p> +<ul> +<li><p><a class="reference internal" href="#id9" id="id22">Генерация документации</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#id10" id="id23">Стикеры</a></p></li> +<li><p><a class="reference internal" href="#c4-model" id="id24">C4 Model</a></p></li> +<li><p><a class="reference internal" href="#archimatetool-troubleshooting" id="id25">Archimatetool troubleshooting</a></p></li> +</ul> +</li> </ul> +</nav> +<section id="id2"> +<h2><a class="toc-backref" href="#id12" role="doc-backlink">Обзор инструментов</a></h2> +<p><a class="reference external" href="https://github.com/tmorin/plantuml-libs/blob/master/distribution/eventstorming/README.md">PlantUML</a> достаточно быстро исчерпал свои возможности и диаграммы стали нечитаемыми и неуправляемым. +Попытки выровнять диаграмму штатными средствами оказались безуспешниыми. +На разных серверах диаграмма отображалась по-разному.</p> +<p>Сервис Miro вынуждает архитектурно-значимую информацию покидать периметр безопасности, образует лицензионную зависимость и находится под давлением геополитических факторов. +Как и PlantUML, не позволяет находить границы микросервисов ввиду <a class="reference external" href="https://c4model.com/#Modelling">отсутствия в нем модели</a>.</p> +<p>Неплохие надежды подает <a class="reference external" href="https://domorobo.to/">domorobo.to</a>, но он пока еще сыроват.</p> </section> +<section id="archi"> +<h2><a class="toc-backref" href="#id13" role="doc-backlink">Archi</a></h2> +<p>В процессе поиска внимание привлекла внимание диаграмма на "Figure 13: Event Storming Model" of "Agile Architecture Modeling Using the ArchiMate® Language" (см. <a class="reference external" href="https://publications.opengroup.org/g20e">здесь</a>, <a class="reference external" href="https://nicea.nic.in/sites/default/files/Agile_Architecture_Modelling_Using_Archimate.pdf">здесь</a> или <a class="reference external" href="https://nicea.nic.in/download-files.php?nid=247">здесь</a>).</p> +<p><a class="reference external" href="https://community.opengroup.org/archimate-user-community/home/-/issues/8">Model used by Jean-Baptiste Sarrodie for presentation "Enterprise Architecture Modelling with ArchiMate in an Agile at Scale Programme"</a></p> +<p>Попробовал сделать Event Storming в Archi, и обнаружил, что он делается с такой же легкостью, как и в Miro. +Разве что для публикации своих изменений другим участникам нужно сделать 5 кликов мышкой. +Технически, это можно автоматизировать по регулярному расписанию, используя <a class="reference external" href="https://www.archimatetool.com/plugins/">jArchi</a>. +А вот изменения других участников уже и так подтягиваются по настраиваемому регулярному расписанию фоновым процессом.</p> +<p>Нотации (т.е. цвета) Event Storming практически идентичны нотациям "<a class="reference external" href="https://pubs.opengroup.org/architecture/archimate31-doc/apdxc.html#_Toc10045506">C.1.10 Business Process Cooperation Viewpoint</a>".</p> </section> -<section id="missing-chapter"> -<h2><a class="toc-backref" href="#id31" role="doc-backlink">Missing chapter</a></h2> -<p>Проектом предусматривается поддержка <a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/guide/multitenant/overview">Multitenancy</a>. -В свете этого, возникает потребность в гибком конфигурировании количества уровней классности для каждого <code class="docutils literal notranslate"><span class="pre">Tenant</span></code>, а также количества требуемых рекомендаций для достижения каждого уровня. -По этой причине, конструктор экземпляра Объекта-значения <code class="docutils literal notranslate"><span class="pre">Grade</span></code> должен создаваться Агрегатом <code class="docutils literal notranslate"><span class="pre">Tenant</span></code>. -Соответственно, фабричные методы Агрегатов <code class="docutils literal notranslate"><span class="pre">Endorser</span></code> и <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> должны переехать в Агрегат <code class="docutils literal notranslate"><span class="pre">Tenant</span></code>, чтобы иметь возможность принимать сконфигурированный экземпляр Объекта-значения <code class="docutils literal notranslate"><span class="pre">Grade</span></code>.</p> -<p>По мере роста гибкости бизнес-правил можно рассмотреть вариант применения "<a class="reference external" href="https://martinfowler.com/bliki/RulesEngine.html">Rules Engine</a>" (aka "<a class="reference external" href="https://martinfowler.com/dslCatalog/productionRule.html">Production Rule System</a>"), например, в виде "<a class="reference external" href="https://github.com/hyperjumptech/grule-rule-engine">Grule-Rule-Engine</a>" - Rule engine implementation in Golang.</p> +<section id="archi-event-storming"> +<h2><a class="toc-backref" href="#id14" role="doc-backlink">Достоинства Archi для Event Storming</a></h2> +<ol class="arabic simple"> +<li><p>On-Premise. Архитектурно-значимая информация не покидает закрытый периметр безопасности.</p></li> +<li><p>Open Source under MIT License</p></li> +<li><p>Наличие модели позволяет:</p> +<ol class="arabic simple"> +<li><p>Определять границы не только Ограниченных Контекстов, но и Микросервисов. Это является следствием наличия модели и возможности классифицировать связи, выделять из них связи, образующие Сoupling &amp; Сohesion, и с математической точностью определять наилучшую форму границ микросервисов.</p></li> +<li><p>Рассматривать любой элемент диаграммы в различных представлениях, например, мгновенно перейти с Context Map на Event Storming. См. вкладку "Properties" выбранного элемента, секция "Analisis".</p></li> +<li><p>Отслеживать трассировку как до выбранного элемента, так и после него. См. окно Window-Navigator и две кнопки: "Show target relations" и "Show source relations".</p></li> +<li><p>При разбиении большой диаграммы на части по некому признаку (например, по базовым сценариям использования), изменение в одной диаграмме (например, изменение целевого элемента связи) будет автоматически отражено на всех остальных диаграммах, что удешевляет сопровождение таких диаграмм. А при добавлении нового элемента из модели в диаграмму, вместе с ним добавляются и все существующие в модели его связи к уже добавленным в диаграмму элементам.</p></li> +</ol> +</li> +<li><p>Использование Git открывает следующие возможности:</p> +<ol class="arabic simple"> +<li><p>Историрование. Возможность восстановления одного из предыдущих состояний. Журналирование изменений.</p></li> +<li><p>Версионирование и ответвления - параллельная разработка различных версий решения.</p></li> +<li><p>Коллективная разработка. Доступ к информации задается обычной конфигурацией git-сервера (обычно средствами GitHub и GitLab).</p></li> +</ol> +</li> +<li><p>Использование <a class="reference external" href="https://pubs.opengroup.org/architecture/archimate31-doc/chap06.html#_Toc10045334">Motivation Elements</a> (Stakeholder, Driver, Assessment, Goal, Outcome, Principle, Requirement, and Constraint) позволяет осуществлять визуализацию факторов влияния на решение, а также фиксацию трассировки требований. +Возможность воплощения принципов <a class="reference external" href="https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=6470589">Twin Peak Model</a>. +В процессе проработки одной из альтернатив, обнаруживаются ее ограничения и новые драйверы, которые влияют на требования. +В визуальном виде аналитическая информация воспринимается намного легче, чем обычная свалка требований в PBI.</p></li> +<li><p>Богатое интеграционное API позволяет использовать модель для автоматизированной её сверки с реализацией или для генерации кода.</p></li> +<li><p>В <a class="reference external" href="https://www.archimatetool.com/blog/2020/04/18/c4-model-architecture-viewpoint-and-archi-4-7/">Archi можно также делать C4 Model</a>, используя единую модель и для C4 Model, и для Event Storming.</p></li> +<li><p><a class="reference external" href="https://community.opengroup.org/archimate-user-community/home/-/issues/8">В Archi можно сделать Context Map</a>, используя единую модель с Event Storming.</p></li> +</ol> </section> -Sun, 11 Jun 2023 00:00:00 Разрешение конфликтов на почве недостатка знанийhttps://dckms.github.io/system-architecture/emacsway/soft-skills/knowledge-vs-opinion.html<span class="target" id="index-0"/><section id="emacsway-knowledge-vs-opinion-in-psychology"> -<span id="id1"/> +<section id="id3"> +<h2><a class="toc-backref" href="#id15" role="doc-backlink">Недостатки</a></h2> +<p>Резольв конфликта слияния через GUI для каждой отдельной диаграммы возможен только путем выбора одной из двух версии целиком - либо своей, либо сливаемой. +При просмотре версий диаграммы их различия никак визуально не выделяются и не подсвечиваются.</p> +<p>Сама модель сохраняется в файл <code class="docutils literal notranslate"><span class="pre">.git/temp.archimate</span></code>. +Преобразуется она в файлы Git репозитория только в момент коммита. +Этот момент нужно учитывать, т.к. изменения модели в Archi не отражаются мгновенно в файлах Git репозитория и, наоборот, изменения в файлах Git репозитория не отражаются мгновенно в модели Archi.</p> +<p>Мне известны два способа слить диаграммы в случае конфликта без утраты изменений обоих её версий.</p> +<section id="git"> +<h3><a class="toc-backref" href="#id16" role="doc-backlink">Средствами Git</a></h3> +<p>Резольва конфликта слияния средствами Git <a class="reference external" href="https://github.com/archi-contribs/archi-grafico-plugin/wiki/Merge-two-(or-more)-models">на уровне текстовых файлов</a>" (см. описание <a class="reference external" href="https://github.com/archi-contribs/archi-grafico-plugin/wiki/GRAFICO-explained">GRAFICO format</a>). +Не самый простой, но самый действенный вариант. +Впрочем, к нему быстро привыкаешь.</p> +<p>Чаще всего конфликты возникают в файлах диаграмм (Views), и их резольв усложняется тем, что в них присутствуют только идентификаторы конфликтующих элементоа. +И эти идентификаторы не сообщают никакой информации о своих элементах. +Чтобы определить смысл элемента по его идентификатору, можно предварительно (т.к. в процессе слияния элемент может быть уже удален из модели) заэкспортировать модель в *.CSV файлы. +Как вариант, можно также сохранить модель в *.archimate файл, если модель относительно небольшая, и затем использовать поиск по файлу. +Можно создать копию файловой структуры Git репозитория перед слиянием и грепать по её файлам.</p> +</section> +<section id="id4"> +<h3><a class="toc-backref" href="#id17" role="doc-backlink">Штатный механизм слияния модели</a></h3> +<p>Сохраняем модель одного бранча в *.archimate файл, а затем импортируем её в выбранную модель другого бранча. +Этот вариант дает меньше контроля над процессом слияния, но и уменьшает вероятность допущения ошибки.</p> +</section> +<section id="id5"> +<h3><a class="toc-backref" href="#id18" role="doc-backlink">Избегание конфликтов</a></h3> +<p>Резольв конфликта в Archi нетривиальный, и лучше его избегать. +На практике обычно кто-то один управляет доской в один момент времени, и, в случае необходимости, передает управление другому участнику.</p> +<p>Частые интеграции и блокировки организационными мерами позволяют снизить вероятность возникновения конфликта.</p> +</section> +</section> +<section id="id6"> +<h2><a class="toc-backref" href="#id19" role="doc-backlink">Установка</a></h2> +<p>Дистрибутив: <a class="reference external" href="https://www.archimatetool.com/download/">https://www.archimatetool.com/download/</a></p> +<p><a class="reference external" href="https://www.archimatetool.com/downloads/Archi%20User%20Guide.pdf">Документация</a> Archi.</p> +<p>Плагин коллективной разработки <a class="reference external" href="https://www.archimatetool.com/plugins/#coArchi">coArchi</a> (<a class="reference external" href="https://github.com/archimatetool/archi-modelrepository-plugin">Source Code</a>). <a class="reference external" href="https://github.com/archimatetool/archi-modelrepository-plugin/wiki">Документация</a> к плагину.</p> +<p>Актуальное <a class="reference external" href="https://github.com/archimatetool/archi-modelrepository-plugin/wiki/SSH-Authentication">руководство по генерации RSA-ключей</a>.</p> +</section> +<section id="id7"> +<h2><a class="toc-backref" href="#id20" role="doc-backlink">Определение границ микросервисов</a></h2> +<p>Изначально мы допускаем, что один микросервис == один агрегат. +Находим "болтливые" микросервисы. +Пробуем объединить болтливые микросервисы в общий микросервис и сравниваем, как изменились совокупный Coupling (внешние связи микросервиса(ов)) &amp; Cohesion (к-т реиспользования агрегатов внутри одного микросервиса). +Например, если у нас совокупный Coupling упал на 5 единиц, при этом Cohesion возрос, то объединение микросервисов оправдано.</p> +<p>Для этого, в каждом микросервисе выделяем отдельную директорию _coupling и _cohesion. +А также создаем отдельную директорию для каждого агрегата и связанной с ним логикой (той самой, которая будет вынесена из текущего микросервиса вместе с агрегатом, если такое понадобится, например, все представления (ReadModels) агрегата).</p> +<p>Дополнительная информация:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="http://www.sdml.cs.kent.edu/library/Allen99.pdf">Measuring Coupling and Cohesion: An Information Theory Approach</a>" by Edward B. Allen, Taghi M. Khoshgoftaar, Florida, Atlantic University Boca Raton, Florida USA</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/model/domain-analysis">Using domain analysis to model microservices</a>"</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/microservices/model/microservice-boundaries">Identifying microservice boundaries</a>"</p></li> +<li><p>"<a class="reference external" href="https://vladikk.com/2018/01/21/bounded-contexts-vs-microservices/">Bounded Contexts are NOT Microservices</a>" by Vladik Khononov</p></li> +<li><p>"<a class="reference external" href="https://vladikk.com/2018/02/28/microservices/">Tackling Complexity in Microservices</a>" by Vladik Khononov</p></li> +<li><p>"Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy" 1st Edition by Vlad Khononov</p></li> +<li><p>"Balancing Coupling in Software Design: Successful Software Architecture in General and Distributed Systems" by Vladislav Khononov</p></li> +</ul> +</section> +<section id="id8"> +<h2><a class="toc-backref" href="#id21" role="doc-backlink">Интеграция</a></h2> +<p>Из коробки Archi уже поддерживает экспорт модели в *.CSV файл.</p> +<p>Существует ряд плагинов, которые облегчают интеграцию:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.archimatetool.com/plugins/#exArchi">https://www.archimatetool.com/plugins/#exArchi</a></p></li> +<li><p><a class="reference external" href="https://github.com/archi-contribs/script-plugin">https://github.com/archi-contribs/script-plugin</a></p></li> +<li><p><a class="reference external" href="https://github.com/archi-contribs/database-plugin">https://github.com/archi-contribs/database-plugin</a></p></li> +</ul> +<p>С помощью этих плагинов Archi позволяет выгружать свою модель в RDBMS, в Excel, а также позволяет обращаться к модели через консольный интерфейс, используя SQL-подобный синтаксис.</p> +<p>С помощью этих плагинов очень легко генерировать PBI, Acceptance Criteria, BDD-specification или тестовые кейсы из <a class="reference external" href="https://pubs.opengroup.org/architecture/archimate31-doc/chap06.html#_Toc10045345">требований</a> модели, а из диаграммы Event Storming и C4 Model - генерировать код микросервисов или автоматизировать сверку модели с кодом.</p> +<p>Archimatetool использует Grafico format файлов:</p> +<blockquote> +<div><p>📝 "GRAFICO stands for "Git Friendly Archi File Collection" and is a way to persist an ArchiMate model in a bunch of XML files (one file per ArchiMate element or view)."</p> +<p class="attribution">—<a class="reference external" href="https://github.com/archi-contribs/archi-grafico-plugin/wiki/GRAFICO-explained">https://github.com/archi-contribs/archi-grafico-plugin/wiki/GRAFICO-explained</a></p> +</div></blockquote> +<section id="id9"> +<h3><a class="toc-backref" href="#id22" role="doc-backlink">Генерация документации</a></h3> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://habr.com/ru/post/583314/">Автоматизируем работу с ArchiMate в CI пайплайнах</a>" / Maxim Levchenko</p></li> +<li><p><a class="reference external" href="https://hub.docker.com/r/woozymasta/archimate-ci-image">Docker container</a> и <a class="reference external" href="https://github.com/marketplace/actions/deploy-archi-report">GH Action</a> для публикации Archimate модели на <a class="reference external" href="https://woozymasta.github.io/archimate-ci-image-example/?view=6875">GitHub</a>/<a class="reference external" href="https://woozymasta.gitlab.io/archimate-ci-image-example/?view=6213">GitLab</a> Pages. <a class="reference external" href="https://github.com/WoozyMasta/archimate-ci-image">Source Code</a>.</p></li> +<li><p><a class="reference external" href="https://github.com/abes-esr/archi-htmlreport-docker">archi-htmlreport-docker</a> (<a class="reference external" href="https://github.com/abes-esr/archi-model-example">example</a>)</p></li> +<li><p><a class="reference external" href="https://hub.docker.com/search?q=ArchiMate">Others...</a></p></li> +</ul> +</section> +</section> +<section id="id10"> +<h2><a class="toc-backref" href="#id23" role="doc-backlink">Стикеры</a></h2> +<p>В Archi есть <a class="reference external" href="https://devlog.archimatetool.com/2010/11/04/sketch/">доска со стикерами</a> (см. New Sketch View на <a class="reference external" href="https://www.archimatetool.com/downloads/Archi%20User%20Guide.pdf">стр. 110 документации</a>).</p> +<p>Можно делать Event Storming обычными стикерами, а не только используя "<a class="reference external" href="https://t.me/emacsway_log/253">C.1.10 Business Process Cooperation Viewpoint</a>".</p> +<p>Можно проводить сеанс Example Mapping и автоматизировать генерацию BDD-specification или тестовых кейсов.</p> +</section> +<section id="c4-model"> +<h2><a class="toc-backref" href="#id24" role="doc-backlink">C4 Model</a></h2> +<p>Event Storming гармонично сочетается с C4 Model, о чем говорил Сергей Баранов в своем <a class="reference external" href="https://habr.com/ru/company/oleg-bunin/blog/537862/">докладе</a>. +И вот тут еще одно интересное открытие - Simon Brown собственноручно <a class="reference external" href="https://c4model.com/">ссылается</a> на статью Jean-Baptiste Sarrodie о том, <a class="reference external" href="https://www.archimatetool.com/blog/2020/04/18/c4-model-architecture-viewpoint-and-archi-4-7/">как делать C4 Model в Archi</a>.</p> +<p>Там же Simon Brown ссылается на Guide <a class="reference external" href="https://publications.opengroup.org/g20e">Agile Architecture Modeling Using the ArchiMate® Language</a> на сайте OMG о том, как использовать C4 Model и Event Storming в Open Agile Architecture, используя Archi. +Jean-Baptiste Sarrodie собственноручно выложил <a class="reference external" href="https://community.opengroup.org/archimate-user-community/home/-/issues/8">демонстрационную модель C4 Model и Event Storming в Archi</a>.</p> +</section> +<section id="archimatetool-troubleshooting"> +<h2><a class="toc-backref" href="#id25" role="doc-backlink">Archimatetool troubleshooting</a></h2> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://github.com/archimatetool/archi/blob/master/com.archimatetool.editor/src/com/archimatetool/editor/model/messages.properties">Список ошибок</a>"</p></li> +<li><p>Расположение незакоммиченной, но сохраненной модели: <code class="docutils literal notranslate"><span class="pre">.git/temp.archimate</span></code>.</p></li> +<li><p>"<a class="reference external" href="https://github.com/archimatetool/archi/wiki/Archi-4.7-%28or-superior%29-can%27t-save-a-model-or-%28if-using-coArchi%29-can%27t-import%2C-refresh-or-publish-a-model-but-instead-gives-%22Error-in-model%22">Archi 4.7 (or superior) can't save a model or (if using coArchi) can't import, refresh or publish a model but instead gives "Error in model"</a>"</p></li> +</ul> +</section> +Tue, 04 Jul 2023 00:00:00 Repository and Causal Consistencyhttps://dckms.github.io/system-architecture/emacsway/it/ddd/tactical-design/repository/causal-consistency.html +<span id="emacsway-repository-in-causal-consistency"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#repository-and-causal-consistency" id="id6">Repository and Causal Consistency</a></p> +<ul> +<li><p><a class="reference internal" href="#id2" id="id7">Контекст</a></p></li> +<li><p><a class="reference internal" href="#id3" id="id8">Варианты решений</a></p> +<ul> +<li><p><a class="reference internal" href="#bounded-context" id="id9">Версионирование состояния Bounded Context</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id10">Отдельная версия на Событие</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#id5" id="id11">Вывод</a></p></li> +</ul> +</li> +</ul> +</nav> +<section id="id2"> +<h2><a class="toc-backref" href="#id7" role="doc-backlink">Контекст</a></h2> +<p>Версия агрегата часто используется для организации "<a class="reference external" href="https://martinfowler.com/eaaCatalog/optimisticOfflineLock.html">Optimistic Offline Lock</a>". +С этой целью она обычно инкрементируется однократно на одну транзакцию, даже если при этом было создано несколько Domain Events (при их <strong>in-process обработке</strong>).</p> +<p>Иначе дело обстоит в Event Sourced Aggregate, где версия инкрементируется на каждое Доменное Событие, поскольку она определяет положение этого События в потоке/журнале Событий. +Взаимосвязанные События для обеспечения атомарности в таком случае помечаются идентификатором запроса в виде CorrelationId.</p> +<p>Проблема заключается в том, что если мы хотим сделать Domain Events публичными и отправить их в шину, либо сформировать на их основе Integration Events, то существует риск нарушения очередности их доставки.</p> +<p>Более подробно эта тема раскрывается в заметке "<a class="reference internal" href="../../../integration/asynchronous/message-ordering-in-competing-consumers.html#emacsway-message-ordering"><span class="std std-ref">О гонке сообщений в условиях конкурирующих подписчиков</span></a>".</p> +<p>Причин нарушения очередности доставки может быть несколько. +Например, <a class="reference external" href="https://learn.microsoft.com/en-us/azure/architecture/patterns/competing-consumers">Конкурирующие Подписчики</a>. +В таком случае проблема решается обычно партиционированием каналов шины, используя идентификатор агрегата для вычисления партиции, таким образом направляя все сообщения одного агрегата к единственному обработчику, устраняя петлю в топологии маршрута сообщений, а значит, устраняя условия для возникновения гонки сообщений.</p> +<p>Однако, не все шины поддерживают партиционирование каналов, либо эта поддержка оставляет желать лучшего. +Кроме того, в интервью "<a class="reference external" href="https://www.infoq.com/articles/modeling-uncertainty-reactive-ddd/">Modeling Uncertainty with Reactive DDD</a>" by Vaughn Vernon reviewed by Thomas Betts, Vaughn Vernon утверждает, что это не спасает.</p> +<p>В книге "Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" Vaughn Vernon объясняет почему: петля может быть образована не только конкурирующими подписчиками, но и самой топологией маршрутов сообщений. +Грубо говоря, если для одного сообщения у нас маршрут A-&gt;C а для другого A-B-&gt;C, то гонка уже не исключена.</p> +<p>В этой же книге Vaughn Vernon отсылает за решением к статьям:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">Don't Settle for Eventual Consistency. Stronger properties for low-latency geo-replicated storage.</a>" (<a class="reference external" href="https://dl.acm.org/ft_gateway.cfm?id=2610533&amp;ftid=1449165&amp;dwn=1">pdf</a>) by Wyatt Lloyd, Facebook; Michael J. Freedman, Princeton University; Michael Kaminsky, Intel Labs; David G. Andersen, Carnegie Mellon University</p></li> +<li><p>"<a class="reference external" href="http://www.bailis.org/papers/bolton-sigmod2013.pdf">Bolt-on Causal Consistency</a>" by Peter Bailis, Ali Ghodsi, Joseph M. Hellerstein†, Ion Stoica, UC Berkeley KTH/Royal Institute of Technology</p></li> +</ul> +<p>Рассмотрим классический пример. Глава родительского комитета школьного класса удалил классного руководителя из группы рассылки (E1), разослал всем оставшимся сообщение о сборе денег на подарок классному руководителю (E2), и вернул классного руководителя назад (E3).</p> +<p>Вот теперь давайте представим, что произойдет, если событие E1 где-то задержалось в шине, и было обработано после E2.</p> +<p>Решение сводится к организации <a class="reference external" href="https://jepsen.io/consistency/models/causal">Causal Consistency</a> посредством векторных часов, используя версию агрегата в качестве их значения. +Каждое сообщение снабжается списком своих Causal Dependencies.</p> +<p>И здесь обнажается проблема, т.к. при инкрементировании версии агрегата единожды на транзакцию, возникает риск образования более одного публичного Доменного События с одной и той же версией Агрегата. +А это означает, что версию Агрегата не получится использовать для восстановления очередности Событий.</p> +</section> +<section id="id3"> +<h2><a class="toc-backref" href="#id8" role="doc-backlink">Варианты решений</a></h2> +<section id="bounded-context"> +<h3><a class="toc-backref" href="#id9" role="doc-backlink">Версионирование состояния Bounded Context</a></h3> +<p>Для указания последовательности События можно использовать порядковый номер механизма доставки, например, автоинкрементальный первичный ключ таблицы Outbox внутри Bounded Context.</p> +<p>Недостатком такого решения является существенное понижение уровня параллелизма вплоть до Sequential Consistency.</p> +<p>Другим недостатком такого решения является трудоемкость миграции <a class="reference internal" href="../domain-model/domain-events/domain-events-in-ddd.html#emacsway-domain-event"><span class="std std-ref">с in-process обработки Доменных Событий на out-of-process</span></a>.</p> +</section> +<section id="id4"> +<h3><a class="toc-backref" href="#id10" role="doc-backlink">Отдельная версия на Событие</a></h3> +<p>Поскольку Доменное Событие является фактом изменения состояния Агрегата, логично предположить, что образование каждого нового События должно инкрементировать версию Агрегата, как это общепринято в Event Sourced Agregate.</p> +<p>Несущественным недостатком такого решения является усложнение реализации оптимистической блокировки, поскольку инкрементация теперь происходит вне SQL-запроса. +Критерий выборки обновляемой строки теперь будет вычисляться как математическая разница версии Агрегата и количества Доменных Событий в нем.</p> +<p>Несколько сложнее дело обстоит с объединением (пакетированием) SQL-запросов, сформированных не из состояния агрегата, а из доменных событий, т.к. версия агрегата сдвигается с каждым запросом. +Но этот вопрос тоже несущественный, и легко решается вынесением оптимистической блокировки в отдельный (либо в объединенный, при отсутствии изменения вложенных сущностей) SQL-запрос.</p> +<p>К достоинствам такого решения можно отнести простоту миграции <a class="reference internal" href="../domain-model/domain-events/domain-events-in-ddd.html#emacsway-domain-event"><span class="std std-ref">с in-process обработки Доменных Событий на out-of-process</span></a>, поскольку интерфейс событий остается неизменным.</p> +</section> +</section> +<section id="id5"> +<h2><a class="toc-backref" href="#id11" role="doc-backlink">Вывод</a></h2> +<p>Вариант с инкрементацией версии Агрегата на каждое Доменное Событие выглядит более приемлемым решением.</p> +</section> +Tue, 04 Jul 2023 00:00:00 Shotgun Surgeryhttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/shotgun-surgery.html +<span id="index-0"/> +<p>Может показаться, что используя Raw-SQL мы обретаем классифицированный Code Smell, известный как Shotgun Surgery (Разлет Дроби), ибо добавление одного поля в Сущность требует правки многих файлов. +Есть два способа решить эту проблему (и снизить Coupling), о которых писал Martin Fowler в главе "Metadata Mapping" книги "Patterns of Enterprise Application Architecture": "reflective program" и "code generation", причем, сам он лично предпочитает второй вариант:</p> +<blockquote> +<div><p>Generated code is more explicit so you can see what's going on in the debugger; +as a result I usually prefer generation to reflection, +and I think it's usually easier for less sophisticated developers +(which I guess makes me unsophisticated).</p> +<p class="attribution">—"Patterns of Enterprise Application Architecture" by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford</p> +</div></blockquote> +<p>Подавляющее большинство ORM использует "reflective program", в то время, как в Golang-сообществе традиционно широко применяется в практике "code generation".</p> +<p>В данном проекте, на определенном этапе развития, появится инструмент кодогенерации по образу <a class="reference external" href="https://github.com/kyleconroy/sqlc">sqlc</a>.</p> +Mon, 03 Jul 2023 00:00:00 Domain Events in DDDhttps://dckms.github.io/system-architecture/emacsway/it/ddd/tactical-design/domain-model/domain-events/domain-events-in-ddd.html +<span id="emacsway-domain-event"/> <p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id2"> +<p>Существует множество спорных точек зрения среди практиков DDD по поводу реализации Domain Events. +Лучший способ понять суть вещей - это обратиться к первоисточнику, чтобы понять его мотивы и те проблемы, решение которым он стремился найти.</p> +<nav class="contents" id="id1"> <p class="topic-title">Содержание</p> <ul class="simple"> -<li><p><a class="reference internal" href="#emacsway-knowledge-vs-opinion-in-psychology" id="id10">Разрешение конфликтов на почве недостатка знаний</a></p> +<li><p><a class="reference internal" href="#domain-events-in-ddd" id="id116">Domain Events in DDD</a></p> <ul> -<li><p><a class="reference internal" href="#id3" id="id11">Теория - это обобщенная практика</a></p></li> -<li><p><a class="reference internal" href="#emacsway-opinion-in-psychology" id="id12">О мнениях</a></p></li> -<li><p><a class="reference internal" href="#emacsway-knowledge-in-psychology" id="id13">О знаниях</a></p></li> -<li><p><a class="reference internal" href="#id6" id="id14">Решение</a></p></li> -<li><p><a class="reference internal" href="#emacsway-theory" id="id15">О роли теории</a></p></li> -<li><p><a class="reference internal" href="#id8" id="id16">Рождается ли в споре истина?</a></p></li> +<li><p><a class="reference internal" href="#domain-event" id="id117">Назначение Domain Event</a></p></li> +<li><p><a class="reference internal" href="#eventual-consistency-vs-strong-transactional-consistency" id="id118">Eventual Consistency vs Strong (Transactional) Consistency</a></p> +<ul> +<li><p><a class="reference internal" href="#eventual-consistency" id="id119">Eventual Consistency - это следствие, а не причина</a></p></li> +<li><p><a class="reference internal" href="#id15" id="id120">Eventual Consistency предпочтительней</a></p></li> +<li><p><a class="reference internal" href="#id18" id="id121">Все решают бизнес-правила</a></p></li> +<li><p><a class="reference internal" href="#ask-whose-job-it-is" id="id122">Принцип "Ask Whose Job It Is"</a></p></li> +<li><p><a class="reference internal" href="#strong-consistency" id="id123">Strong Consistency - новичкам</a></p></li> +<li><p><a class="reference internal" href="#performance" id="id124">Интересы performance</a></p></li> +<li><p><a class="reference internal" href="#id25" id="id125">Обратная совместимость формата объектов событий</a></p></li> +<li><p><a class="reference internal" href="#net-microservices" id="id126">Рекомендации от ".NET Microservices"</a></p></li> +<li><p><a class="reference internal" href="#scott-millett-nick-tune" id="id127">Мнение Scott Millett и Nick Tune</a></p></li> +<li><p><a class="reference internal" href="#jimmy-bogard" id="id128">Мнение Jimmy Bogard</a></p></li> +<li><p><a class="reference internal" href="#kamil-grzybek" id="id129">Мнение Kamil Grzybek</a></p></li> +<li><p><a class="reference internal" href="#udi-dahan" id="id130">Мнение Udi Dahan</a></p></li> +<li><p><a class="reference internal" href="#cesar-de-la-torre" id="id131">Мнение Cesar De la Torre</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#in-process-vs-out-of-process" id="id132">In-process vs out-of-process</a></p></li> +<li><p><a class="reference internal" href="#internal-vs-external" id="id133">Internal vs External</a></p></li> +<li><p><a class="reference internal" href="#one-phase-vs-two-phase" id="id134">One-phase vs Two-phase</a></p></li> +<li><p><a class="reference internal" href="#id70" id="id135">Кто может издавать Domain Event?</a></p></li> +<li><p><a class="reference internal" href="#id73" id="id136">Может ли Domain Event отменить свою причину?</a></p></li> +<li><p><a class="reference internal" href="#id79" id="id137">Решение - это баланс стоимости и обретаемой выгоды</a></p> +<ul> +<li><p><a class="reference internal" href="#cqrs" id="id138">Может ли CQRS-команда возвращать результат?</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#atomicity-and-resiliency-of-integration-events" id="id139">Atomicity and Resiliency of Integration Events</a></p></li> +<li><p><a class="reference internal" href="#integration-events" id="id140">Проблема сохранения очередности Integration Events</a></p></li> +<li><p><a class="reference internal" href="#id104" id="id141">Где создавать Domain Event об удалении объекта?</a></p></li> +<li><p><a class="reference internal" href="#id108" id="id142">Почему важно читать оригиналы вместо переводов</a></p></li> +<li><p><a class="reference internal" href="#id111" id="id143">Послесловие</a></p></li> </ul> </li> </ul> </nav> -<p>Нередко наблюдаю на практике возникновение конфликтов в коллективе практически на пустом месте, по причине принуждения коллектива к принятию решения в условиях недостаточной информированности.</p> -<section id="id3"> -<h2><a class="toc-backref" href="#id11" role="doc-backlink">Теория - это обобщенная практика</a></h2> -<p>Основное отличие <strong>знания</strong> от <strong>мнения</strong> заключается <em>в широте охвата опыта, которым оно было произведено</em>. -Грубо говоря, <strong>теория - это обобщенная практика</strong> (в рассматриваемом нами контексте):</p> +<p>Как сказал Bertrand Meyer,</p> <blockquote> -<div><p>📝 "<strong>Теория</strong> — (1) система научных идей и принципов, <strong>обобщающих практический опыт</strong>, отражающих объективные природные закономерности и положения, которые образуют науку (см.) или раздел какой-либо науки, а также совокупность правил в области какого-либо знания млн. мастерства (Т. вождения или полётов);"</p> -<p class="attribution">—"<a class="reference external" href="https://polytechnic_dictionary.academic.ru/2647/%D0%A2%D0%95%D0%9E%D0%A0%D0%98%D0%AF">Большая политехническая энциклопедия.</a>" - М.: Мир и образование. Рязанцев В. Д.. 2011.</p> +<div><p>The zealots of an idea are often more extreme than its creators - the phase "more royalist than the King" captures that phenomenon - and you will find that foundational agile texts, such as those by Beck, Larman or Cockburn, occupy a higher plane of discourse; in particular they avoid below-the-belt hits at other approaches.</p> +<p>- "Agile!: The Good, the Hype and the Ugly" by Bertrand Meyer</p> +</div></blockquote> +<p>Поэтому, я буду начинать всегда с первоисточников, т.е. с Eric Evans, Bertrand Meyer и др. +Но также буду делать обзор мнений их ключевых последователей - Vaughn Vernon, Jimmy Bogard, Greg Young, Udi Dahan, Kamil Grzybek, Scott Millett, Nick Tune, коллектив авторов руководств Microsoft по архитектуре и др. +К счастью, при внимательном рассмотрении, противоречий между ними практически нет.</p> +<section id="domain-event"> +<h2><a class="toc-backref" href="#id117" role="doc-backlink">Назначение Domain Event</a></h2> +<blockquote> +<div><p>Something happened that domain experts care about. +Model information about activity in the domain as a series of discrete events. Represent each event as a domain object. +&lt;...&gt; +A domain event is a full-fledged part of the domain model, a representation of something that happened in the domain.</p> +<p>- "Domain-Driven Design Reference" <a class="footnote-reference brackets" href="#fndddr" id="id2" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Domain Events"</p> +</div></blockquote> +</section> +<section id="eventual-consistency-vs-strong-transactional-consistency"> +<h2><a class="toc-backref" href="#id118" role="doc-backlink">Eventual Consistency vs Strong (Transactional) Consistency</a></h2> +<section id="eventual-consistency"> +<h3><a class="toc-backref" href="#id119" role="doc-backlink">Eventual Consistency - это следствие, а не причина</a></h3> +<blockquote> +<div><p>A distinct, though related set of issues arises in distributed systems. +The state of a distributed system cannot be kept completely consistent at all times. +We keep the aggregates internally consistent at all times, while making other changes asynchronously. +As changes propagate across nodes of a network, it can be difficult to resolve multiple updates arriving out of order or from distinct sources.</p> +<p>- "Domain-Driven Design Reference" <a class="footnote-reference brackets" href="#fndddr" id="id3" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Domain Events"</p> +</div></blockquote> +<blockquote> +<div><p>It is difficult to guarantee the consistency of changes to objects in a model with complex associations. +Objects are supposed to maintain their own internal consistent state, but they can be blindsided by changes in other objects that are conceptually constituent parts. +Cautious database locking schemes cause multiple users to interfere pointlessly with each other and can make a system unusable. +Similar issues arise when distributing objects among multiple servers, or designing asynchronous transactions.</p> +<p>&lt;...&gt;</p> +<p>Use the same aggregate boundaries to govern transactions and distribution. +Within an aggregate boundary, apply consistency rules synchronously. Across boundaries, handle updates asynchronously. +Keep an aggregate together on one server. +Allow different aggregates to be distributed among nodes.</p> +<p>- "Domain-Driven Design Reference" <a class="footnote-reference brackets" href="#fndddr" id="id4" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Aggregates"</p> +</div></blockquote> +<p>Здесь мы видим, что краеугольной причиной Eventual Consistency является распределенное хранение данных. +Это значит, что, в силу <a class="reference external" href="http://ksat.me/a-plain-english-introduction-to-cap-theorem">CAP-теоремы</a> (<a class="reference external" href="https://habr.com/ru/post/130577/">перевод на Русский</a>), становится невозможно достигнуть одновременно Consistency и Availability при Partition Tolerance. +Это та самая причина, по которой концепция Агрегата лежит в основе практически любого распределенного NoSQL хранилища - агрегат просто хранится целиком на одном узле, поэтому, он всегда и доступен, и согласован одновременно.</p> +<p>Представьте на минутку, что узлы автомобиля хранятся на разных узлах, и они не успели прийти в согласованное состояние после обновления агрегата, в котором был заменен типоразмер шин. +Тогда у нас возникла бы вероятность получить из хранилища автомобиль с различными типоразмерами шин, что нарушило бы инвариант агрегата.</p> +<p>Иными словами, Eventual Consistency является не причиной, а следствием. И сохраняется агрегат одной транзакцией потому, что иное просто технически невозможно в условиях распределенности. Точнее, Агрегат является границей транзакции. И Вернон прибегает к Eventual Consistency потому что это лучше для high availability, чем Two-Phase Commit.</p> +<p>Таким образом, используя распределенное NoSQL хранилище или Actor Model, как правило, просто нет технической возможности сохранить более одного агрегата в одной транзакции. +Хотя, многие распределенные NoSQL хранилища и позволяют пакетировать несколько операций, транзакциями их считать нельзя.</p> +<p>Используя микросервисную архитектуру с RDBMS, существует техническая возможность сохранять более одного агрегата внутри <a class="reference external" href="https://martinfowler.com/bliki/IntegrationDatabase.html">одного и того же микросервиса</a> одной транзакцией. +Правда, это может ухудшить уровень параллелизма, поэтому важно стремиться достигать наименее возможных границ транзакции. +А вот синхронизация агрегатов различных сервисов может быть только асинхронной, либо же с использованием Two-Phase Commit. +То же самое справедливо и для Bounded Contexts DDD-монолита.</p> +<p>Стремление избежать Two-Phase Commit, в целях достижения highly scalable, подталкивает Vaughn Vernon к Eventual Consistency:</p> +<blockquote> +<div><p><strong>It can eliminate the need for two-phase commits (global transactions) and support of the rules of Aggregates (10).</strong> +One rule of Aggregates states that only a single instance should be modified in a single transaction, and all other dependent changes must occur in separate transactions. +So other Aggregate instances in the local Bounded Context may be synchronized using this approach. +We also bring remote dependencies into a consistent state with latency. +The decoupling helps provide <strong>a highly scalable</strong> and peak-performing set of cooperating services. +It also allows us to achieve loose coupling between systems.</p> +<p>-"Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id5" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "Chapter 8. Domain Events :: The When and Why of Domain Events"</p> +</div></blockquote> +<p>Но мы видим, что, кроме проблемы достижения одновременной Согласованности и Доступности при распределенном хранении агрегатов (и устойчивости к разделению), озвучивается еще одна причина - database locking. +Означает ли проблема database locking то, что коммититься должен только один агрегат в одной транзакции при использовании RDBMS (Relational Database Management System)? +Это означает только то, что транзакция должна быть fine-grained. +"Fine-grained system transaction" != "one aggregate per transaction".</p> +<blockquote> +<div><p>This rationale is based on embracing <strong>fine-grained transactions instead of transactions spanning many aggregates</strong> or entities. +The idea is that in the second case, the number of database locks will be substantial in large-scale applications with high scalability needs. +Embracing the fact that <strong>highly scalable</strong> applications need not have instant transactional consistency between multiple aggregates helps with accepting the concept of eventual consistency. +Atomic changes are often not needed by the business, and it is in any case the responsibility of the domain experts to say whether particular operations need atomic transactions or not. +If an operation always needs an atomic transaction between multiple aggregates, you might ask whether your aggregate should be larger or was not correctly designed.</p> +<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id6" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#single-transaction-across-aggregates-versus-eventual-consistency-across-aggregates">Domain events: design and implementation :: Single transaction across aggregates versus eventual consistency across aggregates</a>"</p> +</div></blockquote> +<p>О проблемах ухудшения параллелизма говорит и Vaughn Vernon, причем, причиной проблемы может стать даже один-единственный крупный агрегат. +Как видно, дело не столько в количестве агрегатов, сколько в размере границ транзакции.</p> +<blockquote> +<div><p>Smaller Aggregates not only perform and scale better, they are also biased toward transactional success, meaning that conflicts preventing a commit are rare.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id7" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "Chapter 10 Aggregates :: Rule: Design Small Aggregates"</p> +</div></blockquote> +<p>Сам Eric Evans в своем известном выражении, которое многие приводят как первопричину Eventual Consistency, вовсе не требует одну транзакцию на агрегат, а говорит лишь о том, что после коммита инвариант каждого из агрегатов должен соблюдаться:</p> +<blockquote> +<div><p>Invariants, which are consistency rules that must be maintained whenever data changes, will involve relationships between members of the AGGREGATE. +Any rule that <strong>spans AGGREGATES</strong> will <strong>not be expected</strong> to be up-to-date at all times. +Through event processing, batch processing, or other update mechanisms, other dependencies can be resolved within some specified time. +<strong>But the invariants applied within an AGGREGATE will be enforced with the completion of each transaction.</strong></p> +<p>- "Domain-Driven Design: Tackling Complexity in the Heart of Software" <a class="footnote-reference brackets" href="#fnddd" id="id8" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Six. The Life Cycle of a Domain Object :: Aggregates"</p> +</div></blockquote> +<blockquote> +<div><p>Leave transaction control to the client. Although the REPOSITORY will insert into and delete from the database, it will ordinarily not commit anything. +It is tempting to commit after saving, for example, but the client presumably has the context to correctly initiate and commit units of work. +Transaction management will be simpler if the REPOSITORY keeps its hands off.</p> +<p>- "Domain-Driven Design: Tackling Complexity in the Heart of Software" <a class="footnote-reference brackets" href="#fnddd" id="id9" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Six. The Life Cycle of a Domain Object :: Repositories"</p> +</div></blockquote> +<p>А здесь он говорит о корне агрегата во множественном числе:</p> +<blockquote> +<div><p>Schemes have been developed for defining ownership relationships in the model. The following simple but rigorous system, distilled from those concepts, includes a set of rules for implementing transactions that modify the objects and their owners.</p> +<p>- "Domain-Driven Design: Tackling Complexity in the Heart of Software" <a class="footnote-reference brackets" href="#fnddd" id="id10" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Six. The Life Cycle of a Domain Object :: Aggregates"</p> +</div></blockquote> +<p>Такую же причину озвучивает и Vaughn Vernon:</p> +<blockquote> +<div><p><strong>Transactions across distributed systems are not atomic.</strong> +<strong>The various systems bring multiple Aggregates into a consistent state eventually.</strong></p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id11" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Reference Other Aggregates by Identity :: Scalability and Distribution"</p> +</div></blockquote> +<blockquote> +<div><p>Accepting that <strong>all Aggregate instances in a large-scale, high-traffic enterprise are never completely consistent</strong> helps us accept that eventual consistency also makes sense in the smaller scale where just a few instances are involved.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id12" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary"</p> +</div></blockquote> +<p>Кстати, автором идеи агрегата является даже не Eric Evans, а David Siegel.</p> +<blockquote> +<div><p>Schemes have been developed for defining ownership relationships in the model. +The following simple but rigorous system, distilled from those concepts, includes a set of rules for implementing transactions that modify the objects and their owners. [1] +(<strong>David Siegel devised and used this system on projects in the 1990s but has not published it.</strong>)</p> +<p>First we need an abstraction for encapsulating references within the model. +An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. +Each AGGREGATE has a root and a boundary. +The boundary defines what is inside the AGGREGATE. +The root is a single, specific ENTITY contained in the AGGREGATE. +The root is the only member of the AGGREGATE that outside objects are allowed to hold references to, although objects within the boundary may hold references to each other. +ENTITIES other than the root have local identity, but that identity needs to be distinguishable only within the AGGREGATE, because no outside object can ever see it out of the context of the root ENTITY.</p> +<p>- "Domain-Driven Design: Tackling Complexity in the Heart of Software" <a class="footnote-reference brackets" href="#fnddd" id="id13" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Six. The Life Cycle of a Domain Object :: Aggregates"</p> +</div></blockquote> +<p>Оригинальная работа David Siegel к сожалению, не опубликована (по крайней мере, мне ее отыскать не удалось). +Но он упоминается также в PoEAA, где определение агрегата звучит так:</p> +<blockquote> +<div><p>Eric Evans and David Siegel [Evans] define an <strong>aggregate as a cluster of associated objects that we treat as a unit for data changes</strong>. +Each aggregate has a root that provides the only access point to members of the set and a boundary that defines what's included in the set. +The aggregate's characteristics call for a Coarse-Grained Lock, since working with any of its members requires locking all of them. Locking an aggregate yields an alternative to a shared lock that I call a root lock (see Figure 16.4). +By definition locking the root locks all members of the aggregate. The root lock gives us a single point of contention.</p> +<p>- "Patterns of Enterprise Application Architecture" <a class="footnote-reference brackets" href="#fnpoeaa" id="id14" role="doc-noteref"><span class="fn-bracket">[</span>10<span class="fn-bracket">]</span></a> by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford, Chapter "16. Offline Concurrency Patterns :: Coarse-Grained Lock"</p> +</div></blockquote> +<p>Здесь говорится про единицу изменения, про бизнес-транзакцию и блокировку, но о связи бизнес-транзакции с системной транзакцией говорится только то, что "the system transaction in which you commit the business transaction", т.е. границы системной транзакции включают в себя границы бизнес-транзакции, но не ограничиваются ими.</p> +</section> +<section id="id15"> +<h3><a class="toc-backref" href="#id120" role="doc-backlink">Eventual Consistency предпочтительней</a></h3> +<p>С одной стороны, Vaughn Vernon настоятельно рекомендует использовать Eventual Consistency между Агрегатами. +И тут же объясняет - агрегаты в высоконагруженных масштабируемых распределенных приложениях, устойчивых к разделению, никогда не бывают доступны и согласованы между собой одновременно.</p> +<blockquote> +<div><p>Thus, if executing a command on one Aggregate instance requires that additional business rules execute on one or more other Aggregates, <strong>use eventual consistency</strong>. +Accepting that all <strong>Aggregate instances in a large-scale, high-traffic enterprise are never completely consistent</strong> helps us accept that eventual consistency also makes sense in the smaller scale where just a few instances are involved.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id16" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary"</p> +</div></blockquote> +<blockquote> +<div><p>An invariant is a business rule that must always be consistent. +There are different kinds of consistency. One is transactional consistency, which is considered immediate and atomic. +There is also eventual consistency. When discussing invariants, we are referring to transactional consistency.</p> +<p>&lt;...&gt;</p> +<p>The consistency boundary logically asserts that everything inside adheres to a specific set of business invariant rules no matter what operations are performed. +The consistency of everything outside this boundary is irrelevant to the Aggregate. +Thus, Aggregate is synonymous with transactional consistency boundary.</p> +<p>&lt;...&gt;</p> +<p>When employing a typical persistence mechanism, we use a single <a class="reference external" href="https://martinfowler.com/eaaCatalog/unitOfWork.html">transaction</a> to manage consistency. +When the transaction commits, everything inside one boundary must be consistent. +A properly designed Aggregate is one that can be modified in any way required by the business with its invariants completely consistent within a single transaction. +And a properly designed Bounded Context modifies only one Aggregate instance per transaction in all cases. +What is more, we cannot correctly reason on Aggregate design without applying transactional analysis. +Limiting modification to one Aggregate instance per transaction may sound overly strict. +However, it is a rule of thumb and should be the goal in most cases. +It addresses the very reason to use Aggregates.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id17" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Model True Invariants in Consistency Boundaries"</p> +</div></blockquote> +</section> +<section id="id18"> +<h3><a class="toc-backref" href="#id121" role="doc-backlink">Все решают бизнес-правила</a></h3> +<p>С другой стороны, все решают бизнес-правила:</p> +<blockquote> +<div><p>The main point to remember from this section is that business rules are the drivers for determining what must be whole, complete, and consistent at the end of a single transaction.</p> +<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id19" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "5. Tactical Design with Aggregates :: Why Used"</p> +</div></blockquote> +</section> +<section id="ask-whose-job-it-is"> +<h3><a class="toc-backref" href="#id122" role="doc-backlink">Принцип "Ask Whose Job It Is"</a></h3> +<p>Тем не менее, Vaughn Vernon не считает вопрос Strong (Transactional) Consistency vs Eventual Consistency однозначным, и приводит четыре причины, по которым выбор может отдаваться в пользу Strong (Transactional) Consistency. +Цитировать все не буду - слишком много текста. +Кому интересно - глава "Chapter 10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary :: Ask Whose Job It Is" и далее, вплоть до главы "Gaining Insight through Discovery". +Приведу только отрывок:</p> +<blockquote> +<div><p>Ask Whose Job It Is</p> +<p>Some domain scenarios can make it very challenging to determine whether transactional or eventual consistency should be used. +Those who use DDD in a classic/traditional way may lean toward transactional consistency. +Those who use CQRS may tend toward eventual consistency. +But which is correct? +<strong>Frankly, neither of those tendencies provides a domain-specific answer, only a technical preference. Is there a better way to break the tie?</strong></p> +<p>Discussing this with Eric Evans revealed a very simple and sound guideline. +When examining the use case (or story), ask whether it's the job of the user executing the use case to make the data consistent. +<strong>If it is, try to make it transactionally consistent, but only by adhering to the other rules of Aggregates.</strong> +If it is another user's job, or the job of the system, allow it to be eventually consistent. +That bit of wisdom not only provides a convenient tie breaker, but it helps us gain a deeper understanding of our domain. +It exposes the real system invariants: the ones that must be kept transactionally consistent. +That understanding is much more valuable than defaulting to a technical leaning.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id20" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary :: Ask Whose Job It Is"</p> </div></blockquote> +<p>В цитате Вона Вернона видно, что Эрик Эванс не спешит разделять стремление к одному агрегату на транзакцию, и предлагает рассматривать каждый случай отдельно.</p> +<p>Можно заметить, что принцип "When examining the use case (or story), ask whether it's the job of the user executing the use case to make the data consistent. <strong>If it is, try to make it transactionally consistent, but only by adhering to the other rules of Aggregates.</strong>" не противоречит приведенному ниже принципу "developers and architects like Jimmy Bogard are okay with spanning a single transaction across several aggregates - but only <strong>when those additional aggregates are related to side effects for the same original command</strong>."</p> +<p>Здесь же Vaughn Vernon напоминает нам, что во главе угла стоит, опять же, масштабирование и распределенность:</p> <blockquote> -<div><p>💬 "Their ideas are not "just theory". It's years of accumulated practice and insights. They work — often in many different contexts. We're lucky: we can build on top of their ideas."</p> -<p class="attribution">—"<a class="reference external" href="https://verraes.net/2014/10/software-design-is-just-theory/">Software design is just theory</a>" by Mathias Verraes.</p> +<div><p>We'll have <strong>consistency</strong> where necessary [имеется ввиду CAP-theorem], and support for optimally performing and <strong>highly scalable systems</strong>.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id21" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Reasons to Break the Rules :: Adhering to the Rules"</p> </div></blockquote> +<p>Далее, в главе "Chapter 10 Aggregates :: Gaining Insight through Discovery :: Is It the Team Member's Job?" книги, он демонстрирует применение принципа "Ask Whose Job It Is" на практике.</p> </section> -<section id="emacsway-opinion-in-psychology"> -<span id="id4"/><h2><a class="toc-backref" href="#id12" role="doc-backlink">О мнениях</a></h2> -<p>Обратимся к энциклопедии:</p> +<section id="strong-consistency"> +<h3><a class="toc-backref" href="#id123" role="doc-backlink">Strong Consistency - новичкам</a></h3> +<p>Вот что советует новичкам Vaughn Vernon:</p> <blockquote> -<div><p>📝 "Там, где заканчивается <strong>знание</strong>, начинается <strong>мнение</strong>".</p> -<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/737/%D0%9C%D0%9D%D0%95%D0%9D%D0%98%D0%95">Философия: Энциклопедический словарь.</a>" — М.: Гардарики. Под редакцией А.А. Ивина. 2004.</p> +<div><p>There is nothing incredibly difficult about using eventual consistency. +Still, until you can gain some experience, you may be concerned about using it. +If so, you should still partition your model into Aggregates according to business-defined transactional boundaries. +<strong>However, there is nothing preventing you from committing modifications to two or more Aggregates in a single atomic database transaction.</strong> +You might choose to use this approach in cases that you know will succeed but use eventual consistency for all others. +<strong>This will allow you to get used to the techniques without taking too big an initial step.</strong> +<strong>Just understand that this is not the primary way that Aggregates are meant to be used, and you may experience transactional failures as a result.</strong></p> +<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id22" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "5. Tactical Design with Aggregates :: Rule 4: Update Other Aggregates Using Eventual Consistency"</p> </div></blockquote> +</section> +<section id="performance"> +<h3><a class="toc-backref" href="#id124" role="doc-backlink">Интересы performance</a></h3> +<p>Ранее упоминалось, что одной из ключевых причин fine-grained транзакций является performance. +Но всегда ли? +На самом деле, все зависит от конкретных условий. +Забегая наперед, рассмотрим такое утверждение:</p> <blockquote> -<div><p>📝 "Со времен элеатов, атомистов и Платона <strong>знание</strong> характеризуется через противоположность <strong>мнению</strong>."</p> -<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">Новая философская энциклопедия: В 4 тт.</a>" М.: Мысль. Под редакцией В. С. Стёпина. 2001.</p> +<div><p>NOTE: Try not to confuse this guideline with loading or creating aggregates. +It is perfectly fine to load multiple aggregates inside the same transaction as long as you save only one of them. +<strong>Equally, it is permissible to create multiple aggregates inside a single transaction because adding new aggregates should not cause concurrency issues.</strong></p> +<p>- "Patterns, Principles, and Practices of Domain-Driven Design" <a class="footnote-reference brackets" href="#fnpppddd" id="id23" role="doc-noteref"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></a> by Scott Millett, Nick Tune, Chapter "19 Aggregates :: Special Cases"</p> </div></blockquote> +<p>Какое значение имеет это утверждение для performance? +Я обращусь к статьям двух известных организаций в области highload:</p> <blockquote> -<div><p>📝 "К отличительным особенностям научного знания в настоящее время относят: непротиворечивость, <strong>эмпирическую проверяемость</strong>, логическую или <strong>эмпирическую обоснованность</strong>."</p> -<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">Философия: Энциклопедический словарь.</a>" — М.: Гардарики. Под редакцией А.А. Ивина. 2004.</p> +<div><p>This consistent insert throughput also persists when writing large batches of rows in single operations to TimescaleDB (instead of row-by-row). +Such batched inserts are common practice for databases employed in more high-scale production environments, e.g., when ingesting data from a distributed queue like Kafka. +<strong>In such scenarios, a single Timescale server can ingest 130K rows (or 1.3M metrics) per second, approximately 15x that of vanilla PostgreSQL once the table has reached a couple 100M rows.</strong></p> +<p>- "<a class="reference external" href="https://blog.timescale.com/blog/time-series-data-why-and-how-to-use-a-relational-database-instead-of-nosql-d0cd6975e87c/">Time-series data: Why (and how) to use a relational database instead of NoSQL</a>" by Mike Freedman, Timescale CTO and co-founder. Professor of Computer Science at Princeton.</p> </div></blockquote> <blockquote> -<div><p>📝 "Знание есть такой результат познавательной деятельности, который обладает непреходящей истинностью, может быть логически или фактически обоснован и допускает <strong>эмпирическую или практическую проверку</strong>."</p> -<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">Философия: Энциклопедический словарь.</a>" — М.: Гардарики. Под редакцией А.А. Ивина. 2004.</p> +<div><ol class="arabic simple" start="7"> +<li><p>Insert rows in batches.</p></li> +</ol> +<p>In order to achieve higher ingest rates, you should insert your data with many rows in each INSERT call (or else use some bulk insert command, like COPY or our parallel copy tool).</p> +<p>Don't insert your data row-by-row – instead try at least hundreds (or thousands) of rows per INSERT. +This allows the database to spend less time on connection management, transaction overhead, SQL parsing, etc., and more time on data processing.</p> +<p>- "<a class="reference external" href="https://blog.timescale.com/blog/13-tips-to-improve-postgresql-insert-performance/">13 tips to improve PostgreSQL Insert performance</a>" by Mike Freedman, Timescale CTO and co-founder. Professor of Computer Science at Princeton.</p> </div></blockquote> <blockquote> -<div><p>📝 "3нание, являясь <strong>обобщением</strong> достоверных <strong>фактов</strong>, за случайным находит необходимое и закономерное, за единичным и частным — общее."</p> -<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">Философский энциклопедический словарь.</a>" — М.: Советская энциклопедия. Гл. редакция: Л. Ф. Ильичёв, П. Н. Федосеев, С. М. Ковалёв, В. Г. Панов. 1983.</p> +<div><p>It is of note here that each insert is a transaction. +What this means is Postgres is doing some extra coordination to make sure the transaction is completed before returning. +On every single write this takes some overhead. +Instead of single row transactions, if we wrap all of our inserts in a transaction like below, we'll see some nice performance gains:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span/><span class="n">begin</span><span class="p">;</span> +<span class="n">insert</span> <span class="mi">1</span><span class="p">;</span> +<span class="n">insert</span> <span class="mi">2</span><span class="p">;</span> +<span class="n">insert</span> <span class="mi">3</span><span class="p">;</span> +<span class="o">...</span> +<span class="n">commit</span><span class="p">;</span> +</pre></div> +</div> +<p>This took my inserts down from 15 minutes 30 seconds to 5 minutes and 4 seconds. +We've suddenly boosted our throughput by 3x to about 3k inserts per second.</p> +<p>&lt;...&gt;</p> +<p>By batching our inserts into a single transaction, we saw our throughput go higher. +But hold on, there is even more we can do. The <code class="docutils literal notranslate"><span class="pre">\copy</span></code> mechanism gives a way to bulk load data in an even more performant manner.</p> +<p>&lt;...&gt;</p> +<p>Running this copy completes in 82 seconds! We're now processing over 10k writes per second on some fairly modest hardware.</p> +<p>- "<a class="reference external" href="https://www.citusdata.com/blog/2017/11/08/faster-bulk-loading-in-postgresql-with-copy/">Faster bulk loading in Postgres with copy</a>" by Craig Kerstiens, CitusData</p> </div></blockquote> +<p>Вот что говорит по этому вопросу документация по PostgreSQL:</p> <blockquote> -<div><p>📝 "Знание есть не только <strong>преобразование опыта</strong> в сознание путем структуризации, обозначения его элементов, не только фиксация опыта в социальной памяти. -Оно является способом трансформации знаковых систем, сознания, деятельности и общения, придания им новой формы, т. е. нового смысла и значения. -Знание возникает как осмысление человеком контекстов своего <strong>опыта</strong>."</p> -<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">Новая философская энциклопедия: В 4 тт.</a>" М.: Мысль. Под редакцией В. С. Стёпина. 2001.</p> +<div><p>When using multiple INSERTs, turn off autocommit and just do one commit at the end. +(In plain SQL, this means issuing BEGIN at the start and COMMIT at the end. Some client libraries might do this behind your back, in which case you need to make sure the library does it when you want it done.) +<strong>If you allow each insertion to be committed separately, PostgreSQL is doing a lot of work for each row that is added.</strong></p> +<p>- "<a class="reference external" href="https://www.postgresql.org/docs/11/populate.html#DISABLE-AUTOCOMMIT">PostgreSQL 11 Documentation :: 14.4. Populating a Database :: 14.4.1. Disable Autocommit</a>"</p> </div></blockquote> +<p>Целесообразность использования Eventual Consistency в интересах performance нужно рассматривать в каждом конкретном случае отдельно. +Универсального рецепта не существует. +Этот вопрос особенно актуален при разработке сертифицированных приложений, где свобода выбора базы данных ограничена списком сертифицированных решений (зачастую вся свобода выбора сводится к RDBMS PostgresPro). +Организовать пакетирование запросов можно на уровне <a class="reference external" href="https://martinfowler.com/eaaCatalog/unitOfWork.html">Unit of Work</a>.</p> +<p>В контексте этого вопроса можно еще раз вспомнить утверждение Eric Evans:</p> <blockquote> -<div><p>📝 "В совр. методологии науки принято выделять след. осн. компоненты теории:</p> -<ol class="arabic simple"> -<li><p>исходную эмпирич. основу, которая включает множество зафиксированных в данной области знания фактов, достигнутых в ходе экспериментов и требующих теоретич. объяснения;</p></li> -<li><p>исходную теоретич. основу — множество первичных допущений, постулатов, аксиом, общих законов Т., в совокупности описывающих идеализированный объект Т.;</p></li> -<li><p>логику Т.— множество допустимых в рамках Т. правил ло-гич. вывода и доказательства;</p></li> -<li><p>совокупность выведенных в Т. утверждений с их доказательствами, составляющую осн. массив теоретич. знания."</p></li> -</ol> -<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/1215/%D0%A2%D0%95%D0%9E%D0%A0%D0%98%D0%AF">Философский энциклопедический словарь.</a>" — М.: Советская энциклопедия. Гл. редакция: Л. Ф. Ильичёв, П. Н. Федосеев, С. М. Ковалёв, В. Г. Панов. 1983.</p> +<div><p>Discussing this with Eric Evans revealed a very simple and sound guideline. +When examining the use case (or story), ask whether it's the job of the user executing the use case to make the data consistent. +<strong>If it is, try to make it transactionally consistent, but only by adhering to the other rules of Aggregates.</strong></p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id24" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary :: Ask Whose Job It Is"</p> </div></blockquote> -<p>Когда в коллективе недостаточно знаний, столкновения мнений и конфликты всегда неизбежны. -Потому что <strong>мнение</strong> выражает индивидуальный опыт человека, которым оно призведено. -А это значит, что любое несогласие с его мнением воспринимается как недооценка его опыта, ущемление компетентности и угроза социальному положению, что может усиливаться рядом <a class="reference internal" href="cognitive-biases.html#emacsway-cognitive-biases"><span class="std std-ref">когнитивых искажений</span></a>. -Этим объясняется повышенная токсичность online IT-сообществ.</p> </section> -<section id="emacsway-knowledge-in-psychology"> -<span id="id5"/><h2><a class="toc-backref" href="#id13" role="doc-backlink">О знаниях</a></h2> -<p><strong>Знания</strong> же человек не отождествляет с персональной компетентностью, поскольку знания производятся гораздо более широким охватом опыта. -Соответственно, он уже не воспринимает несогласие с его позицией как ущемление достоинства. -Как говорится, "мопед не мой".</p> +<section id="id25"> +<h3><a class="toc-backref" href="#id125" role="doc-backlink">Обратная совместимость формата объектов событий</a></h3> +<p>Другим достоинством Strong Consistency является отсутствие потребности в обеспечении обратной совместимости формата объектов событий, ведь их время жизни ограничено одной транзакцией. +При использовании же шины сообщений всегда сохраняется вероятность того, что обновленная версия программного обеспечения, после ее развертывания, получит из шины устаревший формат сообщения, отправленный в шину еще предыдущей версией программного обеспечения. +Кроме того, возникает потребность поддерживать оба формата сообщений для организации <a class="reference external" href="https://thenewstack.io/deployment-strategies/">blue-green deployment</a>.</p> +<p>Подробнее о версионировании сообщений смотрите в книге "<a class="reference external" href="https://leanpub.com/esversioning">Versioning in an Event Sourced System</a>" by Greg Young ("<a class="reference external" href="https://leanpub.com/esversioning/read">читать online</a>", "<a class="reference external" href="https://github.com/luque/Notes--Versioning-Event-Sourced-System">конспект книги</a>"), а так же в главе "<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/jj591577(v=pandp.10)#event-versioning">Event versioning</a> книги "CQRS Journey".</p> +</section> +<section id="net-microservices"> +<h3><a class="toc-backref" href="#id126" role="doc-backlink">Рекомендации от ".NET Microservices"</a></h3> +<p>".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id26" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> явно разделяет внутренние Domain Events (для подписчиков внутри Bounded Context) и внешние Integration Events. +Внутренние Domain Events рекомендуется использовать для синхронизации Агрегатов внутри Bounded Context.</p> <blockquote> -<div><p>📝 "As Issac Newton <a class="reference external" href="https://en.wikipedia.org/wiki/Standing_on_the_shoulders_of_giants">said</a>: "If I have seen further, it is by standing on the shoulders of giants.""</p> -<p class="attribution">—Mike Cohn, "<a class="reference external" href="https://www.mountaingoatsoftware.com/blog/my-favorite-resource-for-agile-advice-support-and-answers">My Favorite Resource for Agile Advice, Support, and Answers</a>". -Isaac Newton wrote in a 1675 letter to fellow scientist Robert Hooke.</p> +<div><p>Domain events as a preferred way to trigger side effects across multiple aggregates within the same domain</p> +<p>If executing a command related to one aggregate instance requires additional domain rules to be run on one or more additional aggregates, you should design and implement those side effects to be triggered by domain events. +As shown in Figure 7-14, and as one of the most important use cases, a domain event should be used to propagate state changes across multiple aggregates within the same domain model.</p> +<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id27" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#domain-events-as-a-preferred-way-to-trigger-side-effects-across-multiple-aggregates-within-the-same-domain">Domain events: design and implementation :: Domain events as a preferred way to trigger side effects across multiple aggregates within the same domain</a>"</p> +</div></blockquote> +<p>Причем, Strong Consistency является приемлемым для внутренних Domain Events, синхронизирующих Агрегаты внутри Bounded Context:</p> +<blockquote> +<div><p>Be aware that transactional boundaries come into significant play here. +<strong>If your unit of work and transaction can span more than one aggregate (as when using EF Core and a relational database), this can work well.</strong> +But if the transaction cannot span aggregates, such as when you are using a NoSQL database like Azure CosmosDB, you have to implement additional steps to achieve consistency.</p> +<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id28" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#the-deferred-approach-to-raise-and-dispatch-events">Domain events: design and implementation :: Implement domain events :: The deferred approach to raise and dispatch events</a>"</p> +</div></blockquote> +<p>Оба подхода, и Strong Consistency, и Eventual Consistency, являются приемлемыми для синхронизации Агрегатов внутри Bounded Context:</p> +<blockquote> +<div><p><strong>Actually, both approaches (single atomic transaction and eventual consistency) can be right.</strong> +It really depends on your domain or business requirements and what the domain experts tell you. +It also depends on how scalable you need the service to be (more granular transactions have less impact with regard to database locks). +And it depends on how much investment you are willing to make in your code, since eventual consistency requires more complex code in order to detect possible inconsistencies across aggregates and the need to implement compensatory actions. +Consider that if you commit changes to the original aggregate and afterwards, when the events are being dispatched, if there is an issue and the event handlers cannot commit their side effects, you will have inconsistencies between aggregates.</p> +<p>A way to allow compensatory actions would be to store the domain events in additional database tables so they can be part of the original transaction. +Afterwards, you could have a batch process that detects inconsistencies and runs compensatory actions by comparing the list of events with the current state of the aggregates. +The compensatory actions are part of a complex topic that will require deep analysis from your side, which includes discussing it with the business user and domain experts.</p> +<p>In any case, you can choose the approach you need. +But the initial deferred approach—raising the events before committing, so you use a single transaction—is the simplest approach when using EF Core and a relational database. +It is easier to implement and valid in many business cases. +It is also the approach used in the ordering microservice in eShopOnContainers.</p> +<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id29" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#single-transaction-across-aggregates-versus-eventual-consistency-across-aggregates">Domain events: design and implementation :: Implement domain events :: Single transaction across aggregates versus eventual consistency across aggregates</a>"</p> </div></blockquote> </section> -<section id="id6"> -<h2><a class="toc-backref" href="#id14" role="doc-backlink">Решение</a></h2> -<p>Мне известны два способа решения такого рода конфликтов:</p> -<ol class="arabic"> -<li><p>Восполнить информационный вакуум путем обращения к расширенному обобщенному опыту, т.е. к теории, дабы восполнить недостающие точки зрения, возникшие в силу заведомой ограниченности индивидуального опыта. -Причем, этот метод требует деликатности, ибо знания могут быть отторгнуты коллективом в силу эффекта "<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологической Защиты</a>", так как выводят коллектив из зоны комфорта, и могут спровоцировать чувство ущербности на фоне осведомленности спикера. -Лучшая форма донесения новых знаний - это постановка перед коллективом таких вопросов, которые способны пролить свет на недостающие точки зрения. -Не говорить, а спрашивать. -Об этом писали Kent Beck, Neal Ford, Gregor Hohpe и др. -Это раздвигает границы опыта человека, на котором он основывает свое мнение, и вынуждает переосмыслить его.</p> +<section id="scott-millett-nick-tune"> +<h3><a class="toc-backref" href="#id127" role="doc-backlink">Мнение Scott Millett и Nick Tune</a></h3> <blockquote> -<div><p>📝 "Неприступные крепости легче всего берутся изнутри".</p> +<div><p><strong>Sometimes it is actually good practice to modify multiple aggregates within a transaction.</strong> +But it's important to understand why the guidelines exist in the first place so that you can be aware of the consequences of ignoring them.</p> +<p><strong>When the cost of eventual consistency is too high, it's acceptable to consider modifying two objects in the same transaction.</strong> +Exceptional circumstances will usually be when the business tells you that the customer experience will be too unsatisfactory. +You shouldn't just accept the business's decision, though; it never wants to accept eventual consistency. +You should elaborate on the scalability, performance, and other costs involved when not using eventual consistency so that the business can make an informed, customer‐focused decision.</p> +<p><strong>Another time it's acceptable to avoid eventual consistency is when the complexity is too great.</strong> +You will see later in this chapter that robust eventually consistent implementations often utilize asynchronous, out‐of‐process workflows that add more complexity and dependencies.</p> +<p><strong>To summarize, saving one aggregate per transaction is the default approach.</strong> +But you should collaborate with the business, assess the technical complexity of each use case, and consciously ignore the guideline if there is a worthwhile advantage, such as a better user experience.</p> +<p>NOTE: Try not to confuse this guideline with loading or creating aggregates. +It is perfectly fine to load multiple aggregates inside the same transaction as long as you save only one of them. +<strong>Equally, it is permissible to create multiple aggregates inside a single transaction because adding new aggregates should not cause concurrency issues.</strong></p> +<p>&lt;...&gt;</p> +<p><strong>You should try to align your aggregate boundaries with transactions, because the higher the number of aggregates being modified in a single transaction, the greater the chance of a concurrency failure.</strong> +Therefore, strive to modify a single aggregate per use case to keep the system performant.</p> +<p>&lt;...&gt;</p> +<p>If you find that you are modifying more than one aggregate in a transaction, it may be a sign that your aggregate boundaries can be better aligned with the problem domain.</p> +<p>&lt;...&gt;</p> +<p>In a typical business use case there are often multiple actions that need to succeed or fail together inside a transaction. +By managing transactions in application services, you have full control over which operations that you request of the domain will live inside the same transaction boundary.</p> +<p>This can be demonstrated using an updated RecommendAFriendService. +Imagine the business has decided that if the referral policy cannot be applied, it should not create the new account. +Therefore, the transactional boundary encapsulates creating the new account and applying the referral policy to both accounts, as shown in Figure 25-3.</p> +<p>- "Patterns, Principles, and Practices of Domain-Driven Design" <a class="footnote-reference brackets" href="#fnpppddd" id="id30" role="doc-noteref"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></a> by Scott Millett, Nick Tune, Chapter "19 Aggregates :: Special Cases"</p> </div></blockquote> -<p>Дело может существенно облегчиться, если у коллектива имеются общепризнанные им авторитетные авторы, освещающие решаемый вопрос. -Зачастую помогают стандарты и материалы для сертификации уровня знаний.</p> -<p>Сам по себе отсыл к авторитету не является доказательством, однако, авторитеты находятся в более выгодном положении перед практикующими специалистами, поскольку занимаются этим профессионально, в то время как практикующий специалист основную часть ресурсов времени тратит на добывание средств к существованию, и не располагает ресурсами для обеспечения соизмеримой широты дивергентной фазы исследования и глубины конвергентной её проработки.</p> -<p>Иными словами, обобщение и систематизация коллективного опыта требует таких ресурсов времени, которыми обычный практик, как правило, не располагает (хотя бывают исключения).</p> -<p>Тем не менее, авторитеты тоже люди, и тоже могут ошибаться, пусть и реже. -Так, например, как показала эволюция архитектурной области знаний, границы микросервисов все-таки не должны соответствовать границам Bounded Context, как считал Sam Newman на заре микросервисной архитектуры. -Так что критического мышления никто не отменял.</p> -<p>Разработка стандартов располагает еще большими финансовыми ресурсами для исследовательской фазы:</p> -<ul class="simple"> -<li><p><a class="reference external" href="https://www.iec.ch/standards-development/stages">https://www.iec.ch/standards-development/stages</a></p></li> -<li><p><a class="reference external" href="https://standards.ieee.org/develop/">https://standards.ieee.org/develop/</a></p></li> -</ul> -<p>Стандарты тоже устаревают и регулярно пересматриваются и актуализируются.</p> -</li> -<li><p>Не настаивать на принятии решения в условиях недостаточной информированности. Дейл Карнеги в свое время дал такой совет для борьбы со стрессом - не пытайтесь принять решение в условиях недостаточной информированности. -Просто собирайте информацию, и решение придет само.</p> -<p>Если продолжать настаивать ("Вы должны сегодня определиться!..."), то возможны два сценария развития ситуации:</p> -<ol class="arabic simple"> -<li><p>Силы консолидации коллектива возобладают над силой внешнего принуждения коллектива. Принуждение будет отторгнуто ("А нам это не нужно...").</p></li> -<li><p>Сила внешнего принуждения возобладает над силами консолидации коллектива. Участники коллектива поймут, что защищать свое мнение в виде собственного достоинства легче сообща, и начнут объединяться по признаку отождествления общих угроз, что приведет к расколу коллектива по группам. Исправить такой раскол может оказаться сложно и долго.</p></li> -</ol> -</li> -</ol> </section> -<section id="emacsway-theory"> -<span id="id7"/><h2><a class="toc-backref" href="#id15" role="doc-backlink">О роли теории</a></h2> +<section id="jimmy-bogard"> +<h3><a class="toc-backref" href="#id128" role="doc-backlink">Мнение Jimmy Bogard</a></h3> +<p>Вот что говорит ".NET Microservices: Architecture for Containerized .NET Applications" со ссылкой на Jimmy Bogard:</p> <blockquote> -<div><p>📝</p> -<div class="line-block"> -<div class="line">— Эй, там болото, вот карта моих попыток пройти.</div> -<div class="line">— Зачем тратить время на чтение, если можно совершить собственный поход и вляпаться самолично!</div> -</div> -<p class="attribution">—<a class="reference external" href="http://mellarius.ru/">mellarius.ru</a></p> +<div><p>However, other developers and architects like Jimmy Bogard are <strong>okay with spanning a single transaction across several aggregates - but only when those additional aggregates are related to side effects for the same original command</strong>. +For instance, in <a class="reference external" href="https://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/">A better domain events pattern</a>, Bogard says this:</p> +<blockquote> +<div><p>Typically, I want the side effects of a domain event to occur within the same logical transaction, but not necessarily in the same scope of raising the domain event [...] Just before we commit our transaction, we dispatch our events to their respective handlers.</p> </div></blockquote> +<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id31" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#single-transaction-across-aggregates-versus-eventual-consistency-across-aggregates">Domain events: design and implementation :: Single transaction across aggregates versus eventual consistency across aggregates</a>"</p> +</div></blockquote> +<p>Сам Jimmy Bogard говорит следующее:</p> <blockquote> -<div><p>📝 "Всякий, кто полагается на практику, не зная теории, подобен кормчему, вступающему на судно без руля и компаса, – он не знает, куда плывет. -Практика всегда должна опираться на твердые теоретические основания."</p> -<p class="attribution">—Леонардо да Винчи</p> +<div><p>Domain events are similar to messaging-style eventing, with one key difference. +With true messaging and a service bus, a message is fired and handled to asynchronously. +With domain events, the response is synchronous</p> +<p>- "Strengthening your domain: Domain Events" <a class="footnote-reference brackets" href="#fnjbde1" id="id32" role="doc-noteref"><span class="fn-bracket">[</span>18<span class="fn-bracket">]</span></a> by Jimmy Bogard</p> </div></blockquote> <blockquote> -<div><p>📝 "Знание букв еще не делает человека поэтом."</p> -<p class="attribution">—Автор неизвестен</p> +<div><p>Transactions are handled in our unit of work wrapping each HTTP request. +Since our domain events are synchronous and on the same thread, they are part of the same transaction as the entity that first raised the event.</p> +<p>- "<a class="reference external" href="https://lostechies.com/jimmybogard/2010/04/08/strengthening-your-domain-domain-events/#comment-173067283">Strengthening your domain: Domain Events</a>", comment of Jimmy Bogard</p> </div></blockquote> -<p>Здесь, наверное, было бы уместно сделать небольшое отступление. -Распространенным заблуждением начинающих и толковых ребят является вера в то, что практика и опыт могут заменить работу с теорией, в частности - с литературой.</p> -<p>Во-первых, среднестатистический коммерческий проект на рынке не так уж и часто может служить источником качественной практики (если даже не наоборот). -Более лучшим источником качественной практики могут служить <a class="reference internal" href="../it/self-education/self-education-for-software-engineer.html#emacsway-reference-applications"><span class="std std-ref">открытые проекты</span></a>, основанные компетентными сообществами.</p> -<p>А во-вторых, помните что Дейкстра говорил о строго ограниченных размерах человеческого черепа?</p> <blockquote> -<div><p>📝 "The competent programmer is fully aware of the strictly limited size of his own skull; -therefore, he approaches the programming task in full humility"</p> -<p class="attribution">—Edsger W. Dijkstra, 1972</p> +<div><p>With our domain event in place, we can ensure that our entire <strong>domain model stays consistent with the business rules applied, even when we need to notify other aggregate roots</strong> in our system when something happens. +We've also locked down all the ways the risk status could change (charged a new fee), so <strong>we can keep our Customer aggregate consistent even in the face of changes in a separate aggregate (Fee)</strong>.</p> +<p>This pattern isn't always applicable. +If I need to do something like send an email, notify a web service or any other potentially blocking tasks, I should revert back to normal asynchronous messaging. +But for synchronous messaging across disconnected aggregates, <strong>domain events are a great way to ensure aggregate root consistency across the entire model</strong>. +The alternative would be transaction script design, where consistency is enforced not by the domain model but by some other (non-intuitive) layer.</p> +<p>- "Strengthening your domain: Domain Events" <a class="footnote-reference brackets" href="#fnjbde1" id="id33" role="doc-noteref"><span class="fn-bracket">[</span>18<span class="fn-bracket">]</span></a> by Jimmy Bogard</p> </div></blockquote> -<p>Намерение воспроизвести в одиночку эволюцию целой индустрии - это весьма самонадеянно. -Может не хватить жизни. -Или вы учитесь на своих ошибках, или на чужих. Последний вариант выгодней. -Можно, конечно, попытаться изобрести колесо, и в одиночку обобщить и систематизировать весь совокупный опыт индустрии, и, если человек обладает интеллектом Эриха Гаммы или Мартина Фаулера, и сможет изыскать времени в половину жизни на эти исследования, то у него может даже и получиться. -Вот только совокупный обобщенный опыт индустрии выражается, опять же, в литературе. -Круг замкнулся.</p> -<p>Возьмем пример из спорта. -Сколько бы вы не смотрели выполнение задней подножки на практике, но, без знания теоретической составляющей, выполнить ее вы не сможете. -Более того, при попытке ее провести, вы поставите себя в уязвимое положение, и, с высокой долей вероятности, будете успешно контратакованы. -Это потому, что самая важная часть ее подготовки - перераспределение нагрузки, снаружи не видна, но играет решающую роль. -Множество людей годами систематизировали практику, и создавали теорию. -Благодаря теории, теперь не нужно проживать несколько жизней, чтобы все это постигнуть. -Это я говорил про Самбо - не самая теоретическая наука по сравнению с разработкой программного обеспечения.</p> -<p>Игнорирование теории по сути является проявлением "<a class="reference external" href="https://sergeyteplyakov.blogspot.com/2013/09/blog-post_24.html">Культа Карго</a>". -Еще одним ярким примером игнорирования теории является эпизод о том, как нарисовать семь перпендикулярных линий игнорируя геометрию, из известной короткометражки "<a class="reference external" href="https://youtu.be/UoKlKx-3FcA?t=269">The Expert</a>" (<a class="reference external" href="https://youtu.be/BKorP55Aqvg?t=269">in English</a>, оригинальный текст - "<a class="reference external" href="https://alex-aka-jj.livejournal.com/66984.html">Совещание</a>" / Алексей Березин).</p> <blockquote> -<div><p>📝 "Есть одно только благо – знание, и одно только зло – невежество." - Сократ</p> +<div><p>Typically, I want the side effects of a domain event to occur within the same logical transaction, but not necessarily in the same scope of raising the domain event. If I cared enough to have the side effects occur, I would instead just couple myself directly to that other service as an argument to my domain's method.</p> +<p>Instead of dispatching to a domain event handler immediately, what if instead we recorded our domain events, and before committing our transaction, dispatch those domain events at that point? This will have a number of benefits, besides us not tearing our hair out. Instead of raising domain events, let's define a container for events on our domain object:</p> +<p>&lt;...&gt;</p> +<p>Just before we commit our transaction, we dispatch our events to their respective handlers.</p> +<p>- "A better domain events pattern" <a class="footnote-reference brackets" href="#fnjbde2" id="id34" role="doc-noteref"><span class="fn-bracket">[</span>19<span class="fn-bracket">]</span></a> by Jimmy Bogard</p> </div></blockquote> +</section> +<section id="kamil-grzybek"> +<h3><a class="toc-backref" href="#id129" role="doc-backlink">Мнение Kamil Grzybek</a></h3> +<p>Вот что говорит Kamil Grzybek:</p> <blockquote> -<div><p>📝 "Те компании, которые не осознают, что знания являются средством производства более важным, чем земля, труд или капитал, постепенно умрут и никогда не поймут, что их погубило."</p> -<p class="attribution">—Ларри Прусак</p> +<div><p>The way of handling of domain events depends indirectly on publishing method. +If you use DomainEvents static class, you have to handle event immediately. +In other two cases you control when events are published as well handlers execution – in or outside existing transaction.</p> +<p>In my opinion <strong>it is good approach to always handle domain events in existing transaction</strong> and treat aggregate method execution and handlers processing as atomic operation. +This is good because if you have a lot of events and handlers you do not have to think about initializing connections, transactions and what should be treat in "all-or-nothing" way and what not.</p> +<p>- "How to publish and handle Domain Events" <a class="footnote-reference brackets" href="#fnkgde1" id="id35" role="doc-noteref"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> </div></blockquote> <blockquote> -<div><p>📝 "Глупость — дар Божий, но злоупотреблять им не следует."</p> -<p class="attribution">—Отто фон Бисмарк</p> +<div><p>Thanks for question Andreas!</p> +<p>I know both books of Vaughn Vernon - they are great and must read for every DDD practitioner. From the DDD Distlled book (chapter 5 about aggregates):</p> +<blockquote> +<div><p><strong>...business rules are the drivers for determining what must be whole, complete, and consistent at the end of a single transaction.</strong></p> +</div></blockquote> +<p>So in general this is good rule to have separate transactions, but sometimes it is impossible or very hard to achieve.</p> +<p>My approach is similar to Vaughn Vernon - I try always handle event in separate transaction if it is possible. +To do that I have two types of events: <strong>Domain Events (private, handled in the same transaction)</strong> and <strong>Domain Events Notifications (handled outside transaction)</strong>. +Domain Event Notification often becomes an Integration Event which is send to Events Bus to other Bounded Context. +This way I support all cases - immediate consistency, eventual consistency and integrations scenarios.</p> +<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/how-to-publish-and-handle-domain-events/#comment-4602236620">How to publish and handle Domain Events</a>" <a class="footnote-reference brackets" href="#fnkgde1" id="id36" role="doc-noteref"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></a>, comment of Kamil Grzybek</p> </div></blockquote> <blockquote> -<div><p>📝 "Nothing will come of nothing."</p> -<p class="attribution">—William Shakespeare,"King Lear"</p> +<div><p>Aggregates can publish multiple Domain Events, and for each Domain Event there can be many handlers responsible for different behavior. +This behavior can be communication with an external system or <strong>executing a Command on another Aggregate</strong>, which will again publish its events to which another part of our system will subscribe.</p> +<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id37" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> </div></blockquote> -</section> -<section id="id8"> -<h2><a class="toc-backref" href="#id16" role="doc-backlink">Рождается ли в споре истина?</a></h2> -<p>Вообще, как показывает практика, в спорах люди ищут самоутверждение, а не истину. -Поэтому, они редко когда заканчиваются истиной. -Каждый хочет, чтобы правда была на его стороне, но не каждый хочет быть на стороне правды.</p> -<p>В спорах сходится два <a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/737">мнения</a>. Мнения могут быть противоречивы, т.к. они могут производиться разным подмножеством опыта двух субъектов спора.</p> -<p>Максимум, что можно достигнуть в споре - это выработать "коллективное мнение". Но оно производится все тем же ограниченным, хотя теперь уже и объединенным, мнением. Это пока еще не знание. Для обретения <a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/399">знания</a> нужно обратиться к максимально широкому опыту индустрии, произвести широкую дивергентную исследовательскую фазу, выявить все существующие в отрасли мнения, обнаружить их противоречия, и путем обобщения и систематизации вывести такую непротиворечивую форму информации, которая, в определенных обстоятельствах, может стать знанием. А эта активность выходит далеко за пределы спора и отличается от спора именно тем, что субъекты не настаивают на своей ограниченной позиции, и прилагают все усилия для максимального расширения того опыта, которым эта позиция формируется.</p> -<p>Иными словами, цель спора - присадить оппонента до своего уровня. А цель постижения знаний - максимально расширить свой охват опыта. Вопрос в том, что если человек хочет расширить свой охват опыта, то он в споре, как в малоэффективном инструменте, не нуждается, поскольку существуют другие, более эффективные источники обретения обобщенного и систематизированного коллективного опыта индустрии.</p> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> -<ul class="simple"> -<li><p>"<a class="reference internal" href="../it/self-education/self-education-for-software-engineer.html#emacsway-self-education-literature"><span class="std std-ref">Список литературы для самообучения разработчика программного обеспечения</span></a>"</p></li> -<li><p>"<a class="reference internal" href="planning-in-psychology.html#emacsway-planning-in-psychology"><span class="std std-ref">Психологическое значение планирования</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../it/sdlc/uncertainty-management/adaptation/software-design/patterns.html#emacsway-agile-patterns"><span class="std std-ref">Role of Design Patterns in Agile</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../it/team-topologies/harlan-mills%27-proposal.html#emacsway-brooks-s-law"><span class="std std-ref">Закон Брукса</span></a>"</p></li> -</ul> -</div> -</section> -</section> -Thu, 01 Jun 2023 00:00:00 Балансирование Бизнес/Технических интересовhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/agile/analysis/concerns/balancing-business-technical-concerns.html -<span id="id1"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id2"> -<p class="topic-title">Содержание</p> +<blockquote> +<div><p>Let's assume that in this particular case <strong>both Order placement and Payment creation should take place in the same transaction</strong>. +If transaction is successful, we need to send 2 emails – about the Order and Payment.</p> +<p>&lt;...&gt;</p> +<ol class="arabic simple"> +<li><p><strong>Command Handler defines transaction boundary. Transaction is started when Command Handler is invoked and committed at the end.</strong></p></li> +<li><p><strong>Each Domain Event handler is invoked in context of the same transaction boundary.</strong></p></li> +<li><p>If we want to process something outside the transaction, we need to create a <strong>public event</strong> based on the Domain Event. I call it Domain Event Notification, <a class="reference external" href="http://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/">some people call it a public event</a>, but the concept is the same.</p></li> +</ol> +<p>The second most important thing is when to publish and process Domain Events? Events may be created after each action on the Aggregate, so we must publish them:</p> <ul class="simple"> -<li><p><a class="reference internal" href="#emacsway-agile-balancing-business-technical-concerns" id="id13">Балансирование Бизнес/Технических интересов</a></p> -<ul> -<li><p><a class="reference internal" href="#id3" id="id14">Поиск баланса</a></p> -<ul> -<li><p><a class="reference internal" href="#emacsway-agile-technical-concerns-predominance" id="id15">Преобладание технических интересов</a></p></li> -<li><p><a class="reference internal" href="#emacsway-agile-business-concerns-predominance" id="id16">Преобладание бизнес-интересов</a></p></li> -<li><p><a class="reference internal" href="#emacsway-agile-solution-to-balancing-business-technical-concerns" id="id17">Решение</a></p> -<ul> -<li><p><a class="reference internal" href="#extreme-programming" id="id18">Extreme Programming</a></p> -<ul> -<li><p><a class="reference internal" href="#xp" id="id19">Первая версия XP</a></p></li> -<li><p><a class="reference internal" href="#emacsway-xp2-balancing-business-technical-concerns" id="id20">Вторая версия XP</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#scrum" id="id21">Scrum</a></p> -<ul> -<li><p><a class="reference internal" href="#the-scrum-guide" id="id22">The Scrum Guide™</a></p></li> -<li><p><a class="reference internal" href="#id8" id="id23">К первоисточнику за сутью</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#atam-in-agile" id="id24">ATAM in Agile</a></p></li> -<li><p><a class="reference internal" href="#emacsway-agile-balancing-business-technical-concerns-with-fixed-iteration-ratio" id="id25">Фиксированная часть итерации на технические задачи</a></p></li> -<li><p><a class="reference internal" href="#open-agile-architecture" id="id26">Open Agile Architecture™</a></p></li> -<li><p><a class="reference internal" href="#id10" id="id27">Системное мышление</a></p></li> -</ul> -</li> -</ul> -</li> -<li><p><a class="reference internal" href="#id11" id="id28">Психологическая сторона вопроса</a></p></li> -</ul> -</li> +<li><p>after each Command handling (but BEFORE committing transaction)</p></li> +<li><p>after each Domain Event handling (but WITHOUT committing transaction)</p></li> </ul> -</nav> -<p>Существует довольно распространенная проблема поиска баланса между краткосрочными бизнес-интересами и долгосрочными техническими интересами проекта.</p> +<p>&lt;...&gt;</p> +<p>The second thing we have to do is to save notifications about Domain Events that we want to process outside of the transaction.</p> +<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id38" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> +</div></blockquote> +<p>Обратите внимание, что, по приведенной им ссылке, под термином "public event" понимается сообщение, выходящее за пределы Bounded Context (к этому вопросу мы еще вернемся):</p> <blockquote> -<div><p>📝 "Краткосрочные индивидуальные цели часто конфликтуют с долгосрочными социальными целями. -Общество решает эту проблему при помощи набора ценностей, подкрепленных мифами, ритуалами, наказаниями и наградами. -Без уважения к этим ценностям люди забывают о социальных нуждах и стремятся реализовать свой собственный индивидуальный краткосрочный интерес. -Четыре ценности для ХР — это: коммуникация (communication), простота (simplicity), обратная связь (feedback), храбрость (courage).</p> -<p>Short-term individual goals often conflict with long-term social goals. -Societies have learned to deal with this problem by developing shared sets of values, backed up by myths, rituals, punishments, and rewards. -Without these values, humans tend to revert to their own short-term best interest. -The four values of XP are: Communication, Simplicity, Feedback, Courage."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 7. Four Values", перевод ООО Издательство "Питер"</p> +<div><p>Set up separate messaging channels for inside the Bounded Context and outside. Keep all events private by default, and indicate the ones you want to make public with an explicit @Public annotation, a marker interface, or an isPublic():bool method. When emitting events, the event publishing mechanism knows to read the annotation and either send the event on the private channel only, or on both the private and the public channel.</p> +<p class="attribution">—"<a class="reference external" href="https://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/">Patterns for Decoupling in Distributed Systems: Explicit Public Events</a>" by Mathias Verraes</p> </div></blockquote> -<p>Спустя 23 года Kent Beck продолжает говорить об актуальности проблемы, упоминув среди ее причин когнитивные искажения:</p> +<p>И, в своем демонстрационном приложении sample-dotnet-core-cqrs-api, <a class="reference external" href="https://github.com/kgrzybek/sample-dotnet-core-cqrs-api/blob/01a1d6517bc88773f004abc0cb9c6d79f537e575/src/SampleProject.Application/Orders/PlaceCustomerOrder/OrderPlacedDomainEventHandler.cs#L22">он демонстрирует обработку Domain Event в одной транзакции с агрегатом</a>.</p> +</section> +<section id="udi-dahan"> +<h3><a class="toc-backref" href="#id130" role="doc-backlink">Мнение Udi Dahan</a></h3> <blockquote> -<div><p>💬 "I've always been puzzled why the balance between structure &amp; behavior investment seems so hard to maintain. -I'm also puzzled why the balance we see in the wild is so heavily tilted towards behavior changes when as I geek I think it should be more balanced.</p> -<p>If "behavior change = revenue" &amp; "structure change = option", then the struggle for balance makes more sense. -It's not about the personalities of Product versus Engineering. -It's not about short-sighted versus visionary thinking. -The struggle is economic — <strong>do we make some money now or more money later</strong>? -The answer is always "both". We have to make some money now to survive. -We want to make more money later. -<strong>Fear versus greed. No wonder it's so hard to get time to refactor.</strong>"</p> -<p class="attribution">—"<a class="reference external" href="https://tidyfirst.substack.com/p/behavior-change-revenue-versus-structure">Behavior Change = Revenue Versus Structure Change = Option</a>" by Kent Beck</p> +<div><p>&gt; This might be a bit of a late question. But shouldn't domain events be handled after the transaction ends? +Is there any specific reason for handle domain events within the same transaction scoping DoSomething?</p> +<p>Domain events get handled by service layer objects in the same process which usually send out other messages – as such, we want those messages to be sent (or not) in the same transactional context.</p> +<p>- "<a class="reference external" href="http://udidahan.com/2009/06/14/domain-events-salvation/#comment-4723">Domain Events – Salvation</a>" <a class="footnote-reference brackets" href="#fnudde3" id="id39" role="doc-noteref"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></a> comment of Udi Dahan</p> </div></blockquote> -<p>Решение этой проблемы было одной из целей создания Agile:</p> <blockquote> -<div><p>📝 "During the <a class="reference external" href="https://martinfowler.com/articles/agileStory.html">Snowbird meeting</a>, Kent Beck said that the goal of Agile was to heal the divide between business and development. To that end, the following bill of rights was developed by Kent, Ward Cunningham, and Ron Jeffries, among others."</p> -<p class="attribution">—"Clean Agile: Back to Basics" by Robert C. Martin</p> +<div><p>&gt; In message number 120 above, Lars asks about how to access the data if the event is fired before the commit. +I didn't understand your response. +Maybe my situation is different so I'll explain.</p> +<p>&gt; I have 2 BCs. +One context deals with the merging of employee information. +I'd like to fire a domain event specifying that the employee was merged. +I'd like the 2nd BC to react to this event. +The issue is that the data won't be committed at that point, and this data that changed is vital to the 2nd BC to react.</p> +<p>&gt; Am I going down the wrong path by attempting to use domain events? Is there another solution you could suggest?</p> +<p>The question is whether you need both your BCs to be consistent with each other at *all* times – ergo in the same transaction.</p> +<p><strong>If the answer is yes, then you absolutely do want the event to be raised and handled in the same transaction – you'd also be deploying both BCs together.</strong></p> +<p>If the answer is no, then you should use some kind of message bus between the BCs. +The handler for the domain event would publish a message using the bus, and that would be enlisted in the same transaction – thus is the first BC rolled back, the message wouldn't be sent. +The second BC would be invoked by the bus when the message arrives at its queue where its handling would then be done in a separate transaction.</p> +<p>- "<a class="reference external" href="http://udidahan.com/2009/06/14/domain-events-salvation/#comment-4730">Domain Events – Salvation</a>" <a class="footnote-reference brackets" href="#fnudde3" id="id40" role="doc-noteref"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></a> comment of Udi Dahan</p> </div></blockquote> <blockquote> -<div><p>📝 "There is <strong>always a tension between advancing product functionality and raising product quality</strong>.</p> -<p>Business pressures tend to make us view engineering problems, software bugs, and manufacturing line irregularities as necessary evils. -We see them as distractions that lie outside the Sprint. -And because developers really like to do new stuff, they often smooth over current product problems, or they postpone resolving them until <strong>the tomorrow that never comes</strong>.</p> -<p>&lt;...&gt;</p> -<p>Fixing issues takes time, so we often defer such work. -We believe that the market benefit is not worth the effort to fix them, or that they displace the "more important," revenue-generating work. -However, McConnell (Software Development 4 [McC96]) has shown that bugs in software <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">slow down the Development Team</span></a> because they cause "stumbling" and work-arounds that create a drag on development. -These impediments actually <strong>slow down other development that isn't directly related to fixing bugs</strong>.</p> -<p>[McC96]Steve McConnell. The XP Customer Role in Practice: Three Studies. Software Development. 4[8]:38—42, 1996, August."</p> -<p class="attribution">—"A Scrum Book: The Spirit of the Game" by Jeff Sutherland, James Coplie, chapter "81 Whack the Mole"</p> +<div><p>&gt; Shouldn't the event only be handled when the transaction commits? +Until the transaction commits, the change to the domain object isn't really permanent, right?</p> +<p>Not necessarily – sometimes you want loose-coupling within the same transaction.</p> +<p>I do agree that often where we find a place ready for logical decoupling it coincides with separate transaction boundaries. +In those cases, using a transactionally-aware technology like NServiceBus will be a better choice for publishing events.</p> +<p>- "<a class="reference external" href="http://udidahan.com/2009/06/14/domain-events-salvation/#comment-4773">Domain Events – Salvation</a>" <a class="footnote-reference brackets" href="#fnudde3" id="id41" role="doc-noteref"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></a> comment of Udi Dahan</p> </div></blockquote> <blockquote> -<div><p>📝 "A frequent frustration amongst software developers is the perception that their management team only values things that can be sold. To management, they believe, architectural refactoring is wasted money, occupying development teams for months at a time without a single additional thing being produced that can be sold. And for that matter, why does it take so long for them to add a feature? (Possible answer: that would be because the architecture has not been refactored in years.)</p> -<p>Management teams do have a business to run and customers do not typically hand over money for architectural refactorings, no matter how elegant they are; so without shiny new things to sell, there may be no money to continue to employ the development teams who want to do the refactoring.</p> -<p>As such, this issue has two aspects: firstly, development teams need to learn how to justify such investment; and secondly, such non-functional investment will always have to be balanced with functional requirements."</p> -<p class="attribution">—"Open Agile Architecture™" by The Open Group, Chapter "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard-single/#KLP-CAR-justifying">6.5.1. Justifying Ongoing Investment in Architectural Refactoring</a>"</p> +<div><p>&gt; Domain event could alter multiple aggregates which is common, wouldn't you be updating multiple aggregates in a single transaction?</p> +<p><strong>The more common case is where those multiple aggregates are updated in separate transactions</strong>, usually as a result of some kind of "service bus" event being transmitted from the domain events. +That service bus event gets routed to multiple subscribers, behind which you'd have each of the respective aggregates that would updated in their own transactions.</p> +<p>- "<a class="reference external" href="http://udidahan.com/2009/06/14/domain-events-salvation/#comment-74959">Domain Events – Salvation</a>" <a class="footnote-reference brackets" href="#fnudde3" id="id42" role="doc-noteref"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></a> comment of Udi Dahan</p> </div></blockquote> -<section id="id3"> -<h2><a class="toc-backref" href="#id14" role="doc-backlink">Поиск баланса</a></h2> -<p>В первой версии XP управление разработкой осуществлялось посредством четырех переменных:</p> -<ul class="simple"> -<li><p>затраты (cost)</p></li> -<li><p>время (time)</p></li> -<li><p>качество (quality)</p></li> -<li><p>объем работ (scope)</p></li> -</ul> -<p>Иногда эти четыре переменные можно встретить в виде Iron Triangle, где <a class="reference external" href="https://en.m.wikipedia.org/wiki/Project_management_triangle">Quality ограничено тремя переменными</a>:</p> -<ul class="simple"> -<li><p>затраты (cost)</p></li> -<li><p>время (time)</p></li> -<li><p>объем работ (scope)</p></li> -</ul> -<p>Хотя сам Martin Barnes, PhD говорил, что:</p> +</section> +<section id="cesar-de-la-torre"> +<h3><a class="toc-backref" href="#id131" role="doc-backlink">Мнение Cesar De la Torre</a></h3> <blockquote> -<div><p>💬 I sketched a diagram to make the point – a triangle with time, cost and quality at the corners.</p> -<p class="attribution">—"<a class="reference external" href="https://pmworldlibrary.net/wp-content/uploads/2018/11/pmwl-barnes-how-it-all-began-pmwt-july-2006.pdf">HOW IT ALL BEGAN</a>" by Martin Barnes, PhD</p> +<div><p>When handling the event, any event handler subscribed to the event could run additional domain operations by using other AggregateRoot objects, but again, you still need to be within the same transaction scope.</p> +<p>&lt;..&gt;</p> +<p>for in-memory event based communication across disconnected aggregates that are part of the same domain model and part of the same transaction, domain events are great ensuring consistency across a single domain model within the same microservice or Bounded-Context.</p> +<p>- "Domain Events vs. Integration Events in Domain-Driven Design and microservices architectures" <a class="footnote-reference brackets" href="#fncdltdevie" id="id43" role="doc-noteref"><span class="fn-bracket">[</span>23<span class="fn-bracket">]</span></a> by Cesar De la Torre, Principal Program Manager, .NET</p> </div></blockquote> -<p>Иными словами, Quality было тождественно (или рассматривалось как составная часть) Scope.</p> -<p>Так или иначе, но на заре Agile качество имело такое существенное и нелинейное влияние на разработку, что Iron Triangle стал квадратом, известным также как The "Project Diamond" model, см.:</p> +<p>Ссылки по теме:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="http://www.betterprojects.net/2009/03/it-used-to-be-iron-triangle.html">It used to be the Iron Triangle</a>". Better Project. by Brown, Craig</p></li> -<li><p>"<a class="reference external" href="https://www.projectsmart.co.uk/lifecycle-and-methodology/introduction-to-project-management.php">Introduction to Project Management</a>" by Duncan Haughey</p></li> +<li><p>"<a class="reference external" href="https://www.allthingsdistributed.com/2008/12/eventually_consistent.html">Eventually Consistent - Revisited</a>" by Werner Vogels, CTO - Amazon.com</p></li> +<li><p>"<a class="reference external" href="https://www.allthingsdistributed.com/2007/12/eventually_consistent.html">Eventually Consistent</a>" by Werner Vogels, CTO - Amazon.com</p></li> </ul> -<p>И только во второй версии XP он превратился в треугольник, но уже без Quality. -Но обо всем по порядку.</p> -<blockquote> -<div><p>📝 "Одним из основополагающих правил нашей стратегии является то, что технари концентрируются на решении технических проблем, а бизнесмены — на решении бизнес-проблем. -Проект должен управляться бизнес-решениями, однако для принятия бизнес-решений должна использоваться информация о затратах и риске, предоставляемая техническими специалистами.</p> -<p>Эта информация является результатом технических решений. -<strong>Существуют два широко распространенных неправильных режима взаимоотношений между бизнесом и разработчиками: когда либо бизнес, либо разработчики получают слишком большую власть над проектом, проект начинает страдать.</strong></p> -<p>One key to our strategy is to keep technical people focused on technical problems and business people focused on business problems. -The project must be driven by business decisions, but the business decisions must be informed by technical decisions about cost and risk.</p> -<p>There are two common failure modes in the relationship between Business and Development. -<strong>If either Business or Development gains too much power, the project suffers.</strong>"</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 14. Splitting Business and Technical Responsibility", перевод ООО Издательство "Питер"</p> -</div></blockquote> -<section id="emacsway-agile-technical-concerns-predominance"> -<span id="id4"/><h3><a class="toc-backref" href="#id15" role="doc-backlink">Преобладание технических интересов</a></h3> -<p>Начнем с преобладания технических интересов.</p> -<p id="emacsway-second-system-effect">Frederick Brooks в своем бестселлере "Мифический человеко-месяц" говорит об "<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%B2%D1%82%D0%BE%D1%80%D0%BE%D0%B9_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B">Эффекте второй системы</a>". -Я приведу небольшой фрагмент:</p> +</section> +</section> +<section id="in-process-vs-out-of-process"> +<h2><a class="toc-backref" href="#id132" role="doc-backlink">In-process vs out-of-process</a></h2> +<p>Обычно считается, что in-process - это синхронное исполнение, а out-of-process - асинхронное. +Хотя, сугубо технически, асинхронное исполнение может быть как in-process, так и out-of-process. +К тому же асинхронное исполнение нужно подразделять на использующее event-loop (async/await) и использующее внешнюю инфраструктуру (external event bus).</p> +<p>В большинстве случаев, in-process подразумевает "в той же транзакции", т.е. Strong Consistency.</p> <blockquote> -<div><p>📝 "Если ответственность за спецификацию функций отделить от ответственности за быстрое создание недорогого продукта, то <strong>чем сдержать изобретательский энтузиазм архитектора</strong>?</p> -<p>If one separates responsibility for functional specification from responsibility for building a fast, cheap product, <strong>what discipline bounds the architect's inventive enthusiasm</strong>?"</p> -<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +<div><p>The reference app uses MediatR to propagate domain events synchronously across aggregates, within a single transaction. +However, you could also use some AMQP implementation like RabbitMQ or Azure Service Bus to propagate domain events asynchronously, using eventual consistency but, as mentioned above, you have to consider the need for compensatory actions in case of failures.</p> +<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id44" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#conclusions-on-domain-events">Domain events: design and implementation :: Conclusions on domain events</a>"</p> </div></blockquote> -<p>Похожую проблему описывает и Kent Beck в "Extreme Programming" 1st edition:</p> +</section> +<section id="internal-vs-external"> +<h2><a class="toc-backref" href="#id133" role="doc-backlink">Internal vs External</a></h2> +<p>Существует ряд методик (Anti-Corruption Layer, CQRS etc.), направленных на то, чтобы защитить изменения внутренних интерфейсов от изменения внешних и наоборот. +Это логично, так как они будут изменяться в разное время, с разной частотой и по разным причинам.</p> +<p>Domain Events могут покидать пределы Bounded Context:</p> <blockquote> -<div><p>📝 "Когда разработчикам предоставляется чрезмерная свобода, они начинают использовать все те новые технологии и процессы, для которых у них никогда не хватает времени, если "эти белые воротнички" постоянно подгоняют их. -Когда разработчикам предоставляется свобода, они устанавливают и начинают использовать новые инструменты разработки, новые языки программирования, новые технологии. -При этом инструменты, языки и технологии выбираются исходя из того, что они очень интересны и суперсовременны. -Все только что появившееся на рынке связано с риском. -(Если мы не попробуем это сейчас, то когда же еще?)</p> -<p>Таким образом, в результате предоставления разработчикам слишком широких полномочий, они прикладывают слишком много усилий и генерируют слишком много риска, при этом <strong>они обеспечивают слишком незначительную отдачу</strong>.</p> -<p>When Development is in charge, they put in place all the process and technology that they never had time for when "those suits" were pushing them around. -They install new tools, new languages, new technologies. -And the tools, languages, and technologies are chosen because they are interesting and cutting edge. -Cutting edge implies risk. -(If we haven't learned that by now, when will we?)</p> -<p>So, the net result of the "Development in Charge" scenario is too much effort and way, way <strong>too much risk for too little return</strong>."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 14. Splitting Business and Technical Responsibility", перевод ООО Издательство "Питер"</p> +<div><p>Using Domain Events will help you both to model explicitly and to share what has occurred within your model with the systems that need to know about it. +<strong>The interested parties might be your own local Bounded Context and other remote Bounded Contexts.</strong></p> +<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id45" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "1. DDD for Me :: Tactical Design"</p> </div></blockquote> <blockquote> -<div><p>📝 "Doing infrastructure without customer function leads to the following risks:</p> -<ul class="simple"> -<li><p>You spend a lot of time not delivering things that are valuable to the customer, which strains the relationship with the customer.</p></li> -<li><p>You try to make the infrastructure cover everything you think you might need, which leads to an overly complex infrastructure."</p></li> -</ul> -<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 10. Release Planning :: How Do You Plan Infrastructure?"</p> +<div><p><strong>Publishing the Event outward to any number Bounded Contexts of other Subdomains (2) emphasizes the word Domain in the term Domain Event.</strong> +In other words, Events are a domain-wide concept, not just a concept in a single Bounded Context. +The contract of Event publishing should have the potential to be at least as broad as the enterprise, or even broader. +Yet, wide broadcast does not forbid delivery of Events by consumers in the same Bounded Context.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id46" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Publishing Events from the Domain Model :: Subscribers"</p> </div></blockquote> +<p>Это выдвигает вопрос по отношению к Domain Events - нужно ли отделять внутренние от внешних? +Проблему озвучивает сам Vaughn Vernon:</p> <blockquote> -<div><p>📝 "Программист является сердцем ХР. -На самом деле если бы программисты могли всегда принимать решения, в которых тщательно балансировались краткосрочные и долгосрочные приоритеты, в рамках проекта не нужны были бы никакие другие технические работники, кроме программистов. -Конечно же если заказчику не требуется программное обеспечение для того, чтобы поддерживать функционирование бизнеса, то никакой надобности в программистах не было бы.</p> -<p>The programmer is the heart of XP. -Actually, if programmers could always make decisions that carefully balanced short-term and long-term priorities, there would be no need for any other technical people on the project besides programmers. -Of course, if the customer didn't absolutely need software to keep the business running, there would be no need for the programmers, so it won't do to get too big-headed about being the vital programmer."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 22. Roles for People", перевод ООО Издательство "Питер"</p> +<div><p><strong>Once your Domain Event is saved to the event store, it can be published to any interested parties . This might be within your own Bounded Context and to external Bounded Contexts.</strong> +This is your way of telling the world that something noteworthy has occurred in your Core Domain.</p> +<p>Are Domain Event Consumers Conformists? +<strong>You may be wondering how Domain Events can be consumed by another Bounded Context [это и есть тот самый волнующий вопрос - прим. мое] and not force that consuming Bounded Context into a Conformist relationship.</strong> +As recommended in Implementing Domain-Driven Design [IDDD] , and specifically in Chapter 13, "Integrating Bounded Contexts," <strong>consumers should not use the event types (e.g., classes) of an event publisher</strong>. +Rather, <strong>they should depend only on the schema of the events</strong>, that is, <strong>their Published Language</strong>. +This generally means that if the events are published as JSON, or perhaps a more economical object format, the consumer should consume the events by parsing them to obtain their data attributes."</p> +<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id47" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events:: Designing, Implementing, and Using Domain Events"</p> </div></blockquote> -<blockquote> -<div><p>📝 "Есть масса примеров, подсказанных другими искусствами и ремеслами, которые -подводят к мнению, что дисциплина идет на пользу. -Действительно, афоризм художника гласит, что "форма освобождает". -Самые ужасные строения — это те, бюджет которых был слишком велик для поставленных целей. -Творческую активность Баха едва ли могла подавлять еженедельная необходимость изготавливать кантату определенного вида. -Я уверен, что архитектура компьютера Stretch стала бы лучше, если бы на нее наложили более жесткие ограничения; так, ограничения, наложенные бюджетом на System/360 Model 30, по моему мнению, принесли лишь пользу архитектуре Model 75.</p> -<p>Аналогично, я считаю, что получение архитектуры извне усиливает, а не подавляет творческую активность группы исполнителей. -Они сразу сосредоточиваются на той части задачи, которой никто не занимался, и в результате изобретательность бьет ключом. -В не ограничиваемой группе большая часть обдумывания и обсуждения посвящена архитектурным решениям в ущерб реализации. [5]</p> -<p>There are many examples from other arts and crafts that lead one to believe that discipline is good for art. -Indeed, an artist's aphorism asserts, "Form is liberating." -The worst buildings are those whose budget was too great for the purposes to be served. -Bach's creative output hardly seems to have been squelched by the necessity of producing a limited-form cantata each week. -I am sure that the Stretch computer would have had a better architecture had it been more tightly constrained; the constraints imposed by the System/360 Model 30's budget were in my opinion entirely beneficial for the Model 75's architecture.</p> -<p>Similarly, I observe that the external provision of an architecture enhances, not cramps, the creative style of an implementing group. -They focus at once on the part of the problem no one has addressed, and inventions begin to flow. -In an unconstrained implementing group, most thought and debate goes into architectural decisions, and implementation proper gets short shrift. [5]"</p> -<ol class="arabic simple" start="5"> -<li><p>Englebart, D., and W. English, "A research center for augmenting human intellect," AFIPS Conference Proceedings, Fall Joint Computer Conference, San Francisco (Dec. 9-11, 1968), pp. 395-410.</p></li> +<p>Тут он четко обозначает проблему, которой рано или поздно задаются многие. И он делает две вещи:</p> +<ol class="arabic simple"> +<li><p>Он разделяет реализацию издания Domain Events внутри Bounded Context (ГОФ-паттерны), от реализации издания Domain Events для других Bounded Contexts (интеграционная шина), которая начинает выполняться после завершения первой.</p></li> +<li><p>Он разделяет Domain Events с публичной схемой, от остальных Domain Events. А это, по сути, и есть то самое, что в ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id48" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> именуется как Integration Event.</p></li> </ol> -<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +<p>Поскольку эти виды Ивентов имеют различные цели, различный способ доставки, различные реализации, различные категории подписчиков, различную область действия и различное назначение, то они, резонно, разделили их на два вида события:</p> +<ol class="arabic simple"> +<li><p>Domain Events, которые действуют исключительно внутри Bounded Context, и доставляются посредством ГОФ-паттернов синхронно или асинхронно (но исключительно in-process, используя event-loop и async/await конструкции) в той же транзакции.</p></li> +<li><p>Integration Event, которые выходят за пределы Bounded Context, доставляются интеграционной шиной, всегда асинхронны и в другой транзакции.</p></li> +</ol> +<p>Такого же мнения придерживается и Kamil Grzybek, называя внешние события (public event, которые уже упоминались) термином "Domain Event Notifications":</p> +<blockquote> +<div><p>Last thing to consider is processing of Domain Event Notifications (public events). We need to find a way to process them outside transaction and here Outbox Pattern comes in to play.</p> +<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id49" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> </div></blockquote> -<p>К этой же категории относится и т.н. Resume-Driven Development, когда разработчики безобоснованно переусложняют проект сложными технологиями ради очередной отметки о достижении в резюме.</p> -</section> -<section id="emacsway-agile-business-concerns-predominance"> -<span id="id5"/><h3><a class="toc-backref" href="#id16" role="doc-backlink">Преобладание бизнес-интересов</a></h3> -<p>Но есть и обратная проблема - когда технические специалисты ущемлены в своих полномочиях в пользу представителей бизнеса, проект неизменно загнивает, а <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">экономика разработки деградирует с зависимостью, приближенной к экспоненциальной</span></a>.</p> <blockquote> -<div><p>📝 "Когда бизнесмены получают слишком много полномочий, они начинают диктовать разработчикам значения для всех четырех переменных. -"Вот то, что ты должен сделать. -Это должно быть сделано тогда-то и тогда-то. -Нет, тебе не дадут ни одной дополнительной рабочей станции. -И для тебя будет лучше, если ты сделаешь эту работу с наивысшим возможным качеством, иначе у тебя будут проблемы. -Ты меня хорошо понял? Скотина ленивая!"</p> -<p>В такой ситуации бизнес предписывает слишком многое. -Некоторые элементы в списке требований абсолютно обязательны, но некоторые — нет. -И если у разработчиков не будет никаких полномочий, они не смогут возразить. -Они не смогут принудить бизнес выбрать правильный вариант. -И тогда разработчики, понурив голову, идут работать над невыполнимой задачей, которую перед ними поставили.</p> -<p>Как правило, наименее важные требования являются причиной наибольшего риска. -Похоже, это является следствием их природы. -Они меньше всего обдумываются, меньше всего анализируются и меньше всего осмысливаются, поэтому вероятность того, что именно они изменятся в процессе разработки, выше всего. -Очень часто такие требования оказываются также наиболее рискованными с технической точки зрения.</p> -<p><strong>В результате, если бизнес получает слишком большие полномочия, проект требует слишком много усилий и генерирует слишком много риска, при этом он</strong> <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">обеспечивает слишком незначительную отдачу</span></a>.</p> -<p>If Business has the power, they feel fit to dictate all four variables to Development. -"Here is what you will do. -Here is when it will be done. -No, you can't have any new workstations. -And it better be of the highest quality or you're in trouble, buster."</p> -<p>In this scenario, Business always specifies too much. -Some of the items on the list of requirements are absolutely essential. -But some are not. -And if Development doesn't have any power, they can't object; they can't force Business to choose which is which. -So Development dutifully goes to work, heads down, on the impossible task they have been given.</p> -<p>It seems to be in the nature of the less important requirements that they entail the greatest risk. -They are typically the poorest understood, so there is great risk that the requirements will change all during development. -Somehow, they also tend to be technically riskier.</p> -<p><strong>The result of the "Business in Charge" scenario, then, is that the project takes on too much effort and way, way too much risk for</strong> <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">too little return</span></a>."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 14. Splitting Business and Technical Responsibility", перевод ООО Издательство "Питер"</p> +<div><p>Sometimes, however, it is necessary to communicate with 3rd party service (for example e-mail or web service) based on Domain Event. +As we know, communication with 3rd party services is not usually transactional so we need some additional generic mechanism to handle these types of scenarios. +So I created Domain Events Notifications.</p> +<p>&lt;...&gt;</p> +<p>There is no such thing as domain events notifications in DDD terms. +I gave that name because I think it fits best – it is notification that domain event was published.</p> +<p>&lt;..&gt;</p> +<p>For non-trasactional operations Domain Events Notifications were introduced.</p> +<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/how-to-publish-and-handle-domain-events/">How to publish and handle Domain Events</a>" <a class="footnote-reference brackets" href="#fnkgde1" id="id50" role="doc-noteref"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> </div></blockquote> +<p>В одном из своих комментариев он связывает "Domain Event Notification" с "Integration Events":</p> +<p>My approach is similar to Vaughn Vernon - I try always handle event in separate transaction if it is possible. To do that I have two types of events: Domain Events (private, handled in the same transaction) and Domain Events Notifications (handled outside transaction). Domain Event Notification often becomes an <strong>Integration Event</strong> which is send to Events Bus to other Bounded Context. This way I support all cases - immediate consistency, eventual consistency and integrations scenarios.</p> <blockquote> -<div><p>📝 "Закон Вайнберга-Брукса: От действий менеджеров, основанных на неправильных моделях системы, пострадало больше проектов, чем от всех остальных причин вместе взятых.</p> -<p>Weinberg-Brooks' Law: More software projects have gone awry from management's taking action based on incorrect system models than for all other causes combined."</p> -<p class="attribution">—"<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems Thinking</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">на русском</a>)</p> +<div><p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/how-to-publish-and-handle-domain-events/#comment-4602236620">How to publish and handle Domain Events</a>" <a class="footnote-reference brackets" href="#fnkgde1" id="id51" role="doc-noteref"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></a>, comment of Kamil Grzybek</p> </div></blockquote> +<p>Обратите внимание на окончание - там перечислены три сценария:</p> +<ol class="arabic simple"> +<li><p>Immediate consistency</p></li> +<li><p>Eventual consistency</p></li> +<li><p>Integrations scenarios</p></li> +</ol> +<p>В другом комментарии он вносит уточнение:</p> <blockquote> -<div><p>📝 "Scrum is by far the most widely used agile framework in the world, but we've also found that 58% of Scrum implementations fail."</p> -<p class="attribution">—"<a class="reference external" href="https://www.scruminc.com/better-scrum-with-essence/">Better Scrum with Essence</a>" Jeff Sutherland</p> +<div><p>Domain Event - private event, not persisted [Outbox], part of UL</p> +<p>Domain Event Notification - private event, persisted [Outbox], part of UL. Sometimes called "persisted event"</p> +<p>Integration event - public event, part of PL as you described</p> +<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/#comment-5205858557">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id52" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> </div></blockquote> +<p>Здесь у него, правда, наблюдается небольшое противоречие с предыдущим его комментарием:</p> <blockquote> -<div><p>📝 "Мы попробовали различные варианты работы с техническими историями. -Мы пробовали считать их самыми обычными user story. -Это была неудачная идея: для product owner'а приоритезировать их в product backlog'е было всё равно, что сравнить тёплое с мягким. -По очевидным причинам технические истории получали самый низкий приоритет с объяснением: -"Да, ребята, несомненно, ваш сервер непрерывной интеграции – очень важная штука, но давайте сперва реализуем кое-какие прибыльные функции? -После этого вы можете прикрутить вашу техническую конфетку, окей?"</p> -<p>В некоторых случаях product owner действительно прав, но чаще все-таки нет. -Мы пришли к выводу, что product owner не всегда компетентен, чтобы идти на компромисс.</p> -<p>We've experimented a lot with different ways of handling tech stories. -We tried treating them as first-class stories, just like any others. -That was no good; when the product owner prioritized the product backlog, it was like comparing apples with oranges. -In fact, for obvious reasons, the tech stories were often given low priority with the motivation like -"Yeah guys, I'm sure a continuous-build server is important and all, but let's build some revenue-driving features first shall we? -Then you can add your tech candy later, OK?"</p> -<p>In some cases the product owner is right, but often not. -We've concluded that the product owner is not always qualified to be making that tradeoff."</p> -<p class="attribution">—"Scrum and XP from the Trenches: How We Do Scrum" 2nd edition by Henrik Kniberg, перевод под редакцией Алексея Кривицкого</p> +<div><p>If you want to process Domain Event in separate transaction, you need to create Domain Event Notification <strong>(public event)</strong> which is saved within the same transaction to the Outbox but processed in different (Outbox processing).</p> +<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/#comment-4507778871">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id53" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> </div></blockquote> -</section> -<section id="emacsway-agile-solution-to-balancing-business-technical-concerns"> -<span id="id6"/><h3><a class="toc-backref" href="#id17" role="doc-backlink">Решение</a></h3> +<p>А так же, наблюдается противоречие с другим его выражением, где он, ссылаясь на определение Mathias Verraes, приравнивает Domain Event Notification к "public event":</p> <blockquote> -<div><p>📝 "You notice we have two different criteria set by two different groups of people. -How do we resolve the two of them? -Programmers want to tackle high-risk stories first, and customers want to tackle high-value stories first. -There are plenty of times when these conflicting priorities have to be resolved."</p> -<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 13. Ordering the Stories :: Negotiating Between the Two"</p> +<div><ol class="arabic simple" start="3"> +<li><p>If we want to process something outside the transaction, we need to create a <strong>public event</strong> based on the Domain Event. I call it Domain Event Notification, <a class="reference external" href="http://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/">some people call it a public event</a>, but the concept is the same.</p></li> +</ol> +<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/">Handling Domain Events: Missing Part</a>" <a class="footnote-reference brackets" href="#fnkgde2" id="id54" role="doc-noteref"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> </div></blockquote> +<p>Как уже упоминалось ранее, по приведенной им ссылке, под термином "public event" понимается сообщение, выходящее за пределы Bounded Context:</p> <blockquote> -<div><p>📝 "Our planning process relies on clearly separating the roles of business people and software people. -This ensures that business people make all the business decisions and software people make all the technical decisions.</p> -<p>The key to project management is balancing power between the business people and the programmers. -Done right, software project management has</p> -<ul class="simple"> -<li><p>Business people making business decisions</p></li> -<li><p>Technical people making technical decisions"</p></li> -</ul> -<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 4. Balancing Power"</p> +<div><p>Set up separate messaging channels for inside the Bounded Context and outside. Keep all events private by default, and indicate the ones you want to make public with an explicit @Public annotation, a marker interface, or an isPublic():bool method. When emitting events, the event publishing mechanism knows to read the annotation and either send the event on the private channel only, or on both the private and the public channel.</p> +<p class="attribution">—"<a class="reference external" href="https://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/">Patterns for Decoupling in Distributed Systems: Explicit Public Events</a>" by Mathias Verraes</p> </div></blockquote> +<p>Но, в целом, понятно, что Domain Event обрабатывается внутри транзакции, Domain Event Notification - вне транзакции (и может требовать Outbox pattern), и Integration Event - за пределами Bounded Context.</p> +<p>Позже Kamil Grzybek публикует в Twitter <a class="reference external" href="https://twitter.com/kamgrzybek/status/1471756563400605701?t=DO3_TJK0jncMCGlvb34UuA&amp;s=19">следующее разъяснение</a>:</p> <blockquote> -<div><p>📝 "Это достаточно сложно — разработать процесс, в рамках которого краткосрочные личные интересы служат долгосрочным интересам всей команды. -Вы можете сколько угодно рассуждать на тему, насколько та или иная методика способствует достижению долгосрочной всеобщей цели, однако как только вы оказываетесь под давлением, вы обнаруживаете, что если методика не способствует решению конкретной проблемы, стоящей перед вами в настоящий момент, вы отбрасываете ее в сторону. -Если дисциплина ХР не будет удовлетворять краткосрочным личным интересам людей, она обречена на провал.</p> -<p>It's been tricky, designing a process where following short-term self-interest also serves long-term team interest. -You can expound all you want on how some practice or other is in everybody's best interest long-term, but when the pressure mounts, if the practice doesn't solve an immediate problem it will be discarded. -If XP can't work with people's short-term interest, it is doomed to the outer methodological darkness."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 8. Basic Principles", перевод ООО Издательство "Питер"</p> +<div><p>In your system you should have 3 types of events:</p> +<ol class="arabic simple"> +<li><p>Private, domain events (sth important occured in your domain)</p></li> +<li><p>Private, persisted events (based on 1, for later async processing)</p></li> +<li><p>Public, integration events (based on 2, to integrate with another contexts, part of contract)</p></li> +</ol> +<p class="attribution">—<a class="reference external" href="https://twitter.com/kamgrzybek/status/1471756563400605701?t=DO3_TJK0jncMCGlvb34UuA&amp;s=19">Источник</a></p> </div></blockquote> -<p>Хорошая организация процессов должна взаимокомпенсировать эти перекосы.</p> -<p>Под техническими интересами в данном случае понимаются, в первую очередь, такие Quality Attributes, как <a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=8299">Modifiability</a>, Evolvability, Flexibility, Modularity, Testabilty, Deployability etc.</p> -<p>Разрешение противоречий требований различных групп стейкхолдеров хорошо изучены анализом и архитектурой.</p> +<p>И сопровождает его <a class="reference external" href="https://twitter.com/kamgrzybek/status/1472232661938843657?t=czUCrilodujW8aAIdV6OBw&amp;s=19">иллюстрацией</a>:</p> +<figure class="align-left" id="id112"> +<a class="reference internal image-reference" href="../../../../../../_images/domain-vs-integration-event-by-kamil-grzybek.jpeg"><img alt="The difference between event types. The image source is https://twitter.com/kamgrzybek/status/1472232661938843657?t=czUCrilodujW8aAIdV6OBw&amp;s=19" src="../../../../../../_images/domain-vs-integration-event-by-kamil-grzybek.jpeg" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">The difference between event types.</span></p> +<div class="legend"> +<p>— <a class="reference external" href="https://twitter.com/kamgrzybek/status/1472232661938843657?t=czUCrilodujW8aAIdV6OBw&amp;s=19">Источник</a></p> +</div> +</figcaption> +</figure> +<p>Еще дальше идут авторы книги "Patterns, Principles, and Practices of Domain-Driven Design" <a class="footnote-reference brackets" href="#fnpppddd" id="id55" role="doc-noteref"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></a>, вводя явное разделение внутренних и внешних событий:</p> +<figure class="align-center" id="id113"> +<a class="reference internal image-reference" href="../../../../../../_images/pppddd-18.1.png"><img alt="FIGURE pppddd-18-1: Ensuring correct transactional behavior. The image source is &quot;Patterns, Principles, and Practices of Domain-Driven Design&quot; by Scott Millett, Nick Tune" src="../../../../../../_images/pppddd-18.1.png" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">FIGURE pppddd-18-1: Ensuring correct transactional behavior. The image source is "Patterns, Principles, and Practices of Domain-Driven Design" by Scott Millett, Nick Tune</span></p> +</figcaption> +</figure> <blockquote> -<div><p>📝 "Stakeholder Priority. The <strong>priority of each requirement</strong> should be identified. -This may be established through a consensus process among potential stakeholders. -As appropriate, a scale such as 1-5 or a simple scheme such as High, Medium or Low, could be used for identifying the priority of each requirement. -The priority is not intended to imply that some requirements are not necessary, but it may indicate what <strong>requirements are candidates for the trade space when decisions regarding alternatives are necessary</strong>. -Prioritization needs to consider the stakeholders who need the requirements. -This <strong>facilitates trading off requirements</strong> and balancing the impact of changes among stakeholders."</p> -<p>📝 "trade-off - decision-making actions that select from various requirements (3.1.19) and alternative solutions on the basis of net benefit to the stakeholders (3.1.28)"</p> -<p>📝 "It is important to continue to perform requirements negotiation during the analysis and allocation of requirements, <strong>because conflicts will occur</strong>. -Negotiation might be needed among stakeholders requiring mutually incompatible features, or due to <strong>conflicts between desired performance requirements, constraints, available budget, and delivery schedule</strong>. -In most cases, it is necessary to consult with the stakeholder(s) <strong>to reach a consensus on an appropriate trade-off</strong>. -It is often important for contractual reasons that such decisions are traceable to the stakeholder. -<strong>Various analysis methods and conflict resolution techniques may be applicable to facilitate the resolution and are dependent on the specific situation.</strong> -Some organizations consider requirements negotiation to be part of requirements validation. -The specific process subcategory is not important as long as the conflict resolution occurs as early as possible in the requirements analysis task."</p> -<p class="attribution">—"ISO/IEC/IEEE 29148:2018 Systems and software engineering — Life cycle processes — Requirements engineering", "6.2.3.3 Analyze and maintain stakeholder requirements."</p> +<div><p>An important distinction needs to be made when using the domain events pattern to avoid confusion that can lead to poor technical implementations. It is crucial that you are aware of the difference between internal and external events. Internal events are internal to a domain model–they are not shared between bounded contexts. +In this chapter, you will see how the domain events pattern uses internal events, whereas you saw external events in Part II of this book.</p> +<p>Differentiating internal and external events is important because they have different characteristics. +Because internal events are limited in scope to a single bounded context, it is Ok to put domain objects on them, as the example in Listing 18‐1 showed. This poses no risk, because other bounded contexts cannot become coupled to these domain objects. +Conversely, external events tend to be flat in structure, exposing just a few properties—most of the time just correlational IDs, as typified in Listing 18‐3.</p> +<p>You learned in Part II that external events need to be versioned to avoid breaking changes. +This is another differentiator with internal events, because if you make breaking changes to an internal event your code will not compile (if using a compiled programming language). So there's no need to version internal events.</p> +<p>As you start to implement domain events, you will see that in a typical business use case there may be a number of internal events raised, and just one or two external events that are raised by the service layer. +Figure 18-2 illustrates how the sequence of events may occur in a typical use case.</p> +<p>With all of these differences in mind, it makes sense to put your events in different namespaces to accentuate those that are internal from those that are external.</p> +<p>- "Patterns, Principles, and Practices of Domain-Driven Design" <a class="footnote-reference brackets" href="#fnpppddd" id="id56" role="doc-noteref"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></a> by Scott Millett, Nick Tune, Chapter "18 Domain Events :: Internal vs External Events"</p> </div></blockquote> -<p>Существует целый ряд достаточно зрелых методик, направленных на достижение сбалансированных решений. -Четвертое издание книги "Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman наглядно демонстрирует, как можно интегрировать их в итеративную (agile) разработку.</p> -<p>Появились легковесные варианты этих методик: Lightweight Architecture Evaluation (LAE), Mini-QAW etc. -Многие из этих методик описаны в "<a class="reference external" href="https://www.iso.org/standard/73436.html">ISO/IEC/IEEE 42030:2019 Software, systems and enterprise — Architecture evaluation framework</a>".</p> -<p>Однако, легковесные реализации agile-модели разработки предлагают свои, предельно упрощенные, процессы достижения баланса между краткосрочными бизнес-интересами и долгосрочными техническими интересами.</p> -<p>Если разобраться во всех этих обстоятельствах, то можно убедиться в невозможности избежать конфликта интересов. -Это нормально, так как это отражает неизбежный конфликт ресурсов и невозможность одновременного удовлетворения всех требований различных групп стейкхолдеров, которые зачастую обратно коррелируют. -Нужно не предотвращать этот конфликт, - эта задача есть невозможная, а управлять им путем разрешения противоречий. -В противном случае, вполне естественный конфликт интересов может перерасти в неестественный конфликт межличностный (в лучшем случае), или даже привести к <a class="reference internal" href="business-concerns/developer-motivation.html#emacsway-developer-motivation"><span class="std std-ref">потере кадров</span></a> (в худшем случае).</p> -<section id="extreme-programming"> -<span id="emacsway-xp-balancing-business-technical-concerns"/><h4><a class="toc-backref" href="#id18" role="doc-backlink">Extreme Programming</a></h4> -<section id="xp"> -<span id="emacsway-xp1-balancing-business-technical-concerns"/><h5><a class="toc-backref" href="#id19" role="doc-backlink">Первая версия XP</a></h5> -<p>Решение этой проблемы хорошо описано в главе "Chapter 14. Splitting Business and Technical Responsibility" книги "Extreme Programming Explained" 1st edition by Kent Beck. -Решение слишком объемное, чтобы поместить его сюда полностью, поэтому, я приведу только ключевые его моменты.</p> +<figure class="align-center" id="id114"> +<a class="reference internal image-reference" href="../../../../../../_images/pppddd-18.2.png"><img alt="FIGURE pppddd-18-2: Flow of internal and external events in a typical business use case. The image source is &quot;Patterns, Principles, and Practices of Domain-Driven Design&quot; by Scott Millett, Nick Tune" src="../../../../../../_images/pppddd-18.2.png" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">FIGURE pppddd-18-2: Flow of internal and external events in a typical business use case. The image source is "Patterns, Principles, and Practices of Domain-Driven Design" by Scott Millett, Nick Tune</span></p> +</figcaption> +</figure> +<p>Разделяют Domain Events на внутренние и внешние и специалисты .NET.</p> <blockquote> -<div><p>📝 "Что делать?</p> -<p>Решение состоит в том, чтобы определенным образом <strong>разделить полномочия и ответственность между бизнесом и разработчиками</strong>. -<strong>Бизнесмены должны принимать решения в своей области компетенции, а программисты должны принимать решения в своей области компетенции.</strong> -Решения, принятые одной стороной, должны стать базой для решений, принимаемых другой стороной. -Ни одна сторона не должна в одностороннем порядке решать абсолютно все.</p> -<p>What to Do?</p> -<p>The solution is to somehow <strong>split the responsibility and power between Business and Development</strong>. -<strong>Business people should make the decisions for which they are suited.</strong> -<strong>Programmers should make the decisions for which they are suited.</strong> -Each party's decisions should inform the other's. -Neither party should be able to unilaterally decide anything."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 14. Splitting Business and Technical Responsibility", перевод ООО Издательство "Питер"</p> +<div><p>Basically, by differentiating between Domain Events and Integration Events you can solve the issue of dealing with transactions since domain events are always scoped within a transaction but integration events (using an EventBus.Publish()) are only published to the outside world if the transaction was committed successfully. +By doing this you can be sure that other domain-models, microservices and external systems do not react on something that in fact has rolled back and does not exist anymore.</p> +<p>- "Domain Events vs. Integration Events in Domain-Driven Design and microservices architectures" <a class="footnote-reference brackets" href="#fncdltdevie" id="id57" role="doc-noteref"><span class="fn-bracket">[</span>23<span class="fn-bracket">]</span></a> by Cesar De la Torre, Principal Program Manager, .NET</p> </div></blockquote> <blockquote> -<div><p>📝 "В данной главе я расскажу вам о модели разработки программного обеспечения, которая представляет собой систему контролируемых переменных. -В рамках данной модели разработка программного обеспечения определяется с использованием следующих четырех переменных:</p> -<ul class="simple"> -<li><p>затраты (cost);</p></li> -<li><p>время (time);</p></li> -<li><p>качество (quality);</p></li> -<li><p>объем работ (scope).</p></li> -</ul> -<p>В данном случае игра в разработку программного обеспечения выглядит следующим образом: <strong>внешние силы (заказчики, менеджеры) должны определить значения для любых трех переменных из указанного набора, при этом команда разработчиков должна выбрать результирующее значение для оставшейся переменной</strong>.</p> -<p>Некоторые менеджеры и заказчики полагают, что они обладают правом с успехом установить значение для всех четырех переменных. -"Вы обязаны реализовать все, что указано в техническом задании к первому числу следующего месяца, работая в текущем составе, то есть без увеличения численности, при этом качество должно стоять на первом месте и не уступать нашим обычным стандартам". -Когда происходит подобное, <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">качество, как правило, летит ко всем чертям</span></a> (и это, к сожалению, как раз и является общераспространенным стандартом), потому что никто не в состоянии хорошо делать свою работу под слишком большим давлением. -Помимо качества, время, как правило, также выходит из-под контроля. -Таким образом, вы производите некачественное программное обеспечение, не успевая при этом сдать работу к сроку.</p> -<p>Чтобы решить проблему, необходимо сделать все четыре переменные наблюдаемыми. -Если все — программисты, заказчики и менеджеры — смогут наблюдать за поведением всех четырех переменных, будет легче сознательно выбрать, какие из четырех переменных следует контролировать. -Если результирующее значение четвертой переменной окажется неприемлемым, можно будет либо изменить входные значения, либо выбрать для контроля другие три переменные.</p> -<p>Here is a model of software development from the perspective of a system of control variables. -In this model, there are four variables in software development:</p> -<ul class="simple"> -<li><p>Cost</p></li> -<li><p>Time</p></li> -<li><p>Quality</p></li> -<li><p>Scope</p></li> -</ul> -<p>The way the software development game is played in this model is that <strong>external forces (customers, managers) get to pick the values of any three of the variables</strong>. -<strong>The development team gets to pick the resultant value of the fourth variable.</strong></p> -<p>Some managers and customers believe they can pick the value of all four variables. -"You are going to get all these requirements done by the first of next month with exactly this team. -And quality is job one here, so it will be up to our usual standards." -When this happens, <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">quality always goes out the window</span></a> (this is generally up to the usual standards, though), since nobody does good work under too much stress. -Also likely to go out of control is time. -You get crappy software late.</p> -<p>The solution is to make the four variables visible. -If everyone—programmers, customers, and managers—can see all four variables, they can consciously choose which variables to control. -If they don't like the result implied for the fourth variable, they can change the inputs, or they can pick a different three variables to control."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 4. Four Variables", перевод ООО Издательство "Питер"</p> +<div><p>Domain events versus integration events</p> +<p>Semantically, domain and integration events are the same thing: notifications about something that just happened. +However, their implementation must be different. +Domain events are just messages pushed to a domain event dispatcher, which could be implemented as an in-memory mediator based on an IoC container or any other method.</p> +<p>On the other hand, the purpose of integration events is to propagate committed transactions and updates to additional subsystems, whether they are other microservices, Bounded Contexts or even external applications. +Hence, they should occur only if the entity is successfully persisted, otherwise it's as if the entire operation never happened.</p> +<p>As mentioned before, integration events must be based on asynchronous communication between multiple microservices (other Bounded Contexts) or even external systems/applications.</p> +<p>Thus, the event bus interface needs some infrastructure that allows inter-process and distributed communication between potentially remote services. +It can be based on a commercial service bus, queues, a shared database used as a mailbox, or any other distributed and ideally push based messaging system.</p> +<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id58" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#domain-events-versus-integration-events">Domain events: design and implementation :: Domain events versus integration events</a>"</p> </div></blockquote> -</section> -<section id="emacsway-xp2-balancing-business-technical-concerns"> -<span id="id7"/><h5><a class="toc-backref" href="#id20" role="doc-backlink">Вторая версия XP</a></h5> -<p>Сам же Kent Beck и преобразовал позже квадрат (Quality, Cost, Time, Scope) в треугольник (Cost, Time, Scope), путем преобразования качества (Quality) из переменной в константу.</p> -<p>Если в первой версии XP он боролся за то, чтобы Quality (или хотя бы любую одну из 4-х переменных управления разработкой) контролировали технические специалисты, то во второй версии он и вовсе преобразовал качество в константу.</p> -<p>Вот что он пишет во втором издании:</p> <blockquote> -<div><p>📝 "Quality</p> -<p>Sacrificing quality is not effective as a means of control. -<strong>Quality is not a control variable.</strong> -Projects don't go faster by accepting lower quality. -They don't go slower by demanding higher quality. -Pushing quality higher often results in faster delivery; while lowering quality standards often results in later, less predictable delivery.</p> -<p>One of my biggest surprises since the first edition of Extreme Programming Explained was released has been just how far teams have been able to push quality as measured in defects, design quality, and the experience of development. -Each increase in quality leads to improvements in other desirable project properties, like productivity and effectiveness, as well. -<strong>There is no apparent limit to the benefits of quality, only limits in our ability to understand how to achieve higher quality.</strong></p> -<p>Quality isn't a purely economic factor. -People need to do work <a class="reference internal" href="business-concerns/developer-motivation.html#emacsway-developer-motivation"><span class="std std-ref">they are proud of</span></a>. -I remember talking to the manager of a mediocre team. -He went home on the weekends and made fancy ironwork as a blacksmith. -He met his need for quality; he just met it outside of work.</p> -<p><strong>If you can't control projects by controlling quality, how can you control them?</strong> -Time and cost are most often fixed. -XP chooses scope as the primary means of planning, tracking, and steering projects. -Since scope is never known precisely in advance, it makes a good lever. -The weekly and quarterly cycles provide explicit points for tracking and choosing scope.</p> -<p>A concern for quality is no excuse for inaction. -If you don't know a clean way to do a job that has to be done, do it the best way you can. -If you know a clean way but it would take too long, do the job as well as you have time for now. -Resolve to finish doing it the clean way later. -This often occurs during architectural evolution, where you have to live with two architectures solving the same problem while you transition from one to the other. -Then the transition itself becomes a demonstration of quality: making a big change efficiently in small, safe steps."</p> -<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck</p> +<div><p>Domain events can generate integration events to be published outside of the microservice boundaries</p> +<p>Finally, it's important to mention that you might sometimes want to propagate events across multiple microservices. +That propagation is an integration event, and it could be published through an event bus from any specific domain event handler.</p> +<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id59" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#domain-events-can-generate-integration-events-to-be-published-outside-of-the-microservice-boundaries">Domain events: design and implementation :: Implement domain events :: Domain events can generate integration events to be published outside of the microservice boundaries</a>"</p> </div></blockquote> -<p>Кроме того, во втором издании Kent Beck упоминает книгу "Joint Application Development", и сопровождает её таким комментарием:</p> <blockquote> -<div><p>📝 "Annotated Bibliography</p> -<p>Reading a wide range of books around a topic adds to the richness of my understanding. Here are a few suggestions for interesting reading on ideas related to XP."</p> -<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Annotated Bibliography :: Project Management"</p> +<div><p>Model information about activity in the domain as a series of discrete events. Represent each event as a domain object. These are distinct from system events that reflect activity within the software itself, although often a system event is associated with a domain event, either as part of a response to the domain event or as a way of carrying information about the domain event into the system.</p> +<p>- "Domain-Driven Design Reference" <a class="footnote-reference brackets" href="#fndddr" id="id60" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Domain Events"</p> </div></blockquote> <blockquote> -<div><p>📝 "Jane Wood and Denise Silver , Joint Application Development, 2nd edition, John Wiley and Sons, 1995; ISBN 0471042994.</p> -<p>JAD facilitators facilitate without directing, give power to people who know best how to make a decision, and eventually fade away. -<strong>JAD is focused on creating a requirements document that the developers and customers agree can and should be implemented.</strong>"</p> -<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Annotated Bibliography :: Project Management"</p> +<div><p>More importantly, the outside API is tightly coupled to the internal structure of the Bounded Context. Changing the internals would force an API change.</p> +<p>&lt;..&gt;</p> +<p>Set up separate messaging channels for inside the Bounded Context and outside.</p> +<p>&lt;..&gt;</p> +<p>In general, my feeling is that the problem seldom occurs when the Domain Events have been chosen carefully to reflect the business domain, using Ubiquitous Language, and at the right granularity. +These events then tend to become stable very quickly during development, and rarely need to be altered. +When there are significant changes in the domain, the events may need to change, but in these cases you'll need an API change anyway.</p> +<p>That said, it's a universally useful heuristic in software design to keep everything as closed off as possible, and only open up things where there's a good case for it.</p> +<p>- "Patterns for Decoupling in Distributed Systems: Explicit Public Events" <a class="footnote-reference brackets" href="#fnmvpe" id="id61" role="doc-noteref"><span class="fn-bracket">[</span>25<span class="fn-bracket">]</span></a> by Mathias Verraes</p> </div></blockquote> +</section> +<section id="one-phase-vs-two-phase"> +<h2><a class="toc-backref" href="#id134" role="doc-backlink">One-phase vs Two-phase</a></h2> +<p>Ответ на вопрос о разделении доставки Domain Events во многом зависит от того, разделять ли Domain Events на внутренние и внешние?</p> +<p>Хотя у Vaughn Vernon такое разделение не совсем очевидное, он разделяет реализацию доставки для подписчиков внутри Bounded Context и за его пределами.</p> +<figure class="align-center" id="id115"> +<a class="reference internal image-reference" href="../../../../../../_images/iddd-8.1.png"><img alt="Figure 8.1. Aggregates create Events and publish them. Subscribers may store Events and then forward them to remote subscribers, or just forward them without storing. Immediate forwarding requires XA (two-phase commit) unless messaging middleware shares the model's data store. The image source is &quot;Implementing Domain-Driven Design&quot; by Vaughn Vernon" src="../../../../../../_images/iddd-8.1.png" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">Figure 8.1. Aggregates create Events and publish them. +<strong>Subscribers may store Events and then forward them to remote subscribers, or just forward them without storing.</strong> +Immediate forwarding requires XA (two-phase commit) unless messaging middleware shares the model's data store. +The image source is "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id62" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon</span></p> +</figcaption> +</figure> <blockquote> -<div><p>📝 "The facilitated <strong>JAD workshop brings key users (stakeholders) and systems professionals together to resolve their differences in a neutral, non-hostile atmosphere</strong>. -<strong>Key to the workshop is a specially trained, unbiased facilitator who is not a member of the project team and therefore has no political stake in the outcome of the workshop.</strong> -The workshop will build a team that will stay together, psychologically at least, for the life of the project.</p> -<p>&lt;...&gt;</p> -<p>The Key Players</p> -<ol class="arabic simple"> -<li><p>The Facilitator</p></li> -</ol> -<p>The facilitator is in charge of the workshop - the guardian of the process. -It is the facilitator's responsibility to ensure that the expected workshop deliverables are produced and the expected consensus is achieved. -The facilitator is an unbiased leader who has no ties to the project. -He can come from some other department or from outside the company. -Some companies are training facilitators who work out of a facilitation center attached to the human resources department."</p> -<p class="attribution">—"<a class="reference external" href="https://web.archive.org/web/20090221042620/http://www.bee.net/bluebird/jaddoc.htm">Joint Application Design. Business Requirements Analysis for Successful Re-engineering</a>" by Bill Jennerich</p> +<div><p>Forwarding the Event via a messaging infrastructure would allow asynchronous delivery to out-of-band subscribers. +Each of those asynchronous subscribers could arrange to modify an additional Aggregate instance in one or more separate transactions. +The additional Aggregate instances could be in the same Bounded Context or in others. +Publishing the Event outward to any number Bounded Contexts of other Subdomains (2) emphasizes the word Domain in the term Domain Event. +In other words, Events are a domain-wide concept, not just a concept in a single Bounded Context. +The contract of Event publishing should have the potential to be at least as broad as the enterprise, or even broader. +Yet, wide broadcast does not forbid delivery of Events by consumers in the same Bounded Context. +Refer back to Figure 8.1.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id63" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Publishing Events from the Domain Model :: Subscribers"</p> </div></blockquote> -<p>Баланс краткосрочных бизнес-интересов и долгосрочных технических интересов Kent Beck теперь уже находит в сглаживании по времени "<a class="reference external" href="https://martinfowler.com/bliki/DesignPayoffLine.html">Design Payoff Line</a>" посредством применения принципа <a class="reference internal" href="../../../../uncertainty-management/adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>, см. "<a class="reference internal" href="../../../../uncertainty-management/adaptation/crash-course-in-software-development-economics.html#emacsway-software-development-economics-literature"><span class="std std-ref">Краткий курс по экономике разработки программного обеспечения</span></a>". -Иными словами, вопрос поиска баланса краткосрочных бизнес-интересов и долгосрочных технических интересов перешел полностью под контроль технических специалистов, и вместо разрешения противоречия между двумя группами стейкхолдеров превратился в вопрос минимизации ущерба краткосрочным бизнес-интересам от осуществления технических решений.</p> +<p>В качестве первой ступени доставки Domain Events внутренним подписчикам, Vaughn Vernon предлагает использовать обычные GOF-паттерны (Mediator, Observer), которые вызывают подписчиков в том же самом потоке и в той же самой транзакции.</p> <blockquote> -<div><p>📝 "You have the right to produce quality work at all times."</p> -<p class="attribution">—"Programmer Bill of Rights", "Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 2. Fear"</p> +<div><p>Publishing Events from the Domain Model</p> +<p>Avoid exposing the domain model to any kind of middleware messaging infrastructure. +Those kinds of components live only in the infrastructure. +And while the domain model might at times use such infrastructure indirectly, it would never explicitly couple to it. We'll use an approach that completely avoids the use of infrastructure.</p> +<p>One of the simplest and most effective ways to publish Domain Events without coupling to components outside the domain model is to create a lightweight Observer [Gamma et al.]. +For the sake of naming I use Publish-Subscribe, which is acknowledged by [Gamma et al.] as another name for the same pattern. +The examples in that pattern and my use of it are lightweight because there is no network involved in subscribing to Events and publishing them. +All registered subscribers execute in the same process space with the publisher and run on the same thread. +When an Event is published, each subscriber is notified synchronously, one by one. +This also implies that <strong>all subscribers are running within the same transaction</strong>, perhaps controlled by an Application Service that is the direct client of the domain model.</p> +<p>Considering the two halves of Publish-Subscribe separately helps to explain them in a DDD context.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id64" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Publishing Events from the Domain Model"</p> </div></blockquote> -<p>Вот как комментирует эту фразу организатор создания Agile Manifesto:</p> <blockquote> -<div><p>📝</p> +<div><p>What components register subscribers to Domain Events? +Generally speaking, Application Services (14), and sometimes Domain Services, will. +<strong>The subscriber may be any component that is running on the same thread as the Aggregate that publishes the Event</strong>, and that can subscribe prior to the Event being published. +This means that <strong>the subscriber is registered in the method execution path that uses the domain model</strong>.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id65" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Publishing Events from the Domain Model :: Subscribers"</p> +</div></blockquote> +<p>При этом, Vaughn Vernon делает предостережение относительно первой ступени доставки, т.е. внутренних подписчиков, впрочем, это предостережение зависит от уже рассмотренного ранее вопроса Eventual Consistency vs Strong (Transactional) Consistency.</p> <blockquote> -<div><p>"Developers have the right to produce high-quality work at all times." — Kent Beck</p> +<div><p>Remember, the Application Service controls the transaction. +Don't use the Event notification to modify a second Aggregate instance. +That breaks a rule of thumb to modify one Aggregate instance per transaction.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id66" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Publishing Events from the Domain Model :: Subscribers"</p> </div></blockquote> -<p>This may be the most profound of all these rights. Developers have the right to do good work. -The business has no right to tell developers to cut corners or do low-quality work. -Or, to say this differently, the business has no right to force developers to ruin their professional reputations or violate their professional ethics.</p> -<p class="attribution">—"Clean Agile: Back to Basics" by Robert C. Martin</p> +<p>В другом месте Vaughn Vernon приводит небольшой пример, по которому создается иллюзия, что якобы асинхронные подписчики уведомляются непосредственно (однофазно):</p> +<blockquote> +<div><p>There is a practical way to support eventual consistency in a DDD model. +An Aggregate command method publishes a Domain Event that is in time delivered to one or more asynchronous subscribers:</p> +<p>Each of these subscribers then retrieves a different yet corresponding Aggregate instance and executes its behavior based on it. +Each of the subscribers executes in a separate transaction, obeying the rule of Aggregates to modify just one instance per transaction.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id67" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "10 Aggregates :: Rule: Use Eventual Consistency Outside the Boundary"</p> </div></blockquote> -</section> -</section> -<section id="scrum"> -<span id="emacsway-scrum-balancing-business-technical-concerns"/><h4><a class="toc-backref" href="#id21" role="doc-backlink">Scrum</a></h4> -<section id="the-scrum-guide"> -<h5><a class="toc-backref" href="#id22" role="doc-backlink">The Scrum Guide™</a></h5> -<p>Dean Leffingwell возлагает на Product Owner обязанность по разрешению противоречий требований:</p> +<p>Однако, если найти этот пример в коде, то эта иллюзия рассеивается. +См. <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_agilepm/Domain.Model/Products/BacklogItems/BacklogItem.cs#L201">здесь</a> и <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_common/Domain.Model/DomainEventPublisher.cs#L77">здесь</a></p> +<p>Kamil Grzybek вводит явное разделение механизма доставки на две ступени, первая - для внутренних Domain Events, вторая - для внешних:</p> <blockquote> -<div><p>📝 "Each project stakeholder will have their own vision, requirements, and priorities. As the primary representative to all those stakeholders, this provides a particular challenge to product owners—because all those requirements must be aligned and expectations must be managed toward a single solution.</p> -<p><strong>The product owner's primary job is to merge these diverse stakeholder voices into a single prioritized backlog for the team.</strong> -They can do this by facilitating or leading, or some appropriate mix of each."</p> -<p class="attribution">—"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</p> +<div><p>Domain Events Notifications</p> +<p>There is no such thing as domain events notifications in DDD terms. +I gave that name because I think it fits best – it is notification that domain event was published.</p> +<p>Mechanism is pretty simple. +If I want to inform my application that domain event was published I create notification class for it and as many handlers for this notification as I want. +I always publish my notifications after transaction is committed. +The complete process looks like this:</p> +<ol class="arabic simple"> +<li><p>Create database transaction.</p></li> +<li><p>Get aggregate(s).</p></li> +<li><p>Invoke aggregate method.</p></li> +<li><p>Add domain events to Events collections.</p></li> +<li><p>Publish domain events and handle them.</p></li> +<li><p>Save changes to DB and commit transaction.</p></li> +<li><p>Publish domain events notifications and handle them.</p></li> +</ol> +<p>- "<a class="reference external" href="http://www.kamilgrzybek.com/design/how-to-publish-and-handle-domain-events/">How to publish and handle Domain Events</a>" <a class="footnote-reference brackets" href="#fnkgde1" id="id68" role="doc-noteref"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></a> by Kamil Grzybek</p> </div></blockquote> -<p>Но обладает ли Product Owner достаточным нейтралитетом для этого, или же он сам находится в сфере интересов одной из групп стейкхолдеров? -Ответственнен ли он за финансовую успешность продукта?</p> -<p>Официальный "The 2020 Scrum Guide™" возлагает на Product Owner обязанность по "<em>maximizing the value of the product</em>". -Слово "value" - полисемантическое, которое слишком часто встречается в тексте гайда, в т.ч. и в обязанностях Scrum Master и Scrum Team. -Из гайда установить значение этого слова весьма затруднительно.</p> -<p>Из других источников можно сделать вывод о том, что ответственнен, по крайней мере, был ответственным, ибо в 2020 году модель ролей существенно изменилась, и, вероятно, еще продолжит меняться.</p> +<p>А вот Udi Dahan в своей статье "Domain Events – Salvation" <a class="footnote-reference brackets" href="#fnudde3" id="id69" role="doc-noteref"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></a> предложил использовать единый Mediator как для внутренних синхронных подписчиков, вызываемых в той же транзакции, так и для асинхронных подписчиков.</p> +</section> +<section id="id70"> +<h2><a class="toc-backref" href="#id135" role="doc-backlink">Кто может издавать Domain Event?</a></h2> <blockquote> -<div><p>📝 "The Product Owner is responsible to those funding the project for delivering the vision in a manner that maximizes their ROI.</p> -<p>&lt;...&gt;</p> -<p>The Product Owner's focus is return on investment (ROI)."</p> -<p class="attribution">—"Agile Project Management with Scrum" by Ken Schwaber</p> +<div><p>One more point about what can cause a Domain Event is noteworthy. +Although often it is a user-based command emitted by the user interface that causes an event to occur, sometimes Domain Events +can be caused by a different source. +This might be from a timer that expires, such as at the end of the business day or the end of a week, month, or year. +In cases like this it won't be a command that causes the event, because the ending of some time period is a matter of fact. +You can't reject the fact that some time frame has expired, and if the business cares about this fact, the time expiration is modeled as a Domain Event, and not as a command.</p> +<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id71" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events :: Designing, Implementing, and Using Domain Events"</p> </div></blockquote> <blockquote> -<div><p>📝 "Four, the Product Owner needs to be accountable for value. -In a business context what matters is revenue. -I measure a Product Owner by how much revenue they deliver per "point" of effort."</p> -<p class="attribution">—"Scrum: The Art of Doing Twice the Work in Half the Time" by Jeffrey Sutherland</p> +<div><p>Sometimes Events are designed to be created by direct request from clients. +This is done in response to some occurrence that is not the direct result of executing behavior on an instance of an Aggregate in the model. +Possibly a user of the system initiates some action that is considered an Event in its own right. +When that happens, the Event can be modeled as an Aggregate and retained in its own Repository. +Since it represents some past occurrence, its Repository would not permit its removal. +When Events are modeled in this way, like Aggregates they become part of the model's structure. +Thus, they are not just a record of some past occurrence, although they are that also.</p> +<p>-"Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id72" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "Chapter 8. Domain Events :: Modeling Events :: With Aggregate Characteristics"</p> </div></blockquote> <blockquote> -<div><p>📝 "The Product Owner is responsible for maximizing return on investment (ROI) by identifying product features, translating these into a prioritized feature list, deciding which should be at the top of the list for the next Sprint, and continually re-prioritizing and refining the list.</p> -<p>The Product Owner has profit and loss responsibility for the product, assuming it is a commercial product. -In the case of an internal application, the Product Owner is not responsible for ROI in the sense of a commercial product (that will generate revenue), but they are still responsible for maximizing ROI in the sense of choosing – each Sprint – the highest-business-value lowest-cost items."</p> -<p class="attribution">—"Jeff Sutherland's Scrum Handbook" by Jeff Sutherland</p> +<div><p>Events are facts happening in the domain. There's no implicit filter on the source: in fact, they can happen for different reasons: +- they might be the consequence of some User Initiated Action, +- they might be coming from some external system, +- they might be the result of time passing, +- they might be the direct consequence of some other event.</p> +<p class="attribution">—"Leanpub: Introducing EventStorming" by Alberto Brandolini</p> </div></blockquote> +</section> +<section id="id73"> +<h2><a class="toc-backref" href="#id136" role="doc-backlink">Может ли Domain Event отменить свою причину?</a></h2> <blockquote> -<div><p>📝 "The product owner is responsible for ensuring that good economic decisions are continuously being made at the release, sprint, and product backlog levels."</p> -<p class="attribution">—"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin</p> +<div><p>Domain events are ordinarily immutable, as they are <strong>a record of something in the past</strong>. +In addition to a description of the event, a domain event typically contains a timestamp for the time the event occurred and the identity of entities involved in the event.</p> +<p>- "Domain-Driven Design Reference" <a class="footnote-reference brackets" href="#fndddr" id="id74" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Domain events"</p> </div></blockquote> <blockquote> -<div><p>📝 "The Product Owner is responsible for maximizing return on investment (ROI)"</p> -<p class="attribution">—"<a class="reference external" href="https://less.works/less/scrum/roles">Scrum Roles</a>" by Craig Larman</p> +<div><p>A command is different from a Domain Event in that a command can be rejected as inappropriate in some cases, such as due to supply and availability of some resources (product, funds, etc.), or another kind of business-level validation. +<strong>So, a command may be rejected, but a Domain Event is a matter of history and cannot logically be denied.</strong> +Even so, in response to a time-based Domain Event it could be that the application will need to generate one or more commands in order to ask the application to carry out some set of actions.</p> +<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id75" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events :: Designing, Implementing, and Using Domain Events"</p> </div></blockquote> -<p>Однако, значение термина Value гораздо шире, о чем пишет Ken Schwaber в статье "<a class="reference external" href="https://kenschwaber.wordpress.com/2014/03/28/evidence-of-softwares-value-to-an-organization/">Evidence of Software's Value to an Organization</a>", где Value состоит из трех составляющих:</p> <blockquote> -<div><ol class="arabic simple"> -<li><p>Current value</p></li> -<li><p>Time-to-market</p></li> -<li><p>Ability to innovate</p></li> -</ol> +<div><p>Your Domain Event type names should be <strong>a statement of a past occurrence</strong>, that is, a verb in the past tense. +Here are some examples from the Agile Project Management Context : ProductCreated, for instance, states that a Scrum product was created at some past time. +Other Domain Events are ReleaseScheduled, SprintScheduled, BacklogItemPlanned, and BacklogItemCommitted. +Each of the names clearly and concisely states what happened in your Core Domain.</p> +<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id76" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events :: Designing, Implementing, and Using Domain Events"</p> </div></blockquote> -<p>Интересно, что таким образом они пытались решить другую проблему, которая тоже связана с балансированием долгосрочных и краткосрочных интересов:</p> <blockquote> -<div><p>📝 "One common approach is to hire a project manager to oversee the team's day-to-day work. -The project manager does the work that management may feel is too important to ignore but not important enough to distract from their own pressing agendas. -Though this is very common—almost ubiquitous—the approach in fact slows product delivery and may reduce quality and profitability. -First, the organization is building a product rather than carrying out a project. -When project development completes, the product is still in the field and questions of maintenance and added feature development find only awkward answers. -<strong>Organizationally separating product creation from ongoing development ("maintenance") creates many problems.</strong> -Secondly, the company rarely gives the project manager responsibility for value such as ROI or net present value (see Value and ROI), so his or her incentive is to deliver as fast as possible within the financial constraints. -<strong>Without this responsibility, the project manager is more likely to make short-term decisions with long-term consequences, and short-term decisions tend not to have positive long-term consequences.</strong>"</p> -<p class="attribution">—"A Scrum Book: The Spirit of the Game" by Jeff Sutherland, James Coplie, chapter "11 Product Owner"</p> +<div><p>As noted earlier, an important characteristic of events is that since an event is something that happened in the past, it should not change. +Therefore, it must be an immutable class. You can see in the previous code that the properties are read-only. +There's no way to update the object, you can only set values when you create it.</p> +<p>- ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id77" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos, Chapter "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation#implement-domain-events">Domain events: design and implementation :: Implement domain events</a>"</p> </div></blockquote> -<p>Какие выводы можно сделать?</p> -<p>Решая одну проблему, они создали другую (см. другие цитаты Jeff Sutherland на этой же странице). -С точки зрения архитектуры, Product Owner становится заинтересованным лицом и теряет нейтралитет своей позиции, а значит, в силу когнитивных искажений и давления обстоятельств, он всегда будет предвзят, и будет руководствоваться краткосрочными бизнес-интересами в ущерб долгосрочным техническим, если только не обладает развитым <a class="reference internal" href="business-concerns/common-planning-errors.html#emacsway-planning-technical-task"><span class="std std-ref">системным мышлением и волей</span></a>.</p> -<p>Ну а поскольку никаких методик разрешения противоречий требований стейкхолдеров Scrum не предлагает, то в ранней версии "The 2011 Scrum Guide™" этот конфликт разрешался тем, что Product Owner не мог навязывать конкретную реализацию, оставляя переменную управления разработкой Quality на усмотрение разработчиков, <a class="reference internal" href="#emacsway-xp1-balancing-business-technical-concerns"><span class="std std-ref">как и в XP1</span></a>:</p> +<p>Таким образом, Событие не может изменить прошлого, хотя и может <a class="reference external" href="https://microservices.io/patterns/data/saga.html">инициировать компенсационную транзакцию</a> и изменить будущее. +Если вы когда-нибудь работали с Emacs, то заметили, что его команда Undo <a class="reference external" href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Undo.html">не возвращает в прошлое</a>, а компенсирует ранее выполненные команды. +По этой причине в Emacs отсутствует Redo.</p> <blockquote> -<div><p>📝 "They [The Development Team] are self-organizing. -No one (not even the Scrum Master) tells the Development Team how to turn Product Backlog into Increments of potentially releasable functionality;"</p> -<p class="attribution">—"The 2011 Scrum Guide™"</p> +<div><p>Starting from that moment, the entire sequence of undo commands that you have just performed are themselves placed into the undo record. +Therefore, to re-apply changes you have undone, type C-f or any other command that harmlessly breaks the sequence of undoing; then type C-/ one or more times to undo some of the undo commands.</p> +<p>- <a class="reference external" href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Undo.html">The Emacs Editor</a></p> </div></blockquote> -<p>Именно об этом говорит Jeffrey Sutherland в высказывании, к которому мы скоро вернемся.</p> -<p>А вот в гайде 2020 года это звучит уже так:</p> +<p>Однако, рассмотрение <a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/compensating-transaction">компенсационных транзакций</a> уже выходит за рамки данного поста.</p> <blockquote> -<div><p>📝 "They [Scrum Team] are also self-managing, meaning they internally decide who does what, when, and how."</p> -<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> +<div><p>Eventual consistency can lead to undesirable scenarios. +For example, if a payment has been rejected, you can't just roll back the transaction and not create the order (as many non‐eventually consistent systems would); the order was already created as part of a previous transaction in a different component and currently lives in that component's database. +What you can do, though, is roll forward into a new state. +You'd probably tell the customer the order could not be completed because payment failed. +Ideally you would tell her immediately when she tries to place an order. +However, you have to remember that you're trying to build a scalable fault‐tolerant solution and you need to make sacrifices. +Upsetting the few customers who cannot successfully place orders so that everybody else gets a superior user experience is often an acceptable trade‐off. +When you are in an inconsistent state, you need to roll forward into a new state that represents the wishes of the business or the real‐world domain processes you are modeling.</p> +<p>- "Patterns, Principles, and Practices of Domain-Driven Design" <a class="footnote-reference brackets" href="#fnpppddd" id="id78" role="doc-noteref"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></a> by Scott Millett, Nick Tune, Chapter "12 Integrating via Messaging :: Building an E‐Commerce Application with NServiceBus :: Eventual Consistency in Practice :: Dealing with Inconsistency"</p> </div></blockquote> -<p>, где Scrum Team уже включает в себя и Product Owner тоже, что вносит путаницу в распределение обязанностей, так как получается, что Product Owner теперь уже может влиять на реализацию (how). -Причем, сделано это было, как можно догадаться, из-за сложности достижения консенсуса между Product Owner и Development Teams:</p> -<blockquote> -<div><p>📝 "One Team, Focused on One Product</p> +</section> +<section id="id79"> +<h2><a class="toc-backref" href="#id137" role="doc-backlink">Решение - это баланс стоимости и обретаемой выгоды</a></h2> +<p>Любое решение - это баланс выгод и затрат на его реализацию. +Решение не должно базироваться на <a class="reference external" href="https://youtu.be/LDW0QWie21s?t=1363">"религиозном" догматизме</a>, основываясь на бездумной вере только в то, что кто-то так сказал, не понимая при этом причин и следствий. +Нужно понимать причину решения, решаемую им проблему, и применять его сообразно стоящими перед конкретным проектом проблемами.</p> +<section id="cqrs"> +<span id="emacsway-domain-event-cqrs-command-result"/><h3><a class="toc-backref" href="#id138" role="doc-backlink">Может ли CQRS-команда возвращать результат?</a></h3> +<p>Хорошим примером, демонстрирующим архитектурную гибкость мышления, является ответ Jimmy Bogard по поводу того, может ли Команда в CQRS возвращать результат?</p> <blockquote> -<div><p>The goal was to eliminate the concept of a separate team within a team that has led to "proxy" or "us and them" behavior between the PO and Dev Team. -There is now just one Scrum Team focused on the same objective, with three different sets of accountabilities: PO, SM, and Developers."</p> -</div></blockquote> -<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/revisions.html">Changes between 2017 and 2020 Scrum Guides</a>"</p> +<div><p>It might seem rather strange that commands always have a result, but it's much, much easier to deal with side effects of commands through return parameters than through some other means (global registry, static field, re-querying some object, collecting parameter, etc.). <strong>For commands that create an item, I usually want to redirect to a screen showing that item, very easily accomplished when I can get the created item and as for its ID.</strong></p> +<p>This is a bit controversial, but don't frankly care, as it's the simplest thing that could possibly work. If I want to have a command that returns Void, I could steal a page from F# and have a Command base class that returns a Unit type:</p> +<p>- "<a class="reference external" href="https://lostechies.com/jimmybogard/2013/12/19/put-your-controllers-on-a-diet-posts-and-commands/">Put your controllers on a diet: POSTs and commands</a>" by Jimmy Bogard</p> </div></blockquote> -<p>Однако, при этом Quality сделали константой, <a class="reference internal" href="#emacsway-xp2-balancing-business-technical-concerns"><span class="std std-ref">как и в XP2</span></a>:</p> +<p>Причины такого решения он раскрывает в другой своей статье:</p> <blockquote> -<div><p>📝 "During the Sprint: Quality does not decrease;"</p> -<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> +<div><p>Myth #2 – CQRS requires an eventual consistent read store</p> +<p>No, it does not. You can make your read store immediately consistent. That is, your read store can be updated when your command side succeeds (in the same transaction).</p> +<p>For many legacy/existing apps, transitioning to eventually consistent read stores will either force you to go through bogus hoops of mimicking synchronous calls. Users will bang down on your door with pitchforks and torches if you try and transition to an asynchronous model if you don't change their business process first.</p> +<p>Instead, you can start with immediate consistency and transition where and when it's needed. Unless a user expects a confirmation page, making every command page have a series of confirmations of "your request was received" is going to annoy the snot out of your users.</p> +<p>Myth #3 – CQRS requires a bus/queues/asynchronous messaging</p> +<p>See above myth. <strong>Nothing about CQRS says "thou shalt use NServiceBus". It's just not there. You're merely separating infrastructure between handling commands and queries, but the how is quite varied. Don't start with a bus until you prove you need eventual consistency.</strong></p> +<p>Consistency models are a business decision because it directly impacts user experience. An eventually consistent model requires a different user experience than an immediate one, and this is not something you can just "slip in" to your users, or try to emulate. If you're attempting to emulate immediate consistency in an eventually consistent model, you're doing something wrong.</p> +<p>- "<a class="reference external" href="https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/">Busting some CQRS myths</a>" by Jimmy Bogard</p> </div></blockquote> -<p>А все отклонения продукта должны устраняться как можно скорее:</p> +<p>Что он также подтверждает своим комментарием к этой статье:</p> <blockquote> -<div><p>📝 "If any aspects of a process deviate outside acceptable limits or if the resulting <strong>product is unacceptable</strong>, the process being applied or the <strong>materials being produced must be adjusted</strong>. -The adjustment must be made <strong>as soon as possible to minimize further deviation</strong>".</p> -<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> +<div><p>Scaling and CQRS are orthogonal, it's highly contextual and certainly doesn't require async.</p> +<p>- "<a class="reference external" href="https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/#comment-3422377189">Busting some CQRS myths</a>" by Jimmy Bogard</p> </div></blockquote> -<p>И предупредили о проблеме дисбаланса интересов:</p> +<p>Итак, ответ прост - если вы не используете асинхронное исполнение Команды посредством инфраструктуры (Command Bus), то ничто не препятствует вам получить идентификатор вновь созданной записи БД в возвращаемом командой результате, и реализацию можно существенно упростить.</p> +<p>Вы можете удивиться, какая связь между Командами CQRS и Domain Events? +А связь заключается в том, что и в первом, и во втором случае, отступление от принципа приводит к упрощению реализации, но к ухудшению возможностей масштабирования. +И в том, и в другом случае, решением является баланс между простотой реализации и потребностью в масштабировании.</p> +<p>Впрочем, вопрос относительно того, должна ли Команда CQRS возвращать результат, и не противоречит ли это CQS принципу Bertrand Meyer, заслуживает на "<a class="reference internal" href="../../cqrs/cqrs-command-and-result.html"><span class="doc">отдельное исследование</span></a>". +Как известно, термин CQRS ввел Greg Young, разделив CQS на два отдельных класса.</p> <blockquote> -<div><p>📝 "Adaptation becomes more difficult when the people involved are not empowered or self-managing."</p> -<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> +<div><p>Starting with CQRS, CQRS is simply the creation of two objects where there was previously only one. +The separation occurs based upon whether the methods are a command or a query (the same definition that is used by Meyer in Command and Query Separation, a command is any method that mutates state and a query is any method that returns a value).</p> +<p>- "CQRS, Task Based UIs, Event Sourcing agh!" <a class="footnote-reference brackets" href="#fngycqrs" id="id80" role="doc-noteref"><span class="fn-bracket">[</span>26<span class="fn-bracket">]</span></a> by Greg Young</p> </div></blockquote> -<p>Сам Ken Schwaber под "прозрачностью" понимает полное отсутствие Technical Debt:</p> +<p>Забегая наперед, скажу, что не противоречит, при соблюдении определенных условий.</p> +<p>Во-первых, в основе CQS лежит принцип функциональной чистоты:</p> <blockquote> -<div><p>📝 "Transparency means the software is ready. -It can either be immediately deployed or built upon without regression. -<strong>It has no technical debt.</strong>"</p> -<p class="attribution">—"<a class="reference external" href="https://kenschwaber.wordpress.com/2014/04/09/can-software-developers-meet-the-needs/">Can Software Developers Meet the Need?</a>" by Ken Schwaber</p> +<div><p>Command-Query Separation principle - Functions should not produce abstract side effects.</p> +<p>- "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id81" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Objects as machines"</p> </div></blockquote> +<p>Во-вторых, кроме функций-команд и функций-запросов, Bertrand Meyer вводит еще и функции-конструкторы. И тут кроется интересное:</p> <blockquote> -<div><p>📝 "I also reminded the team members that Scrum requires transparency. -When the Team demonstrates functionality to the Product Owner and stakeholders at the Sprint review, those viewing the functionality have a right to presume that the code is complete, meaning not only that the code is written but also that it is written according to standards, easy to read, refactored, unit tested, harness tested, and even functionality tested. -If this isn't true, the Team isn't allowed to demonstrate the functionality, because in that case, the viewer's assumption would be incorrect."</p> -<p class="attribution">—"Agile Project Management with Scrum" by Ken Schwaber</p> +<div><p>From a mathematical perspective we may pretend that all of the objects of interest, for all times past, present and future, are already inscribed in the Great Book of Objects; <strong>a creation instruction is just a way to obtain one of them, but it does not by itself change anything in the environment</strong>. It is common, and legitimate, for a function to create, initialize and return such an object. +<strong>These observations assume that in the second form the creation procedure make does not produce side effects on any object other than the one being created.</strong></p> +<p>- "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id82" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Functions that create objects"</p> </div></blockquote> -<p>Jeff Sutherland возлагает устранение Technical Debt на Definition of Done:</p> +<p>Этот пример наглядно демонстрирует нам, почему важно всегда изучать мнение первоисточника. +Сравните это с тем, какие выводы можно сделать на основе утверждений Vaughn Vernon и Википедии:</p> <blockquote> -<div><p>📝 "In the long run, Definition of Done helps to remove technical debt."</p> -<p>&lt;...&gt;</p> -<p>With a good Definition of Done, the team will avoid technical debt."</p> -<p class="attribution">—"A Scrum Book: The Spirit of the Game" by Jeff Sutherland, James Coplie, chapter "82 Definition of Done"</p> -</div></blockquote> -<p>Jeff Sutherland так же советует устранять технические проблемы немедленно, в главе "81 Whack the Mole" книги "A Scrum Book: The Spirit of the Game" by Jeff Sutherland, James Coplie (текст слишком объемный для его цитирования).</p> -<p>А баланс бизнес и технических интересов обеспечивается тем, что решения Product Owner инспектируемы:</p> +<div><p>This principle, devised by Bertrand Meyer, asserts the following:</p> <blockquote> -<div><p>📝 "For Product Owners to succeed, the entireorganization must respect their decisions. -These decisions are visible in the content and ordering of the Product Backlog, -and through the <strong>inspectable</strong> Increment at the Sprint Review."</p> -<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> +<div><dl class="simple"> +<dt>Every method should be either a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer.</dt><dd><p>More formally, methods should return a value only if they are referentially transparent and hence possess no side effects. [Wikipedia, CQS]</p> +</dd> +</dl> </div></blockquote> -<p>А инспектирует их сбалансированный круг внутренних (команда) и внешних стейкхолдеров:</p> +<p>At an object level this means:</p> +<ol class="arabic simple"> +<li><p>If a method modifies the state of the object, it is a command, and its method must not return a value. In Java and C# the method must be declared void .</p></li> +<li><p><strong>If a method returns some value, it is a query</strong>, and it must not directly or indirectly cause the modification of the state of the object. In Java and C# the method must be declared with the type of the value it returns.</p></li> +</ol> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id83" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "4. Architecture :: Command-Query Responsibility Segregation, or CQRS"</p> +</div></blockquote> +<p>Или из CQRS Journey:</p> <blockquote> -<div><p>📝 "Scrum Definition: The <strong>Scrum Team and its stakeholders inspect</strong> the results and adjust for the next Sprint.</p> -<p>&lt;...&gt;</p> -<p>Sprint Review: During the event, the <strong>Scrum Team and stakeholders review</strong> what was accomplished in the Sprint -and what has changed in their environment."</p> -<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> +<div><p>A query returns data and does not alter the state of the object; a command changes the state of an object but does not return any data.</p> +<p>- "<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/jj591573(v=pandp.10)#what-is-cqrs">CQRS Journey :: Reference 2: Introducing the Command Query Responsibility Segregation Pattern :: What is CQRS?</a>"</p> </div></blockquote> -<p>Это работает для маленьких команд. -В больших коллективах лучше работают практики для работы со стейкхолдерами типа QAW, Mini-QAW, etc.</p> -</section> -<section id="id8"> -<h5><a class="toc-backref" href="#id23" role="doc-backlink">К первоисточнику за сутью</a></h5> -<p>Bertrand Meyer был прав - лучший способ понять суть вещей - это обратиться к первоисточнику. -Jeffrey Sutherland о том, как и зачем он ввел роль Product Owner:</p> +<p>Но как быть, если команда исполняется асинхронно, используя инфраструктуру (Command Bus), и мы должны вернуть результат команды в исполнение требований <a class="reference external" href="https://tools.ietf.org/html/rfc7231#page-25">RFC-7231</a> для HTTP-method POST REST API:</p> <blockquote> -<div><p>📝 "When I started the first Scrum team in 1993, I didn't have a Product Owner. -I was part of the leadership team and had a bunch of other responsibilities besides figuring out exactly what the team should do in each Sprint. -I carried out management and marketing duties, dealt with customers, and plotted strategy. -But in that first Sprint I figured I could handle the Backlog. -I just needed to make sure I had enough "stories" and features for the team to work on during the next Sprint. -The problem was, after the second Sprint we introduced the Daily Stand-up meeting. -Velocity went up 400 percent in the next Sprint, and the team finished in a week what we thought would take us a month. -There was no more Backlog for them to work on! I thought I'd have a month to create more "stories." A great problem to have, admittedly, but one that had to be addressed. -So I thought about this role of Product Owner and what qualities someone would need to execute it properly.</p> -<p>My inspiration for the role came from Toyota's Chief Engineer. -A Chief Engineer at Toyota is responsible for a whole product line, such as the Corolla or the Camry. -To do this, they have to draw on the talents of groups specializing in body engineering, or chassis, or electrical, or whatever. -The Chief Engineer has to draw from all those groups to create a cross-functional team capable of creating a car. -Outside of Toyota everyone thinks of these legendary Chief Engineers (or Shusas, as they were originally called) as all-powerful leaders of the "Toyota Way." And in a way they are. -But what they don't have is authority. -No one reports to them—rather, they report to their own groups. -People can tell Chief Engineers that they're wrong, so they have to make sure they're right. -They don't give anyone performance appraisals or promotions or raises. -But they do decide on the vision of the car, and how the car will be made—by persuasion, not coercion.</p> -<p>It's this idea that I wanted to embody within Scrum. -John Shook of the Lean Enterprise Institute once began his description of the Chief Engineer role by quoting the US Marine Corps leadership manual:</p> -<p>"An individual's responsibility for leadership is not dependent on authority.… the deep-rooted assumption that authority should equal responsibility is the root of much organizational evil. -I believe misunderstanding around this issue is rampant, problematic, and runs so deep in our consciousness that we don't even realize it." [Shook, John. "The Remarkable Chief Engineer." Lean Enterprise Institute, February 3, 2009]</p> -<p>Reflecting on my time at West Point and in Vietnam, I found myself agreeing that leadership has nothing to do with authority. -Rather, it has to do with—among other things—knowledge and being a servant-leader. -The Chief Engineer can't simply say something has to be done a particular way. -He has to persuade, cajole, and demonstrate that his way is the right way, the best way. -It usually takes someone with thirty years of experience to fill the role. -I wanted that in Scrum, but I'm also well aware that very few people have that level of skill and experience. -So I split the role in two, giving the Scrum Master the how and the Product Owner the what.</p> -<p>Even in those early days of Scrum I knew that I needed someone who was deeply connected to the customer. -The Product Owner needed to be able to deliver feedback to the team from the customer each and every Sprint. -They needed to spend half their time talking to the people buying the product (getting their thoughts on the latest incremental release and how it delivered value) and half their time with the team creating the Backlog (showing them what the customers valued and what they didn't)."</p> -<p class="attribution">—"Scrum: The Art of Doing Twice the Work in Half the Time" by Jeffrey Sutherland</p> +<div><p>the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created (Section 7.1.2) and a representation that describes the status of the request while referring to the new resource(s).</p> +<p>- "<a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-4.3.3">Section 4.3.3. POST of RFC-7231</a>"</p> </div></blockquote> -<p>Отдельно следует выделить два критически важных момента, непонимание которых является корнем проблем большинства Scrum-проектов:</p> +<p>Есть два варианта (помимо того, что можно просто запросить идентификатор у сервера предварительно).</p> +<p>Первый предлагает Udi Dahan:</p> <blockquote> -<div><p>📝 "So I split the role in two, giving the Scrum Master the <strong>how</strong> and the Product Owner the <strong>what</strong>.</p> -<p>&lt;...&gt;</p> -<p>The Scrum Master and the team are responsible for <strong>how fast they're going and how much faster they can get</strong>. -The Product Owner is accountable for <strong>translating the team's productivity into value</strong>."</p> -<p class="attribution">—"Scrum: The Art of Doing Twice the Work in Half the Time" by Jeffrey Sutherland</p> +<div><p>If the data is needed by the client as soon as it is submitted, it is there – on the client that submitted it. No need to poll the query side. The only thing that might not have been there is an ID from the database – which is easily solved with client-generated GUIDs instead of database-generated IDs.</p> +<p>- "<a class="reference external" href="http://udidahan.com/2009/12/09/clarified-cqrs/#comment-5118">Clarified CQRS</a>" comment 68 of Udi Dahan</p> </div></blockquote> -<p>Иными словами, Product Owner отвечает за то, что нужно сделать (problem space), а команда отвечает за правильный выбор надлежащей реализации (solution space).</p> -<p>С команды не снимается ответственность за ухудшение темпов разработки, если причиной этого ухудшения стали технические решения о реализации, на которые команда согласилась против своего желания под давлением Product Owner, полагая, что тем самым она делегирует ему свою ответственность. -Именно эту ошибку я нередко наблюдал у малоопытных разработчиков, и, увы, когда падение внутреннего качества программы начинало вызывать проблемы со сроками, то аргументы типа "Вы же сами так решили" и "Вас же предупреждали" не помогали им переложить вину на Product Owner. -Как правило, за этим следовали кадровые решения. -Зачастую Product Owner уверен в том, что, если команда согласилась, то она знает что делает и трезво оценивает ситуацию.</p> -<p>Тут нужно заметить, что Product Owner в Scrum отвечает как за функциональные, так и за нефункциональные требования, в отличии от, например, SAFe, где за NFR отвечает системный архитектор.</p> -<p>Другое проявление этой же ловушки - это когда все думают, что "<a class="reference internal" href="business-concerns/common-planning-errors.html#emacsway-agile-common-planning-errors"><span class="std std-ref">позже исправим</span></a>". -Однако, самый выгодный момент для исправления, если смотреть сугубо с математической точки зрения, - это именно сейчас, пока величина технического долга наименьшая. -Чем больше накапливается <a class="reference internal" href="business-concerns/compound-interest.html#emacsway-compound-interest"><span class="std std-ref">технический долг</span></a>, тем больше <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">падает скорость разработки</span></a>, и тем меньше остается ресурсов на технические задачи. -Потом будет менее выгодное положение, чем сейчас.</p> +<p>Мы просто генерируем идентификатор на стороне клиента (используя <a class="reference external" href="https://en.wikipedia.org/wiki/Universally_unique_identifier">UUID</a>, <a class="reference external" href="https://en.wikipedia.org/wiki/Hi/Lo_algorithm">Hi/Lo algorithm</a> и т.п.), а затем применяем <a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-4.3.4">PUT Request Method</a> для создания объекта.</p> <blockquote> -<div><div class="line-block"> -<div class="line">- We don't have time to do it right!</div> -<div class="line">- Do you have time to do it twice?</div> +<div><p>The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. &lt;...&gt; If the target resource does not have a current representation and the PUT successfully creates one, then the origin server MUST inform the user agent by sending a 201 (Created) response.</p> +<p>- "<a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-4.3.4">Section 4.3.4. PUT of RFC-7231</a>"</p> +</div></blockquote> +<p>Идею второго варианта выразил самим Bertrand Meyer, в виде введения концепции буфера:</p> +<blockquote> +<div><p>buffer — the concurrent equivalent of a first-in, first out queue.</p> +<p>- "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id84" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Objections"</p> +</div></blockquote> +<p>И приводит пример:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span/><span class="n">next_element</span> <span class="o">:=</span> <span class="n">buffer</span><span class="o">.</span><span class="n">item</span> +<span class="n">buffer</span><span class="o">.</span><span class="n">remove</span> +</pre></div> </div> -<p class="attribution">—<a class="reference external" href="https://www.infoq.com/presentations/microservices-data-centric">Randy Shoup</a>, VP Engineering at Stitch Fix in San Francisco</p> +<blockquote> +<div><p>With the notation of this chapter, it is easy to obtain exclusive access without sacrificing the Command-Query Separation principle: simply enclose the two instructions above, with buffer replaced by b, in a procedure of formal argument b, and call that procedure with the attribute buffer as argument.</p> +<p>- "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id85" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition by Bertrand Meyer, chapter "30.12 DISCUSSION :: Support for command-query separation"</p> </div></blockquote> -<p>Эту ситуацию следует отличать от принципа <a class="reference internal" href="../../../../uncertainty-management/adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>, который отличается тем, что:</p> -<ol class="arabic simple"> -<li><p>YAGNI управляет неопределенностью в отношении востребованности реализации.</p></li> -<li><p>YAGNI оправдан лишь в том случае, когда стоимость реализации в будущем не будет существенно дороже, чем сейчас.</p></li> -<li><p>YAGNI имеет целью сгладить "<a class="reference external" href="https://martinfowler.com/bliki/DesignPayoffLine.html">Design Payoff Line</a>" верного решения, а не подменить его неверным.</p></li> -<li><p>YAGNI имеет целью достигнуть наилучшей экономики разработки в балансе краткосрочных и долгосрочных интересов, а не пожертвовать долгосрочными интересами в угоду краткосрочным.</p></li> -<li><p>YAGNI должен способствовать эволюции программы, а не препятствовать ей.</p></li> -</ol> -<p>YAGNI как раз и является тем самым инструментом, который позволяет максимально удовлетворить требования Product Owner, не жертвуя при этом качеством программы.</p> +<p>Если транслировать этот же принцип на REST-API, то мы получим паттерн "<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/async-request-reply">Asynchronous Request-Reply pattern</a>", использующий <a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-6.3.3">202 Response Status Code</a>.</p> +<p>У Bertrand Meyer в главе "23.1 SIDE EFFECTS IN FUNCTIONS :: Pseudo-random number generators: a design exercise" книги "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id86" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition, есть пример с генератором случайных чисел, который решает задачу, аналогичную задаче с получением идентификатора ресурса. +Цитировать не буду, ибо много текста, если интересно, можно посмотреть в книге. +На примере с генератором случайных чисел хорошо видно, какую критическую роль играет правильное именование и правильное моделирование процессов предметной области. +И как легко можно создать кривое решение, если не иметь ясного понимания этих процессов, или если использовать недостаточно ясное именование.</p> +<p>Также он разделяет абстрактное состояние от конкретного состояния, и приводит пример, в значительной мере похожий на добавление нового ресурса через REST-API:</p> +<blockquote> +<div><p>What this means for us is that a function that modifies a concrete object is harmless if the result of this modification still represents the same abstract object — yields the same a value. +For example assume in a function on stacks contains the operation</p> +<p>representation.put (some_value, count + 1)</p> +<p>(with the guarantee that the array's capacity is at least count + 1). +<strong>This side effect changes a value above the stack-significant section of the array; it can do no ill.</strong></p> +<p>- "Object-Oriented Software Construction" <a class="footnote-reference brackets" href="#fnoosc" id="id87" role="doc-noteref"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></a> 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Abstract state, concrete state"</p> +</div></blockquote> +<p>Как видно, внимательное изучение первоисточника дает глубокое понимание целей, причин, спектра решаемых проблем, достоинств и недостатков, и, как следствие, приводит к более гибким и менее догматичным архитектурным решениям.</p> +<p>Как результат, в одном из лучших демонстрационных приложений, Команда возвращает результат, смотрите <a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs#L151">здесь</a> и <a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderDraftCommandHandler.cs#L40">здесь</a>.</p> </section> </section> -<section id="atam-in-agile"> -<span id="emacsway-agile-atam"/><h4><a class="toc-backref" href="#id24" role="doc-backlink">ATAM in Agile</a></h4> -<p>Использование ATAM в Agile-разработке (скачивание свободное):</p> +<section id="atomicity-and-resiliency-of-integration-events"> +<h2><a class="toc-backref" href="#id139" role="doc-backlink">Atomicity and Resiliency of Integration Events</a></h2> +<p>Если отправить Integration Event до коммита транзакции базы данных, то другой процесс не увидит изменений. +К тому же, может произойти откат транзакции, и согласованность данных будет утрачена. +А если после коммита, то существует вероятность, что процесс может аварийно завершиться, и сообщение так и не будет отправлено, что приведет к утрате согласованности данных.</p> +<p>Подробно эта проблема рассмотрена в главе "<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/subscribe-events#designing-atomicity-and-resiliency-when-publishing-to-the-event-bus">Subscribing to events :: Publishing events through the event bus :: Designing atomicity and resiliency when publishing to the event bus</a>" книги ".NET Microservices: Architecture for Containerized .NET Applications" <a class="footnote-reference brackets" href="#fnnetms" id="id88" role="doc-noteref"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></a> by Cesar de la Torre, Bill Wagner, Mike Rousos.</p> +<p>Chris Richardson называет эту проблему <a class="reference external" href="https://microservices.io/patterns/#transactional-messaging">Transactional messaging</a> рассматривает ее в главе "<a class="reference external" href="https://livebook.manning.com/book/microservices-patterns/chapter-3/section-3-3-7?origin=product-toc">3.3.7 Transactional messaging</a>" книги "Microservices Patterns: With examples in Java" <a class="footnote-reference brackets" href="#fnmsp" id="id89" role="doc-noteref"><span class="fn-bracket">[</span>14<span class="fn-bracket">]</span></a>.</p> +<p>Vaughn Vernon посвящает этой проблеме главу "8 Domain Events :: Spreading the News to Remote Bounded Contexts :: Messaging Infrastructure Consistency" книги "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id90" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>.</p> +<p>Очень глубокое понимание этой проблемы и способов ее решения дается в главе "10.Messaging Endpoints :: Transactional Client" книги "Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions" <a class="footnote-reference brackets" href="#fneip" id="id91" role="doc-noteref"><span class="fn-bracket">[</span>11<span class="fn-bracket">]</span></a> by Gregor Hohpe, Bobby Woolf.</p> +<p>А также эта тема затрагивается в главе "Chapter 9. Message Endpoints :: Transactional Client/Actor" книги "Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" <a class="footnote-reference brackets" href="#fnrmp" id="id92" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> by Vaughn Vernon.</p> +<p>Существует три основных способа решения этой проблемы:</p> +<ol class="arabic simple"> +<li><p><a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing">Event Sourcing pattern</a> (сюда же относится <a class="reference external" href="https://github.com/obsidiandynamics/goharvest/wiki/Comparison-of-messaging-patterns#front-door-queue">Front-Door Queue</a> pattern и Transactional Consumer <a class="footnote-reference brackets" href="#fneip" id="id93" role="doc-noteref"><span class="fn-bracket">[</span>11<span class="fn-bracket">]</span></a> vs Transactional Sender)</p></li> +<li><p><a class="reference external" href="https://www.scoop.it/t/sql-server-transaction-log-mining">Transaction log mining</a> (и <a class="reference external" href="https://microservices.io/patterns/data/transaction-log-tailing.html">еще</a>)</p></li> +<li><p><a class="reference external" href="https://www.kamilgrzybek.com/design/the-outbox-pattern/">Outbox pattern</a></p></li> +</ol> +<p>Говорят, что "Transactional Outbox" под названием "Local Messaging" впервые был опубликован в статье "<a class="reference external" href="https://dl.acm.org/doi/10.1145/1394127.1394128">BASE: An Acid Alternative: In partitioned databases, trading some consistency for availability can lead to dramatic improvements in scalability</a>" to ACM by ebay architect Dan Pritchett in 2008.</p> +<p>Ссылки по теме:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://www.researchgate.net/publication/276317148_Insights_from_15_Years_of_ATAM_Data_Towards_Agile_Architecture">Insights from 15 Years of ATAM Data: Towards Agile Architecture</a>" by Stephany Bellomo, Ian Gorton, and Rick Kazman, IEEE Software, September/October, 2015, 32:5, 38-45</p></li> +<li><p><a class="reference external" href="https://dzone.com/articles/event-driven-data-management-for-microservices-1">Event-Driven Data Management for Microservices</a></p></li> +<li><p><a class="reference external" href="https://github.com/ThreeDotsLabs/watermill/tree/master/_examples/real-world-examples/transactional-events">Готовая реализация паттерна outbox на Golang с примером использования (см. README)</a></p></li> </ul> +</section> +<section id="integration-events"> +<h2><a class="toc-backref" href="#id140" role="doc-backlink">Проблема сохранения очередности Integration Events</a></h2> +<p>Подписчики не всегда получают Integration Events в той же последовательности, в которой они были отправлены, по ряду причин. +Одно из решений этой проблемы заключается в том, что, если получатель обнаруживает, что сообщение не соответствует ожидаемому порядку, то он просто не забирает его из очереди.</p> <blockquote> -<div><p>📝 "Agile teams strive to <strong>balance short term feature development with longer term quality concerns</strong>. -These evolutionary approaches often hit a "complexity wall" from the cumulative effects of unplanned changes, resulting in unreliable, poorly performing software. -Consequently, there is renewed focus on approaches to address architectural concerns within the Agile community. -We present an analysis of quality attribute concerns from 15 years of Architecture Trade-off Analysis Method data, gathered from 31 projects. -We found that modifiability is the dominant concern across all project types; additionally there was considerable focus on performance, availability, and interoperability. -For information technology projects, a relatively new quality—deployability—has emerged as a key concern. -Our results provide insights for Agile teams allocating architecture-related tasks to iterations. -For example they can use these results to create checklists for release planning or retrospectives to help assess whether a given quality should be addressed to support future needs.</p> -<p>&lt;...&gt;</p> -<p>One of the major challenges Agile teams face in building an architecture foundation is balancing the competing concerns of delivery of near-term functional requirements (based on the Agile philosophy of delivering user value early and often) and near and long term quality attribute goals (without which the project can grind to a halt as system complexity makes efficient modifications impossible). -In particular, quality attribute (QA) prioritization can be especially difficult in early increments, and a wrong decision can have serious ramifications resulting in hard-to-modify, unreliable, slow, or insecure systems [5].</p> -<ol class="arabic simple" start="5"> -<li><ol class="upperalpha simple" start="19"> -<li><p>Bellomo, R. Nord, and I. Ozkaya. A Study of Enabling Factors for Rapid Fielding; Combined Practices to Balance Tension between Speed and Stability Proceedings of International Conference on Software Engineering 2013."</p></li> -</ol> -</li> -</ol> -<p class="attribution">—"<a class="reference external" href="https://www.researchgate.net/publication/276317148_Insights_from_15_Years_of_ATAM_Data_Towards_Agile_Architecture">Insights from 15 Years of ATAM Data: Towards Agile Architecture</a>" by Stephany Bellomo, Ian Gorton, and Rick Kazman, IEEE Software, September/October, 2015</p> +<div><p>Note that just saving the Domain Event in its causal order doesn't guarantee that it will arrive at other distributed nodes in the same order. +Thus, it is also the responsibility of the consuming Bounded Context to recognize proper causality. +It might be the Domain Event type itself that can indicate causality, or it may be metadata associated with the Domain Event, such as a sequence or causal identifier. +The <strong>sequence</strong> or <strong>causal identifier</strong> would indicate <strong>what caused this Domain Event</strong>, and <strong>if the cause was not yet seen, the consumer must wait to apply the newly arrived event until its cause arrives</strong>. +In some cases it is possible to ignore latent Domain Events that have already been superseded by the actions associated with a later one; in this case causality has a dismissible impact.</p> +<p>- "Domain-Driven Design Distilled" <a class="footnote-reference brackets" href="#fndddd" id="id94" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events:: Designing, Implementing, and Using Domain Events"</p> </div></blockquote> -<p>Подробнее про ATAM можно узнать здесь:</p> +<p>В книге "Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" <a class="footnote-reference brackets" href="#fnrmp" id="id95" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> by Vaughn Vernon также говорится о том, что Actor должен сам решать, принимать ли ему сообщение:</p> +<blockquote> +<div><p>Actors must be prepared to accept and reject messages based on their current state, which is reflected by the order in which previous messages were received. +Sometimes a latent message could be accepted even if it is not perfect timing, but the actor's reaction to the latent message may have to carefully take into account its current state beforehand. +This may be dealt with more gracefully by using the actors become() capabilities.</p> +<p>- "Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" <a class="footnote-reference brackets" href="#fnrmp" id="id96" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "5. Messaging Channels :: Point-to-Point Channel"</p> +</div></blockquote> +<p>Этой же проблеме посвящена и глава "Chapter 7 Message Routing :: Resequencer" <a class="footnote-reference brackets" href="#fnrmp" id="id97" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> той же книги.</p> +<p>Pattern <a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/Resequencer.html">Resequencer</a> описан также и в главе "7.Message Routing :: Resequencer" книги "Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions" <a class="footnote-reference brackets" href="#fneip" id="id98" role="doc-noteref"><span class="fn-bracket">[</span>11<span class="fn-bracket">]</span></a> by Gregor Hohpe, Bobby Woolf.</p> +<p>Существует open source integration framework <a class="reference external" href="https://camel.apache.org/">Camel</a>, который предоставляет <a class="reference external" href="https://camel.apache.org/components/latest/eips/resequence-eip.html">готовую из коробки реализацию паттерна Resequencer</a>. +Он легко интегрируется с различными системами обмена сообщениями, например, <a class="reference external" href="https://camel.apache.org/components/latest/nats-component.html">с Nats</a> (<a class="reference external" href="https://nats.io/blog/apache-camel-nats-connector/">подробнее</a>).</p> +<p>В "CQRS Journey" <a class="footnote-reference brackets" href="#fncqrsj" id="id99" role="doc-noteref"><span class="fn-bracket">[</span>8<span class="fn-bracket">]</span></a> предлагается два варианта решения:</p> +<blockquote> +<div><p>The first option is to <strong>use message sessions</strong>, a feature of the Azure Service Bus. If you use message sessions, this guarantees that messages within a session are delivered in the same order that they were sent.</p> +<p>The second alternative is to modify the handlers within the application to detect out-of-order messages through the use of sequence numbers or timestamps added to the messages when they are sent. +<strong>If the receiving handler detects an out-of-order message, it rejects the message and puts it back onto the queue or topic to be processed later</strong>, after it has processed the messages that were sent before the rejected message.</p> +<p>- "CQRS Journey" <a class="footnote-reference brackets" href="#fncqrsj" id="id100" role="doc-noteref"><span class="fn-bracket">[</span>8<span class="fn-bracket">]</span></a> by Dominic Betts, Julián Domínguez, Grigori Melnik, Fernando Simonazzi, Mani Subramanian, Chapter "<a class="reference external" href="https://docs.microsoft.com/ru-ru/previous-versions/msp-n-p/jj591565(v=pandp.10)#message-ordering">Journey 6: Versioning Our System :: Message ordering</a>"</p> +</div></blockquote> +<p>Проблема сохранения очередности сообщений в условиях конкурирующих подписчиков рассматривается и в главе "<a class="reference external" href="https://livebook.manning.com/book/microservices-patterns/chapter-3/section-3-3-5?origin=product-toc">3.3.5 Competing receivers and message ordering</a>" книги "Microservices Patterns: With examples in Java" <a class="footnote-reference brackets" href="#fnmsp" id="id101" role="doc-noteref"><span class="fn-bracket">[</span>14<span class="fn-bracket">]</span></a> by Chris Richardson, где для решения проблемы предлагается использовать партиционирование каналов.</p> +<p>Но даже если подписчик всего один, и сообщения доставляются последовательно, то и тогда очередность обработки сообщений может быть нарушена:</p> +<blockquote> +<div><p>With the redelivery feature, order can't be guaranteed, since by definition server will resend messages that have not been acknowledged after a period of time. Suppose your consumer receives messages 1, 2 and 3, does not acknowledge 2. Then message 4 is produced, server sends this message to the consumer. The redelivery timer then kicks in and server will resend message 2. The consumer would see messages: 1, 2, 3, 4, 2, 5, etc...</p> +<p>In conclusion, the server does not offer this guarantee although it tries to redeliver messages first thing on startup. That being said, if the durable is stalled (number of outstanding messages &gt;= MaxInflight), then the redelivery will also be stalled, and new messages will be allowed to be sent. When the consumer resumes acking messages, then it may receive redelivered and new messages interleaved (new messages will be in order though).</p> +<p>- nats-streaming-server, <a class="reference external" href="https://github.com/nats-io/nats-streaming-server/issues/187#issuecomment-257024506">issue #187 "Order of delivery"</a>, comment by Ivan Kozlovic</p> +</div></blockquote> +<p>Ну а лучше всего эта тема раскрывается в Chapter "12 The Future of Data Systems :: Data Integration :: Combining Specialized Tools by Deriving Data :: Ordering events to capture causality" книги "Designing Data-Intensive Applications. The Big Ideas Behind Reliable, Scalable, and Maintainable Systems" <a class="footnote-reference brackets" href="#fnddia" id="id102" role="doc-noteref"><span class="fn-bracket">[</span>12<span class="fn-bracket">]</span></a> by Martin Kleppmann.</p> +<p>Еще проблемы распределенности хорошо освещаются в книге "Database Reliability Engineering. Designing and Operating Resilient Database Systems." <a class="footnote-reference brackets" href="#fndre" id="id103" role="doc-noteref"><span class="fn-bracket">[</span>13<span class="fn-bracket">]</span></a> by Laine Campbell and Charity Majors.</p> +<p>Ссылки по теме:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=5177">ATAM: Method for Architecture Evaluation</a>" by Rick Kazman, Mark H. Klein, Paul C. Clements (<a class="reference external" href="https://resources.sei.cmu.edu/asset_files/TechnicalReport/2000_005_001_13706.pdf">pdf</a>, <a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=513908">collection</a>)</p></li> +<li><p>"<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">Don't Settle for Eventual Consistency. Stronger properties for low-latency geo-replicated storage.</a>" (<a class="reference external" href="https://dl.acm.org/ft_gateway.cfm?id=2610533&amp;ftid=1449165&amp;dwn=1">pdf</a>) by Wyatt Lloyd, Facebook; Michael J. Freedman, Princeton University; Michael Kaminsky, Intel Labs; David G. Andersen, Carnegie Mellon University</p></li> +<li><p>"<a class="reference external" href="http://www.bailis.org/papers/bolton-sigmod2013.pdf">Bolt-on Causal Consistency</a>" by Peter Bailis, Ali Ghodsi, Joseph M. Hellerstein†, Ion Stoica, UC Berkeley KTH/Royal Institute of Technology</p></li> +<li><p>"<a class="reference external" href="https://disco.ethz.ch/courses/hs08/seminar/papers/mattern4.pdf">Detecting Causal Relationships in Distributed Computations:In Search of the Holy Grail</a>" by Reinhard Schwarz, Friedemann Mattern</p></li> +<li><p>"<a class="reference external" href="https://www.microsoft.com/en-us/research/publication/principles-of-eventual-consistency/">Principles of Eventual Consistency</a>" (<a class="reference external" href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/final-printversion-10-5-14.pdf">pdf</a>) by Sebastian Burckhardt, Microsoft Research</p></li> +<li><p>"<a class="reference external" href="https://eventsourcing.readthedocs.io/en/stable/topics/process.html#causal-dependencies">Causal dependencies at eventsourcing framework by Python</a>" by John Bywater</p></li> +<li><p>"<a class="reference external" href="http://labix.org/vclock">The vclock package</a> offers full vector clock support for the Go language. Vector clocks allow recording and analyzing the inherent partial ordering of events in a distributed system in a comfortable way." by Gustavo Niemeyer (<a class="reference external" href="https://blog.labix.org/2010/12/21/vector-clock-support-for-go">more info</a>)</p></li> </ul> -<p>Интересно, что обе эти статьи упоминаются в стандарте "<a class="reference external" href="https://www.iso.org/standard/73436.html">ISO/IEC/IEEE 42030:2019 Software, systems and enterprise — Architecture evaluation framework</a>".</p> -<p>Смотрите также статьи про Mini-QAW в Agile:</p> +<p>Ссылки для начинающих в Integration Events:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://re-magazine.ireb.org/articles/discover-quality-requirements-with-the-mini-qaw">Discover Quality Requirements with the Mini-QAW. A short and fun elicitation workshop for Agile teams and architects.</a>" by Thijmen de Gooijer Michael Keeling Will Chaparro</p></li> -<li><p>"<a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=4995">Quality Attribute Workshop Participants Handbook</a>" by Mario R. Barbacci, Robert J. Ellison, Charles B. Weinstock, William G. Wood (<a class="reference external" href="https://resources.sei.cmu.edu/asset_files/SpecialReport/2000_003_001_13640.pdf">pdf</a>)</p></li> -<li><p>"<a class="reference external" href="https://resources.sei.cmu.edu/asset_files/Presentation/2014_017_101_89563.pdf">Facilitating the Mini-Quality Attributes Workshop. A Lightweight, Architecture-Focused Method.</a>" by Will Chaparro IBM, Michael Keeling IBM</p></li> +<li><p>Хороший лаконичный обзорный блог-пост по возможностям NATS Streaming Server "<a class="reference external" href="https://nats.io/blog/use-cases-for-persistent-logs-with-nats-streaming/">Guest Post: Use cases for persistent logs with NATS Streaming</a>" by Byron Ruth</p></li> +<li><p>Лучше один раз увидеть. <a class="reference external" href="https://github.com/bruth/code-examples/tree/master/patterns-nats-streaming">Живые примеры по работе с NATS Streaming Server</a>.</p></li> </ul> -<p>Смотрите также о "Lightweight Architecture Evaluation (LAE)" в "Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman.</p> +<p>Более подробно тема раскрывается в заметке "<a class="reference internal" href="../../../../integration/asynchronous/message-ordering-in-competing-consumers.html#emacsway-message-ordering"><span class="std std-ref">О гонке сообщений в условиях конкурирующих подписчиков</span></a>".</p> </section> -<section id="emacsway-agile-balancing-business-technical-concerns-with-fixed-iteration-ratio"> -<span id="id9"/><h4><a class="toc-backref" href="#id25" role="doc-backlink">Фиксированная часть итерации на технические задачи</a></h4> +<section id="id104"> +<h2><a class="toc-backref" href="#id141" role="doc-backlink">Где создавать Domain Event об удалении объекта?</a></h2> +<p>Информации по этому вопросу практически нет, поэтому, я поделюсь своими мыслями.</p> +<p>В Английском языке есть <a class="reference external" href="https://english.stackexchange.com/a/52509">разница</a> между словом "delete" и "remove". +"Delete" подразумевает "уничтожить". +"Remove" - "изъять", "вынести".</p> +<p>Кстати, русское слово "удалить" <a class="reference external" href="https://ru.wiktionary.org/wiki/%D1%83%D0%B4%D0%B0%D0%BB%D0%B8%D1%82%D1%8C#%D0%AD%D1%82%D0%B8%D0%BC%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F">происходит</a> от слова "даль". +Например, "Удалить ненужные вещи из комнаты", "Удалить занозу".</p> +<p>Термин "remove" (удаление) применим к Коллекции, содержащей объект, и означает то, что объект удаляется от Коллекции (в даль). +Но при этом, объект, сам по себе, продолжает существовать. +Он может быть удален от (из) одной Коллекции, а затем вставлен в иную Коллекцию. +Как говорилось ранее, источником Domain Event не обязательно должен быть Агрегат или Команда. +Источником может быть и Коллекция, т.е. Repository.</p> +<p>Но если мы будем говорить не об удалении, а об "уничтожении" ("delete"), то мы говорим о состоянии, т.е. о части жизненного цикла объекта. +В таком случае было бы уместно, чтобы событие о переходе в новое состояние жизненного цикла объекта создавал сам объект. +Это становится особенно заметно, если мы используем soft delete (смотрите статью "<a class="reference external" href="http://udidahan.com/2009/09/01/dont-delete-just-dont/">Don't Delete – Just Don't</a>" by Udi Dahan по этому поводу). +Пример можно посмотреть <a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd/blob/78810bb44ae10cd88ca12b8d81712ba20c0ca43f/src/Modules/Meetings/Domain/Meetings/MeetingAttendee.cs#L124">здесь</a> (вызывается <a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd/blob/78810bb44ae10cd88ca12b8d81712ba20c0ca43f/src/Modules/Meetings/Domain/Meetings/Meeting.cs#L289">здесь</a>). +Это не Агрегат - это вложенная Сущность.</p> +<p>В другом <a class="reference external" href="https://github.com/kgrzybek/sample-dotnet-core-cqrs-api/blob/1d344b90658c6593993eaa1391410b5ab1ebabfc/src/SampleProject.Domain/Customers/Orders/Order.cs#L111">примере</a> реализации soft delete, событие <a class="reference external" href="https://github.com/kgrzybek/sample-dotnet-core-cqrs-api/blob/01a1d6517bc88773f004abc0cb9c6d79f537e575/src/SampleProject.Domain/Customers/Customer.cs#L89">создается</a> Агрегатом, владеющим Сущностью. +Похожие примеры можно найти и у Vaughn Vernon, см. <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_identityaccess/Domain.Model/Identity/Group.cs#L159">здесь</a> и <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_identityaccess/Domain.Model/Identity/Group.cs#L142">здесь</a>.</p> +<p>Посмотреть <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_agilepm/Domain.Model/Products/BacklogItems/BacklogItem.cs#L360">пример реализации soft delete Агрегата</a> (а не Сущности) можно у Vaughn Vernon (Агрегат BacklogItem хоть и <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/90fcc52d9c1af29640ec2a8a3e0e7c692f3e6663/iddd_agilepm/Domain.Model/Products/Product.cs#L128">создается</a> Агрегатом Product, но является самостоятельным корнем).</p> +<p>Скрыть присутствие Repository помогает pattern "<a class="reference external" href="https://martinfowler.com/eaaCatalog/unitOfWork.html">Unit of Work</a>". +В одноименной главе книги "Patterns of Enterprise Application Architecture" <a class="footnote-reference brackets" href="#fnpoeaa" id="id105" role="doc-noteref"><span class="fn-bracket">[</span>10<span class="fn-bracket">]</span></a> приводится пример класса DomainObject, который содержит метод markRemoved().</p> <blockquote> -<div><p>📝 "Business should sequence stories. -Business people understand uncertainty in estimates. -They face risk all the time with financial projections. -They also understand the cost of reworking in the cases where reworking is an issue. -If they wish to run a risk in order to get better value now, it is really their call. -It is the programmers' task to make the risk visible, not to make the decision for the customer.</p> -<p>While this arrangement is the ideal, sometimes you need something extra to make it work, perhaps allowing developers to choose a certain amount of [technical high-risk] stories per iteration so that they can bring the risk forward."</p> -<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 13. Ordering the Stories :: Negotiating Between the Two"</p> +<div><p>With object registration (Figure 11.2), the onus is removed from the caller. +The usual trick here is to place registration methods in object methods. Loading an object from the database registers the object as clean; +the setting methods register the object as dirty. +For this scheme to work the Unit of Work needs either to be passed to the object or to be in a well-known place. +Passing the Unit of Work around is tedious but usually no problem to have it present in some kind of session object.</p> +<p>- "Patterns of Enterprise Application Architecture" <a class="footnote-reference brackets" href="#fnpoeaa" id="id106" role="doc-noteref"><span class="fn-bracket">[</span>10<span class="fn-bracket">]</span></a> by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford, Chapter "16. Offline Concurrency Patterns :: Coarse-Grained Lock"</p> </div></blockquote> +<p>Для этих целей удобно применять Aspect-oriented programming:</p> <blockquote> -<div><p>📝 "Я всё еще считаю технику технических историй классной и часто её использую. -Мелкие тех-истории, просто встраиваются в ежедневную работу, в то время как большие записываются в тех беклог, видимый product owner'у, но управляемый командой. -Команда и product owner договариваются о правиле, к примеру: 10-20% нашего времени мы используем на тех-истории. -Такой подход не требует придумывать сложные схемы, как focus factor или time reports, просто используйте интуицию. -Спросите на ретроспективе: "Грубо, сколько нашей ёмкости спринта ушло на тех-истории, и кажется ли, что это была хорошая инвестиция?</p> -<p>I still find tech stories to be a great pattern and use it a lot. -Smaller tech stories are just embedded into the day-to-day work, while larger stories are written down and placed in a tech backlog, visible to the product owner but managed by the team. -The team and product owner agree on a guideline such as "10-20% of our time is spent on tech stories". -No need for elaborate tracking schemes like focus factor or time reports, just use gut feel. -Ask at the retro, "Roughly how much of our sprint capacity did we spend on tech stories, and did that feel about right?"".</p> -<p class="attribution">—"Scrum and XP from the Trenches: How We Do Scrum" 2nd edition by Henrik Kniberg, перевод под редакцией Алексея Кривицкого</p> +<div><p>This is a natural place for code generation to generate appropriate calls, but that only works when you can clearly separate generated and nongenerated code. +This problem turns out to be particularly suited to aspect-oriented programming. +I've also come across post-processing of the object files to pull this off. +In this example a post-processor examined all the Java .class files, looked for the appropriate methods and inserted registration calls into the byte code. +Such finicking around feels dirty, but it separates the database code from the regular code. +Aspect-oriented programming will do this more cleanly with source code, and as its tools become more commonplace I expect to see this strategy being used.</p> +<p>- "Patterns of Enterprise Application Architecture" <a class="footnote-reference brackets" href="#fnpoeaa" id="id107" role="doc-noteref"><span class="fn-bracket">[</span>10<span class="fn-bracket">]</span></a> by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford, Chapter "16. Offline Concurrency Patterns :: Coarse-Grained Lock"</p> +</div></blockquote> +<p>Также существует разница и между термином "insert" ("вставить") и "create" ("создать"). +Первый применим к Коллекции объектов (как и "remove"), а второй - к состоянию жизненного цикла самого объекта (как и "delete").</p> +<p>Вопрос о том, где создавать Domain Event об уничтожении/удалении объекта, во многом зависит от того, где создавался Domain Event о его создании/вставке, который, в свою очередь, зависит от того, каким образом создается идентификатор создаваемого объекта, если он необходим для Domain Event.</p> +<p>Как вариант, если нужно создавать Domain Event о создании ("create") объекта внутри него самого, но при этом используется автоинкрементный первичный ключ базы данных, то обойти это ограничение можно вложив сам экземпляр созданного объекта в Domain Event. +Тогда, в момент вызова обработчика Domain Event, если он, конечно, будет происходить после сохранения созданного объекта в Хранилище (хотя и до коммита), созданному объекту уже будет присвоен идентификатор. +Агрегат, в таком случае, можно снабдить методом <a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/blob/1d8c6178de2830ad809eae138a0a99011c26ac2c/src/Services/Ordering/Ordering.Domain/SeedWork/Entity.cs#L42">IsTransient</a>. +Другим возможным вариантом обхода этого ограничения может быть передача в Domain Event объекта отложенного значения (в крайнем случае - указателя на значение). +Ну и, разумеется, можно использовать <a class="reference external" href="https://en.wikipedia.org/wiki/Universally_unique_identifier">UUID</a>, <a class="reference external" href="https://en.wikipedia.org/wiki/Hi/Lo_algorithm">Hi/Lo algorithm</a> и т.п.</p> +<p>В целом я придерживаюсь такого правила - если Domain Event о "вставке" ("insert") объекта создает Коллекция (Repository), то и Domain Event об "удалении" ("remove") объекта должна создавать тоже Коллекция (Repository), на том же уровне абстракции. +А если Domain Event о "создании" ("create") объекта создает сам объект, как уведомление о переходе в новое состояние своего жизненного цикла, то и Domain Event об "уничтожении" ("delete") объекта должен создавать он же.</p> +</section> +<section id="id108"> +<h2><a class="toc-backref" href="#id142" role="doc-backlink">Почему важно читать оригиналы вместо переводов</a></h2> +<p>В самом начале этого поста я говорил, что важно читать первоисточники. +Теперь я хочу показать, почему важно читать оригиналы, а не их переводы.</p> +<p>Возьмем известную фразу Эрика Эванса, которая послужила первопричиной для eventual consistency между агрегатами. Сравните ее смысл в оригинале:</p> +<blockquote> +<div><p>Invariants, which are consistency rules that must be maintained whenever data changes, will involve relationships between members of the AGGREGATE. +<strong>Any rule that spans AGGREGATES [мн. число] will not be expected to be up-to-date at all times.</strong> +Through event processing, batch processing, or other update mechanisms, other dependencies can be resolved within some specified time. +But the invariants applied within an AGGREGATE will be enforced with the completion of each transaction.</p> +<p>- "Domain-Driven Design: Tackling Complexity in the Heart of Software" <a class="footnote-reference brackets" href="#fnddd" id="id109" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Eric Evans, Chapter "Six. The Life Cycle of a Domain Object:: Aggregates"</p> +</div></blockquote> +<p>И ее смысл в переводе:</p> +<blockquote> +<div><p>Из взаимосвязей между объектами АГРЕГАТА можно составить так называемые инварианты, т.е. правила совместности, которые должны соблюдаться при любых изменениях данных. +<strong>Не всякое правило, распространяющееся на АГРЕГАТ [ед. число], обязано выполняться непрерывно.</strong> +Восстановить нужные взаимосвязи за определенное время можно с помощью обработки событий, пакетной обработки и других механизмов обновления системы. +Но соблюдение инвариантов, имеющих силу внутри агрегата, должно контролироваться немедленно по завершении любой транзакции.</p> +</div></blockquote> +<p>Смысл утрачен. А этот смысл имеет ключевое значение - он говорит о распространении правил между агрегатами.</p> +<p>Или другой пример.</p> +<blockquote> +<div><p>There are several possible ways for remote Bounded Contexts to become aware of Events that occur in your Bounded Context. +The primary idea is that some form of messaging takes place, and an enterprise messaging mechanism is needed. +To be clear, the mechanism being spoken of here goes well beyond the simple, lightweight Publish-Subscribe components just discussed. +Here we are discussing what takes over <strong>where the lightweight mechanism leaves off</strong>.</p> +<p>- "Implementing Domain-Driven Design" <a class="footnote-reference brackets" href="#fniddd" id="id110" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Vaughn Vernon, Chapter "8. Domain Events :: Spreading the News to Remote Bounded Contexts"</p> </div></blockquote> -</section> -<section id="open-agile-architecture"> -<h4><a class="toc-backref" href="#id26" role="doc-backlink">Open Agile Architecture™</a></h4> +<p>Сравните с русским переводом:</p> <blockquote> -<div><p>📝 "It is worth, at this point, returning to Fowler's distinction [Fowler 2019] between code refactoring and architectural restructuring. Fowler would strongly promote the view that code refactoring requires no justification; rather it is part of a developer's "day job". This does not mean that we have to take on a massive code restructuring exercise for a legacy codebase; on the contrary, there may be no reason whatsoever to restructure the code for a stable legacy project. However, that said, developers should refactor their code when the opportunity arises. Such activity constitutes a "Type 2" decision as documented in [Ries 2011].</p> -<p>Architectural refactoring (restructuring), however, often requires explicit investment because the required effort is significant. In such cases, it is incumbent on development teams and architects to "sell" the refactoring in monetary, time, or customer success terms. For example, "if we perform refactoring A, the build for Product B will be reduced by seven minutes, resulting in us being able to deploy C times more frequently per day"; or, "implementing refactoring D will directly address key Customer E's escalated pain point; their annual subscription and support fee is $12 million per annum". Note, however, that claims that "refactoring F will make us G% more productive" should be avoided as software productivity is notoriously difficult to measure."</p> -<ul class="simple"> -<li><p>[Fowler 2019] Refactoring: Improving the Design of Existing Code, by Martin Fowler, January 2019, published by Addison-Wesley</p></li> -<li><p>[Ries 2011] The Lean Startup: How Constant Innovation Creates Radically Successful Businesses, by Eric Ries, October 2011, published by Portfolio Penguin</p></li> -</ul> -<p class="attribution">—"Open Agile Architecture™" by The Open Group, Chapter "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard-single/#KLP-CAR-justifying">6.5.1. Justifying Ongoing Investment in Architectural Refactoring</a>"</p> +<div><p>Существует несколько способов сообщить удаленным ОГРАНИЧЕННЫМ КОНТЕКСТАМ о событии, произошедшем в вашем ОГРАНИЧЕННОМ КОНТЕКСТЕ. +Основная идея заключается в том, чтобы организовать какую-то форму передачи сообщений и создать механизм передачи сообщений в масштабе предприятия. +Точнее говоря, механизм, о котором идет речь, выходит далеко за рамки простых облегченных компонентов шаблона ИЗДАТЕЛЬ - ПОДПИСЧИК. +Ниже мы обсудим, что произойдет, <strong>если отказаться от этого упрощенного механизма</strong>.</p> </div></blockquote> +<p>Русский перевод не отражает оригинального смысла, который, кстати, опять же имеет немаловажное значение. +И даже если считать оригинальный смысл недостаточно ясным, допускающим несколько трактовок, из которых можно выбрать наиболее корректную исходя из контекста и предыдущих утверждений автора, то русский перевод такой возможности нас лишает. +Я трактую эту фразу так, чтобы она находилась в согласованности с другими утверждениями Вернона, т.е. "Ниже мы обсудим, что произойдет <strong>за пределами этого упрощенного механизма</strong>", что полностью соответствует рис.8.1. и его описанию.</p> </section> -<section id="id10"> -<h4><a class="toc-backref" href="#id27" role="doc-backlink">Системное мышление</a></h4> -<p>См. "<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems Thinking</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">на русском</a>).</p> -</section> -</section> +<section id="id111"> +<h2><a class="toc-backref" href="#id143" role="doc-backlink">Послесловие</a></h2> +<p>Эта статья отражает мое мнение на текущий момент времени, которое, однако, я не спешил бы называть окончательно сформированным, поскольку существует еще достаточно большой пласт информации по этому вопросу, который мне только предстоит переработать. +Основной посыл статьи - больше внимания уделять первоисточникам, и быть более гибким в принятии решений, хорошо осознавая их причины и следствия.</p> +<p class="rubric">Footnotes</p> +<aside class="footnote-list brackets"> +<aside class="footnote brackets" id="fnddd" role="note"> +<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id8">1</a>,<a role="doc-backlink" href="#id9">2</a>,<a role="doc-backlink" href="#id10">3</a>,<a role="doc-backlink" href="#id13">4</a>,<a role="doc-backlink" href="#id109">5</a>)</span> +<p>"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p> +</aside> +<aside class="footnote brackets" id="fndddr" role="note"> +<span class="label"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id2">1</a>,<a role="doc-backlink" href="#id3">2</a>,<a role="doc-backlink" href="#id4">3</a>,<a role="doc-backlink" href="#id60">4</a>,<a role="doc-backlink" href="#id74">5</a>)</span> +<p>"<a class="reference external" href="https://domainlanguage.com/ddd/reference/">Domain-Driven Design Reference</a>" by Eric Evans</p> +</aside> +<aside class="footnote brackets" id="fniddd" role="note"> +<span class="label"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id5">1</a>,<a role="doc-backlink" href="#id7">2</a>,<a role="doc-backlink" href="#id11">3</a>,<a role="doc-backlink" href="#id12">4</a>,<a role="doc-backlink" href="#id16">5</a>,<a role="doc-backlink" href="#id17">6</a>,<a role="doc-backlink" href="#id20">7</a>,<a role="doc-backlink" href="#id21">8</a>,<a role="doc-backlink" href="#id24">9</a>,<a role="doc-backlink" href="#id46">10</a>,<a role="doc-backlink" href="#id62">11</a>,<a role="doc-backlink" href="#id63">12</a>,<a role="doc-backlink" href="#id64">13</a>,<a role="doc-backlink" href="#id65">14</a>,<a role="doc-backlink" href="#id66">15</a>,<a role="doc-backlink" href="#id67">16</a>,<a role="doc-backlink" href="#id72">17</a>,<a role="doc-backlink" href="#id83">18</a>,<a role="doc-backlink" href="#id90">19</a>,<a role="doc-backlink" href="#id110">20</a>)</span> +<p>"<a class="reference external" href="https://kalele.io/books/">Implementing Domain-Driven Design</a>" by Vaughn Vernon</p> +</aside> +<aside class="footnote brackets" id="fndddd" role="note"> +<span class="label"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id19">1</a>,<a role="doc-backlink" href="#id22">2</a>,<a role="doc-backlink" href="#id45">3</a>,<a role="doc-backlink" href="#id47">4</a>,<a role="doc-backlink" href="#id71">5</a>,<a role="doc-backlink" href="#id75">6</a>,<a role="doc-backlink" href="#id76">7</a>,<a role="doc-backlink" href="#id94">8</a>)</span> +<p>"<a class="reference external" href="https://kalele.io/books/">Domain-Driven Design Distilled</a>" by Vaughn Vernon</p> +</aside> +<aside class="footnote brackets" id="fnrmp" role="note"> +<span class="label"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id92">1</a>,<a role="doc-backlink" href="#id95">2</a>,<a role="doc-backlink" href="#id96">3</a>,<a role="doc-backlink" href="#id97">4</a>)</span> +<p>"<a class="reference external" href="https://kalele.io/books/">Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka</a>" by Vaughn Vernon</p> +</aside> +<aside class="footnote brackets" id="fnpppddd" role="note"> +<span class="label"><span class="fn-bracket">[</span>6<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id23">1</a>,<a role="doc-backlink" href="#id30">2</a>,<a role="doc-backlink" href="#id55">3</a>,<a role="doc-backlink" href="#id56">4</a>,<a role="doc-backlink" href="#id78">5</a>)</span> +<p>"Patterns, Principles, and Practices of Domain-Driven Design" by Scott Millett, Nick Tune</p> +</aside> +<aside class="footnote brackets" id="fnnetms" role="note"> +<span class="label"><span class="fn-bracket">[</span>7<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id6">1</a>,<a role="doc-backlink" href="#id26">2</a>,<a role="doc-backlink" href="#id27">3</a>,<a role="doc-backlink" href="#id28">4</a>,<a role="doc-backlink" href="#id29">5</a>,<a role="doc-backlink" href="#id31">6</a>,<a role="doc-backlink" href="#id44">7</a>,<a role="doc-backlink" href="#id48">8</a>,<a role="doc-backlink" href="#id58">9</a>,<a role="doc-backlink" href="#id59">10</a>,<a role="doc-backlink" href="#id77">11</a>,<a role="doc-backlink" href="#id88">12</a>)</span> +<p>"<a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/index">.NET Microservices: Architecture for Containerized .NET Applications</a>" edition v2.2.1 (<a class="reference external" href="https://aka.ms/microservicesebook">mirror</a>) by Cesar de la Torre, Bill Wagner, Mike Rousos</p> +</aside> +<aside class="footnote brackets" id="fncqrsj" role="note"> +<span class="label"><span class="fn-bracket">[</span>8<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id99">1</a>,<a role="doc-backlink" href="#id100">2</a>)</span> +<p>"<a class="reference external" href="https://docs.microsoft.com/en-US/previous-versions/msp-n-p/jj554200(v=pandp.10)">CQRS Journey</a>" by Dominic Betts, Julián Domínguez, Grigori Melnik, Fernando Simonazzi, Mani Subramanian</p> +</aside> +<aside class="footnote brackets" id="fnoosc" role="note"> +<span class="label"><span class="fn-bracket">[</span>9<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id81">1</a>,<a role="doc-backlink" href="#id82">2</a>,<a role="doc-backlink" href="#id84">3</a>,<a role="doc-backlink" href="#id85">4</a>,<a role="doc-backlink" href="#id86">5</a>,<a role="doc-backlink" href="#id87">6</a>)</span> +<p>"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer</p> +</aside> +<aside class="footnote brackets" id="fnpoeaa" role="note"> +<span class="label"><span class="fn-bracket">[</span>10<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id14">1</a>,<a role="doc-backlink" href="#id105">2</a>,<a role="doc-backlink" href="#id106">3</a>,<a role="doc-backlink" href="#id107">4</a>)</span> +<p>"<a class="reference external" href="https://www.martinfowler.com/books/eaa.html">Patterns of Enterprise Application Architecture</a>" by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford</p> +</aside> +<aside class="footnote brackets" id="fneip" role="note"> +<span class="label"><span class="fn-bracket">[</span>11<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id91">1</a>,<a role="doc-backlink" href="#id93">2</a>,<a role="doc-backlink" href="#id98">3</a>)</span> +<p>"<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/">Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions</a>" by Gregor Hohpe, Bobby Woolf</p> +</aside> +<aside class="footnote brackets" id="fnddia" role="note"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id102">12</a><span class="fn-bracket">]</span></span> +<p>"<a class="reference external" href="https://dataintensive.net/">Designing Data-Intensive Applications. The Big Ideas Behind Reliable, Scalable, and Maintainable Systems</a>" by Martin Kleppmann</p> +</aside> +<aside class="footnote brackets" id="fndre" role="note"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id103">13</a><span class="fn-bracket">]</span></span> +<p>"Database Reliability Engineering. Designing and Operating Resilient Database Systems." by Laine Campbell and Charity Majors</p> +</aside> +<aside class="footnote brackets" id="fnmsp" role="note"> +<span class="label"><span class="fn-bracket">[</span>14<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id89">1</a>,<a role="doc-backlink" href="#id101">2</a>)</span> +<p>"<a class="reference external" href="https://www.manning.com/books/microservice-patterns">Microservices Patterns: With examples in Java</a>" 1st edition by Chris Richardson (<a class="reference external" href="https://microservices.io/book">more info</a>)</p> +</aside> +<aside class="footnote brackets" id="fnkgde1" role="note"> +<span class="label"><span class="fn-bracket">[</span>15<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id35">1</a>,<a role="doc-backlink" href="#id36">2</a>,<a role="doc-backlink" href="#id50">3</a>,<a role="doc-backlink" href="#id51">4</a>,<a role="doc-backlink" href="#id68">5</a>)</span> +<p>"<a class="reference external" href="http://www.kamilgrzybek.com/design/how-to-publish-and-handle-domain-events/">How to publish and handle Domain Events</a>" by Kamil Grzybek</p> +</aside> +<aside class="footnote brackets" id="fnkgde2" role="note"> +<span class="label"><span class="fn-bracket">[</span>16<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id37">1</a>,<a role="doc-backlink" href="#id38">2</a>,<a role="doc-backlink" href="#id49">3</a>,<a role="doc-backlink" href="#id52">4</a>,<a role="doc-backlink" href="#id53">5</a>,<a role="doc-backlink" href="#id54">6</a>)</span> +<p>"<a class="reference external" href="http://www.kamilgrzybek.com/design/handling-domain-events-missing-part/">Handling Domain Events: Missing Part</a>" by Kamil Grzybek</p> +</aside> +<aside class="footnote brackets" id="fnkgoutbox" role="note"> +<span class="label"><span class="fn-bracket">[</span>17<span class="fn-bracket">]</span></span> +<p>"<a class="reference external" href="https://www.kamilgrzybek.com/design/the-outbox-pattern/">The Outbox Pattern</a> by Kamil Grzybek</p> +</aside> +<aside class="footnote brackets" id="fnjbde1" role="note"> +<span class="label"><span class="fn-bracket">[</span>18<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id32">1</a>,<a role="doc-backlink" href="#id33">2</a>)</span> +<p>"<a class="reference external" href="https://lostechies.com/jimmybogard/2010/04/08/strengthening-your-domain-domain-events/">Strengthening your domain: Domain Events</a>" by Jimmy Bogard</p> +</aside> +<aside class="footnote brackets" id="fnjbde2" role="note"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id34">19</a><span class="fn-bracket">]</span></span> +<p>"<a class="reference external" href="https://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/">A better domain events pattern</a>" by Jimmy Bogard</p> +</aside> +<aside class="footnote brackets" id="fnudde1" role="note"> +<span class="label"><span class="fn-bracket">[</span>20<span class="fn-bracket">]</span></span> +<p>"<a class="reference external" href="http://udidahan.com/2008/02/29/how-to-create-fully-encapsulated-domain-models/">How to create fully encapsulated Domain Models</a>" by Udi Dahan</p> +</aside> +<aside class="footnote brackets" id="fnudde2" role="note"> +<span class="label"><span class="fn-bracket">[</span>21<span class="fn-bracket">]</span></span> +<p>"<a class="reference external" href="http://udidahan.com/2008/08/25/domain-events-take-2/">Domain Events – Take 2</a>" by Udi Dahan</p> +</aside> +<aside class="footnote brackets" id="fnudde3" role="note"> +<span class="label"><span class="fn-bracket">[</span>22<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id39">1</a>,<a role="doc-backlink" href="#id40">2</a>,<a role="doc-backlink" href="#id41">3</a>,<a role="doc-backlink" href="#id42">4</a>,<a role="doc-backlink" href="#id69">5</a>)</span> +<p>"<a class="reference external" href="http://udidahan.com/2009/06/14/domain-events-salvation/">Domain Events – Salvation</a>" by Udi Dahan</p> +</aside> +<aside class="footnote brackets" id="fncdltdevie" role="note"> +<span class="label"><span class="fn-bracket">[</span>23<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id43">1</a>,<a role="doc-backlink" href="#id57">2</a>)</span> +<p>"<a class="reference external" href="https://devblogs.microsoft.com/cesardelatorre/domain-events-vs-integration-events-in-domain-driven-design-and-microservices-architectures/">Domain Events vs. Integration Events in Domain-Driven Design and microservices architectures</a>" by Cesar De la Torre, Principal Program Manager, .NET</p> +</aside> +<aside class="footnote brackets" id="fnntuhbr" role="note"> +<span class="label"><span class="fn-bracket">[</span>24<span class="fn-bracket">]</span></span> +<p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/uncovering-hidden-business-rules-with-ddd-aggregates-67fb02abc4b">Uncovering Hidden Business Rules with DDD Aggregates</a> by Nick Tune</p> +</aside> +<aside class="footnote brackets" id="fnmvpe" role="note"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id61">25</a><span class="fn-bracket">]</span></span> +<p>"<a class="reference external" href="https://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/">Patterns for Decoupling in Distributed Systems: Explicit Public Events</a>" by Mathias Verraes</p> +</aside> +<aside class="footnote brackets" id="fngycqrs" role="note"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id80">26</a><span class="fn-bracket">]</span></span> +<p>"<a class="reference external" href="http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/">CQRS, Task Based UIs, Event Sourcing agh!</a>" by Greg Young</p> +</aside> +<aside class="footnote brackets" id="fnvkdesars" role="note"> +<span class="label"><span class="fn-bracket">[</span>27<span class="fn-bracket">]</span></span> +<p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-events-simple-reliable-solution/">Domain events: simple and reliable solution</a>" by Vladimir Khorikov</p> +</aside> +<aside class="footnote brackets" id="fnvkmdebd" role="note"> +<span class="label"><span class="fn-bracket">[</span>28<span class="fn-bracket">]</span></span> +<p>"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/merging-domain-events-dispatching/">Merging domain events before dispatching</a>" by Vladimir Khorikov</p> +</aside> +</aside> </section> -<section id="id11"> -<h2><a class="toc-backref" href="#id28" role="doc-backlink">Психологическая сторона вопроса</a></h2> -<p>Проблеме достижения понимания между представителями бизнеса и техническими специалистами посвятили свои статьи даже такие всемирно-известные светила, как Gregor Hohpe, который пытался объяснить бизнесу важность архитектурных решений на примере <a class="reference internal" href="business-concerns/architecture-options.html#emacsway-architecture-options"><span class="std std-ref">фондовых опционов</span></a>.</p> -<p>А Ward Cunningham предложил использовать метафору <a class="reference internal" href="business-concerns/compound-interest.html#emacsway-compound-interest"><span class="std std-ref">сложного процента (TechnicalDebt)</span></a>, хорошо демонстрирующую экспоненциальную деградацию velocity при дисбалансе решений в пользу краткосрочных бизнес-интересов.</p> -<p>Даже основатели Agile, такие, как Ron Jeffries, имели сложности в достижении понимания с представителями бизнеса, и термин Story Point возник именно потому, что они <a class="reference external" href="https://twitter.com/RonJeffries/status/1052858860539658240?s=20">не смогли объяснить представителю бизнеса, почему 2 идеальных дня занимали 5 календарных дней</a>:</p> -<blockquote> -<div><p>📝 "we estimated stories initially in "ideal time", later in points, tracked number accomplished to adjust how many to pull each iteration. -switched to points because ideal time confused people (why did 2 day story take 5 days).</p> -<p>it worked, i think, because we had low politics."</p> -<p class="attribution">—<a class="reference external" href="https://twitter.com/RonJeffries/status/1052858860539658240?s=20">Ron Jeffries</a></p> -</div></blockquote> -<p>По словам Craig Larman, проблемы могут возникать даже в таких компаниях, как Microsoft, являющихся "колыбелью архитектуры" (откуда вышли такие авторы, как Steve McConnell), см. "<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems Thinking</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">на русском</a>).</p> -<p>Нужно учитывать еще и психологическую составляющую.</p> -<p>Технарь всегда будет отстаивать внутреннее качество программы потому, что от этого зависит его velocity. -Он понимает, что за сорванные сроки виноватым будет именно он. -И даже, если руководство не обвинит его явно, но оно может это запомнить ("взять на карандаш") и учесть это в будущем при принятии кадровых решений (что вызывает еще больше ежедневного страха из-за неопределенности будущего).</p> -<p>Наконец, представитель бизнеса, который сегодня выдает индульгенции на снижение внутреннего качества программы, завтра может быть заменен другим представителем, который эти индульгенции может легко отозвать, и технари останутся с проблемой наедине. -Качество кода не исправляется так же быстро, как отзываются индульгенции, что ставит разработчиков в зависимое положение от конкретной персоны, которая, вероятно, не будет работать в одной и той же должности вечно.</p> -<p>Эти риски создают неопределенность, которая, в результате действия психологического "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%BE%D0%B4%D0%BD%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Эффекта Неоднозначности</a>", вынуждает технаря отстаивать решение, обладающее наименьшей неопределенностью (т.е. настаивать на выполнении технической задачи). -Возникает "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологическая Защита</a>", которая может перерасти в открытый конфликт. -Этот эффект дополнительно еще мультиплицируется распространенным среди технарей "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC_%D1%81%D0%B0%D0%BC%D0%BE%D0%B7%D0%B2%D0%B0%D0%BD%D1%86%D0%B0">Эффектом Самозванца</a>".</p> -<p>Страх неопределенности возникает и у представителя бизнеса. -Зачастую он не уверен в том, хватит ли команде квалификации, чтобы эффективно использовать выделенные ресурсы на технические задачи, и зачастую эта неуверенность подкреплена негативным опытом в прошлом. -Эти страхи, действительно, обоснованы, поскольку на рынке не так уж и много специалистов, способных писать экономически высокоэффективный код. -В силу психологического "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%BE%D0%B4%D0%BD%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Эффекта Неоднозначности</a>", возникает стремление к варианту, обладающему наименьшей неопределенностью, т.е. лучше "запилить еще одну осязаемую бизнес-фичу" вместо того, чтобы потратить ресурсы на призрачную возможность повысить velocity.</p> -<p>Также нужно учитывать и "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%B4%D0%B0%D0%B2%D0%BD%D0%B5%D0%B3%D0%BE">Эффект Недавнего</a>". -Психолог, нобелевский лауреат Даниэль Канеман выделил «правило пик-конец» нашей памяти. -Мы помним прошлое неравномерно. -Наибольший вес мы придаем двум видам событий: тем, что вызвали максимальные эмоции и тем, которые произошли недавно.</p> -<p>В силу <a class="reference internal" href="../../../../../../soft-skills/cognitive-biases.html#emacsway-cognitive-biases"><span class="std std-ref">когнитивных искажений</span></a>, технарь всегда будет недооценивать бизнес-потребности, а бизнесмен - технические потребности. -Это нормально. -К тому же, представители бизнеса всегда находится под давлением других стейкхолдеров бизнес-группы. -Хорошая организация процессов должна взаимокомпенсировать эти перекосы.</p> +Mon, 03 Jul 2023 00:00:00 Immutabilityhttps://dckms.github.io/system-architecture/emacsway/it/ddd/tactical-design/domain-model/value-objects/immutability.html +<span id="emacsway-immutability-in-value-object"/> +<section id="id1"> +<h2>Что делать, если ЯП не поддерживает неизменяемость?</h2> +<p>Когда язык программирования не поддерживает неизменяемость, то странствующий Value Object копируется:</p> <blockquote> -<div><p>📝 "Software development is risky. -<strong>People involved have many fears of what may go wrong.</strong> -To develop effectively we must acknowledge these fears.</p> -<p><strong>Why do we need a software process? For the same reason that we need laws, governments, and taxes: fear.</strong></p> -<p>&lt;...&gt;</p> -<p>Unacknowledged Fear Is the Source of All Software Project Failures</p> -<p>&lt;...&gt;</p> -<p><strong>In order to be successful, a development process must be instituted among customers and developers that secures certain inalienable rights.</strong></p> -<p>&lt;...&gt;</p> -<p>If we are going to develop well, we must create a culture that makes it possible for programmers and customers to acknowledge their fears and accept their rights and responsibilities. -Without such guarantees, we cannot be courageous. -We huddle in fear behind fortress walls, building them ever stronger, adding ever more weight to the development processes we have adopted. -We continually add cannonades and battlements, documents and reviews, procedures and sign-offs, moats with crocodiles, -torture chambers, and huge pots of boiling oil.</p> -<p>But when our fears are acknowledged and our rights are accepted, then we can be courageous. -We can set goals that are hard to reach and collaborate to make those goals. -We can tear down the structures that we built out of fear and that impede us. -We will have the courage to do only what is necessary and no more, to spend our time on what's important rather than on protecting ourselves."</p> -<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 2. Fear"</p> -</div></blockquote> -<p>Глава "Chapter 2. Fear" книги "Planning Extreme Programming" by Kent Beck, Martin Fowler обладает уникальной ценностью, но немного великовата для того, чтобы поместить её сюда полностью.</p> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> -<ul class="simple"> -<li><p>"<a class="reference internal" href="../requirements/nonfunctional-requirements.html#emacsway-agile-nonfunctional-requirements"><span class="std std-ref">Agile nonfunctional Requirements</span></a>"</p></li> -<li><p>"<a class="reference internal" href="business-concerns/compound-interest.html#emacsway-compound-interest"><span class="std std-ref">Technical Debt и сложный процент</span></a>"</p></li> -<li><p>"<a class="reference internal" href="business-concerns/architecture-options.html#emacsway-architecture-options"><span class="std std-ref">Architecture: Selling Options</span></a>"</p></li> -<li><p>"<a class="reference internal" href="business-concerns/common-planning-errors.html#emacsway-agile-common-planning-errors"><span class="std std-ref">Наиболее частые ошибки планирования</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../../../../soft-skills/cognitive-biases.html#emacsway-cognitive-biases"><span class="std std-ref">Список психологических эффектов</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../../uncertainty-management/adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../../uncertainty-management/adaptation/crash-course-in-software-development-economics.html#emacsway-software-development-economics-literature"><span class="std std-ref">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> -<li><p>"<a class="reference internal" href="technical-concerns/when-to-refactor.html#emacsway-when-to-refactor"><span class="std std-ref">Когда делать refactoring в legacy</span></a>"</p></li> -<li><p>"<a class="reference internal" href="technical-concerns/when-to-write-unit-tests.html#emacsway-when-to-write-unit-tests"><span class="std std-ref">Когда писать Unit Tests в legacy</span></a>"</p></li> -</ul> -</div> +<div><p>💬 В принципе два объекта Человек могут и не нуждаться в собственных экземплярах объекта-имени. +Один и тот же объект Имя может совместно использоваться двумя объектами Человек (в каждом будет содержаться указатель на один и тот же экземпляр Имени ), и при этом никаких изменений в их поведении или способе идентификации не потребуется. +То есть, они будут работать правильно, пока у одного человека не изменится имя. +Тогда так же изменится имя и другого человека! +Чтобы этого избежать и сделать совместное использование объекта безопасным, его нужно сделать неизменяемым запрещенным для любых изменений иначе как путем полной замены.</p> +<p>Та же проблема возникает, когда объект передает один из своих атрибутов другому объекту в качестве аргумента или возвращаемого значения. +Со странствующим объектом может случиться все, что угодно, за то время, пока он не находится под контролем владельца. +3НАЧЕНИЕ (VALUE) может измениться таким образом, что будет поврежден и объект-владелец путем искажения его инвариантов. +Чтобы избежать этого, передаваемый объект делают неизменяемым или же передают его КОПИЮ.</p> +<p>In fact, the two Person objects might not need their own name instances. +The same Name object could be shared between the two Person objects (each with a pointer to the same name instance) with no change in their behavior or identity. +That is, their behavior will be correct until some change is made to the name of one person. Then the other person's name would change also! +To protect against this, in order for an object to be shared safely, it must be immutable: it cannot be changed except by full replacement.</p> +<p>The same issues arise when an object passes one of its attributes to another object as an argument or return value. +Anything could happen to the wandering object while it is out of control of its owner. +The VALUE could be changed in a way that corrupts the owner, by violating the owner's invariants. +This problem is avoided either by making the passed object immutable, or by passing a copy.</p> +<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> +</div></blockquote> </section> -Tue, 17 Jan 2023 00:00:00 Как стать успешным разработчикомhttps://dckms.github.io/system-architecture/emacsway/it/self-education/success-roadmap.html<span class="target" id="index-0"/><section id="emacsway-success-roadmap"> -<span id="id1"/> +Mon, 03 Jul 2023 00:00:00 Repository and Anticorruption Layerhttps://dckms.github.io/system-architecture/emacsway/it/ddd/tactical-design/repository/anticorruption-layer.html +<span id="emacsway-repository-in-anticorruption-layer"/> <p><em>Автор раздела: Ivan Zakrevsky</em></p> <blockquote> -<div><p>"My career mission is to help geeks feel safe in the world."</p> -<p class="attribution">—Kent Beck, description of his Linkedin profile</p> +<div><p>💬 In Implementing #DDDesign why use Anticorruption Layer rather than a Repository to integrate with another Bounded Context?</p> +<p>Typically the Repository pattern is used as an Adapter in front of a database. +In general you could think of a Repository as an AcL over a database.</p> +<p>But then again, an AcL is at least both of these: (1) an Adapter, and (2) a Translator. +Typically a Repository doesn't translate from database data into a model's data. +Usually database data is at most reshaped when hydrating models. In other words, you think of an AcL more as a translator between two different model languages, where one language might not be carefully defined. +<strong>A Repository isn't translating between languages, just adapting database data shapes to/from domain model data shapes.</strong></p> +<p>With AcL, make sure you have very good reason to duplicate data across context boundaries. +In general replicating/duplicating data across boundaries is a bad thing.</p> +<p>Every chapter of Implementing #DDDesign, and Chapter 13 in this case, demonstrates different ways of handling similar challenges. The Agile PM Context has a very high autonomy quality attribute. +The Collaboration Context is designed earlier before SaaSOvation had a lot of experience with DDD. +Decisions are never static and certainly imperfect. +Continuous improvement matters.</p> +<p>If you are going to deliver software that is useful and provides valuable customer outcomes, you must make decisions now and later.</p> +<p>As with all software decisions, pattern choice depends. This thread should help make choices clearer.</p> +<p class="attribution">—<a class="reference external" href="https://twitter.com/VaughnVernon/status/1506090113582841859?s=20">Vaughn Vernon</a></p> +</div></blockquote> +<p>Другим отличительным признаком Repository от Adapter (<a class="reference external" href="https://alistair.cockburn.us/hexagonal-architecture/">Ports &amp; Adapter</a>) является их цель: Adapter реализует Port, который явно обозначает границу компонента, в то время как Repository имеет цель эту границу скрыть, и подделать удаленный источник локальным:</p> +<blockquote> +<div><p>💬 Mediates between the domain and data mapping layers using <strong>a collection-like interface</strong> for accessing domain objects.</p> +<p>💬 A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. +Client objects construct query specifications declaratively and submit them to Repository for satisfaction. +<strong>Objects can be added to and removed from the Repository, as they can from a simple collection of objects</strong>, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes.</p> +<p class="attribution">—<a class="reference external" href="https://martinfowler.com/eaaCatalog/repository.html">Repository homepage</a></p> </div></blockquote> +Mon, 03 Jul 2023 00:00:00 О гонке сообщений в условиях конкурирующих подписчиковhttps://dckms.github.io/system-architecture/emacsway/it/integration/asynchronous/message-ordering-in-competing-consumers.html<span class="target" id="index-0"/><section id="emacsway-message-ordering"> +<span id="id1"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<p>Одной из непростых тем в DDD и микросервисной архитектуре является т.н. <strong>проблема "конкурирующих подписчиков"</strong>. Это когда два причинно-зависимых события попадают на конкурирующие узлы обработки событий, и второе событие может "обогнать" первое, например, по причине того, что при обработке первого события возникли сетевые издержки, или запустился сборщик мусора, или по какой-либо причине первое сообщение не было обработано и подтверждено (ack) с первого раза. Возникает гонка сообщений.</p> <nav class="contents" id="id2"> <p class="topic-title">Содержание</p> <ul class="simple"> -<li><p><a class="reference internal" href="#emacsway-success-roadmap" id="id10">Как стать успешным разработчиком</a></p> -<ul> -<li><p><a class="reference internal" href="#id3" id="id11">Несколько исторических примеров</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id12">Дорожная карта</a></p> +<li><p><a class="reference internal" href="#emacsway-message-ordering" id="id7">О гонке сообщений в условиях конкурирующих подписчиков</a></p> <ul> -<li><p><a class="reference internal" href="#id5" id="id13">1. Учимся писать экономически эффективный код</a></p></li> -<li><p><a class="reference internal" href="#id6" id="id14">2. Обучаем команду</a></p></li> -<li><p><a class="reference internal" href="#id7" id="id15">3. Организовываем процессы</a></p></li> -<li><p><a class="reference internal" href="#id8" id="id16">4. Изменяем коллектив</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#id9" id="id17">Если хочется все бросить...</a></p></li> +<li><p><a class="reference internal" href="#id3" id="id8">Поддержка коммутативности</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id9">Исключение причин нарушения очередности событий</a></p></li> +<li><p><a class="reference internal" href="#id5" id="id10">Восстановление очередности сообщений</a></p></li> +<li><p><a class="reference internal" href="#id6" id="id11">Восстановление очередности обработки сообщений</a></p></li> </ul> </li> </ul> </nav> -<p>По поводу "<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC_%D1%81%D0%B0%D0%BC%D0%BE%D0%B7%D0%B2%D0%B0%D0%BD%D1%86%D0%B0">Эффекта Самозванца</a>" (ощущение того, что человек не заслуживает профессиональной позиции, полагая, что окружающие ошибочно думают иначе). -Видно, что эта тема многих беспокоит. -Мне даже известны люди, которые не выдержали напряжения и бросили разработку.</p> -<p>Хотя этот термин здесь не совсем корректно употреблен, и означает он немного другую проблему, но в индустрии этот термин хорошо закрепился и многим понятен.</p> -<p>Наверное, каждого разработчика волнует вопрос его эффективности. -Чаще всего собственная недооценка провоцируется хронической неуспеваемостью, о чем и пойдет речь далее.</p> -<p>Нужно учитывать, что через "Долину Отчаяния" на графике <a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%94%D0%B0%D0%BD%D0%BD%D0%B8%D0%BD%D0%B3%D0%B0_%E2%80%94_%D0%9A%D1%80%D1%8E%D0%B3%D0%B5%D1%80%D0%B0">Даннинга-Крюгера</a> проходят все. -Если вы относите причины неуспеваемости на свой счет, то, вероятно, в вашей компании что-то не так с процессами, которые искажают это восприятие. -Впрочем, подобный уровень организации процессов является, скорее, правилом на рынке труда, чем исключением.</p> -<section id="id3"> -<h2><a class="toc-backref" href="#id11" role="doc-backlink">Несколько исторических примеров</a></h2> -<p>Фрагмент биографии легендарного летчика-аса Ивана Кожедуба:</p> +<p>Например, <a class="reference external" href="https://docs.nats.io/nats-concepts/queue">NATS использует Round-robin для балансировки подписчиков группы</a>, и там эта проблема хорошо проявляется. Партиционирование каналов <a class="reference external" href="https://bravenewgeek.com/building-a-distributed-log-from-scratch-part-5-sketching-a-new-system/">появилось</a> только в пока еще нестабильном <a class="reference external" href="https://github.com/nats-io/jetstream">jetstream</a>.</p> <blockquote> -<div><p>📝 "В начале военной карьеры Ивана Никитовича преследовали неудачи, его даже чуть было не перевели на пост оповещения. -Только заступничество командира полка майора И. Солдатенко помогло ему остаться в полку. -Свою первую победу летчик одержал в ходе 40-го боевого вылета, сбив немецкий пикировщик."</p> -<p class="attribution">—"<a class="reference external" href="https://w.histrf.ru/articles/article/show/kozhiedub_ivan_nikitovich_08_06_1920_08_08_1991_ghgh">Кожедуб Иван Никитович</a>" / Киселев О. Н.</p> +<div><p>Scaling with queue subscribers</p> +<p>This is ideal <strong>if you do not rely on message order</strong>.</p> +<p class="attribution">—"<a class="reference external" href="https://docs.nats.io/running-a-nats-service/nats_admin/slow_consumers#handling-slow-consumers">Slow Consumers - NATS Docs</a>"</p> </div></blockquote> -<p>Каждая ошибка - это ориентир на пути к успеху. -Неважно, сколько ошибок было сделано, важно сколько выводов из них было вынесено. -Правильные решения возникают из опыта. -Опыт возникает из неправильных решений.</p> -<p>Еще один назидательный пример - Кубинец Лопес стал первым в истории четырехкратным олимпийским чемпионом в греко-римской борьбе, превзойдя достижение Александра Карелина.</p> +<p>Обходной путь:</p> <blockquote> -<div><p>📝 В 13 лет его карьера могла завершиться досрочно — он получил страшный двойной перелом ноги...</p> -<p>Лопес уже в 17 лет попал в сборную Кубы, но не все шло гладко. На своем первом крупном соревновании — чемпионате мира 2002 года — молодой Лопес с треском провалился. Он финишировал 13-м в весовой категории до 120 кг. А на следующий год выступил и того хуже — занял 16-е место.</p> -<p>Не заладилось и на Олимпиаде в Афинах — в четвертьфинале кубинца остановил россиянин Хасан Бароев, ставший впоследствии Олимпийским чемпионом и лишенный медали.</p> -<p>"Не понимаю, что я тогда делал не так. Я был готов, был заряжен. Но медали не шли ко мне", — вспоминал об этом впоследствии Лопес.</p> -<p>Но начиная с 2005 года результаты упорного и упрямого кубинца пошли вверх. Он стал чемпионом мира в 2005, 2007, 2009 и 2010 годах.</p> -<p class="attribution">—"<a class="reference external" href="https://tass.ru/opinions/12047595">Скромный кубинский гигант. Кто побил рекорд Карелина в борьбе?</a>" / Лазорин Игорь, ТАСС</p> +<div><p>Create a subject namespace that can scale</p> +<p>You can distribute work further through the subject namespace, with some forethought in design. This approach is useful if you need to preserve message order. The general idea is to publish to a deep subject namespace, and consume with wildcard subscriptions while giving yourself room to expand and distribute work in the future.</p> +<p>For a simple example, if you have a service that receives telemetry data from IoT devices located throughout a city, you can publish to a subject namespace like Sensors.North, Sensors.South, Sensors.East and Sensors.West. Initially, you'll subscribe to Sensors.&gt; to process everything in one consumer. As your enterprise grows and data rates exceed what one consumer can handle, you can replace your single consumer with four consuming applications to subscribe to each subject representing a smaller segment of your data. Note that your publishing applications remain untouched.</p> +<p class="attribution">—"<a class="reference external" href="https://docs.nats.io/running-a-nats-service/nats_admin/slow_consumers#handling-slow-consumers">Slow Consumers - NATS Docs</a>"</p> </div></blockquote> -<p>Кстати, сам Александр Карелин говорил:</p> +<p>Еще одина возможная причина нарушения очередности обработки сообщений:</p> <blockquote> -<div><p>💬 "В успехе только 5% таланта, а остальное - это пот и трудолюбие. -Поэтому нужно захотеть стать чемпионом и не бояться преодолевать трудности. -Самое главное - сделать первый шаг, не бояться наступать на леность, трусость и самовосприятие. -Нужно встать с дивана, поднять сначала свою "тушу", а потом тело соперника на ковре..."</p> -<p class="attribution">—Александр Карелин</p> +<div><p>Note: For a given subscription, messages are dispatched serially, one message at a time. If your application <strong>does not care about processing ordering</strong> and would prefer the messages to be dispatched concurrently, it is the application's responsibility to move them to some internal queue to be picked up by threads/go routines.</p> +<p class="attribution">—"<a class="reference external" href="https://docs.nats.io/using-nats/developer/receiving/async">Asynchronous Subscriptions - NATS Docs</a>"</p> </div></blockquote> -<p>Нередко импульс волевых усилий, необходимый для решения неудач в начале своего профессионального пути, обретает момент инерции уже на всю жизнь, помогая <a class="reference internal" href="../../soft-skills/planning-in-psychology.html#emacsway-planning-in-psychology"><span class="std std-ref">достигнуть уровень высококлассного специалиста</span></a>. Таких примеров история знает немало, в самых различных отраслях.</p> -<p>Юрий Никулин не был принят во ВГИК, т.к. в нем не обнаружили актерских способностей. -Примерно по этой же причине он не поступил в ГИТИС. -Приняли его лишь в школу-студию разговорных жанров при Московском цирке на Цветном бульваре. -Вот такие дела с талантами бывают у людей, оказавшимися позже наиболее талантливыми.</p> -<p>Sylvester Stallone в свое время пришлось даже написать собственный сценарий, чтоб получить роль.</p> -</section> -<section id="id4"> -<h2><a class="toc-backref" href="#id12" role="doc-backlink">Дорожная карта</a></h2> -<section id="id5"> -<h3><a class="toc-backref" href="#id13" role="doc-backlink">1. Учимся писать экономически эффективный код</a></h3> -<p>Первым важным навыком на пути к обретению успеваемости является умение писать <a class="reference internal" href="../sdlc/uncertainty-management/adaptation/crash-course-in-software-development-economics.html#emacsway-software-development-economics-literature"><span class="std std-ref">экономически эффективный код</span></a> с <a class="reference internal" href="../sdlc/models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">пологим характером роста стоимости его изменения</span></a>. -На эту тему было написано <a class="reference internal" href="self-education-for-software-engineer.html"><span class="doc">немало книг</span></a>. -Не понимая истинных причин снижения velocity, человек склонен относить это на свой счет, что препятствует их обнаружению и устранению.</p> -</section> -<section id="id6"> -<h3><a class="toc-backref" href="#id14" role="doc-backlink">2. Обучаем команду</a></h3> -<p>Второй важный навык выводится исходя из модели коллективного владения кодом. -Вы работаете по большей части с кодом, написанным другими участниками команды. -Вы тратите на его чтение, понимание и изменение основную часть времени. -От его качества зависит и ваша персональная успеваемость.</p> -<p>Здесь есть несколько вариантов:</p> +<p>Кроме того, доставка сообщений может пакетироваться из соображений оптимизации.</p> +<p>Один из примеров, который мне запомнился (с какой-то статьи) - это когда один из пользователей соц.сети удаляет из списка друзей другого пользователя, и тут же шлет оставшимся друзьям письмо, в котором дискредитирует удаленного друга. Возникает два события, первое - на удаление друга, второе - на отправку сообщения списку оставшихся друзей. Причем, второе сообщение находится в причинной зависимости от первого, и должно быть обработано после первого. Возникает гонка событий.</p> +<p>В условиях конкурирующих подписчиков, хронология обработки событий может измениться. И тогда, в момент отправки дискредитирующего письма списку друзей, удаленный пользователь все еще будет присутствовать в списке получателей.</p> +<p>Существует несколько стратегий решения этой проблемы:</p> <ol class="arabic simple"> -<li><p>Попасть в струю коллектива, которая работает с качественным кодом. Для этого нужно уметь их собой заинтересовать, поэтому см. п.1.</p></li> -<li><p>Изолироваться от командного legacy и начать формировать новую кодовую базу под себя (вариант кажется фантастическим, но, тем не менее, вполне реальнен).</p></li> -<li><p>Влиять на коллектив, и вместе с коллективом изменять код. Этот вариант тоже возможен, но требует обладания совокупностью качеств. Больше всего мне в этом вопросе помогла книга "Extreme Programming Explained" 1st edition by Kent Beck.</p></li> +<li><p>Нивелировать побочные эффекты (устранить симптомы) от нарушения очередности событий (коммутативность).</p></li> +<li><p>Исключить причины нарушения очередности событий.</p></li> +<li><p>Восстановить очередность сообщений.</p></li> +<li><p>Восстановить очередность обработки сообщений.</p></li> </ol> -<p>Полученные знания нужно умело применять. -Здесь важно понять, с какой стороны начать. -Этот вопрос хорошо освещает статья "<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">Системное мышление</a> by Craig Larman.</p> -</section> -<section id="id7"> -<h3><a class="toc-backref" href="#id15" role="doc-backlink">3. Организовываем процессы</a></h3> -<p>Итак. Теперь вы можете писать высокоэффективный код вместе с командой. -Но это еще не победа. -Успешность во многом зависит от качества организации процессов. -Одно неверное управленческое решение, и команда демотивирована, уходят ключевые специалисты, возникают разногласия и конфликты.</p> -<p>Попасть работать к хорошему менедженту хотя и возможно, но это сложнее, чем попасть работать в хорошую команду. -А это значит, что вы можете рассчитывать только на себя.</p> -<p>Наиболее частые проблемы исходят из-за неверного распределения обязанностей, например, когда продакт занимается не требованиями, а реализацией. -Или методика оценивания задач не соответствует уровню культуры коллектива - индивидуальная оценка задачи может повысить точность планирования в зрелом коллективе, а может напрочь убить взаимопомощь и распространение знаний в развивающемся коллективе, и разогнать комплекс неполноценности до уровня психологического предела (см. "Agile Estimating and Planning" by Mike Cohn), особенно, если при этом еще и путают оценку с обязательством. -Непонимание того, чем является макет UX/UI дизайна (problem vs. solution space) приводит конфликту между продактом и командой. -Неудачная топология заблокирует автономность команд, и команды будут бОльшую часть времени потопать в дискуссиях. -Список можно продолжать. -Вообще, по моим наблюдением, качество организации процессов является основной причиной увольнения значимых специалистов.</p> -<p>Собственно, даже Steve McConnell советовал в некоторых случаях "голосовать ногами". -Вот только вероятность того, что на новом месте менеджмент будет поставлен получше, не сильно высокая.</p> -<p>Поскольку процессы влияют на вас, то вы можете изменить свое положение, влияя на процессы. -Поэтому, грамотный специалист должен уметь <a class="reference internal" href="../sdlc/sdlc-reference.html#emacsway-sdlc-literature"><span class="std std-ref">разбираться в процессах</span></a>.</p> +<p>Будем рассматривать каждый из вариантов поочередно в отдельных постах.</p> +<p>А пока - список литературы, который хорошо освещает эту проблему:</p> +<ul class="simple"> +<li><p>"Designing Data-Intensive Applications. The Big Ideas Behind Reliable, Scalable, and Maintainable Systems" by Martin Kleppmann</p></li> +<li><p>"<a class="reference external" href="https://martin.kleppmann.com/2020/11/18/distributed-systems-and-elliptic-curves.html">Lecture notes (PDF) (including exercises)</a>" by Martin Kleppmann (<a class="reference external" href="https://www.cl.cam.ac.uk/teaching/2021/ConcDisSys/dist-sys-notes.pdf">download</a>, <a class="reference external" href="https://github.com/ept/dist-sys">source code</a>, <a class="reference external" href="https://www.youtube.com/playlist?list=PLeKd45zvjcDFUEv_ohr_HdUFe97RItdiB">video</a>)</p></li> +<li><p>"Database Internals: A Deep Dive into How Distributed Data Systems Work" by Alex Petrov</p></li> +<li><p>"Distributed systems: principles and paradigms" 3d edition by Andrew S. Tanenbaum, Maarten Van Steen</p></li> +<li><p>"<a class="reference external" href="http://books.ifmo.ru/file/pdf/1551.pdf">Введение в распределенные вычисления</a>" / Косяков М. С. — СПб: НИУ ИТМО, 2014. — С. 75-82. — 155 с.</p></li> +<li><p>"Building Event-Driven Microservices" by Adam Bellemare, "<a class="reference external" href="https://www.oreilly.com/library/view/building-event-driven-microservices/9781492057888/ch06.html">Chapter 6. Deterministic Stream Processing</a>"</p></li> +<li><p>"<a class="reference external" href="http://book.mixu.net/distsys/">Distributed systems: for fun and profit</a>" (2013). An introduction to distributed systems. (<a class="reference external" href="https://github.com/mixu/distsysbook">source code</a>)</p></li> +<li><p>"Database Reliability Engineering. Designing and Operating Resilient Database Systems." by Laine Campbell and Charity Majors</p></li> +<li><p>"Streaming Systems: The What, Where, When, and How of Large-Scale Data Processing", by Tyler Akidau, Slava Chernyak, and Reuven Lax, "Chapter 2. The What, Where, When, and How of Data Processing", "Chapter 3. Watermarks"</p></li> +<li><p>"<a class="reference external" href="https://oreil.ly/WO2OC">The Dataflow Model: A Practical Approach to Balancing Correctness, Latency, and Cost in Massive-Scale, Unbounded, Out-of-Order Data Processing</a>" by Tyler Akidau, Robert Bradshaw, Craig Chambers, Slava Chernyak, Rafael J. Fernandez-Moctezuma, Reuven Lax, Sam McVeety, Daniel Mills, Frances Perry, Eric Schmidt, Sam Whittle; Google</p></li> +<li><p>"<a class="reference external" href="https://leanpub.com/dddwithpython">Event Sourced Building Blocks for Domain-Driven Design with Python</a>" by John Bywater</p></li> +</ul> +<p>Статьи по теме:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">Don't Settle for Eventual Consistency. Stronger properties for low-latency geo-replicated storage.</a>" (<a class="reference external" href="https://dl.acm.org/ft_gateway.cfm?id=2610533&amp;ftid=1449165&amp;dwn=1">pdf</a>) by Wyatt Lloyd, Facebook; Michael J. Freedman, Princeton University; Michael Kaminsky, Intel Labs; David G. Andersen, Carnegie Mellon University</p></li> +<li><p>"<a class="reference external" href="http://www.bailis.org/papers/bolton-sigmod2013.pdf">Bolt-on Causal Consistency</a>" by Peter Bailis, Ali Ghodsi, Joseph M. Hellerstein†, Ion Stoica, UC Berkeley KTH/Royal Institute of Technology</p></li> +<li><p>"<a class="reference external" href="https://disco.ethz.ch/courses/hs08/seminar/papers/mattern4.pdf">Detecting Causal Relationships in Distributed Computations:In Search of the Holy Grail</a>" by Reinhard Schwarz, Friedemann Mattern</p></li> +<li><p>"<a class="reference external" href="https://www.microsoft.com/en-us/research/publication/principles-of-eventual-consistency/">Principles of Eventual Consistency</a>" (<a class="reference external" href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/final-printversion-10-5-14.pdf">pdf</a>) by Sebastian Burckhardt, Microsoft Research</p></li> +<li><p>"<a class="reference external" href="https://habr.com/ru/company/ua-hosting/blog/487638/">HighLoad++, Михаил Тюленев (MongoDB): Causal consistency: от теории к практике</a>"</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/articles/patterns-of-distributed-systems/version-vector.html">Version Vector</a>" by Unmesh Joshi</p></li> +<li><p>"<a class="reference external" href="https://www.infoq.com/articles/no-reliable-messaging/">Nobody Needs Reliable Messaging</a>" by Marc de Graauw</p></li> +<li><p>"<a class="reference external" href="https://www.infoq.com/articles/modeling-uncertainty-reactive-ddd/">Modeling Uncertainty with Reactive DDD</a>" by Vaughn Vernon reviewed by Thomas Betts</p></li> +<li><p>"<a class="reference external" href="https://queue.acm.org/detail.cfm?id=3025012">Life Beyond Distributed Transactions</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.confluent.io/blog/error-handling-patterns-in-kafka/">Error Handling Patterns for Apache Kafka Applications</a>" by Gerardo Villeda</p></li> +<li><p>"<a class="reference external" href="https://learn.microsoft.com/en-us/azure/architecture/patterns/competing-consumers">Competing Consumers pattern</a>"</p></li> +</ul> +<p>Список литературы по интеграционным паттернам:</p> +<ul class="simple"> +<li><p>"Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions" by Gregor Hohpe, Bobby Woolf</p></li> +<li><p>"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon</p></li> +<li><p>"Camel in Action" 2nd Edition by Claus Ibsen and Jonathan Anstey</p></li> +</ul> +<p>Примеры интеграционных паттернов:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/VaughnVernon/ReactiveMessagingPatterns_ActorModel">https://github.com/VaughnVernon/ReactiveMessagingPatterns_ActorModel</a></p></li> +<li><p><a class="reference external" href="https://camel.apache.org/components/latest/eips/enterprise-integration-patterns.html">https://camel.apache.org/components/latest/eips/enterprise-integration-patterns.html</a></p></li> +<li><p><a class="reference external" href="https://github.com/camelinaction/camelinaction2">https://github.com/camelinaction/camelinaction2</a></p></li> +<li><p><a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/">https://www.enterpriseintegrationpatterns.com/patterns/messaging/</a></p></li> +</ul> +<p>Каталог моделей согласованности:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://jepsen.io/consistency">https://jepsen.io/consistency</a></p></li> +</ul> +<p>Шпаргалка по EIP-паттернам:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/download/EIPTutorialReferenceChart.pdf">Enterprise Integration Patterns Tutorial Reference Chart</a>"</p></li> +</ul> +<p>Каталоги:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/">Cloud Design Patterns</a>"</p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn568099(v=pandp.10)">Cloud Design Patterns. Prescriptive architecture guidance for cloud applications</a>" by Alex Homer, John Sharp, Larry Brader, Masashi Narumoto, Trent Swanson.</p></li> +</ul> +<p>Code Samples:</p> +<ul class="simple"> +<li><p><a class="reference external" href="http://aka.ms/cloud-design-patterns-sample">http://aka.ms/cloud-design-patterns-sample</a></p></li> +<li><p>"<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/best-practices/">Cloud Best Practices</a>" by Microsoft Corporation and community</p></li> +</ul> +<section id="id3"> +<h2><a class="toc-backref" href="#id8" role="doc-backlink">Поддержка коммутативности</a></h2> +<p>Первая из перечисленных стратегий решения проблемы "конкурирующих подписчиков" - это "<strong>нивелировать побочные эффекты (устранить симптомы) от нарушения очередности событий (коммутативность)</strong>".</p> +<p>Часто бывает так, что два действия подряд над одним и тем же агрегатом приводят к тому, что, в условиях конкурирующих подписчиков, сообщение второго события может обогнать сообщение первого события. Если при этом используется "<strong>Event-Carried State Transfer</strong>" ( <a class="reference external" href="https://martinfowler.com/articles/201701-event-driven.html">https://martinfowler.com/articles/201701-event-driven.html</a> ), то при обработке следующего сообщения (которое было отправлено первым), система будет оперировать уже устаревшими данными.</p> +<p>Как один из вариантов решения проблемы в таком случае, может быть переход на "<strong>Event Notification</strong>". В некоторых случаях прокатывает. Но он ухудшает availability (CAP-Theorem) из-за каскадного синхронного запроса.</p> +<p>В некоторых случаях также прокатывает игнорирование предыдущего события, если последующее событие уже было обработано.</p> </section> -<section id="id8"> -<h3><a class="toc-backref" href="#id16" role="doc-backlink">4. Изменяем коллектив</a></h3> -<p>И, наконец, мы подходим к самой сложной карьерной проблеме - это <a class="reference internal" href="../../soft-skills/change-making.html"><span class="doc">осуществление изменений в коллективе</span></a> с точки зрения <a class="reference internal" href="../../soft-skills/cognitive-biases.html"><span class="doc">коммуникативной, социальной и управленческой психологии</span></a>. -Мало знать, что нужно изменить, нужно еще иметь понимание как это осуществить.</p> +<section id="id4"> +<h2><a class="toc-backref" href="#id9" role="doc-backlink">Исключение причин нарушения очередности событий</a></h2> +<p>Вторая из перечисленных стратегий решения проблемы "конкурирующих подписчиков" - это "<strong>исключить причины нарушения очередности событий</strong>".</p> +<p>Этому способу решения проблемы посвящена глава "<a class="reference external" href="https://livebook.manning.com/book/microservices-patterns/chapter-3/section-3-3-5?origin=product-toc">3.3.5 Competing receivers and message ordering</a>" книги "Microservices Patterns: With examples in Java" by Chris Richardson</p> +<p>Если mеssaging system не поддерживает партиционирование каналов, то его можно реализовать с помощью паттерна EIP "<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/ContentBasedRouter.html">Content-Based Router</a>"</p> +<p>Например, <a class="reference external" href="https://camel.apache.org/components/latest/eips/content-based-router-eip.html">используя Camel Framework</a>.</p> +<p>С помощью партиционирования каналов мы добиваемся того, что все сообщения одного и того же <strong>причинно-зависимого (causal) потока</strong> попадают на один и тот же узел группы подписчиков. Нет конкуренции - нет проблемы. Здесь вводится новый и достаточно обширный термин "<strong>Causal Consistency</strong>", имеющий критически важное значение для всех, кто имеет дело с распределенными системами.</p> +<p>Vaughn Vernon в "Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" (RMPwAM) ссылается на следующие две статьи по этому вопросу:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">https://queue.acm.org/detail.cfm?id=2610533</a></p></li> +<li><p><a class="reference external" href="http://www.bailis.org/papers/bolton-sigmod2013.pdf">http://www.bailis.org/papers/bolton-sigmod2013.pdf</a></p></li> +</ul> +<p>Каталог моделей согласованности:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://jepsen.io/consistency">https://jepsen.io/consistency</a></p></li> +</ul> +<p>Было бы, наверное, уместно упомянуть в контексте этого обсуждения пару превосходных материалов на тему CAP-theorem и Consistency:</p> +<p>Самое понятное объяснение CAP-Theorem, которое я когда-либо видел:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="http://ksat.me/a-plain-english-introduction-to-cap-theorem">A plain english introduction to CAP Theorem</a>" by Kaushik Sathupadi (<a class="reference external" href="https://habr.com/ru/post/130577/">перевод на русский</a>)</p></li> +</ul> +<p>Превосходная статья от CTO of Amazon.com Werner Vogels:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.allthingsdistributed.com/2008/12/eventually_consistent.html">Eventually Consistent - Revisited</a>"</p></li> +</ul> +<p>Превосходная статья по Causal Consistency (Causal Dependencies) доступным языком:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://habr.com/ru/company/ua-hosting/blog/487638/">HighLoad++, Михаил Тюленев (MongoDB): Causal consistency: от теории к практике</a>"</p></li> +</ul> </section> +<section id="id5"> +<h2><a class="toc-backref" href="#id10" role="doc-backlink">Восстановление очередности сообщений</a></h2> +<p>Третья из перечисленных стратегий решения проблемы "конкурирующих подписчиков" - это "<strong>восстановить очередность сообщений</strong>".</p> +<blockquote> +<div><p>📝 "Хьюитт был против включения требований о том, что сообщения должны прибывать в том порядке, в котором они отправлены на модель актора. Если желательно упорядочить входящие сообщения, то это можно смоделировать с помощью очереди акторов, которая обеспечивает такую функциональность. Такие очереди акторов упорядочивали бы поступающие сообщения так, чтобы они были получены в порядке FIFO. В общем же случае, если актор X отправляет сообщение M1 актору Y, а затем тот же актор X отправляет другое сообщение M2 к Y, то не существует никаких требований о том, что M1 придёт к Y раньше M2."</p> +<p class="attribution">—Pаздел "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2#%D0%9D%D0%B8%D0%BA%D0%B0%D0%BA%D0%B8%D1%85_%D1%82%D1%80%D0%B5%D0%B1%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B9_%D0%BE_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BA%D0%B5_%D0%BF%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D0%B9">Никаких требований о порядке поступления сообщений</a>" статьи "Модель акторов" Википедии</p> +</div></blockquote> +<p>Для решения этой задачи можно использовать EIP Pattern "<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/Resequencer.html">Resequencer</a>". Например, <a class="reference external" href="https://camel.apache.org/components/latest/eips/resequence-eip.html">используя Camel Framework</a>.</p> </section> -<section id="id9"> -<h2><a class="toc-backref" href="#id17" role="doc-backlink">Если хочется все бросить...</a></h2> +<section id="id6"> +<h2><a class="toc-backref" href="#id11" role="doc-backlink">Восстановление очередности обработки сообщений</a></h2> +<p>Четвертая из перечисленных стратегий решения проблемы "конкурирующих подписчиков" - это "<strong>восстановить очередность обработки сообщений</strong>".</p> +<p>Иными словами, можно пойти другим путем, и отказаться от гарантированной очередности доставки сообщений. Но, в таком случае, подписчик сам должен будет решать, может ли он обработать поступившее сообщение, или же причинно-предшествующее сообщение еще пока не было обработано, и тогда он должен оставить поступившее сообщение в очереди. Правда, на выяснение этого требуется потратить ресурсы (где-то нужно фиксировать обработку сообщений и потом удостоверяться, что предшествующее причинное сообщение уже было обработано).</p> +<p>Как красиво заметил Alexey Zimarev, "мир occasionally-connected устройств по определению не упорядочен".</p> +<p>Такой подход применяется в Actor Model:</p> <blockquote> -<div><p>📝 "Чтобы жить честно, надо рваться, путаться, ошибаться, начинать и бросать... и вечно бороться и лишаться. -А спокойствие — душевная подлость".</p> -<p class="attribution">—Лев Николаевич Толстой</p> +<div><p>📝 "... модель акторов зеркально отражает систему коммутации пакетов, которая не гарантирует, что пакеты будут получены в порядке отправления. Отсутствие гарантий порядка доставки сообщений позволяет системе коммутации пакетов буферизовать пакеты, использовать несколько путей отправки пакетов, повторно пересылать повреждённые пакеты и использовать другие методы оптимизации."</p> +<p class="attribution">—Pаздел "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2#%D0%9D%D0%B8%D0%BA%D0%B0%D0%BA%D0%B8%D1%85_%D1%82%D1%80%D0%B5%D0%B1%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B9_%D0%BE_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BA%D0%B5_%D0%BF%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BE%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D0%B9">Никаких требований о порядке поступления сообщений</a>" статьи "Модель акторов" Википедии</p> </div></blockquote> <blockquote> -<div><p>📝 "Никогда не ошибается тот, кто ничего не делает."</p> -<p>📝 "Лучше осмеливаться на могучие дела, добиваться славных триумфов, пусть и перемежающихся с неудачами, чем стоять в одном ряду со слабыми духом, которые не могут ни наслаждаться от души, ни сильно страдать, потому что живут в серых сумерках, где нет ни побед, ни поражений.</p> -<p>📝 "Мужество, это когда продолжаешь, хотя сил уже нет.</p> -<p>📝 "Не критик имеет значение, не человек, указывающий, где сильный споткнулся, или где тот, кто делает дело, мог бы справиться с ним лучше. -Уважения достоин тот, кто сам стоит на арене, у кого лицо покрыто потом, кровью и грязью; кто отважно борется; -кто совершает промахи и ошибки, потому что никакой труд не обходится без них; -кто познал великий энтузиазм и великую преданность, кто посвящает себя достойной цели; -кто, при лучшем исходе, достигает высочайшего триумфа, а при худшем, если его постигает неудача, это по крайней мере неудача в великом дерзновении; -и потому никогда он не будет среди тех холодных и робких душ, которым не знакомы ни победа, ни поражение." (Париж, Сорбонна, 1910)</p> -<p class="attribution">—<a class="reference external" href="https://ru.wikiquote.org/wiki/%D0%A2%D0%B5%D0%BE%D0%B4%D0%BE%D1%80_%D0%A0%D1%83%D0%B7%D0%B2%D0%B5%D0%BB%D1%8C%D1%82">Теодор Рузвельт</a></p> +<div><p>📝 "Messages in the Actor model are generalizations of packets in Internet computing in that they need not be received in the order sent. Not implementing the order of delivery, allows packet switching to buffer packets, use multiple paths to send packets, resend damaged packets, and to provide other optimizations.</p> +<p>For example, Actors are allowed to pipeline the processing of messages. What this means is that in the course of processing a message m1, an Actor can designate how to process the next message, and then in fact begin processing another message m2 before it has finished processing m1. Just because an Actor is allowed to pipeline the processing of messages does not mean that it must pipeline the processing. Whether a message is pipelined is an engineering tradeoff."</p> +<p class="attribution">—"<a class="reference external" href="https://arxiv.org/abs/1008.1459">Actor Model of Computation: Scalable Robust Information Systems</a>" by Carl Hewitt</p> </div></blockquote> +<p>Тут нужно сделать короткое отступление. Хотя, как говорилось ранее, "<em>Хьюитт был против включения требований о том, что сообщения должны прибывать в том порядке, в котором они отправлены на модель актора</em>", в современных реализациях Actor Model mailbox представлен как FIFO-queue:</p> <blockquote> -<div><p>📝 "Лучше иногда падать, чем никогда не летать."</p> -<p>📝 "Никогда не бойся делать то, что ты не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник."</p> -<p>📝 "Конь о четырех ногах и то спотыкается."</p> -<p class="attribution">—Народная мудрость (автор неизвестен)</p> +<div><p>📝 "One of the guarantees of the Actor model is sequential message delivery. That is, by default actor mailboxes are first-in, first-out (FIFO) channels. When a message arrives through the actor's channel, it will be received in the order in which it was sent. Thus, if actor A sends a message to actor B and then actor A sends a second message to actor B, the message that was sent first will be the first message received by actor B."</p> </div></blockquote> +<p>Однако, вопрос все-равно остается открытым:</p> <blockquote> -<div><p>📝 "Лучше зажечь одну свечу, чем проклинать темноту."</p> -<p class="attribution">—Махатма Ганди</p> +<div><p>📝 "What if you introduce a third actor, C? Now actor A and actor C both send one or more messages to actor B. There is no guarantee which message actor B will receive first, either the first from actor A or the first from actor C. Nevertheless, the first message from actor A will always be received by actor B before the second message that actor A sends, and the first message from actor C will always +be received by actor B before the second message that actor C sends...</p> +<p>What is implied? Actors must be prepared to accept and reject messages based on their current state, which is reflected by the order in which previous messages were received. Sometimes a latent message could be accepted even if it is not perfect timing, but the actor's reaction to the latent message may have to carefully take into account its current state beforehand. This may be dealt with more gracefully by using the actors become() capabilities."</p> +<p class="attribution">—"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon, Chapter "5. Messaging Channels :: Point-to-Point Channel"</p> </div></blockquote> +<p>Кроме того,</p> <blockquote> -<div><p>📝 "Солнцу безразлично, почитает его светлячок или нет."</p> -<p>📝 "Избегайте тех, кто старается подорвать вашу веру в себя. -Великий человек, наоборот, внушает чувство, что вы можете стать великим."</p> -<p>📝 "Смелость — это сопротивление страху и господство над страхом, а не отсутствие страха."</p> -<p>📝 "Главное — верить. Если веришь, то всё обязательно будет хорошо — даже лучше, чем ты сам можешь устроить."</p> -<p class="attribution">—Марк Твен</p> +<div><p>📝 "Because individual messages may follow different routes, some messages are likely to pass through the processing steps sooner than others, <strong>resulting in the messages getting out of order</strong>. However, some subsequent processing steps do require in-sequence processing of messages, for example to maintain referential integrity.</p> +<p>One common way things get out of sequence is the fact that different messages may take different processing paths. Let's look at a simple example. Let's assume we are dealing with a numbered sequence of messages. If all even numbered messages have to undergo a special transformation whereas all odd numbered messages can be passed right through, then odd numbered messages will appear on the resulting channel while the even ones queue up at the transformation. If the transformation is quite slow, all odd messages may appear on the output channel before a single even message makes it, bringing the sequence completely out of order.</p> +<p>To avoid getting the messages out of order, we could introduce a loop-back (acknowledgment) mechanism that makes sure that only one message at a time passes through the system. The next message will not be sent until the last one is done processing. This conservative approach will resolve the issue, but has two significant drawbacks. First, it can slow the system significantly. If we have a large number of parallel processing units, we would severely underutilize the processing power. In many instances, the reason for parallel processing is that we need to increase performance, so throttling traffic to one message at a time would complete erase the purpose of the solution. The second issue is that this approach requires us to have control over messages being sent into the processing units. However, often we find ourselves at the receiving end of an out-of-sequence message stream without having control over the message origin."</p> +<p class="attribution">—"Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions" by Gregor Hohpe, Bobby Woolf</p> </div></blockquote> +<p>Решение?</p> <blockquote> -<div><p>📝 "Если ты не научишься управлять собой, тобой будут управлять другие."</p> -<p class="attribution">—Хасай Алиев</p> +<div><p>📝 "While not discussed in detail here, Message Metadata can be used to achieve causal consistency [<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">AMC-Causal Consistency</a>] among Messages (130) that must be replicated across a network with full ordering preserved [<a class="reference external" href="http://www.bailis.org/papers/bolton-sigmod2013.pdf">Bolt-on Causal Consistency</a>]."</p> +<p class="attribution">—"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon, Chapter "10. System Management and Infrastructure :: Message Metadata/History"</p> </div></blockquote> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +<blockquote> +<div><p>📝 "Even so, a technique called causal consistency [<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">AMC-Causal Consistency</a>] can be used to achieve the same."</p> +<p class="attribution">—"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon, Chapter "10. System Management and Infrastructure :: Message Journal/Store"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "To see the full power that results from using Domain Events , consider the concept of causal consistency. A business domain provides causal consistency if its operations that are causally related —one operation causes another—are seen by every dependent node of a distributed system in the same order [<a class="reference external" href="https://queue.acm.org/detail.cfm?id=2610533">Causal</a>] . This means that causally related operations must occur in a specific order, and thus one thing cannot happen unless another thing happens before it. Perhaps this means that one Aggregate cannot be created or modified until it is clear that a specific operation occurred to another +Aggregate."</p> +<p class="attribution">—"Domain-Driven Design Distilled" by Vaughn Vernon</p> +</div></blockquote> +<p>Посмотреть вживую <a class="reference external" href="https://eventsourcing.readthedocs.io/en/v8.3.0/topics/process.html#causal-dependencies">обеспечение Causal Consistency</a> на уровне подписчика можно в EventSourcing Framework. Реализация <a class="reference external" href="https://github.com/johnbywater/eventsourcing/blob/fd73c5dbd97c0ae759c59f7bb0700afb12db7532/eventsourcing/application/process.py#L273">здесь</a>.</p> +<p>Собственно, Causal является промежуточным уровнем строгости согласованности, чтобы избежать строгую линеаризацию сообщений (которая часто избыточна) из соображений сохранения параллелизма и повышения производительности, но при этом, не допускать параллелизма в потоках причинно-зависимых сообщений (где очередность сообщений, действительно, востребована).</p> +<p>Обычно идентификатором потока (<code class="docutils literal notranslate"><span class="pre">streamId</span></code>) выступает идентификатор агрегата. А идентификатором последовательности события в этом потоке (<code class="docutils literal notranslate"><span class="pre">position</span></code>) обычно <a class="reference external" href="https://github.com/johnbywater/eventsourcing/blob/fd73c5dbd97c0ae759c59f7bb0700afb12db7532/eventsourcing/application/process.py#L82">выступает номер версии агрегата</a></p> +<p>Другой пример кода, реализующего Causal Store можно посмотреть в главе "6.4.2 Causal Store" статьи "<a class="reference external" href="https://www.microsoft.com/en-us/research/publication/principles-of-eventual-consistency/">Principles of Eventual Consistency</a>" (<a class="reference external" href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/final-printversion-10-5-14.pdf">pdf</a>) by Sebastian Burckhardt, Microsoft Research.</p> +<p>Реализация Vector Clock на Golang - <a class="reference external" href="https://labix.org/vclock">vclock</a>. +Статья об этой библиотеке на сайте автора: "<a class="reference external" href="https://blog.labix.org/2010/12/21/vector-clock-support-for-go">Vector clock support for Go</a>" by Gustavo Niemeyer.</p> +<blockquote> +<div><p>📝 "Note that just <strong>saving the Domain Event in its causal order doesn't guarantee that it will arrive at other distributed nodes in the same order</strong>. Thus, it is also the responsibility of the consuming Bounded Context to recognize proper <strong>causality</strong>. It might be the Domain Event type itself that can indicate causality, or it may be <strong>metadata</strong> associated with the Domain Event, such as a <strong>sequence</strong> or <strong>causal identifier</strong>. The <strong>sequence</strong> or <strong>causal identifier</strong> would <strong>indicate what caused this Domain Event, and if the cause was not yet seen, the consumer must wait to apply the newly arrived event until its cause arrives</strong>. In some cases it is possible to ignore latent Domain Events that have already been superseded by the actions associated with a later one; in this case causality has a dismissible impact [об этом способе уже говорилось ранее, прим. моё]."</p> +<p class="attribution">—"Domain-Driven Design Distilled" by Vaughn Vernon, Chapter "6. Tactical Design with Domain Events:: Designing, Implementing, and Using Domain Events"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "The first option is to use message sessions, a feature of the Azure Service Bus. If you use <strong>message sessions</strong>, this guarantees that messages within a session are delivered in the same order that they were sent. +The second alternative is to modify the handlers within the application to detect out-of-order messages through the use of sequence numbers or timestamps added to the messages when they are sent. <strong>If the receiving handler detects an out-of-order message, it rejects the message and puts it back onto the queue or topic to be processed later, after it has processed the messages that were sent before the rejected message.</strong>"</p> +<p class="attribution">—"CQRS Journey" by Dominic Betts, Julián Domínguez, Grigori Melnik, Fernando Simonazzi, Mani Subramanian, Chapter "<a class="reference external" href="https://docs.microsoft.com/ru-ru/previous-versions/msp-n-p/jj591565(v=pandp.10)#message-ordering">Journey 6: Versioning Our System :: Message ordering</a>"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "<strong>Actors must be prepared to accept and reject messages based on their current state, which is reflected by the order in which previous messages were received.</strong> Sometimes a latent message could be accepted even if it is not perfect timing, but the actor's reaction to the latent message may have to carefully take into account its current state beforehand. This may be dealt with more gracefully by using the actors become() capabilities."</p> +<p class="attribution">—"Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka" by Vaughn Vernon, Chapter "5. Messaging Channels :: Point-to-Point Channel"</p> +</div></blockquote> +<p>Возникает вопрос о том, нужно ли заниматься восстановлением очередности сообщений на уровне Domain Logic, или на уровне Application Logic. +В статье "<a class="reference external" href="https://www.infoq.com/articles/no-reliable-messaging/">Nobody Needs Reliable Messaging</a>" by Marc de Graauw приводятся убедительные аргументы о том, что если это важно для бизнеса, то это должно быть на уровне бизнес-логики (Domain Logic). +Однако, нужно учитывать, что термина "Сообщение" в предметной области вообще не существует (есть только "Событие"). +Зато существует термин "время", которое едино для всего в предметной области, в отличии от времени приложения в распределенной системе.</p> +<p>Таким образом, очередность доставки сообщений - это проблема, свойственная не предметной области, а приложению. +Нужно ли решать её на уровне бизнеса? +Ответ зависит от конкретных обстоятельств.</p> +<p>Еще один из способов решения проблемы согласованности - это дублирование данных, сохранение, обработка и передача зависимых данных атомарно. +Этот прием часто используется для обеспечения границ согласованности Aggregate в DDD, для обеспечения автономности микросервисов и Bounded Contexts.</p> +<blockquote> +<div><p>An implementation consistent with this model would guarantee the invariant relating PO [Purchase Order] and its items, while changes to the price of a part would not have to immediately affect the items that reference it. +Broader consistency rules could be addressed in other ways. +For example, the system could present a queue of items with outdated prices to the users each day, so they could update or exempt each one. +But this is not an invariant that must be enforced at all times. +By making the dependency of line items on parts looser, we avoid contention and reflect the realities of the business better. +At the same time, tightening the relationship of the PO and its line items guarantees that an important business rule will be followed.</p> +<p class="attribution">—"Domain-Driven Design" by Eric Evans</p> +</div></blockquote> +<p>Родственные EIP patterns:</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="self-education-for-software-engineer.html#emacsway-self-education-literature"><span class="std std-ref">Список литературы для самообучения разработчика программного обеспечения</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../soft-skills/planning-in-psychology.html#emacsway-planning-in-psychology"><span class="std std-ref">Психологическое значение планирования</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../soft-skills/learning.html#emacsway-learning-in-psychology"><span class="std std-ref">Кристаллизация знаний. Как читать и не превратиться в коллекционера информации.</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../README.html"><span class="doc">Как пользоваться</span></a>"</p></li> +<li><p>"<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/CorrelationIdentifier.html">Correlation Identifier</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/MessageSequence.html">Message Sequence</a>"</p></li> </ul> -</div> +<p>Применяется в том числе и в Event Sourcing.</p> +<p>В метаданных eventstore есть переменные <code class="docutils literal notranslate"><span class="pre">$causationid</span></code> and <code class="docutils literal notranslate"><span class="pre">$correlationid</span></code>.</p> +<blockquote> +<div><p>📝 "The are both really simple patterns I have never quite understood why they end up so misunderstood. +Let's say every message has 3 ids. 1 is its id. Another is correlation the last it causation. +The rules are quite simple. If you are responding to a message, you copy its correlation id as your correlation id, its message id is your causation id. +This allows you to see an entire conversation (correlation id) or to see what causes what (causation id). +Cheers, +Greg Young"</p> +<p><a class="reference external" href="https://discuss.eventstore.com/t/causation-or-correlation-id/828/4">https://discuss.eventstore.com/t/causation-or-correlation-id/828/4</a></p> +</div></blockquote> +<p>Примеры:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/microsoftarchive/cqrs-journey/blob/6ffd9a8c8e865a9f8209552c52fa793fbd496d1f/scripts/CreateDatabaseObjects.sql#L57-L62">раз</a></p></li> +<li><p><a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd/blob/4e2d66d16f97b3c863fbecd072dad52338516882/src/Modules/Payments/Infrastructure/AggregateStore/SqlStreamAggregateStore.cs#L44-L45">два</a></p></li> +</ul> +<p>Шпаргалка по EIP-паттернам:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/download/EIPTutorialReferenceChart.pdf">Enterprise Integration Patterns Tutorial Reference Chart</a>"</p></li> +</ul> +<p>Но даже если подписчик всего один, и сообщения доставляются последовательно, то и тогда очередность обработки сообщений может быть нарушена. Пример из NATS Streaming Server:</p> +<blockquote> +<div><p>📝 "With the redelivery feature, order can't be guaranteed, since by definition server will resend messages that have not been acknowledged after a period of time. Suppose your consumer receives messages 1, 2 and 3, does not acknowledge 2. Then message 4 is produced, server sends this message to the consumer. The redelivery timer then kicks in and server will resend message 2. The consumer would see messages: 1, 2, 3, 4, 2, 5, etc...</p> +<p>In conclusion, the server does not offer this guarantee although it tries to redeliver messages first thing on startup. That being said, if the durable is stalled (number of outstanding messages &gt;= MaxInflight), then the redelivery will also be stalled, and new messages will be allowed to be sent. When the consumer resumes acking messages, then it may receive redelivered and new messages interleaved (new messages will be in order though)."</p> +<p class="attribution">—nats-streaming-server, <a class="reference external" href="https://github.com/nats-io/nats-streaming-server/issues/187#issuecomment-257024506">issue #187 "Order of delivery"</a>, comment by Ivan Kozlovic</p> +</div></blockquote> +<p>Кстати, проблема очередности доставки сообщений хорошо описана в главе "Projections and Queries :: Building read models from events :: Subscriptions" книги "<a class="reference external" href="https://www.amazon.com/Hands-Domain-Driven-Design-NET-ebook/dp/B07C5WSR9B">Hands-On Domain-Driven Design with .NET Core: Tackling complexity in the heart of software by putting DDD principles into practice</a>" by Alexey Zimarev. И он добавил несколько <a class="reference external" href="https://t.me/emacsway_chat/85">интересных аргументов в чат канала</a>.</p> </section> </section> -Sat, 31 Dec 2022 00:00:00 Краткий курс по экономике разработки программного обеспеченияhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/crash-course-in-software-development-economics.html<span class="target" id="index-0"/><section id="emacsway-software-development-economics-literature"> -<span id="id1"/> +Mon, 03 Jul 2023 00:00:00 Может ли CQRS-команда возвращать результат?https://dckms.github.io/system-architecture/emacsway/it/ddd/tactical-design/cqrs/cqrs-command-and-result.html +<span id="emacsway-cqrs-command-result"/> <p><em>Автор раздела: Ivan Zakrevsky</em></p> -<p>Краткий курс по экономике разработки программного обеспечения:</p> +<p>Статья посвящена довольно дискуссионному вопросу о том, может ли CQRS-команда возвращать результат.</p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p>"Extreme Programming Explained" 1st edition by Kent Beck</p> -<ul> -<li><p>"Chapter 3. Economics of Software Development"</p></li> -<li><p>"Chapter 17. Design Strategy"</p></li> -<li><p>"Chapter 20. Retrofitting XP"</p></li> -<li><p>"Chapter 24. What Makes XP Hard"</p></li> -</ul> -</li> -<li><p>"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin</p> -<ul> -<li><p>"Chapter 3. Agile Principles"</p></li> -<li><p>"Chapter 8. Technical Debt"</p></li> -</ul> -</li> -<li><p>"Software Engineering: A Practitioner's Approach" 9th edition by Roger S. Pressman, Bruce Maxim</p> -<ul> -<li><p>"3.2 Agility and the cost of change"</p></li> -</ul> -</li> -<li><p>"Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman</p> -<ul> -<li><p>"Chapter 7. Modifiability"</p></li> -<li><p>"Chapter 23. Economic analysis of architectures"</p></li> -</ul> -</li> -<li><p>"Refactoring: Improving the Design of Existing Code" 1st (and 2nd) edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p> +<li><p><a class="reference internal" href="#cqrs" id="id10">Может ли CQRS-команда возвращать результат?</a></p> <ul> -<li><p>"Chapter 2. Principles in Refactoring"</p></li> -</ul> -</li> -<li><p>"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +<li><p><a class="reference internal" href="#reference-transparency" id="id11">Значение Reference Transparency в распределенной среде</a></p></li> +<li><p><a class="reference internal" href="#cqrs-cqs" id="id12">Чем отличается CQRS от CQS?</a></p></li> +<li><p><a class="reference internal" href="#id2" id="id13">А есть ли противоречие в авторитетных точках зрения?</a></p></li> +<li><p><a class="reference internal" href="#cqs-referential-transparency-query" id="id14">CQS - это больше о referential transparency для Query</a></p></li> +<li><p><a class="reference internal" href="#command" id="id15">Может ли Command возвращать служебную информацию (код ошибки или успешность выполнения)?</a></p></li> +<li><p><a class="reference internal" href="#command-query" id="id16">Кроме Command и Query существуют еще и функции-конструкторы</a></p></li> +<li><p><a class="reference internal" href="#query-abstract-side-effect-concrete-side-effect" id="id17">Query не должен иметь abstract side effect, но может иметь concrete side effect</a></p></li> +<li><p><a class="reference internal" href="#emacsway-cqs-atomic-routine" id="id18">Что делать с атомарными операциями?</a></p> <ul> -<li><p>"Chapter 1. What Is Design and Architecture?"</p></li> +<li><p><a class="reference internal" href="#emacsway-cqs-reference-argument" id="id19">Процедура не возвращает значения, но может изменить ссылочный аргумент</a></p></li> +<li><p><a class="reference internal" href="#emacsway-cqs-buffer" id="id20">Концепция буфера для разделения атомарных операций Command и Query</a></p></li> </ul> </li> -<li><p>"<a class="reference external" href="https://www.computer.org/education/bodies-of-knowledge/software-engineering">Software Engineering Body of Knowledge (SWEBOK) v.3</a>" (<a class="reference external" href="https://github.com/ligurio/swebok-2004-in-russian">на русском</a>)</p> -<ul> -<li><p>"Chapter 12: Software Engineering Economics"</p></li> +<li><p><a class="reference internal" href="#emacsway-cqrs-command-resource-id" id="id21">Что делать, если CQRS-команда должна вернуть идентификатор созданного ресурса?</a></p></li> +<li><p><a class="reference internal" href="#emacsway-cqrs-one-way-data-flow" id="id22">Однонаправленный поток изменений</a></p></li> +<li><p><a class="reference internal" href="#jimmy-bogard" id="id23">Точка зрения Jimmy Bogard</a></p></li> +<li><p><a class="reference internal" href="#id8" id="id24">Вывод</a></p></li> </ul> </li> -<li><p>"<a class="reference external" href="https://waseda.app.box.com/v/ieee-cs-swebok">Software Engineering Body of Knowledge (SWEBOK) v.4 (draft)</a>"</p> -<ul> -<li><p>"Chapter 15: Software Engineering Economics"</p></li> </ul> -</li> -<li><p>"Working Effectively with Legacy Code" by Michael C. Feathers</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" (хорошо разъясняет виды экономических ущербов: "cost of build", "cost of delay", "cost of carry", "cost of repair", "cost of removing")</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebt.html">Technical Debt</a>"</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebtQuadrant.html">Technical Debt Quadrant</a>"</p></li> -<li><p>"<a class="reference external" href="https://architectelevator.com/architecture/architecture-options/">Architecture: Selling Options</a>" by Gregor Hohpe. How do you explain the value of architecture to business stakeholders? Deferring to the Nobel-prize winning economists Black and Scholes can work surprisingly well.</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/DesignPayoffLine.html">Design Payoff Line</a>"</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>"</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/articles/is-quality-worth-cost.html">Is High Quality Software Worth the Cost?</a>"</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler</p></li> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>" / Сергей Тепляков</p></li> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2012/04/blog-post_19.html">О повторном использовании кода</a>" / Сергей Тепляков</p></li> -<li><p>"<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems thinking</a>" (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">на русском</a>)</p></li> -<li><p>"<a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=8299">Modifiability</a>"</p></li> -<li><p>"<a class="reference external" href="https://youtu.be/DngAZyWMGR0">Making Architecture Matter - Martin Fowler Keynote</a>" - превосходное 14-ти минутное видео.</p></li> -<li><p>"<a class="reference external" href="https://doi.org/10.1155/2020/2976564">Comparing Maintainability Index, SIG Method, and SQALE for Technical Debt Identification</a>" by Peter Strecansky, Stanislav Chren, and Bruno Rossi</p></li> +</nav> +<section id="reference-transparency"> +<span id="emacsway-reference-transparency-in-distributed-systems"/><h2><a class="toc-backref" href="#id11" role="doc-backlink">Значение Reference Transparency в распределенной среде</a></h2> +<p>В последнее время наметилась определенная поляризация парадигм программирования в индустрии.</p> +<p>Стремительный рост объема обрабатываемых данных, потребность в масштабировании, распределенном хранении и параллельной обработке данных, пробудили интерес к функциональному программированию.</p> +<blockquote> +<div><p>📝 "Все состояния гонки (race condition), взаимоблокировки (deadlocks) и проблемы параллельного обновления обусловлены изменяемостью переменных. Если в программе нет изменяемых переменных, она никогда не окажется в состоянии гонки и никогда не столкнется с проблемами одновременного изменения. В отсутствие изменяемых блокировок программа не может попасть в состояние взаимоблокировки.</p> +<p>All race conditions, deadlock conditions, and concurrent update problems are due to mutable variables. You cannot have a race condition or a concurrent update problem if no variable is ever updated. You cannot have deadlocks without mutable locks."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin, перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Однако, индустрия не готова отказаться от императивных подвидов парадигм, таких как OOP.</p> +<p>Можно ли их сочетать, используя достоинства обоих видов парадигм, в зависимости от контекста использования? Как эффективно использовать мультипарадигменные языки, такие как F#, Scala, Elixir?</p> +<p>B.Meyer утверждает, что OOP и FP не противопоставляются, а дополняют друг друга, и ключем к достижению этого является принцип <a class="reference external" href="https://martinfowler.com/bliki/CommandQuerySeparation.html">CQS</a>.</p> +<blockquote> +<div><p>Интервью с Бертраном Мейером</p> +<p>- В последнее время наметилась тенденция в популяризации функциональных языков и функциональной парадигмы программирования. Что вы скажите, является ли объектная технология конкурентом функциональному программированию?</p> +<p>- Нет, эти две парадигмы не являются конкурентами, они успешно могут дополнять друг друга. Тем не менее, тенденция к функциональному программированию является важной и интересной.</p> +<p>На мой взгляд, когда речь идет о высокоуровневой структуре приложения (особенно больших программ), то в мире нет ничего лучше объектного подхода. Я просто не вижу, как можно писать действительно большую программу исключительно на функциональном языке.</p> +<p>С другой стороны, если общая структура приложения построена на основе объектов, то очень даже полезно, если некоторые ее части будут написаны на функциональном языке, для обеспечения простоты и возможности доказательства корректности, о которых я говорил ранее.</p> +<p>Несколько лет назад я опубликовал статью на эту тему, где сравнивал ОО и ФП подходы. В ней я постарался показать, что ОО метод включает функциональное программирование, а не наоборот.</p> +<p>- Да, я кажется читал эту статью, которая затем вошла в качестве одной из глав в книгу "Beautiful Architecture".</p> +<p>- Вы знаете об этом? Я очень впечатлен.</p> +<p>- (Смеюсь...) Да, и насколько я помню, это был ваш ответ на статью Саймона Пейтона Джонса, в которой автор старался показать, что ФП подход является более предпочтительным.</p> +<p>- Да, совершенно верно.</p> +<p>ПРИМЕЧАНИЕ: Речь идет о статье Бертрана "<a class="reference external" href="http://se.ethz.ch/~meyer/publications/functional/meyer_functional_oo.pdf">Software Architecture: Functional vs. Object-Oriented Design in Beautiful Architecture</a>", опубликованной в книге "<a class="reference external" href="https://www.amazon.com/Beautiful-Architecture-Leading-Thinkers-Software/dp/059651798X">Идеальная архитектура. Ведущие специалисты о красоте программных архитектур.</a>". +Эта статья Мейера была ответом на статью Саймона "Composing contracts: an adventure in financial engineering."</p> +<p>- Давайте все же немного вернемся к вопросу OOP vs FP. Какие именно преимущества у функционального подхода на "низком уровне"?</p> +<p>- В Eiffel существует очень важный принцип, под названием <strong>Command-Query Separation Principle, который можно рассматривать, в некотором роде, как сближение ОО и ФП миров</strong>. Я не считаю, что наличие состояния – это однозначно плохо. Но <strong>очень важно, чтобы мы могли ясно различать операции, которые это состояние изменяют (т.е. командами), и операции, которые лишь возвращают информацию о состоянии, его не изменяя (т.е. запросами)</strong>. В других языках эта разница отсутствует. Так, например, в С/С++ часто пишут функции, которые возвращают результат и изменяют состояние. <strong>Следование этому принципу позволяет безопасно использовать выражения с запросами зная, что они не изменяют состояние.</strong> В некоторых случаях можно пойти еще дальше и работать в чисто функциональном мире с полным отсутствием побочных эффектов."</p> +<p class="attribution">—Bertrand Meyer в интервью Сергея Теплякова "<a class="reference external" href="https://sergeyteplyakov.blogspot.com/2014/05/interview-with-bertrand-meyer.html">Интервью с Бертраном Мейером</a>"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "For both theoretical and practical reasons detailed elsewhere [10], the command-query separation principle is a methodological rule, not a language feature, but all serious software developed in Eiffel observes it scrupulously, to great referential transparency advantage. Although other schools of object-oriented programming regrettable do not apply it (continuing instead the C style of calling functions rather than procedures to achieve changes), but in my view it is a key element of the object-oriented approach. It seems like a viable way to obtain the referential transparency goal of functional programming — since expressions, which only involve queries, will not change the state, and hence can be understood as in traditional mathematics or a functional language — while acknowledging, through the notion of command, the fundamental role of the concept of state in modeling systems and computations."</p> +<p class="attribution">—"<a class="reference external" href="http://se.ethz.ch/~meyer/publications/functional/meyer_functional_oo.pdf">Software architecture: object-oriented vs functional</a>" by Bertrand Meyer</p> +</div></blockquote> +<p>Две известные статьи от Rober Martin на тему OOP vs FP:</p> +<ul class="simple"> +<li><p><a class="reference external" href="http://blog.cleancoder.com/uncle-bob/2014/11/24/FPvsOO.html">http://blog.cleancoder.com/uncle-bob/2014/11/24/FPvsOO.html</a></p></li> +<li><p><a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2018/04/13/FPvsOO.html">https://blog.cleancoder.com/uncle-bob/2018/04/13/FPvsOO.html</a></p></li> </ul> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +<p>Ну а я, как поклонник Emacs и Lisp, не могу обойти вниманием его статью про Clojure:</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a></p></li> -<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/technical-concerns/when-to-refactor.html#emacsway-when-to-refactor"><span class="std std-ref">Когда делать refactoring в legacy</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/technical-concerns/when-to-write-unit-tests.html#emacsway-when-to-write-unit-tests"><span class="std std-ref">Когда писать Unit Tests в legacy</span></a>"</p></li> -<li><p>"<a class="reference internal" href="software-design/software-design.html#emacsway-agile-software-design"><span class="std std-ref">Role of Software Design in Agile</span></a>"</p></li> -<li><p>"<a class="reference internal" href="software-design/patterns.html#emacsway-agile-patterns"><span class="std std-ref">Role of Design Patterns in Agile</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../../soft-skills/icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Принцип ледокола</span></a>"</p></li> -<li><p>"<a class="reference internal" href="adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">Что такое Agile Development</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/balancing-business-technical-concerns.html#emacsway-agile-balancing-business-technical-concerns"><span class="std std-ref">Балансирование Бизнес/Технических интересов</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/business-concerns/common-planning-errors.html#emacsway-agile-common-planning-errors"><span class="std std-ref">Наиболее частые ошибки планирования</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/business-concerns/compound-interest.html#emacsway-compound-interest"><span class="std std-ref">Technical Debt и сложный процент</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/business-concerns/architecture-options.html#emacsway-architecture-options"><span class="std std-ref">Architecture: Selling Options</span></a>"</p></li> +<li><p><a class="reference external" href="http://blog.cleancoder.com/uncle-bob/2019/08/22/WhyClojure.html">http://blog.cleancoder.com/uncle-bob/2019/08/22/WhyClojure.html</a></p></li> </ul> -</div> +<p>Хорошая статья "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/what-is-functional-programming/">What is functional programming?</a>" by Vladimir Khorikov.</p> </section> -Wed, 02 Nov 2022 00:00:00 Что такое Adaptationhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.html -<span id="emacsway-adaptation"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> +<section id="cqrs-cqs"> +<span id="emacsway-cqrs-vs-cqs"/><h2><a class="toc-backref" href="#id12" role="doc-backlink">Чем отличается CQRS от CQS?</a></h2> +<p><a class="reference external" href="https://martinfowler.com/bliki/CQRS.html">CQRS</a> лишь немного отличается от <a class="reference external" href="https://martinfowler.com/bliki/CommandQuerySeparation.html">CQS</a> по исполнению. +Ввел этот термин Greg Young, поэтому, к нему и обратимся:</p> +<blockquote> +<div><p>📝 "<strong>Starting with CQRS, CQRS is simply the creation of two objects where there [CQS] was previously only one.</strong> The separation occurs based upon whether the methods are a command or a query (the same definition that is used by Meyer in Command and Query Separation, a command is any method that mutates state and a query is any method that returns a value)... That is it. That is the entirety of the CQRS pattern. There is nothing more to it than that…" +— "<a class="reference external" href="http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/">CQRS, Task Based UIs, Event Sourcing agh!</a>" by Greg Young</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Command and Query Responsibility Segregation was originally considered just to be an extension of this [CQS] concept."</p> +<p>📝 "Command and Query Responsibility Segregation (CQRS) originated with Bertrand Meyer's Command and Query Separation Principle."</p> +<p>📝 "Command and Query Responsibility Segregation uses the same definition of Commands and Queries that Meyer used and maintains the viewpoint that they should be pure. <strong>The fundamental difference is that in CQRS objects are split into two objects, one containing the Commands one containing the Queries.</strong>"</p> +<p class="attribution">—"<a class="reference external" href="https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf">CQRS Documents by Greg Young</a>"</p> +</div></blockquote> +<p>Хорошая статья про CQRS: "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/types-of-cqrs/">Types of CQRS</a>" by Vladimir Khorikov. +Обратите внимание на комментарии внизу статьи - ее прорецензировал собственноручно Greg Young, автор термина CQRS.</p> +</section> +<section id="id2"> +<h2><a class="toc-backref" href="#id13" role="doc-backlink">А есть ли противоречие в авторитетных точках зрения?</a></h2> +<p>В одном из самых авторитетных reference application eShopOnContainers от Microsoft, одна из CQRS-команд возвращает результат:</p> <ul class="simple"> -<li><p><a class="reference internal" href="#adaptation" id="id6">Что такое Adaptation</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id7">Суть Адаптации</a></p></li> -<li><p><a class="reference internal" href="#id3" id="id8">Назначение Адаптации</a></p></li> -</ul> -</li> +<li><p><a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderDraftCommandHandler.cs#L40">раз</a></p></li> +<li><p><a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs#L151">два</a></p></li> </ul> -</nav> -<section id="id2"> -<h2><a class="toc-backref" href="#id7" role="doc-backlink">Суть Адаптации</a></h2> +<p>Однако, в известной "Красной книге", Vaughn Vernon пишет:</p> <blockquote> -<div><p>📝 "No crystal balls. -Humans are not able to predict the future. -For example, your competition makes an announcement that was not expected. -Unanticipated technical problems crop up that force a change in direction. -Furthermore, people are particularly bad at planning uncertain things far into the future – guessing today how you will be spending your week eight months from now is something of a fantasy. -It has been the downfall of many a carefully constructed Gantt chart."</p> -<p class="attribution">—"Jeff Sutherland's Scrum Handbook" by Jeff Sutherland</p> +<div><p>📝 "This principle, devised by Bertrand Meyer, asserts the following:</p> +<p>"Every method should be either a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer.More formally, methods should return a value only if they are referentially transparent and hence possess no side effects." [Wikipedia, CQS]</p> +<p>At an object level this means:</p> +<ol class="arabic simple"> +<li><p>If a method modifies the state of the object, it is a command, and its method must not return a value. In Java and C# the method must be declared void.</p></li> +<li><p><strong>If a method returns some value, it is a query, and it must not directly or indirectly cause the modification of the state of the object.</strong> In Java and C# the method must be declared with the type of the value it returns."</p></li> +</ol> +<p class="attribution">—"Implementing Domain-Driven Design" by Vaughn Vernon, Chapter "4. Architecture :: Command-Query Responsibility Segregation, or CQRS"</p> +</div></blockquote> +<p>Другое, не менее авторитетное архитектурное руководство от Microsoft, утверждает:</p> +<blockquote> +<div><p>📝 "A query returns data and does not alter the state of the object; <strong>a command changes the state of an object but does not return any data.</strong>"</p> +<p class="attribution">—"<a class="reference external" href="https://docs.microsoft.com/en-us/previous-versions/msp-n-p/jj591573(v=pandp.10)#what-is-cqrs">CQRS Journey :: Reference 2: Introducing the Command Query Responsibility Segregation Pattern :: What is CQRS?</a>"</p> </div></blockquote> +<p>Противоречие? Архитектура - это, как известно, наука об ограничениях, о том, как не надо делать. +Почему же тогда одно из самых авторитетных reference application, консультантами которого являются такие светила, как Cesar De la Torre, Jimmy Nilsson, Udi Dahan, Jimmy Bogard, и другие, это ограничение нарушает? +Что это - компромисс, вызванный практической целесообразностью, или демонстрация принципиального архитектурно чистого решения?</p> +<p>Ответ на этот вопрос мы попытаемся найти в этой статье.</p> +</section> +<section id="cqs-referential-transparency-query"> +<span id="emacsway-cqs-query-referential-transparency"/><h2><a class="toc-backref" href="#id14" role="doc-backlink">CQS - это больше о referential transparency для Query</a></h2> +<p>Итак, начнем по порядку, с принципа CQS:</p> <blockquote> -<div><p>📝 "Глаза боятся - руки делают."</p> -<p class="attribution">—Народная пословица.</p> +<div><p>📝 "Command-Query Separation <strong>principle - Functions should not produce abstract side effects</strong>."</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> </div></blockquote> -<p>Суть Adaptation (Адаптации) заключается в том, что мы не пытаемся разрешить неопределенность заблаговременно путем логического вывода, а, в противовес <a class="reference internal" href="../prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Prediction</span></a>, разрешаем неопределенность опытным, экспериментальным путем (широко известным как "метод научного тыка" 🙂️). -Выдвигаем гипотезу, вносим её в план, реализуем Системный Инкремент, инспектируем результат на практике, и адаптируем план на следующую итерацию. -Этот цикл образует <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">итерацию</span></a>.</p> -<p>Полученные практическим способом знания, снижающие неопределенность, являются входными аргументами для следующей <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">итерации</span></a>.</p> +<p id="emacsway-cqs-concrete-side-effect">Обратите внимание на термин abstract. B.Meyer различает abstract и concrete side effects.</p> <blockquote> -<div><p>📝 ""Iteration" here means applying a function to itself."</p> -<p class="attribution">—"Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik</p> +<div><p>📝 "Definition: concrete side effect: A function produces a concrete side effect if its body contains any of the following: +1. An assignment, assignment attempt or creation instruction whose target is an attribute. +2. A procedure call."</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +</div></blockquote> +<span class="target" id="emacsway-cqs-abstract-side-effect"/><blockquote> +<div><p>📝 "Since not every class definition is accompanied by a full-fledged specification of the underlying abstract data type, we need a more directly usable definition of "abstract side effect". This is not difficult. In practice, the abstract data type is defined by the interface offered by a class to its clients (expressed for example as the short form of the class). A side effect will affect the abstract object if it changes the result of any query accessible to these clients. Hence the definition:</p> +<p>Definition: abstract side effect: An abstract side effect is a concrete side effect that can change the value of a non-secret query.</p> +<p>The definition refers to "non-secret" rather than exported queries. The reason is that in-between generally exported and fully secret status, we must permit a query to be selectively exported to a set of clients. As soon as a query is non-secret — exported to any client other than NONE — we consider that changing its result is an abstract side effect, since the change will be visible to at least some clients."</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "The Command-Query Separation principle brings <strong>referential transparency</strong> back."</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +</div></blockquote> +<span class="target" id="emacsway-reference-transparency"/><blockquote> +<div><p>📝 "Definition: referential transparency: An expression e is referentially transparent if it is possible to exchange any subexpression with its value without changing the value of e."</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> </div></blockquote> +<p>Подведу короткое резюме всему ранее сказанному: CQS не запрещает изменять состояние, если оно не нарушает ссылочную прозрачность. Соблюдение этого условия открывает нам возможность пользоваться всеми преимуществами функционального программирования. Это и есть цель CQS.</p> </section> -<section id="id3"> -<h2><a class="toc-backref" href="#id8" role="doc-backlink">Назначение Адаптации</a></h2> -<p>Рость неопределенности приводит к росту стоимости Prediction по мере роста его точности. -Предел экономической целесообразности Prediction определяется пересечением графика роста стоимости Prediction (в зависимости от его точности) с графиком роста бизнес-выгод от точности Прогнозирования.</p> -<p>Там, где сумма произведений количества Адаптаций Системного Инкремента на стоимость Адаптации системного инкремена для каждой итерации пересечет сумму экономически целесообразной стоимости Prediction на горизонте планирования, возникает предел экономической целесообразности эмпирического способа обработки неопределенности Проекта при допущении, что остаточная стоимость самой реализации (которая не имеет отношения к разрешению неопределенности) остается неизменной в обоих случаях. -Обратите внимание, в данном случае речь идет о стоимости Адаптации Системного Инкремента, а не Плана. -Т.е. речь идет о стоимости экспериментального разрешения неопределенности (цикл ошибка - исправление).</p> -<p>Prediction при этом не исчезает полностью, а понижает свою точность и дополняется Адаптацией. -Для наилучшего совокупного экономического эффекта важно правильно находить <a class="reference internal" href="../balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">баланс между Prediction и Adaptation</span></a>, а также обеспечивать <a class="reference internal" href="../../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">характер роста стоимости Adaptation максимально приближенный к горизонтальной асимптоте</span></a>, поскольку, чем больше Адаптаций Системного Инкремента возникает на горизонте планирования, тем дороже становится экспериментальный способ разрешения неопределенности по сравнению с логическим.</p> -<p>При этом нужно учитывать, что стоимость Prediction также не константна по отношению к жизненному циклу системы, а имеет тенденцию к понижению. -Т.е. чем большая часть системы уже реализована, тем больше баланс экономической целесообразности смещается от Adaptation к Prediction.</p> -<figure class="align-left" id="id4"> -<a class="reference internal image-reference" href="../../../../../_images/cost-of-decision-over-time.png"><img alt="FIGURE 3.6 Make decisions at the last responsible moment. The image source is &quot;Essential Scrum: A Practical Guide to the Most Popular Agile Process&quot; by Kenneth Rubin, &quot;Chapter 3 Agile Principles :: Prediction and Adaptation&quot;." src="../../../../../_images/cost-of-decision-over-time.png" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">FIGURE 3.6 Make decisions at the last responsible moment. The image source is "Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation".</span></p> -<div class="legend"> +<section id="command"> +<span id="emacsway-cqs-command-status-code"/><h2><a class="toc-backref" href="#id15" role="doc-backlink">Может ли Command возвращать служебную информацию (код ошибки или успешность выполнения)?</a></h2> +<p>Не Команде запрещено возвращать информацию об объекте, а Запросу на получение информации об объекте запрещено нарушать ссылочную прозрачность. +На это указывает и сам B. Meyer (учтите, что <a class="reference external" href="https://fsharpforfunandprofit.com/rop/">Railway Oriented Programming</a> и <a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/results">Result type</a> в то время еще не было):</p> <blockquote> -<div><p>📝 "Most of us would prefer to wait until we have more information so that we can make a more informed decision. -When dealing with important or irreversible decisions, if we decide too early and are wrong, we will be on the exponential part of the cost-of-deciding curve in Figure 3.6. -As we acquire a better understanding regarding the decision, the cost of deciding declines (the likelihood of making a bad -decision declines because of increasing market or technical certainty). -That's why we should wait until we have better information before committing to a decision."</p> -<p class="attribution">—"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin, "Chapter 3 Agile Principles :: Prediction and Adaptation"</p> +<div><p>📝 "It is important here two deal with two common objections to the side-effect-free style.</p> +<p>The first has to do with error handling. Sometimes a function with side effects is really a procedure, which in addition to doing its job returns a status code indicating how things went. But there are better ways to do this; roughly speaking, the proper O-O technique is to <strong>enable the client, after an operation on an object, to perform a query on the status, represented for example by an attribute of the object</strong>, as in</p> +<p>target.some_operation(...)</p> +<p>how_did_it_go := target.status</p> +<p>Note that the technique of returning a status as function result is lame anyway. It transforms a procedure into a function by adding the status as a result; <strong>but it does not work if the routine was already a function, which already has a result of its own</strong>. It is also problematic if you need more than one status indicator. In such cases the C approach is either to return a "structure" (the equivalent of an object) with several components, which is getting close to the above scheme, or to use global variables — which raises a whole set of new problems, especially in a large system where many modules can trigger errors."</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> </div></blockquote> -</div> -</figcaption> -</figure> -<p>Это и есть та самая причина, по которой выбор SDLC-модели является неотъемлемой частью процесса проектирования, и изучается архитектурой. -Ведь различные SDLC-модели (итеративные, инкрементальные, спиральные, гибридные, каскадные), реализованные в виде Scrum, RUP, SAFe, BDUF etc., обладают различным соотношением Prediction vs. Adaptation, имеют разные подходы к масштабированию команд и различные ограничения. -Выбор SDLC-модели сильно зависит от ситуативного контекста проектирования. -Повторюсь, основная цель итеративной разработки - удешевить стоимость проектирования в условиях неопределенности.</p> -<p>Об этом Брукс писал в Мифическом человеко-месяце еще до появления Agile Manifesto:</p> +<p>Таким образом, строгого запрета на возврат командой чего-либо (например, информации об ошибке выполнения) не существует. +Существует только пояснение почему и в пользу чего нужно стремиться этого избегать, где основной причиной для избегания является как раз именно то, что <strong>команда может возвращать значение, отличное от информации об ошибке</strong>.</p> +<p>Таким образом, мы выяснили, что команда может быть функцией, возвращающей служебную информацию об успешности выполнения, если иной способ невозможен.</p> +<p>Вернемся к основам:</p> <blockquote> -<div><p>📝 "Therefore the most important function that software builders do for their clients is the <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a> <strong>extraction and refinement of the product requirements</strong>...</p> -<p>I would go a step further and assert that it is really impossible for clients, even those working with software engineers, to specify completely, precisely, and correctly the exact requirements of a modern software product before having built and tried some versions of the product they are specifying.</p> -<p>Therefore one of the most promising of the current technological efforts, and one which attacks the essence, not the accidents, of the software problem, is the development of approaches and tools for rapid prototyping of systems as part of the <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a> <strong>specification of requirements</strong>."</p> -<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr.</p> +<div><p>📝 "Commands and queries.</p> +<p>A few reminders on terminology will be useful. The features that characterize a class are divided into commands and queries. <strong>A command serves to modify objects, a query to return information about objects. A command is implemented as a procedure.</strong> A query may be implemented either as an attribute, that is to say by reserving a field in each run-time instance of the class to hold the corresponding value, or as a function, that is to say through an algorithm that computes the value when needed. Procedures (which also have an associated algorithm) and functions are together called routines.</p> +<p><strong>The definition of queries does not specify whether in the course of producing its result a query may change objects.</strong> For commands, the answer is obviously yes, since it is the role of commands (procedures) to change things. Among queries, the question only makes sense for functions, since accessing an attribute cannot change anything. A change performed by a function is known as a side effect to indicate that it is ancillary to the function's official purpose of answering a query. Should we permit side effects?"</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> </div></blockquote> +<p>Отсюда следует ряд выводов. Основной вопрос CQS лежит в плоскости Queries, и сводится с ссылочной прозрачности.</p> +<p>Хотя B.Meyer и использует термин procedure, которая, по определению ничего не возвращает ("Procedure - A routine which does not return a result. (The other form of routine is the function.)" - glossary книги "Object-Oriented Software Construction" 2nd edition by Bertrand Meyer), он ясно выразил разделение Команд и Запросов <strong>по назначению</strong>: "A command serves to modify objects, a query to return information about objects."</p> +<p>Это определение не отвечает на вопрос, изменится ли суть команды, если она будет возвращать служебную информацию о процессе выполнения, которая не является информацией об объекте, и не нарушает ссылочную прозрачность (которая по определению не применима к командам). +Этот момент очень важен, и в будущем мы еще к нему вернемся. +Но, зато, он ясно дал понять, что команда может возвращать значение, и именно поэтому, желательно избегать возврата ею информации об ошибке. +В наши дни, напомню, такая проблема больше не актуальна. +Тем более, она не актуальна при переносе этого вопроса на способы сетевого взаимодействия.</p> +</section> +<section id="command-query"> +<span id="emacsway-cqs-factory-result"/><h2><a class="toc-backref" href="#id16" role="doc-backlink">Кроме Command и Query существуют еще и функции-конструкторы</a></h2> +<p>А теперь самое важное. +При обсуждении CQRS этот момент часто незаслуженно опускается. +Кроме процедур-команд и функций-запросов, Bertrand Meyer вводит еще и <strong>функции-конструкторы</strong>! +И вот тут кроется интересное. +Накладывается ли на функцию-конструктор ограничение на side effect - зависит от контекста её применения:</p> <blockquote> -<div><p>💬 Furthermore, a waterfall approach forces us into a predictive style of planning, it assumes that once you are done with a phase, such as requirements analysis, the resulting deliverable is a stable platform for later phases to base their work on. -In practice the vast majority of software projects find they need to change their requirements significantly within a few months, due to everyone learning more about the domain, the characteristics of the software environment, and changes in the business environment. -Indeed we've found that delivering a subset of features does more than anything to help clarify what needs to be done next, so an iterative approach allows us to shift to an adaptive planning approach where we update our plans as we learn what the real software needs are.</p> -<p>These are the major reasons why I've <a class="reference external" href="https://martinfowler.com/books/uml.html">glibly said that</a> "you should use iterative development only in projects that you want to succeed".</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/WaterfallProcess.html">Waterfall Process</a>" by Martin Fowler</p> +<div><p>📝 "Functions that create objects.</p> +<p>A technical point needs to be clarified before we examine further consequences of the Command-Query Separation principle: <strong>should we treat object creation as a side effect</strong>?</p> +<p>The answer is yes, as we have seen, if the target of the creation is an attribute a: in this case, the instruction !! a changes the value of an object's field. The answer is no if the target is a local entity of the routine. But what if the target is the result of the function itself, as in !! Result or the more general form !! Result.make (...)?</p> +<p>Such a creation instruction need not be considered a side effect. It does not change any existing object and so does not endanger referential transparency (at least if we assume that there is enough memory to allocate all the objects we need).</p> +<p>From a mathematical perspective we may pretend that all of the objects of interest, for all times past, present and future, are already inscribed in the Great Book of Objects; <strong>a creation instruction is just a way to obtain one of them, but it does not by itself change anything in the environment</strong>. It is common, and legitimate, for a function to create, initialize and return such an object.</p> +<p><strong>These observations assume that in the second form the creation procedure make does not produce side effects on any object other than the one being created.</strong>"</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> </div></blockquote> -<p>Конечно, сугубо семантически, термин "<a class="reference internal" href="../../models/agile/analysis/requirements/requirements.html#emacsway-agile-requirements"><span class="std std-ref">requirements</span></a>" немного вводит в заблуждение в Agile, ведь заранее требования к продукту неизвестны полностью, и они изменяются по мере реализации продукта. -А в таком случае, как они могут что-то требовать? -Вы, наверное, встречали картинку с треугольником "<a class="reference external" href="https://www.atlassian.com/agile/agile-at-scale/agile-iron-triangle">Iron Triangle</a>" (Requirements/Scope, Cost, Time), где в waterfall он обращен вершиной Requirements вниз (константная область), а в Agile - вверх (переменная область). The iron triangle of planning:</p> -<figure class="align-left" id="id5"> -<a class="reference internal image-reference" href="../../../../../_images/iron-triangle.png"><img alt="Iron Triangle. Agile fixes the date and resources and varies the scope. The image source is &quot;Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise&quot; by Dean Leffingwell" src="../../../../../_images/iron-triangle.png" style="width: 90%;"/></a> -<figcaption> -<p><span class="caption-text">Iron Triangle. Agile fixes the date and resources and varies the scope. The image source is "Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</span></p> -</figcaption> -</figure> -<p>Итеративная разработка востребована, когда невозможно достигнуть полноты (Complete) требований (set of <a class="reference internal" href="../../models/agile/analysis/requirements/requirements.html#emacsway-agile-requirements"><span class="std std-ref">requirements</span></a>).</p> +<p>Это замечание B.Meyer является очень важным, так как наиболее частый вопрос CQRS - это возврат идентификатора созданного ресурса и исполнение требований RFC-7231 для HTTP-method POST REST API:</p> +<blockquote> +<div><p>📝 "the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created (Section 7.1.2) and a representation that describes the status of the request while referring to the new resource(s).</p> +<p class="attribution">—"<a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-4.3.3">Section 4.3.3. POST of RFC-7231</a>"</p> +</div></blockquote> +</section> +<section id="query-abstract-side-effect-concrete-side-effect"> +<span id="emacsway-cqs-query-side-effect"/><h2><a class="toc-backref" href="#id17" role="doc-backlink">Query не должен иметь abstract side effect, но может иметь concrete side effect</a></h2> +<p>Говоря о "<a class="reference internal" href="#emacsway-cqs-query-referential-transparency"><span class="std std-ref">side effect</span></a>", B.Meyer накладывает ограничение на "<a class="reference internal" href="#emacsway-cqs-abstract-side-effect"><span class="std std-ref">abstract side effect</span></a>", и поясняет на примере. +Сразу скажу, без прочтения главы 11 вряд ли можно понять о чем здесь идет речь. +Но обойти вниманием этот пример тоже нельзя.</p> +<blockquote> +<div><p>📝 "Unfortunately, this would be unacceptably restrictive, explaining why the Command-Query Separation principle only prohibits abstract side effects, a notion that will now be defined. The problem is that some concrete side effects are not only harmless but necessary. They are of two kinds.</p> +<p>&lt;...&gt;</p> +<p>Side effects of the second acceptable category may change the state of the object, but only affecting properties that are not visible to clients. To understand the concepts in depth, it will be useful to make sure that you are familiar with the discussion of "abstraction function" and "implementation invariants" in the presentation of Design by Contract. (In particular, take a look at the accompanying figures to refresh your memory.)</p> +<p>We saw then that an object of our software (a concrete object) is the representation of an abstract object, and that two concrete objects may represent the same abstract object.</p> +<p>For example two different stack representations, each made of an array and a top marker count, represent the same stack if they have the same value for count and the same array elements up to index count. They may differ in other properties, such as the array sizes and the values stored at indices above count. In mathematical terms, every concrete object belongs to the domain of the abstraction function a, and we can have c1 ≠ c2 even with a(c1) = a(c2).</p> +<p>What this means for us is that a function that modifies a concrete object is harmless if the result of this modification still represents the same abstract object — yields the same a value. For example assume in a function on stacks contains the operation</p> +<p>representation.put (some_value, count + 1)</p> +<p>(with the guarantee that the array's capacity is at least count + 1). <strong>This side effect changes a value above the stack-significant section of the array; it can do no ill.</strong></p> +<p>More generally, a concrete side effect which changes the concrete state of an object c is an abstract side effect if it also changes its abstract state, that is to say the value of a (c) (a more directly usable definition of abstract side effects will appear shortly). If a side effect is only concrete — does not affect the abstract state — it is harmless.</p> +<p>In the object-as-machine metaphor, functions producing concrete-only side effects correspond to query buttons that may produce an internal state change having absolutely no effect on the answers given by any query button. For example the machine might save energy by automatically switching off some internal circuits if nobody presses a button for some time, and turning them on again whenever someone presses any button, queries included. Such an internal state change is unnoticeable from the outside and hence legitimate."</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +</div></blockquote> +<p>Что это означает в контексте REST-API, мы увидим ниже.</p> +<p>И последнее на тему CQS. +Далее мы будем рассматривать уже CQRS. +Как видим, тема CQS намного более обширна и тонка, чем может показаться на первый взгляд. +И за один день её точно не освоить.</p> +</section> +<section id="emacsway-cqs-atomic-routine"> +<span id="id3"/><h2><a class="toc-backref" href="#id18" role="doc-backlink">Что делать с атомарными операциями?</a></h2> +<p>Для погружения в CQRS нужно обратить внимание на еще два существенных момента.</p> +<section id="emacsway-cqs-reference-argument"> +<span id="id4"/><h3><a class="toc-backref" href="#id19" role="doc-backlink">Процедура не возвращает значения, но может изменить ссылочный аргумент</a></h3> +<p>Момент первый - routine может возвращать информацию наружу не только в виде возвращаемого значения, но и путем изменения объекта, переданного аргументом по ссылке.</p> +<blockquote> +<div><p>📝 "Function clone creates a new object as a carbon copy of an existing one. Sometimes the target object already exists; all we want to do is to overwrite its fields. Procedure copy achieves this. It is called through the instruction x.copy (y)"</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "8.6 OPERATIONS ON REFERENCES :: Object copying"</p> +</div></blockquote> +<p>Именно на этом основан <a class="reference external" href="https://martinfowler.com/eaaDev/Notification.html">Notification Pattern</a>, который широко применяется в языках, не поддерживающих механизм исключений (Golang, например).</p> +<p>Как можно организовать ссылочную связь через сетевое взаимодействие? +Через идентификатор адресации в виде callback url.</p> +</section> +<section id="emacsway-cqs-buffer"> +<span id="id5"/><h3><a class="toc-backref" href="#id20" role="doc-backlink">Концепция буфера для разделения атомарных операций Command и Query</a></h3> +<p>И второй момент - это известный кейс с примером, широко известным как метод .pop(), который одновременно и удаляет, и возвращает элемент списка.</p> +<p>B.Meyer решает эту проблему с помощью концепции буффера:</p> +<blockquote> +<div><p>📝 "buffer — the concurrent equivalent of a first-in, first out queue."</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Objections"</p> +</div></blockquote> +<p>И приводит пример:</p> +<blockquote> +<div><p>next_element := buffer.item +buffer.remove</p> +<p>📝 "With the notation of this chapter, it is easy to obtain exclusive access without sacrificing the Command-Query Separation principle: simply enclose the two instructions above, with buffer replaced by b, in a procedure of formal argument b, and call that procedure with the attribute buffer as argument."</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "30.12 DISCUSSION :: Support for command-query separation"</p> +</div></blockquote> +<p>Вы уже, наверное, догадались, что я подвожу к паттерну "<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/async-request-reply">Asynchronous Request-Reply pattern</a>", использующему "<a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-6.3.3">202 Response Status Code</a>".</p> +</section> +</section> +<section id="emacsway-cqrs-command-resource-id"> +<span id="id6"/><h2><a class="toc-backref" href="#id21" role="doc-backlink">Что делать, если CQRS-команда должна вернуть идентификатор созданного ресурса?</a></h2> +<p>Вернемся к вопросу о возврате ID созданного ресурса в ответ на POST запрос REST-API. +Как говорилось <a class="reference internal" href="#emacsway-cqs-factory-result"><span class="std std-ref">ранее</span></a>, RFC-7231 требует, чтобы REST API вернул идентификатор созданного ресурса в ответ на HTTP POST запрос.</p> +<p>Какие вообще есть альтернативы?</p> <blockquote> -<div><p>📝 "Agile methods are most valuable when we're dealing with high levels of uncertainty."</p> -<p class="attribution">—"<a class="reference external" href="https://architectelevator.com/transformation/agile_architecture/">Agile and Architecture: Friend, not Foe</a>" by Gregor Hohpe</p> +<div><p>📝 "If the data is needed by the client as soon as it is submitted, it is there – on the client that submitted it. No need to poll the query side. The only thing that might not have been there is an ID from the database – which is easily solved with client-generated GUIDs instead of database-generated IDs."</p> +<p class="attribution">—"Clarified CQRS" <a class="reference external" href="http://udidahan.com/2009/12/09/clarified-cqrs/#comment-5118">comment 68</a> of Udi Dahan</p> </div></blockquote> +<p>Идентификатор может быть сгенерирован на стороне клиентского приложения, используя <a class="reference external" href="https://en.wikipedia.org/wiki/Universally_unique_identifier">UUID</a>, <a class="reference external" href="https://github.com/ulid/spec">ULID</a>, <a class="reference external" href="https://en.wikipedia.org/wiki/Hi/Lo_algorithm">Hi/Lo algorithm</a> и т.п. +После этого, ресурс может быть создан посредством PUT Request Method:</p> <blockquote> -<div><p>📝 "Complete. -The set of requirements stands alone such that it sufficiently describes the necessary capabilities, characteristics, constraints or quality factors to meet entity needs without needing further information. -In addition, the set does not contain any To Be Defined (TBD), To Be Specified (TBS), or To Be Resolved (TBR) clauses. -Resolution of the TBx designations may be iterative and there is an acceptable timeframe for TBx items, determined by risks and dependencies."</p> -<p class="attribution">—"ISO/IEC/IEEE 29148:2018 Systems and software engineering - Life cycle processes - Requirements engineering"</p> +<div><p>📝 "The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. &lt;...&gt; If the target resource does not have a current representation and the PUT successfully creates one, then the origin server MUST inform the user agent by sending a 201 (Created) response."</p> +<p class="attribution">—"<a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-4.3.4">Section 4.3.4. PUT of RFC-7231</a>"</p> </div></blockquote> -<p>Но это и не требуется стандартом по SDLC:</p> +<p>Другим вариантом, как говорилось <a class="reference internal" href="#emacsway-cqs-buffer"><span class="std std-ref">ранее</span></a>, может быть "<a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/patterns/async-request-reply">Asynchronous Request-Reply pattern</a>", использующий <a class="reference external" href="https://tools.ietf.org/html/rfc7231#section-6.3.3">202 Response Status Code</a>.</p> +<p>Но действительно ли нам нужно получать идентификатор в ответ на команду? Часто такая потребность возникает просто из-за недостаточного понимания тех выгод, которые предоставляет CQS и Referential Transparency - однонаправленный поток изменений и единственный источник истины.</p> +</section> +<section id="emacsway-cqrs-one-way-data-flow"> +<span id="id7"/><h2><a class="toc-backref" href="#id22" role="doc-backlink">Однонаправленный поток изменений</a></h2> +<p>Referential Transparency означает, что вызов функции можно многократно повторять без какого-либо ущерба, и она всегда будет возвращать один и тот же результат.</p> +<p>Более того, - возникает возможность легко управлять потоком изменений, сделав его однонаправленным, и сформировав единственный источник истины (single source of truth - один из ключевых принципов <a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/three-principles">Redux</a>, который <a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/motivation">следует принципам CQRS</a>).</p> <blockquote> -<div><p>📝 "To deal with the <strong>issues of incompletely known requirements</strong> and inaccurate estimates, a number of other types of models have been proposed: <a class="reference internal" href="../../models/incremental.html#emacsway-incremental-development"><span class="std std-ref">incremental</span></a>, <a class="reference internal" href="../../models/spiral.html#emacsway-spiral-development"><span class="std std-ref">spiral</span></a>, <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a>, and <a class="reference internal" href="../../models/evolutionary.html#emacsway-evolutionary-development"><span class="std std-ref">evolutionary (adaptive)</span></a>.</p> -<p>&lt;...&gt;</p> -<p>The "<a class="reference internal" href="../../models/evolutionary.html#emacsway-evolutionary-development"><span class="std std-ref">evolutionary model</span></a>" is intended to deal with <strong>incomplete knowledge of requirements</strong>."</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> +<div><p>Following in the steps of <a class="reference external" href="https://facebook.github.io/flux">Flux</a>, <a class="reference external" href="https://martinfowler.com/bliki/CQRS.html">CQRS</a>, and <a class="reference external" href="https://martinfowler.com/eaaDev/EventSourcing.html">Event Sourcing</a>, Redux attempts to make state mutations predictable by imposing certain restrictions on how and when updates can happen. These restrictions are reflected in the <a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/three-principles">three principles</a> of Redux.</p> +<p class="attribution">—"<a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/motivation">Motivation</a>"</p> </div></blockquote> -<p>Как можно заметить, неполнота требований здесь первична, и именно для её разрешения и применяются такие SDLC-модели, как <a class="reference internal" href="../../models/incremental.html#emacsway-incremental-development"><span class="std std-ref">incremental</span></a>, <a class="reference internal" href="../../models/spiral.html#emacsway-spiral-development"><span class="std std-ref">spiral</span></a>, <a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">iterative</span></a>, and <a class="reference internal" href="../../models/evolutionary.html#emacsway-evolutionary-development"><span class="std std-ref">evolutionary (adaptive)</span></a>.</p> -<p>Интересно, что, во времена появления термина User Story, полнота требований так же не требовалась старым стандартом:</p> <blockquote> -<div><p>📝 "The SRS may need to evolve as the development of the software product progresses. It may be impossible to specify some details at the time the project is initiated.</p> +<div><p>Redux can be described in three fundamental principles: 1) Single source of truth... 2) State is read-only... 3) Changes are made with pure functions</p> <p>&lt;...&gt;</p> -<p>Requirements should be specified as completely and thoroughly as is known at the time, even if evolutionary revisions can be foreseen as inevitable. The fact that they are incomplete should be noted."</p> -<p class="attribution">—"IEEE Std 830-1998, IEEE Std 830-1993 IEEE Recommended Practice for Software Requirements Specifications"</p> -</div></blockquote> -<p>Таким образом, использование термина <a class="reference internal" href="../../models/agile/analysis/requirements/requirements.html#emacsway-agile-requirements"><span class="std std-ref">requirements</span></a>, несмотря на то, что вызывает вопросы относительно семантики, никоим образом не противоречит использованию его в Agile SDLC-моделе, которая, кстати, описана тем же стандартом - ISO/IEC/IEEE 12207:2017, в разделах "5.4.2. Life cycle model for the software system" и "Annex H".</p> -<p>См. также:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.martinfowler.com/articles/newMethodology.html#PredictiveVersusAdaptive">The New Methodology :: Predictive versus Adaptive</a>" by Martin Fowler</p></li> -</ul> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> -<ul class="simple"> -<li><p>"<a class="reference internal" href="../../models/iterative.html#emacsway-iterative-development"><span class="std std-ref">Iterative Development</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">Что такое Agile Development</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../models/agile/index.html"><span class="doc">Agile</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../models/agile/analysis/requirements/requirements.html#emacsway-agile-requirements"><span class="std std-ref">Agile Requirements</span></a>"</p></li> -</ul> -</div> -</section> -Fri, 28 Oct 2022 00:00:00 Что такое Predictionhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/prediction/prediction.html -<span id="emacsway-prediction"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<blockquote> -<div><p>📝 A second common style of definition for architecture is that it's "the design decisions that need to be made early in a project", but Ralph complained about this too, saying that it was more like the decisions you wish you could get right early in a project.</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/architecture/">Software Architecture Guide</a>" by Martin Fowler</p> +<p>The only way to change the state is to emit an action, an object describing what happened.</p> +<p class="attribution">—"<a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/three-principles">Three Principles</a>"</p> </div></blockquote> -<p>К Prediction (Прогнозированию) относится ряд активностей на основе правил логического вывода, предшествующих производству Системного Инкремента и направленных на заблаговременное разрешение неопределенности. -К ним относятся Business/System Requirements Definition and Analysis, Architecture Definition, Design Definition, разработка макетов UX/UI-Design, Estimation и Planning. -Но главным образом к ним относится разрешение неопределенности в problem-space (т.е. требований), что оказывает существенное влияние на выбор SDLC-модели.</p> -<p>В Scrum эти активности традиционно выражаются в событиях, предшествующих Definition Of Ready (DOR):</p> -<ul class="simple"> -<li><dl class="simple"> -<dt>Со стороны Product Owner:</dt><dd><ul> -<li><p>Reveal needs of stakeholders</p></li> -<li><p>Creating PBI</p></li> -</ul> -</dd> -</dl> -</li> -<li><dl class="simple"> -<dt>Со стороны Team:</dt><dd><ul> -<li><p>PBR</p></li> -<li><p>Planning</p></li> -<li><p>Spike</p></li> -</ul> -</dd> -</dl> -</li> -</ul> -<p>Основная проблема Prediction заключается в том, что характер роста стоимости Прогнозирования, в зависимости от его точности, близок к экспоненциальному. -В то время как характер роста бизнес-выгод от точности Прогнозирования близок к логарифмическому. -Пересечение этих графиков образует предел экономической целесообразности разрешения неопределенности путем Прогнозирования. -Здесь подразумевается, что стоимость самой реализации уже вычтена из бизнес-выгод.</p> <blockquote> -<div><p>💬 "WaterFall is based on the empirical observation of 30 years ago (ref: BarryBoehm, Software Engineering Economics, Prentice Hall, 1981.) that the cost of change rises exponentially (base 10) by phases. The conclusion is that you should make the big decisions up front, because changing them is so expensive."</p> -<p class="attribution">—"<a class="reference external" href="https://wiki.c2.com/?WaterFall">Water Fall</a>" at c2.com</p> +<div><p>Redux uses a "one-way data flow" app structure</p> +<p class="attribution">—"<a class="reference external" href="https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow">Redux Fundamentals, Part 2: Concepts and Data Flow</a>"</p> </div></blockquote> <blockquote> -<div><p>💬 "There is a fundamental truth to work breakdown structure estimation - the only way to estimate using a work breakdown structure to really accurately to get the number right is to implement the project. -Then you'll have the estimate.</p> -<p>The cost of improving the estimate, the initial work breakdown estimation, the cost of refining that grows exponentially. -With every next layer you want to take it down. -And the benefit of doing that does not grow exponentially. -It grows logarithmically.</p> -<p>Managers understand there is an extremely high cost involved with refining the estimate."</p> -<p class="attribution">—<a class="reference external" href="https://youtu.be/eisuQefYw_o?t=1995">"YOW! 2016 Robert C. Martin - Effective Estimation (or: How not to Lie)" at 33:15</a></p> +<div><p>ORMs are complex because they have to handle a bi-directional mapping. A uni-directional problem is much easier to work with, particularly if your needs aren't too complex and you are comfortable with SQL. This is one of the arguments for CQRS.</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/OrmHate.html">Orm Hate</a>" by Martin Fowler</p> </div></blockquote> -<p>Robert C. Martin упомянул о таком способе обработки неопределенности, как реализовать Проект (или Системный Инкремент). -Это уже другой, эмпирический (т.е. опытным путем) способ обработки неопределенности, который называется <a class="reference internal" href="../adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Adaptation</span></a> и составляет основу итеративной разработки. -Чем сложнее предметная область Проекта, тем раньше наступает предел экономической целесообразности Prediction.</p> -Thu, 27 Oct 2022 00:00:00 Borrowing troublehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/borrowing-trouble.html -<span id="emacsway-borrowing-trouble"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> +<p>Это существенно облегчает создание сложных приложений, используя Task Based UI, позволяет легко организовать репликацию и кэширование, устранить задержки. +Подробнее эти вопросы хорошо раскрывает Udi Dahan в монументальной статье "<a class="reference external" href="http://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>".</p> +<p>Статья доступна для скачивания <a class="reference external" href="https://udidahan.com/wp-content/uploads/Clarified_CQRS.pdf">в формате pdf</a>.</p> +<p>Представьте, что пользователь добавил в корзину последний товар, используя совмещенную операцию Команды и Запроса. В ответ на Команду, сервер сообщил, что товар снят с продажи. Клиентское приложение пользователя обновило свое состояние, и заблокировало в UI возможность заказать уже недоступный товар.</p> +<p>Я намеренно примитивизирую ситуацию - на самом деле она гораздо более сложнее в распределенных системах:</p> <ul class="simple"> -<li><p><a class="reference internal" href="#borrowing-trouble" id="id2">Borrowing trouble</a></p></li> +<li><p>"<a class="reference external" href="https://youtu.be/fWU8ZK0Dmxs">Udi Dahan - If (domain logic) then CQRS, or Saga?</a>"</p></li> +<li><p>хороший пример с overbooking в книге <a class="reference external" href="https://martinfowler.com/books/nosql.html">NoSQL Distilled</a>.</p></li> </ul> -</nav> -<p>Чем выше интеллект человека, тем больше он склонен продумывать все заблаговременно в условиях недостаточной информированности. -Это приводит к тому, что его продуктивность зачастую становится ниже продуктивности рядовых разработчиков (которые сильно не парятся). -Выгодней принимать решение в момент наибольшей полноты информированности (чем позже - тем лучше).</p> -<blockquote> -<div><p>📝 "Иногда очень умные программисты с трудом овладевают ХР. -Для очень умных людей тяжело поменять их умение делать правильные дальновидные предположения на тесную коммуникацию и постоянную эволюцию системы.</p> -<p>Really smart programmers sometimes have a hard time with XP. -Sometimes the smart people have the hardest time trading the "Guess Right" game for close communication and continuous evolution."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 25. When You Shouldn't Try XP", перевод ООО Издательство "Питер"</p> -</div></blockquote> +<p>Проблема в том, что между пользователем и сервером существует двунаправленный поток изменений, который недоступен остальным пользователям, так как операция модификации и чтения данных совмещена.</p> +<p>Другой пользователь, для которого источником истины является локальное состояние его клиентского приложения, ничего не знает о том, что товар уже недоступен, пытается его заказать, но, вместо подтверждения заказа, получает сообщение о недоступности товара.</p> +<p>Сюда можно добавить еще время, требуемое на обновление реплик чтения.</p> <blockquote> -<div><p>📝 "Не надо обладать ученой степенью в области компьютерных наук для того, чтобы участвовать в ХР-проекте (в действительности ученая степень частенько является одним из серьезных мешающих факторов).</p> -<p>It doesn't take a Ph.D. in computer science to contribute to an XP project (in fact, the Ph.D.'s sometimes have the most trouble)."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 24. What Makes XP Hard", перевод ООО Издательство "Питер"</p> +<div><p>📝 "Staleness refers to the fact that in a collaborative environment, once data has been shown to a user, that same data may have been changed by another actor – it is stale. Almost any system which makes use of a cache is serving stale data – often for performance reasons. What this means is that we cannot entirely trust our users decisions, as they could have been made based on out-of-date information."</p> +<p class="attribution">—"<a class="reference external" href="https://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" by Udi Dahan</p> </div></blockquote> +<p>Отделение Команд от Запросов позволяет организовать однонаправленный поток изменений, и тогда оба пользователя одновременно получат сообщение о событии, что последний товар закончился.</p> +<figure class="align-center" id="id9"> +<a class="reference internal image-reference" href="../../../../../_images/cqrs.png"><img alt="CQRS. The image from &quot;Clarified CQRS&quot; by Udi Dahan https://udidahan.com/2009/12/09/clarified-cqrs/" src="../../../../../_images/cqrs.png" style="width: 70%;"/></a> +<figcaption> +<p><span class="caption-text">CQRS. The image from "<a class="reference external" href="https://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" by Udi Dahan</span></p> +</figcaption> +</figure> <blockquote> -<div><p>📝 "ХР работает против многих программистских инстинктов. -Мы, программисты, привыкли ожидать появления проблем. -Если проблемы откладываются на более позднее время, мы счастливы. -Если проблемы не появляются, мы не обращаем на это внимания. -Поэтому наша стратегия проектирования должна увести нас в сторону от этих "размышлений о будущем". -К счастью, большинство разработчиков способно отучится от этой привычки "брать неприятности взаймы" (как про это говорила моя бабушка). -К сожалению, чем вы умнее, тем сложнее вам отучиться от этого.</p> -<p>XP works against many programmers' instincts. -As programmers, we get in the habit of anticipating problems. -When they appear later, we're happy. -When they don't appear, we don't notice. -So the design strategy will have to go sideways of this "guessing at the future" behavior. -Fortunately, most folks can unlearn the habit of "borrowing trouble" (as my grandmother called it). -Unfortunately, the smarter you are, the harder it will be to unlearn."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 17. Design Strategy", перевод ООО Издательство "Питер"</p> +<div><p>📝 "After the command-processing autonomous component has decided to accept a command, modifying its persistent store as needed, it publishes an event notifying the world about it."</p> +<p class="attribution">—"<a class="reference external" href="https://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" by Udi Dahan</p> </div></blockquote> <blockquote> -<div><p>📝 "We often forget that it is also best to postpone decisions until the last possible moment. -This isn’t lazy or irresponsible; it lets us make informed choices with the best possible information. -A premature decision is a decision made with suboptimal knowledge. -We will have that much less customer feedback, mental reflection on the project, and experience with our implementation choices if we decide too soon."</p> -<p class="attribution">—"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p> +<div><p>📝 "CQRS is about coming up with an appropriate architecture for multi-user collaborative applications. It explicitly takes into account factors like data staleness and volatility and exploits those characteristics for creating simpler and more scalable constructs."</p> +<p class="attribution">—"<a class="reference external" href="https://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" by Udi Dahan</p> </div></blockquote> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> -<ul class="simple"> -<li><p>"<a class="reference internal" href="yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../crash-course-in-software-development-economics.html#emacsway-software-development-economics-literature"><span class="std std-ref">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">Balancing Prediction/Adaptation</span></a>"</p></li> -</ul> -</div> -Thu, 06 Oct 2022 00:00:00 YAGNIhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.html -<span id="emacsway-yagni"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> +<p>Теперь, понимая важность однонаправленного потока изменений в условиях collaborative evironment, нам становится легче понять разницу между abstract side effect и concrete side effect.</p> +<p>В <a class="reference external" href="https://youtu.be/fWU8ZK0Dmxs">этом видео</a> Udi Dahan использовал термин sandbox.</p> +<p>Часто ресурс начинает создаваться как черновик. +Он не доступен никому через публичный интерфейс, кроме его автора. +Никто не должен знать о его существовании, кроме его автора. +И если мы нарушим здесь CQS, то никто этого не заметит. +На ресурс распространяется <strong>concrete side effect</strong>:</p> <ul class="simple"> -<li><p><a class="reference internal" href="#yagni" id="id6">YAGNI</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id7">Когда реализовывать проектное решение</a></p></li> -<li><p><a class="reference internal" href="#id3" id="id8">Экономический ущерб от преждевременной реализации</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id9">В каких случаях момент реализации не стоит откладывать</a></p></li> -<li><p><a class="reference internal" href="#emacsway-yagni-literature" id="id10">Литература о YAGNI</a></p></li> -</ul> -</li> +<li><p>"<a class="reference internal" href="#emacsway-cqs-query-referential-transparency"><span class="std std-ref">CQS - это больше о referential transparency для Query</span></a>"</p></li> +<li><p>"<a class="reference internal" href="#emacsway-cqs-query-side-effect"><span class="std std-ref">Query не должен иметь abstract side effect, но может иметь concrete side effect</span></a>"</p></li> </ul> -</nav> -<p>Существует очень распространенная проблема, с которой сталкиваются почти все начинающие интеллектуально развитые разработчики. -Называется эта проблема "<a class="reference internal" href="borrowing-trouble.html#emacsway-borrowing-trouble"><span class="std std-ref">Заимствование Проблем</span></a>" ("<a class="reference internal" href="borrowing-trouble.html#emacsway-borrowing-trouble"><span class="std std-ref">Borrowing Trouble</span></a>"). -Я её иногда называю "проблемой умных людей". -Заключается она в непреодолимом желании разработчика осуществить реализацию впрок, исходя из предположения о том, что она может быть востребована в будущем. -К сожалению, чаще всего она так и остается невостребованной. -А если даже когда-нибудь и становится востребованной, то она все-равно причиняет ущерб экономике разработки.</p> -<p>Непонимание того, как этот ущерб образуется, является основной причиной продолжения этой практики и деградации экономики разработки. -Хороший архитектор или тимлид имеет ясное представление о причинах и составляющих этого ущерба, и способен пояснить их каждому разработчику, ведь это влияет непосредственно на темпы разработки. -Образно говоря, вы можете быть насколько угодно великим полководцем, но грош этому цена, если ваши солдаты не умеют метко стрелять.</p> -<p>Когда я узнал о YAGNI, моя персональная эффективность выросла в разы. -Этот подход хорошо сочетается с <a class="reference external" href="https://en.wikipedia.org/wiki/Emergent_Design#Emergent_design_in_agile_software_development">Emergent (Incremental) Design</a>.</p> -<section id="id2"> -<h2><a class="toc-backref" href="#id7" role="doc-backlink">Когда реализовывать проектное решение</a></h2> -<p>Martin Fowler о выборе момента реализации проектного решения:</p> -<blockquote> -<div><p>📝 "До введения рефакторинга в свою работу я всегда искал гибкие решения. -Для каждого технического требования я рассматривал возможности его изменения в течение срока жизни системы. -Поскольку изменения в проекте были дорогостоящими, я старался создать проект, способный выдержать изменения, которые я мог предвидеть. -Недостаток гибких решений в том, что за гибкость приходится платить. -Гибкие решения сложнее обычных. -Создаваемые по ним программы в целом труднее сопровождать, хотя и легче перенацеливать в том направлении, которое предполагалось изначально. -И даже такие решения не избавляют от необходимости разбираться, как модифицировать проект. -Для одной двух функций это сделать не очень трудно, но изменения происходят по всей системе. -Если предусматривать гибкость во всех этих местах, то вся система становится значительно сложнее и дороже в сопровождении. -Весьма разочаровывает, конечно, то, что вся эта гибкость и не нужна. -Потребуется лишь какая то часть ее, но невозможно заранее сказать какая.</p> -<p>Чтобы достичь гибкости, приходится вводить ее гораздо больше, чем требуется в действительности. -Рефакторинг предоставляет другой подход к рискам модификации. -Возможные изменения все равно надо пытаться предвидеть, как и рассматривать гибкие решения. -<strong>Но вместо реализации этих гибких решений следует задаться вопросом: "Насколько сложно будет с помощью рефакторинга преобразовать обычное решение в гибкое?"</strong> -<strong>Если, как чаще всего случается, ответ будет "весьма несложно", то надо просто реализовать обычное решение.</strong></p> -<p>Рефакторинг позволяет создавать более простые проекты, не жертвуя гибкостью, благодаря чему процесс проектирования становится более легким и менее напряженным. -Научившись в целом распознавать то, что легко поддается рефакторингу, о гибкости решений даже перестаешь задумываться. -Появляется уверенность в возможности применения рефакторинга, когда это понадобится. -Создаются самые простые решения, которые могут работать, а гибкие и сложные решения по большей части не потребуются.</p> -<p>Before I used refactoring, I always looked for flexible solutions. -With any requirement I would wonder how that requirement would change during the life of the system. -Because design changes were expensive, I would look to build a design that would stand up to the changes I could foresee. -The problem with building a flexible solution is that flexibility costs. -Flexible solutions are more complex than simple ones. -The resulting software is more difficult to maintain in general, although it is easier to flex in the direction I had in mind. -Even there, however, you have to understand how to flex the design. -For one or two aspects this is no big deal, but changes occur throughout the system. -Building flexibility in all these places makes the overall system a lot more complex and expensive to maintain. -The big frustration, of course, is that all this flexibility is not needed. -Some of it is, but it's impossible to predict which pieces those are. -To gain flexibility, you are forced to put in a lot more flexibility than you actually need.</p> -<p>With refactoring you approach the risks of change differently. -You still think about potential changes, you still consider flexible solutions. -<strong>But instead of implementing these flexible solutions, you ask yourself, "How difficult is it going to be to refactor a simple solution into the flexible solution?"</strong> -<strong>If, as happens most of the time, the answer is "pretty easy," then you just implement the simple solution.</strong></p> -<p>Refactoring can lead to simpler designs without sacrificing flexibility. -This makes the design process easier and less stressful. -Once you have a broad sense of things that refactor easily, you don't even think of the flexible solutions. -You have the confidence to refactor if the time comes. -You build the simplest thing that can possibly work. -As for the flexible, complex design, most of the time you aren't going to need it."</p> -<p class="attribution">—"Refactoring: Improving the Design of Existing Code" 1st edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts, перевод С. Маккавеева</p> +<p>Другое дело, когда мы должны опубликовать этот ресурс - тогда он должен появиться у всех, кто просматривает коллекцию, содержащую опубликованный ресурс (если, разумеется, это имеет ценность с точки зрения предметной области), а не только инициатор публикации. +И все пользователи, включая автора, должны получить уведомление о публикации ресурса, через единый однонаправленный канал потока изменений.</p> +<p>Такой же вывод возникает и из принципа <strong>функции-конструктора</strong> - до тех пор, пока ресурс не принадлежит ни к одной из публичных коллекций, доступной остальным пользователям, <a class="reference internal" href="#emacsway-cqs-factory-result"><span class="std std-ref">side effect не имеет последствий</span></a>.</p> +<p>Но когда коллекция изменилась, то все пользователи, просматривающие эту коллекцию, должны быть уведомлены единовременно.</p> +</section> +<section id="jimmy-bogard"> +<h2><a class="toc-backref" href="#id23" role="doc-backlink">Точка зрения Jimmy Bogard</a></h2> +<p>Ответ Jimmy Bogard по поводу того, может ли CQRS-Команда возвращать результат:</p> +<blockquote> +<div><p>📝 "It might seem rather strange that commands always have a result, but it's much, much easier to deal with side effects of commands through return parameters than through some other means (global registry, static field, re-querying some object, collecting parameter, etc.). <strong>For commands that create an item, I usually want to redirect to a screen showing that item, very easily accomplished when I can get the created item and as for its ID.</strong></p> +<p>This is a bit controversial, but don't frankly care, as it's the simplest thing that could possibly work. If I want to have a command that returns Void, I could steal a page from F# and have a Command base class that returns a Unit type:"</p> +<p class="attribution">—"<a class="reference external" href="https://lostechies.com/jimmybogard/2013/12/19/put-your-controllers-on-a-diet-posts-and-commands/">Put your controllers on a diet: POSTs and commands</a>" by Jimmy Bogard</p> </div></blockquote> -<p>Простое и понятное определение дает Сергей Тепляков:</p> +<p>Обратите внимание, в последнем предложении он говорит о том, как вернуть и результат, и ошибку одновременно. +Это является решением именно того вопроса, который пытался разрешить B.Meyer с помощью <a class="reference internal" href="#emacsway-cqs-command-status-code"><span class="std std-ref">side-effect-free style</span></a>.</p> +<p>Причины такого решения он раскрывает в другой своей статье:</p> <blockquote> -<div><p>📝 "Существует простая лакмусовая бумажка принципа YAGNI: <strong>выделение лишних абстракций (и любое другое усложнение) оправдано лишь в том случае, если стоимость их выделения в будущем будет существенно дороже, чем сейчас</strong>."</p> -<p class="attribution">—"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>", Сергей Тепляков</p> +<div><p>📝 "Myth #2 – CQRS requires an eventual consistent read store</p> +<p>No, it does not. You can make your read store immediately consistent. That is, your read store can be updated when your command side succeeds (in the same transaction).</p> +<p>For many legacy/existing apps, transitioning to eventually consistent read stores will either force you to go through bogus hoops of mimicking synchronous calls. Users will bang down on your door with pitchforks and torches if you try and transition to an asynchronous model if you don't change their business process first.</p> +<p>Instead, you can start with immediate consistency and transition where and when it's needed. Unless a user expects a confirmation page, making every command page have a series of confirmations of "your request was received" is going to annoy the snot out of your users.</p> +<p>Myth #3 – CQRS requires a bus/queues/asynchronous messaging</p> +<p>See above myth. <strong>Nothing about CQRS says "thou shalt use NServiceBus". It's just not there. You're merely separating infrastructure between handling commands and queries, but the how is quite varied. Don't start with a bus until you prove you need eventual consistency.</strong></p> +<p>Consistency models are a business decision because it directly impacts user experience. An eventually consistent model requires a different user experience than an immediate one, and this is not something you can just "slip in" to your users, or try to emulate. If you're attempting to emulate immediate consistency in an eventually consistent model, you're doing something wrong.</p> +<p class="attribution">—"<a class="reference external" href="https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/">Busting some CQRS myths</a>" by Jimmy Bogard</p> </div></blockquote> -<p>Там же присутствует и другой немаловажный момент:</p> +<p>Что он также подтверждает своим комментарием к этой статье:</p> <blockquote> -<div><p>📝 "Хороший дизайн заключается в простом решении, когда изменения требований ведут к линейным трудозатратам."</p> -<p class="attribution">—"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>", Сергей Тепляков</p> +<div><p>📝 "Scaling and CQRS are orthogonal, it's highly contextual and certainly doesn't require async."</p> +<p class="attribution">—"<a class="reference external" href="https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/#comment-3422377189">Busting some CQRS myths</a>" by Jimmy Bogard</p> </div></blockquote> -<p>Решение о выборе момента реализации зависит от условий конкретного проекта и <a class="reference internal" href="../../../models/agile/agile.html#emacsway-agile-development-essence"><span class="std std-ref">характера кривой стоимости изменения его кода</span></a>, который, в свою очередь, зависит от уровня команды, <a class="reference internal" href="../software-design/software-design.html#emacsway-agile-software-design"><span class="std std-ref">качества кода</span></a> и других объективных причин для каждого конкретного случая. -Для принятия решения достаточно просто сравнить затраты на реализацию сейчас и потом.</p> +</section> +<section id="id8"> +<h2><a class="toc-backref" href="#id24" role="doc-backlink">Вывод</a></h2> +<p>Итак, ответ прост - если вы не используете асинхронное исполнение Команды посредством инфраструктуры (Command Bus), то ничто не препятствует вам получить идентификатор вновь созданной записи БД в возвращаемом командой результате, и реализацию можно существенно упростить. +Впрочем, возвратить результат можно даже используя Command Bus, но тут вопрос к потреблению ресурсов (все зависит от конкретного случая).</p> +<p>Вопрос не в том, возвращает ли команда результат (при этом нужно отличать результат от служебной информации, например, от успешности валидации и принятия команды), а в том, можно ли получить информацию о ресурсе без abstract side effect, т.е. смогут ли другие клиенты получить ту же информацию, если она им нужна.</p> +<p>Этот вопрос также разбирали следующие авторы:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://habr.com/ru/post/347908/">CQRS. Факты и заблуждения</a>" / Максим Аршинов</p></li> +<li><p>"<a class="reference external" href="https://event-driven.io/en/can_command_return_a_value/">Can command return a value?</a>" by Oskar Dudycz</p></li> +<li><p>"<a class="reference external" href="https://event-driven.io/en/cqrs_facts_and_myths_explained/">CQRS facts and myths explained</a>" by Oskar Dudycz</p></li> +<li><p>"<a class="reference external" href="https://blog.ploeh.dk/2014/08/11/cqs-versus-server-generated-ids/">CQS versus server generated IDs</a>" by Mark Seemann</p></li> +<li><p>"<a class="reference external" href="https://blogs.cuttingedge.it/steven/posts/2012/returning-data-from-command-handlers/">Returning data from command handlers</a>" by Steven van Deursen</p></li> +</ul> +<p>Ранее, этот вопрос <a class="reference internal" href="../domain-model/domain-events/domain-events-in-ddd.html#emacsway-domain-event-cqrs-command-result"><span class="std std-ref">частично уже рассматривался</span></a>.</p> +</section> +Wed, 28 Jun 2023 00:00:00 Файловая структура Доменной моделиhttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/file-structure.html +<span id="id1"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<p>О причинах образования такой файловой структуры.</p> +<nav class="contents" id="id2"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#emacsway-golang-domain-file-structure" id="id7">Файловая структура Доменной модели</a></p> +<ul> +<li><p><a class="reference internal" href="#bounded-context-internal" id="id8">Зачем в каждом Bounded Context директория internal?</a></p></li> +<li><p><a class="reference internal" href="#id3" id="id9">Почему агрегаты резмещены в собственных директориях?</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id10">Почему Сущности Агрегатов выделены в отдельные директории?</a></p></li> +<li><p><a class="reference internal" href="#id5" id="id11">Почему в директории Агрегата нет директории для его Объектов-значений?</a></p></li> +<li><p><a class="reference internal" href="#id6" id="id12">Почему Доменные События размещены в директории Агрегата и его Сущностей?</a></p></li> +</ul> +</li> +</ul> +</nav> +<section id="bounded-context-internal"> +<h2><a class="toc-backref" href="#id8" role="doc-backlink">Зачем в каждом Bounded Context директория internal?</a></h2> +<p>Доменная модель должна быть инкапсулирована. +Другим Bounded Contexts должны быть доступны только CQRS-Commands и Public Domain Events (Integration Events).</p> </section> <section id="id3"> -<h2><a class="toc-backref" href="#id8" role="doc-backlink">Экономический ущерб от преждевременной реализации</a></h2> -<p>Как оценить финансово стоимость от преждевременного усложения программы (преждевременная реализация, введение излишнего уровня абстракции, косвенности и т.п.)?</p> +<h2><a class="toc-backref" href="#id9" role="doc-backlink">Почему агрегаты резмещены в собственных директориях?</a></h2> +<p>Причины две:</p> +<ol class="arabic simple"> +<li><p>Чтобы подчеркнуть High Cohesion, см. главу "Chapter Five. A Model Expressed in Software :: Modules" книги "Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans.</p></li> +<li><p>В Golang это необходимо для реализации <a class="reference internal" href="aggregate-encapsulation.html#emacsway-golang-encapsulation"><span class="std std-ref">инкапсуляции Агрегата</span></a>, чтобы ограничить доступ к защищенным атрибутам Агрегата извне.</p></li> +</ol> <blockquote> -<div><p>📝 "Пример</p> -<p>Представьте, что вы занимаетесь программированием фактически в одиночку. -Вы видите, что добавление в программу некоторой возможности обойдется вам в $10. -Вы ожидаете, что вы сможете заработать на этой возможности приблизительно $15. -Таким образом, чистая текущая ценность (Net Present Value, NPV) добавления в программу данной возможности составит $5.</p> -<p>Представьте, что вы не можете сказать точно, какова будет на самом деле ценность рассматриваемой вами возможности, — вы можете лишь предположить, что заказчик будет готов заплатить за нее $15. -В действительности этот параметр может отличаться от предполагаемого вами значения на 100% в обе стороны. -Теперь предположим, что если вы соберетесь добавлять данную возможность спустя год от текущего момента, то это все равно будет стоить вам те же $10 (см. главу 5).</p> -<p>Какова будет ценность стратегии, в рамках которой вы не будете реализовывать эту возможность прямо сейчас, а подождете в течение года? -В настоящее время средняя процентная ставка составляет около 5% годовых. -С учетом этой процентной ставки искомая ценность составит около $7,87.</p> -<p>Следовательно, стратегия годичного ожидания, прежде чем добавить в программу новую возможность, <em>нам выгоднее</em> [в оригинальном переводе: <em>обойдется нам дороже</em>], чем если бы мы, ничего не ожидая, прямо сейчас инвестировали деньги в разработку данной возможности (напомню, что на текущий момент соответствующая NVP составляет $5). -Почему? В настоящее время мы находимся в неопределенности и не можем точно сказать, будет ли данная возможность действительно полезна для нашего заказчика и сможет ли он прямо сейчас начать зарабатывать на ней деньги. -Если мы реализуем возможность прямо сейчас и возможность окажется действительно полезной, то наш заказчик через год получит за счет этого определенную прибыль. -Однако может оказаться, что для нашего заказчика эта возможность не представляет никакой ценности, и поэтому, отказавшись на текущий момент от ее реализации, мы можем сэкономить собственные ресурсы.</p> -<p>Говоря проще, варианты помогают нам избавиться от нежелательного риска.</p> -<p>Example</p> -<p>Suppose you're programming merrily along and you see that you could add a feature that would cost you $10. -You figure the return on this feature (its net present value) is somewhere around $15. -So the net present value of adding this feature is $5.</p> -<p>Suppose you knew in your heart that it wasn't clear at all how much this new feature would be worth—it was just your guess, not something you really knew was worth $15 to the customer. -In fact, you figure that its value to the customer could vary as much as 100% from your estimate. -Suppose further (see Chapter 5, Cost of Change, page 21) that it would still cost you about $10 to add that feature one year from now.</p> -<p>What would be the value of the strategy of just waiting, of not implementing the feature now? -Well, at the usual interest rates of about 5%, the options theory calculator cranks out a value of $7.87.</p> -<p>The option of waiting is worth more than the value (NPV = $5) of investing now to add the feature. -Why? With that much uncertainy, the feature certainly might be much more valuable to the customer, in which case you're no worse off waiting than you would have been by implementing it now. -Or it could be worth zilch—in which case you've saved the trouble of a worthless exercise.</p> -<p>In the jargon of trading, options "eliminate downside risk."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 3. Economics of Software Development", перевод ООО Издательство "Питер"</p> +<div><p>💬 "МОДУЛИ дают возможность посмотреть на модель с разных сторон: +во-первых, можно изучить подроб­ности устройства модуля, не вникая в сложное целое; +во-вторых, удобно рассматривать взаимоотношения между модулями, не вдаваясь в детали их внутреннего устройства.</p> +<p>&lt;...&gt;</p> +<p>То, что при делении на модули должна соблюдаться низкая внешняя зависимость (low coupling) при высокой внутренней связности (high cohesion)- это общие слова. +Определения зависимости и связности грешат уклоном в чисто технические, количест­венные критерии, по которым их якобы можно измерить, подсчитав количество ассо­циаций и взаимодействий. +Но это не просто механические характеристики подразде­ления кода на модули, а идейные концепции. +Человек не может одновременно удер­живать в уме слишком много предметов (отсюда низкая внешняя зависимость). +А плохо связанные между собой фрагменты информации так же трудно понять, как неструктурированную "кашу" из идей (отсюда высокая внутренняя связность).</p> +<p>MODULES give people two views of the model: +They can look at detail within a MODULE without being overwhelmed by the whole, or they can look at relationships between MODULES in views that exclude interior detail.</p> +<p>&lt;...&gt;</p> +<p>It is a truism that there should be low coupling between MODULES and high cohesion within them. +Explanations of coupling and cohesion tend to make them sound like technical metrics, to be judged mechanically based on the distributions of associations and interactions. Yet it isn't just code being divided into MODULES, but concepts. +There is a limit to how many things a person can think about at once (hence low coupling). +Incoherent fragments of ideas are as hard to understand as an undifferentiated soup of ideas (hence high cohesion)."</p> +<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> </div></blockquote> -<p>Плюс к этому добавляется ущерб от упущенной выгоды:</p> +</section> +<section id="id4"> +<h2><a class="toc-backref" href="#id10" role="doc-backlink">Почему Сущности Агрегатов выделены в отдельные директории?</a></h2> +<p>Чтобы логически выделить связанные этой Сущностью объекты. +Не очень удобно рассматривать винегрет вложенных объектов различных Сущностей, поскольку они нерелевантны в момент рассмотрения и повышают когнитивную нагрузку.</p> +<p>Впрочем, это решение является пока что экспериментальным и не окончательным.</p> +<p>Есть у этого решения контраргумент, который заключается в том, что Сущность, хотя и кратковременно, но может отдаваться наружу Агрегата, если при этом она остается неизменяемой.</p> <blockquote> -<div><p>📝 "By expending our effort on the piracy pricing software we didn't build some other feature. -If we'd instead put our energy into building the sales software for weather risks, we could have put a full storm risks feature into production and be generating revenue two months earlier. -This <strong>cost of delay</strong> due to the presumptive feature is two months revenue from storm insurance."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" by Martin Fowler</p> +<div><p>💬️ "Группируйте СУЩНОСТИ и ОБЪЕКТЫ-ЗНАЧЕНИЯ в АГРЕГАТЫ и определяйте границы каждого из них. +Выберите о дин объект-СУЩНОСТЬ и сделайте его корневым. +Осуществляйте все обращения к объектам в границах АГРЕГАТА только через его корневой объект. +Разрешайте внешним объектам хранить ссылки только на корневой объект. +<strong>Ссылки на внутренние объекты АГРЕГАТА следует передавать только во временное пользование, на время одной операции.</strong> +<strong>Поскольку доступ к объектам АГРЕГАТА кон­тролируется через корневой объект, неожиданные изменения внутренних объектов невозможны.</strong> +В такой схеме разумно требовать удовлетворения всех инвариантов для объектов в АГРЕГАТЕ и для всего АГРЕГАТА в целом при любом изменении состояния.</p> +<p>Cluster the ENTITIES and VALUE OBJECTS into AGGREGATES and define boundaries around each. +Choose one ENTITY to be the root of each AGGREGATE, and control all access to the objects inside the boundary through the root. +Allow external objects to hold references to the root only. +<strong>Transient references to internal members can be passed out for use within a single operation only.</strong> +<strong>Because the root controls access, it cannot be blindsided by changes to the internals.</strong> +This arrangement makes it practical to enforce all invariants for objects in the AGGREGATE and for the AGGREGATE as a whole in any state change."</p> +<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> </div></blockquote> -<p>И ущерб от роста стоимости сопровождения системы в связи с переусложнением:</p> +<p>О чем это говорит? +Это говорит о том, что если мы разместим Сущность в одном пакете с Агрегатом, то это значит, что Агрегату не требуются публичные методы для того, чтобы иметь доступ к своей Сущности. +Это значит, что Агрегат обладает другим уровнем доступа, нежели посторонние клиенты. +Это значит, что посторонние клиенты не получат доступа к мутирующим методам Сущности только потому, что они нужны Агрегату.</p> +<p>Но здесь возникает другой вопрос - следовать ли <a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D0%94%D0%B5%D0%BC%D0%B5%D1%82%D1%80%D1%8B">Law of Demeter</a> внутри Агрегата? +Следует ли ограничивать прямой доступ Агрегата к Сущностям его Сущностей? +Плоская структура файлов Агрегата не позволяет это обеспечить.</p> +</section> +<section id="id5"> +<h2><a class="toc-backref" href="#id11" role="doc-backlink">Почему в директории Агрегата нет директории для его Объектов-значений?</a></h2> +<p>Причина, по которой эта директория была вначале, заключалась в необходимости реализации ациклического графа зависимостей с целью исключения циклических импортов. +Это было связано с тем, что Сущности Агрегата имели собственную директорию. +Например, Агрегат может быть осведомлен о своей Сущности, а Сущность может быть осведомлена об Объекте-значении Агрегата.</p> +<p>По этой причине, все Объекты-значения Агрегата/Сущности были выделены в отдельную директорию внутри директории Агрегата/Сущности. +Иначе пришлось бы абсолютно все Cущности и Объекты-значения Агрегата разметить плоским списком в одной директории, что затрудняло навигацию по файловой структуре.</p> +<p>Позже я обнаружил еще один способ решения проблемы циклического импорта - для этого было достаточно, чтобы Агрегат заимствовавал Объект-значение у Сущности, а не наоборот.</p> +<p>В крайнем случае, внутри директории Агрегата можно делать директорию <code class="docutils literal notranslate"><span class="pre">shared</span></code>, <code class="docutils literal notranslate"><span class="pre">common</span></code>, или <code class="docutils literal notranslate"><span class="pre">aggregate_name</span></code>, для реализации ациклического графа зависимостей.</p> +<p>Этот вариант также может оказаться востребованным, если Доменные События расположены в поддиректории, например, <code class="docutils literal notranslate"><span class="pre">events</span></code>, и используют Объекты-значения Агрегатов. +В таком случае, директория для совместно используемых Объектов-значений может иметь название (в дополнение к уже перечисленным) <code class="docutils literal notranslate"><span class="pre">exportable</span></code>, <code class="docutils literal notranslate"><span class="pre">public</span></code>.</p> <blockquote> -<div><p>📝 "The cost of delay is one cost that a successful presumptive feature imposes, but another is the <strong>cost of carry</strong>. -The code for the presumptive feature adds some complexity to the software, this complexity makes it harder to modify and debug that software, thus increasing the cost of other features."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" by Martin Fowler</p> +<div><p>All Value Objects which are part of a Customer live in another subpackage named value. I have to do this because in Go circular dependencies are not allowed. If I would put the Value Objects into the customer package then Commands and Events in domain would import the Value Objects from customer and functions in customer would import Commands and Events from domain. Having them in a subpackage additionally gives more privacy for the Value Objects. Not even functions of the Customer Aggregate can access private parts or create/modify a value without using the proper methods.</p> +<p class="attribution">—"<a class="reference external" href="https://medium.com/@TonyBologni/implementing-domain-driven-design-and-hexagonal-architecture-with-go-2-efd432505554">Implementing Domain-Driven Design and Hexagonal Architecture with Go (2)</a>" by Anton Stöckl — Part 2 — How I implement tactical DDD patterns — the Domain layer.</p> </div></blockquote> -<p>Виды стоимостей, образующих экономический ущерб от преждевременной реализации, хорошо разбираются в статье "<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" by Martin Fowler:</p> -<blockquote> -<div><ul class="simple"> -<li><p>cost of build</p></li> -<li><p>cost of delayed value (ущерб упущенной выгоды)</p></li> -<li><p>cost of carry</p></li> -<li><p>cost of other features</p></li> -<li><p>cost of removing</p></li> -<li><p>cost of repair</p></li> -<li><p>on-going costs of working around its difficulties</p></li> +<p>Еще одним способом предотвращения циклических импортов является использование интерфейсов, размещенных в отдельном пакете либо продублированных у своих клиентов (но это привело бы к дублированию интерфейсов-экспортеров). +Интерфейс дает то, что требуется сигнатурой методов клиента, не тащит за собой кучу зависимостей, необходимых для реализации, и даже может быть объявлен локально у своего клиента.</p> +<p>Попробовав различные варианты, я решил не выделять доменные события в отдельную директорию, т.к. избыток директорий создает ощущение переусложненности.</p> +</section> +<section id="id6"> +<h2><a class="toc-backref" href="#id12" role="doc-backlink">Почему Доменные События размещены в директории Агрегата и его Сущностей?</a></h2> +<p>Альтернативным вариантом является размещение Доменных Событий <a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers/tree/ce50bb8a2f1fa30e419d9a6863d19eb9999e9ef8/src/Services/Ordering/Ordering.Domain/Events">отдельно от Агрегатов</a>.</p> +<p>Но удобней информация воспринимается тогда, когда следствие расположено ближе к своей причине.</p> +<p>При этом, поскольку Доменные События выражают взаимоотношения между Агрегатами, удобно иметь возможность рассматривать их <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples_NET/blob/master/iddd_agilepm/Domain.Model/Products/ProductDiscussionInitiated.cs">не вдаваясь</a> в детали внутреннего устройства Агрегатов.</p> +<p>Точно так же, как Интеграционные (Публичные Доменные) События, выражающие взаимоотношения между Ограниченными Контекстами, расположены в единой директории порождающего их Ограниченного Контекста.</p> +<p>Однако, если Доменные События вынести в отдельную поддиректорию внутри директории Агрегата, то возникает циклический импорт, ведь Доменные События могут содержать Объекты-Значения, объявленные в том же самом пакете, где они инстанционируются. +Чтобы предотвратить циклический импорт, Объекты-Значения так же нужно вынести поддиректорию. +Это было бы логично еще и потому, что Сущности/Агрегаты, Объекты-Значения и Доменные События служат разным целям:</p> +<ol class="arabic simple"> +<li><p>Сущности/Агрегаты - моделируют предметную область.</p></li> +<li><p>Объекты-Значения - описывают характеристики предметов (элементов предметной области), например, возраст - это не предмет.</p></li> +<li><p>Доменные События - фиксируют факт изменения состояния предметов.</p></li> +</ol> +<p>Поддиректории <code class="docutils literal notranslate"><span class="pre">events``и</span> <span class="pre">``values</span></code> имеют множественное число, что позволяет предотвратить коллизии с названиями директорий Сущностей Агрегата, которые именуются в единственном числе.</p> +</section> +Sat, 24 Jun 2023 00:00:00 Поиск границ Агрегатовhttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/aggregate-boundaries.html +<span id="id1"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id2"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#emacsway-golang-aggregate" id="id14">Поиск границ Агрегатов</a></p> +<ul> +<li><p><a class="reference internal" href="#id3" id="id15">Бизнес-требования</a></p></li> +<li><p><a class="reference internal" href="#strong-consistency-rdbms" id="id16">Strong Consistency (RDBMS)</a></p></li> +<li><p><a class="reference internal" href="#eventual-consistency" id="id17">Eventual Consistency</a></p> +<ul> +<li><p><a class="reference internal" href="#id4" id="id18">Первоначальная модель</a></p> +<ul> +<li><p><a class="reference internal" href="#id5" id="id19">Упрощенная реализация первоначальной модели</a></p></li> +<li><p><a class="reference internal" href="#id6" id="id20">Реализация требований</a></p></li> +<li><p><a class="reference internal" href="#id7" id="id21">Проблемы данной модели</a></p> +<ul> +<li><p><a class="reference internal" href="#id8" id="id22">Вероятность утраты согласованности</a></p></li> +<li><p><a class="reference internal" href="#id9" id="id23">Уникальность артефакта</a></p></li> +<li><p><a class="reference internal" href="#endorsement" id="id24">Преобразование Endorsement в Сущность</a></p></li> +<li><p><a class="reference internal" href="#id10" id="id25">Достижение согласованности</a></p> +<ul> +<li><p><a class="reference internal" href="#data-context-and-interaction-dci" id="id26">Data, context, and interaction (DCI)</a></p></li> +<li><p><a class="reference internal" href="#process-manager-pattern" id="id27">Process Manager Pattern</a></p></li> +<li><p><a class="reference internal" href="#pessimistic-offline-lock" id="id28">Pessimistic Offline Lock</a></p></li> +<li><p><a class="reference internal" href="#id11" id="id29">Резервирование</a></p></li> </ul> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" by Martin Fowler</p> -</div></blockquote> +</li> +</ul> +</li> +</ul> +</li> +<li><p><a class="reference internal" href="#id12" id="id30">Упрощенная реализация итоговой модели</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#missing-chapter" id="id31">Missing chapter</a></p></li> +</ul> +</li> +</ul> +</nav> +<section id="id3"> +<h2><a class="toc-backref" href="#id15" role="doc-backlink">Бизнес-требования</a></h2> +<p>Бизнес-требования к Reference Application описаны в разделе "<a class="reference external" href="https://github.com/ru-arc/charter/blob/main/charter.md#46-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0-%D0%BA%D0%B2%D0%B0%D0%BB%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%BE%D0%B9-%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%B8-%D1%87%D0%BB%D0%B5%D0%BD%D0%BE%D0%B2-%D0%BE%D1%80%D0%B3%D0%B0%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8">4.6. Система квалификационной классификации членов Организации</a>" Устава региональной общественной организации "Объединение ИТ-Архитекторов".</p> +<p>Выделим основные из них:</p> +<ol class="arabic simple"> +<li><p>Каждый член Организации может отдать 20 рекомендаций (признаний) в год в пользу других членов.</p></li> +<li><p>Одна рекомендация от члена Организации претендуемого (или более высокого) квалификационного класса равноценна двум рекомендациям от членов Организации текущего квалификационного класса (излишки не переносятся).</p></li> +<li><p>Рекомендации от членов Организации более низкого квалификационного класса не допускаются.</p></li> +<li><p>Допускается одна рекомендация рекомендующего за один конкретный артефакт рекомендуемого.</p></li> +<li><p>Требуемые количества рекомендаций по квалификационным классам:</p> +<ol class="arabic simple"> +<li><p>Эксперт - 20 рекомендаций Экспертов или 40 рекомендаций Кандидатов в эксперты;</p></li> +<li><p>Кандидат в эксперты - 10 рекомендаций Кандидатов в эксперты или 20 рекомендаций 1-го класса;</p></li> +<li><p>1 класс - 7 рекомендаций 1-го класса или 14 рекомендаций 2-го класса;</p></li> +<li><p>2 класс - 5 рекомендаций 2-го класса или 10 рекомендаций 3-го класса;</p></li> +<li><p>3 класс - 3 рекомендации 3-го класса или 6 рекомендаций без класса;</p></li> +<li><p>без класса - по умолчанию.</p></li> +</ol> +</li> +</ol> +<p>Остальные требования в настоящий момент рассмотрения пока не сильно релевантны.</p> +</section> +<section id="strong-consistency-rdbms"> +<h2><a class="toc-backref" href="#id16" role="doc-backlink">Strong Consistency (RDBMS)</a></h2> +<p>Этот вариант реализации хорошо был расcмотрен в статье "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/modeling-relationships-in-ddd-way/">Modeling Relationships in a DDD Way</a>" by Vladimir Khorikov, поэтому подробно рассматривать мы его не будем. +Приведу только заключительный фрагмент его статьи:</p> +<div class="literal-block-wrapper docutils container" id="id13"> +<div class="code-block-caption"><span class="caption-text"><a class="reference external" href="https://stackoverflow.com/questions/24921227/save-and-load-objects-without-breaking-encapsulation">Example from Stackoverflow</a></span></div> +<div class="highlight-csharp notranslate"><div class="highlight"><pre><span/><span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="nc">Student</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">Entity</span><span class="w"/> +<span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="n">Name</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="n">Email</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">readonly</span><span class="w"> </span><span class="n">IList</span><span class="p">&lt;</span><span class="n">StudentInstructor</span><span class="p">&gt;</span><span class="w"> </span><span class="n">_studentInstructors</span><span class="p">;</span><span class="w"/> +<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">IReadOnlyList</span><span class="p">&lt;</span><span class="n">Instructor</span><span class="p">&gt;</span><span class="w"> </span><span class="n">Instructors</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">_studentInstructors</span><span class="w"/> +<span class="w"> </span><span class="p">.</span><span class="n">Select</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">Instructor</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">.</span><span class="n">OrderBy</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">DateAdded</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">.</span><span class="n">ToList</span><span class="p">();</span><span class="w"/> + +<span class="w"> </span><span class="k">internal</span><span class="w"> </span><span class="k">void</span><span class="w"> </span><span class="nf">AddInstructor</span><span class="p">(</span><span class="n">StudentInstructor</span><span class="w"> </span><span class="n">instructor</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="n">_studentInstructors</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="n">instructor</span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="nc">Instructor</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">Entity</span><span class="w"/> +<span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="n">Name</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">readonly</span><span class="w"> </span><span class="n">IList</span><span class="p">&lt;</span><span class="n">StudentInstructor</span><span class="p">&gt;</span><span class="w"> </span><span class="n">_studentInstructors</span><span class="p">;</span><span class="w"/> +<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">IReadOnlyList</span><span class="p">&lt;</span><span class="n">Student</span><span class="p">&gt;</span><span class="w"> </span><span class="n">Students</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">_studentInstructors</span><span class="w"/> +<span class="w"> </span><span class="p">.</span><span class="n">Select</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">Student</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">.</span><span class="n">OrderBy</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">DateAdded</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">.</span><span class="n">ToList</span><span class="p">();</span><span class="w"/> + +<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="k">void</span><span class="w"> </span><span class="nf">AddStudent</span><span class="p">(</span><span class="n">Student</span><span class="w"> </span><span class="n">student</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="kt">var</span><span class="w"> </span><span class="n">studentInstructor</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">StudentInstructor</span><span class="p">(</span><span class="n">student</span><span class="p">,</span><span class="w"> </span><span class="k">this</span><span class="p">,</span><span class="w"> </span><span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="n">_studentInstructors</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="n">studentInstructor</span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="n">student</span><span class="p">.</span><span class="n">AddInstructor</span><span class="p">(</span><span class="n">studentInstructor</span><span class="p">);</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="nc">StudentInstructor</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">Entity</span><span class="w"/> +<span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">Student</span><span class="w"> </span><span class="n">Student</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">Instructor</span><span class="w"> </span><span class="n">Instructor</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">DateTime</span><span class="w"> </span><span class="n">DateAdded</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">get</span><span class="p">;</span><span class="w"> </span><span class="p">}</span><span class="w"/> + +<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="nf">StudentInstructor</span><span class="p">(</span><span class="n">Student</span><span class="w"> </span><span class="n">student</span><span class="p">,</span><span class="w"> </span><span class="n">Instructor</span><span class="w"> </span><span class="n">instructor</span><span class="p">,</span><span class="w"> </span><span class="n">DateTime</span><span class="w"> </span><span class="n">dateAdded</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="n">Student</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">student</span><span class="p">;</span><span class="w"/> +<span class="w"> </span><span class="n">Instructor</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">instructor</span><span class="p">;</span><span class="w"/> +<span class="w"> </span><span class="n">DateAdded</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">dateAdded</span><span class="p">;</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="p">}</span><span class="w"/> +</pre></div> +</div> +</div> </section> +<section id="eventual-consistency"> +<h2><a class="toc-backref" href="#id17" role="doc-backlink">Eventual Consistency</a></h2> <section id="id4"> -<h2><a class="toc-backref" href="#id9" role="doc-backlink">В каких случаях момент реализации не стоит откладывать</a></h2> -<blockquote> -<div><p>📝 "Если стоимость сегодняшнего решения высока, вероятность того, что оно окажется правильным, низка, вероятность того, что завтра вы найдете лучший способ решить проблему, высока, а стоимость внесения изменений в дизайн завтра низка, то мы можем прийти к выводу, что если сегодня мы можем обойтись без решения, значит, мы ни в коем случае не должны принимать это решение сегодня. -Именно такой подход используется в рамках ХР. -"Количество сложностей ровно на один день и не более того".</p> -<p>Однако некоторые факторы могут стереть наши выводы в порошок. -Если затраты, которые возникнут в случае, если мы будем принимать решение завтра, существенно больше сегодняшних, значит, мы должны принять решение сегодня в надежде на то, что завтра мы окажемся правы. -Если инерция дизайна достаточно низка (над проектом работают очень-очень умные люди), значит, у дизайна, формируемого по мере разработки, остается все меньше и меньше преимуществ. -Если вы действительно очень хороший провидец, значит, вы можете спроектировать все без исключения с самого начала, а затем приступать к реализации готового завершенного плана. -Однако для всех остальных обычных людей я не вижу иной альтернативы, кроме той, в рамках которой предлагается проектировать сегодня только то, что требует проектирования именно сегодня, и откладывать на завтра то, что можно спроектировать завтра.</p> -<p>If the cost of today's decision is high, and the probability of its being right is low, and the probability of knowing a better way tomorrow is high, and the cost of putting in the design tomorrow is low, then we can conclude that we should never make a design decision today if we don't need it today. -In fact, that is what XP concludes. -"Sufficient to the day are the troubles thereof."</p> -<p>Now, several factors can make the above evaluation null and void. -If the cost of making the change tomorrow is very much higher, then we should make the decision today on the off chance that we are right. -If the inertia of the design is low enough (for example, you have really, really smart people), then the benefits of just-in-time design are less. -If you are a really, really good guesser, then you could go ahead and design everything today. -For the rest of us, however, I don't see any alternative to the conclusion that today's design should be done today and tomorrow's design should be done tomorrow."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 17. Design Strategy", перевод ООО Издательство "Питер"</p> -</div></blockquote> +<h3><a class="toc-backref" href="#id18" role="doc-backlink">Первоначальная модель</a></h3> +<p>Хотя предполагается использование RDBMS, но была предпринята попытка найти такие контуры Агрегатов, которые без существенной переработки могли бы функционировать и в условиях отсутствия транзакционной согласованности.</p> +<p>Самый первый вариант модели практически полностью воспроизводил структуру (online) excel-таблиц, использовавшихся на тот момент. +Упрощенная реализация модели выглядела примерно так:</p> +<section id="id5"> +<h4><a class="toc-backref" href="#id19" role="doc-backlink">Упрощенная реализация первоначальной модели</a></h4> +<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kn">package</span><span class="w"> </span><span class="nx">grade_1</span><span class="w"/> + +<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="s">"errors"</span><span class="w"/> +<span class="w"> </span><span class="s">"time"</span><span class="w"/> +<span class="p">)</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="kt">uint64</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">AvailableEndorsementCount</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">ReceivedEndorsementCount</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">EndorsementId</span><span class="w"> </span><span class="kt">uint64</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="w"> </span><span class="kt">string</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Weight</span><span class="w"> </span><span class="kt">uint8</span><span class="w"/> + +<span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="nx">PeerWeight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="w"> </span><span class="nx">HigherWeight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">2</span><span class="w"/> +<span class="p">)</span><span class="w"/> + +<span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="nx">Expert</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">Candidate</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">Grade1</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">Grade2</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">Grade3</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">WithoutGrade</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"/> +<span class="p">)</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Specialist</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">grade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="nx">ReceivedEndorsementCount</span><span class="w"/> +<span class="w"> </span><span class="nx">assignments</span><span class="w"> </span><span class="p">[]</span><span class="nx">Assignment</span><span class="w"/> +<span class="w"> </span><span class="nx">version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">GetId</span><span class="p">()</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">GetGrade</span><span class="p">()</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">GetVersion</span><span class="p">()</span><span class="w"> </span><span class="kt">uint</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">IncreaseReceivedEndorsementCount</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">Weight</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nx">ReceivedEndorsementCount</span><span class="p">(</span><span class="nx">w</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">WithoutGrade</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">6</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade3</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade3</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade2</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade2</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade1</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade1</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Candidate</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Candidate</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">40</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Expert</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsementCount</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">g</span><span class="w"> </span><span class="nx">Grade</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">assignments</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">assignments</span><span class="p">,</span><span class="w"> </span><span class="nx">Assignment</span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="p">,</span><span class="w"> </span><span class="nx">g</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">})</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">g</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">IncreaseVersion</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Assignment</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">assignedGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Endorser</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">grade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="nx">AvailableEndorsementCount</span><span class="w"/> +<span class="w"> </span><span class="nx">version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">Endorse</span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">Specialist</span><span class="p">,</span><span class="w"> </span><span class="nx">aDesc</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">Endorsement</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">{},</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="s">"it is allowed to endorse only members with equal or lower grade"</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">{},</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="s">"you have reached the limit of available recommendations this year"</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nb">uint64</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">uint64</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">GetId</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">{},</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="s">"endorser can't endorse himself"</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">grade</span><span class="p">,</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">GetVersion</span><span class="p">(),</span><span class="w"/> +<span class="w"> </span><span class="nx">aDesc</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="kc">nil</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">DecreaseAvailableEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"no endorsement is available"</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">IncreaseVersion</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Endorsement</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">endorserId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">endorserGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">endorserVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">artifactDescription</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> +</pre></div> +</div> +<p>Метод <code class="docutils literal notranslate"><span class="pre">Endorser.Endorse(Specialist,</span> <span class="pre">ArtifactDescription,</span> <span class="pre">time.Time)</span></code> является фабричным методом Агрегата <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>. +При сохранении Агрегата <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> в Хранилище, из него извлекаются Доменные События, и отправляются подписчикам через некий механизм доставки. +Мы предполагаем, что они могут быть обработаны как синхронно в той же транзакции (Mediator/Observer Design Pattern), так и асинхронно в другой транзакции (<a class="reference external" href="https://www.enterpriseintegrationpatterns.com/MessageBroker.html">Message Broker</a>).</p> +<p>На Доменное Событие <code class="docutils literal notranslate"><span class="pre">EndorsementCreated</span></code> подписаны:</p> +<ol class="arabic simple"> +<li><p><code class="docutils literal notranslate"><span class="pre">Endorser</span></code>, у которого вызывается метод <code class="docutils literal notranslate"><span class="pre">Endorser.DecreaseAvailableEndorsementCount()</span></code> для вычитания использованной рекомендации из счетчика доступных в этом году рекомендаций;</p></li> +<li><p><code class="docutils literal notranslate"><span class="pre">Endorse</span></code>, у которого вызывается метод <code class="docutils literal notranslate"><span class="pre">Specialist.IncreaseReceivedEndorsementCount(Weight)</span></code> с указанием веса рекомендации, зависящего от отношения квалификационного класса рекомендующего к квалификационному классу рекомендуемого.</p></li> +</ol> +<p>Обратите внимание, <code class="docutils literal notranslate"><span class="pre">Assignment</span></code>, как и <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>, имеет значение для бизнес-правил, и он не может быть усечен снэпшотом event sourced log. +Например, он может устанавливать правила минимального, либо максимального периода времени между присваиваниями классности, например, не чаще одного раза в полгода. +Или, например, требовать подтверждения текущей классности в случае отсутствия присваиваний в течении года. +Поэтому, он выполнен в виде самостоятельного Объекта-Значения. +В ином случае он мог бы быть перемещен в ReadModel.</p> +<p><code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>, в свою очередь, отвечает за то, чтобы <code class="docutils literal notranslate"><span class="pre">Endorser</span></code> не смог порекомендовать один и тот же <code class="docutils literal notranslate"><span class="pre">Artifact</span></code> одного и того же <code class="docutils literal notranslate"><span class="pre">Specialist</span></code> дважды.</p> </section> -<section id="emacsway-yagni-literature"> -<span id="id5"/><h2><a class="toc-backref" href="#id10" role="doc-backlink">Литература о YAGNI</a></h2> -<ul class="simple"> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>" / Сергей Тепляков</p></li> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2012/04/blog-post_19.html">О повторном использовании кода</a>" / Сергей Тепляков</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" (хорошо разъясняет виды экономических ущербов: "cost of build", "cost of delay", "cost of carry", "cost of repair", "cost of removing")</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebt.html">Technical Debt</a>"</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebtQuadrant.html">Technical Debt Quadrant</a>"</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/DesignPayoffLine.html">Design Payoff Line</a>"</p></li> -<li><dl class="simple"> -<dt>"Extreme Programming Explained" 1st edition by Kent Beck</dt><dd><ul> -<li><p>"Chapter 3. Economics of Software Development"</p></li> -<li><p>"Chapter 17. Design Strategy"</p></li> -<li><p>"Chapter 20. Retrofitting XP"</p></li> -<li><p>"Chapter 24. What Makes XP Hard"</p></li> -</ul> +<section id="id6"> +<h4><a class="toc-backref" href="#id20" role="doc-backlink">Реализация требований</a></h4> +<p>Пройдемся по требованиям:</p> +<dl class="simple"> +<dt>Каждый член Организации может отдать 20 рекомендаций (признаний) в год в пользу других членов.</dt><dd><p>Это требование реализуется счетчиком <code class="docutils literal notranslate"><span class="pre">Endorser.availableEndorsementCount</span></code> и инвариантом <code class="docutils literal notranslate"><span class="pre">Объекта-Значения</span> <span class="pre">AvailableEndorsementCount</span></code>, который не может превышать установленное ограничение.</p> </dd> -</dl> -</li> -<li><dl class="simple"> -<dt>"Refactoring: Improving the Design of Existing Code" 1st (and 2nd) edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</dt><dd><ul> -<li><p>"Chapter 2. Principles in Refactoring"</p></li> -</ul> +<dt>Одна рекомендация от члена Организации претендуемого (или более высокого) квалификационного класса равноценна двум рекомендациям от членов Организации текущего квалификационного класса (излишки не переносятся).</dt><dd><p>Это требование реализуется обработчиком Доменного События <code class="docutils literal notranslate"><span class="pre">EndorsementCreated</span></code> перед вызовом метода <code class="docutils literal notranslate"><span class="pre">Specialist.IncreaseReceivedEndorsementCount(Weight)</span></code>.</p> +</dd> +<dt>Рекомендации от членов Организации более низкого квалификационного класса не допускаются.</dt><dd><p>Реализуется фабричным методом <code class="docutils literal notranslate"><span class="pre">Endorser.Endorse(...)</span></code>.</p> +</dd> +<dt>Допускается одна рекомендация рекомендующего за один конкретный артефакт рекомендуемого.</dt><dd><p>Это требование обсудим отдельно.</p> +</dd> +<dt>Требуемые количества рекомендаций по квалификационным классам...</dt><dd><p>Реализуется фабричным методом <code class="docutils literal notranslate"><span class="pre">Endorser.Endorse(...)</span></code>.</p> </dd> </dl> -</li> -<li><p>"Working Effectively with Legacy Code" by Michael C. Feathers</p></li> -</ul> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> -<ul class="simple"> -<li><p>"<a class="reference internal" href="borrowing-trouble.html#emacsway-borrowing-trouble"><span class="std std-ref">Borrowing trouble</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../models/agile/analysis/concerns/technical-concerns/when-to-refactor.html#emacsway-when-to-refactor"><span class="std std-ref">Когда делать refactoring в legacy</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../models/agile/analysis/concerns/technical-concerns/when-to-write-unit-tests.html#emacsway-when-to-write-unit-tests"><span class="std std-ref">Когда писать Unit Tests в legacy</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../software-design/solid.html#emacsway-agile-solid"><span class="std std-ref">Role of SOLID principles in Agile</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../software-design/software-design.html#emacsway-agile-software-design"><span class="std std-ref">Role of Software Design in Agile</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../models/agile/analysis/concerns/balancing-business-technical-concerns.html#emacsway-agile-balancing-business-technical-concerns"><span class="std std-ref">Балансирование Бизнес/Технических интересов</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../crash-course-in-software-development-economics.html#emacsway-software-development-economics-literature"><span class="std std-ref">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">Balancing Prediction/Adaptation</span></a>"</p></li> -</ul> -</div> -</section> -Thu, 06 Oct 2022 00:00:00 Роль архитектуры в масштабировании команд, DDD и микросервисахhttps://dckms.github.io/system-architecture/emacsway/it/team-topologies/harlan-mills'-proposal.html -<span id="emacsway-team-topologies-at-scale"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> -<ul class="simple"> -<li><p><a class="reference internal" href="#ddd" id="id16">Роль архитектуры в масштабировании команд, DDD и микросервисах</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id17">Закон Брукса и роль автономности команд</a></p> -<ul> -<li><p><a class="reference internal" href="#emacsway-brooks-s-law" id="id18">Закон Брукса</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id19">Противоречие между эффективностью и производительностью</a></p></li> -<li><p><a class="reference internal" href="#emacsway-harlan-mills-proposal" id="id20">Предложение Харлана Миллза</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#program-management" id="id21">Program Management</a></p> -<ul> -<li><p><a class="reference internal" href="#spotify" id="id22">Spotify</a></p></li> -<li><p><a class="reference internal" href="#agile-software-requirements-lean-requirements-practices-for-teams-programs-and-the-enterprise" id="id23">Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise</a></p></li> -<li><p><a class="reference internal" href="#scaled-agile-framework-safe" id="id24">Scaled Agile Framework (SAFe)</a></p></li> -<li><p><a class="reference internal" href="#agile-practice-guide-by-pmi" id="id25">"Agile Practice Guide" by PMI</a></p></li> -<li><p><a class="reference internal" href="#disciplined-agile-delivery-dad" id="id26">Disciplined agile delivery (DAD)</a></p></li> -<li><p><a class="reference internal" href="#iso-iec-ieee-12207-2017" id="id27">ISO/IEC/IEEE 12207:2017</a></p></li> -<li><p><a class="reference internal" href="#nexus" id="id28">Nexus</a></p></li> -<li><p><a class="reference internal" href="#extreme-programming" id="id29">Extreme Programming</a></p></li> -<li><p><a class="reference internal" href="#scrum-of-scrums" id="id30">Scrum of Scrums</a></p></li> -<li><p><a class="reference internal" href="#id6" id="id31">Другие</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#emacsway-fractal-team" id="id32">Фрактальная структура</a></p></li> -<li><p><a class="reference internal" href="#id8" id="id33">Социальная роль архитектуры</a></p></li> -<li><p><a class="reference internal" href="#emacsway-team-topologies-at-scale-literature" id="id34">Литература</a></p></li> -<li><p><a class="reference internal" href="#id10" id="id35">Ссылки по теме</a></p></li> -</ul> -</li> -</ul> -</nav> -<section id="id2"> -<h2><a class="toc-backref" href="#id17" role="doc-backlink">Закон Брукса и роль автономности команд</a></h2> -<section id="emacsway-brooks-s-law"> -<span id="id3"/><h3><a class="toc-backref" href="#id18" role="doc-backlink">Закон Брукса</a></h3> -<p>Сегодня, наверное, каждый знает Закон Брукса:</p> -<blockquote> -<div><p>📝 "Если проект не укладывается в сроки, то добавление рабочей силы задержит его ещё больше.</p> -<p>Adding manpower to a late software project makes it later."</p> -<p class="attribution">—The Brooks's Law</p> -</div></blockquote> -<blockquote> -<div><p>📝 "Brooks' law is based on the idea that communications overhead is a significant factor on software projects, and that work on a software project is not easily partitioned into isolated, independent tasks. Ten people can pick cotton ten times as fast as one person because the work is almost perfectly partitionable, requiring little communication or coordination. But nine women can't have a baby any faster than one woman can because the work is not partitionable. Brooks argues that work on a software project is more like having a baby than picking cotton. When new staff are brought into a late project, they aren't immediately productive, and they must be trained. The staff who must train them are already productive, but they lose productivity while they're training new staff. Brooks argues that, on balance, more effort is lost to training and additional coordination and communications overhead than is gained when the new staff eventually becomes productive."</p> -<p class="attribution">—"<a class="reference external" href="https://stevemcconnell.com/articles/brooks-law-repealed/">Brooks' Law Repealed?</a>" by Steve McConnell</p> -</div></blockquote> -<blockquote> -<div><p>📝 "Число занятых [специалистов] и число месяцев [в термине человеко-месяц] являются взаимозаменяемыми величинами лишь тогда, когда задачу можно распределить среди ряда работников, которые не имеют между собой взаимосвязи (рис. 2.1).</p> -<p>Men and months [in term man-month] are interchangeable commodities only when a task can be partitioned among many workers with no communication among them (Fig. 2.1)."</p> -<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>Сравните это с</p> -<blockquote> -<div><p>📝 "Microservices' main benefit, in my view, is enabling parallel development by establishing a hard-to-cross boundary between different parts of your system."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/dont-start-monolith.html">Don't start with a monolith</a>" by Stefan Tilkov, a co-founder and principal consultant at innoQ</p> -</div></blockquote> </section> -<section id="id4"> -<h3><a class="toc-backref" href="#id19" role="doc-backlink">Противоречие между эффективностью и производительностью</a></h3> -<p>Frederick Brooks формулирует противоречие. С одной стороны:</p> -<blockquote> -<div><p>📝 "Выше я доказал, что само число разработчиков, действия которых нужно согласовывать, оказывает влияние на стоимость проекта, поскольку значительная часть издержек вызвана необходимостью общения и устранения отрицательных последствий разобщенности (системная отладка). Это также наводит на мысль, что <strong>желательно разрабатывать системы возможно меньшим числом людей</strong>. Действительно, опыт разработки больших программных систем, как правило, показывает, что подход с позиций грубой силы влечет удорожание, замедленность, неэффективность, а создаваемые в результате системы не являются концептуально целостными. Список, иллюстрирующий это, бесконечен: OS/360, Exec 8, Scop 6600, Multics, TSS, SAGE и другие.</p> -<p>I have earlier argued that the sheer number of minds to be coordinated affects the cost of the effort, for a major part of the cost is communication and correcting the ill effects of miscommunication (system debugging). This, too, suggests that one wants the system to be built by <strong>as few minds as possible</strong>. Indeed, most experience with large programming systems shows that the brute-force approach is costly, slow, inefficient, and produces systems that are not conceptually integrated. OS/360, Exec 8, Scope 6600, Multics, TSS, SAGE, etc.—the list goes on and on."</p> -<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>Таким же наблюдением делится и Sam Newman:</p> -<blockquote> -<div><p>📝 "... небольшие команды, работающие с небольшим объемом исходного кода, как правило, показывают более высокую продуктивность.</p> -<p>... smaller teams working on smaller codebases tend to be more productive!"</p> -<p class="attribution">—"Building Microservices. Designing Fine-Grained Systems" by Sam Newman, перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>Но, с другой стороны:</p> -<blockquote> -<div><p>📝 "В этом и состоит <strong>изъян идеи маленькой активной команды: для создания по-настоящему крупных систем ей потребуется слишком много времени</strong>. Посмотрим, как разработка OS/360 осуществлялась бы маленькой активной командой, допустим, из 10 человек. Положим, что они в семь раз более продуктивны средних программистов (что далеко от истины). Допустим, что уменьшение объема общения благодаря малочисленности команды позволило еще в семь раз повысить производительность. Допустим, что на протяжении всего проекта работает одна и та же команда. Таким образом, 5000/(10*7*7)=10, т.е. работу в 5000 человеко-лет они выполнят за 10 лет. Будет ли продукт представлять интерес через 10 лет после начала разработки или устареет благодаря стремительному развитию программных технологий?</p> -<p>This then is <strong>the problem with the small, sharp team concept: it is too slow for really big systems. Consider the OS/360 job as it might be tackled with a small, sharp team</strong>. Postulate a 10-man team. As a bound, let them be seven times as productive as mediocre programmers in both programming and documentation, because they are sharp. Assume OS/360 was built only by mediocre programmers (which is far from the truth). As a bound, assume that another productivity improvement factor of seven comes from reduced communication on the part of the smaller team. Assume the same team stays on the entire job. Well, 5000/(10 X 7 X 7 ) = 10; they can do the 5000 man-year job in 10 years. Will the product be interesting 10 years after its initial design? Or will it have been made obsolete by the rapidly developing software technology?"</p> -<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>Возникает противоречие:</p> -<blockquote> -<div><p>📝 "Дилемма представляется жестокой. Для эффективности и концептуальной целостности предпочтительнее, чтобы проектирование и создание системы осуществили <strong>несколько светлых голов</strong>. Однако для больших систем желательно поставить под ружье <strong>значительный контингент</strong>, чтобы продукт мог увидеть свет вовремя. <strong>Как можно примирить эти два желания?</strong></p> -<p>The dilemma is a cruel one. For efficiency and conceptual integrity, one prefers <strong>a few good minds</strong> doing design and construction. Yet for large systems one wants a way to bring <strong>considerable manpower to bear</strong>, so that the product can make a timely appearance. <strong>How can these two needs be reconciled?</strong>"</p> -<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>Добавим немного контекста:</p> -<blockquote> -<div><p>📝 "Вторая ошибка рассуждений заключена в самой единице измерения, используемой при оценивании и планировании: человеко-месяц. Стоимость действительно измеряется как произведения числа занятых на количество затраченных месяцев. Но не достигнутый результат. Поэтому использование человеко-месяца как единицы измерения объема работы является опасным заблуждением.</p> -<p>Число занятых и число месяцев являются взаимозаменяемыми величинами лишь тогда, когда задачу можно распределить среди ряда работников, которые не имеют между собой взаимосвязи (рис. 2.1). Это верно, когда жнут пшеницу или собирают хлопок, но в системном программировании это далеко не так.</p> -<figure class="align-left" id="id11"> -<a class="reference internal image-reference" href="../../../_images/fig-2.1-perfectly-partitionable-task.png"><img alt="Рис. 2.1 Зависимость времени от числа занятых — полностью разделимая задача. Fig. 2.1 Time versus number of workers—perfectly partitionable task. The image source is &quot;The Mythical Man-Month Essays on Software Engineering Anniversary Edition&quot; by Frederick P. Brooks, Jr., &quot;Chapter 2 The Mythical Man-Month&quot;, перевод ООО Издательство &quot;Питер&quot;." src="../../../_images/fig-2.1-perfectly-partitionable-task.png" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">Рис. 2.1 Зависимость времени от числа занятых — полностью разделимая задача. Fig. 2.1 Time versus number of workers—perfectly partitionable task. The image source is "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., "Chapter 2 The Mythical Man-Month", перевод ООО Издательство "Питер".</span></p> -</figcaption> -</figure> -<p>Если задачу нельзя разбить на части, поскольку существуют ограничения на последовательность выполнения этапов, то увеличение затрат не оказывает влияния на график (рис. 2.2). Чтобы родить ребенка требуется девять месяцев независимо от того, сколько женщин привлечено к решению данной задачи. Многие задачи программирования относятся к этому типу, поскольку отладка по своей сути носит последовательный характер.</p> -<figure class="align-left" id="id12"> -<a class="reference internal image-reference" href="../../../_images/fig-2.2-unpartitionable-task.png"><img alt="Рис. 2.2 Зависимость времени от числа занятых — неразделимая задача. Fig. 2.2 Time versus number of workers—unpartitionable task. The image source is &quot;The Mythical Man-Month Essays on Software Engineering Anniversary Edition&quot; by Frederick P. Brooks, Jr., &quot;Chapter 2 The Mythical Man-Month&quot;, перевод ООО Издательство &quot;Питер&quot;." src="../../../_images/fig-2.2-unpartitionable-task.png" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">Рис. 2.2 Зависимость времени от числа занятых — неразделимая задача. Fig. 2.2 Time versus number of workers—unpartitionable task. The image source is "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., "Chapter 2 The Mythical Man-Month", перевод ООО Издательство "Питер".</span></p> -</figcaption> -</figure> -<p>Для задач, которые могут быть разбиты на части, но требуют обмена данными между подзадачами, затраты на обмен данными должны быть добавлены к общему объему необходимых работ. Поэтому достижимый наилучший результат оказывается несколько хуже, чем простое соответствие числа занятых и количества месяцев (рис. 2.3).</p> -<figure class="align-left" id="id13"> -<a class="reference internal image-reference" href="../../../_images/fig-2.3-partitionable-task-requiring-communication.png"><img alt="Рис. 2.3 Зависимость времени от числа занятых — разделимая задача, требующая обмена данными. Fig. 2.3 Time versus number of workers—partitionable task requiring communication. The image source is &quot;The Mythical Man-Month Essays on Software Engineering Anniversary Edition&quot; by Frederick P. Brooks, Jr., &quot;Chapter 2 The Mythical Man-Month&quot;, перевод ООО Издательство &quot;Питер&quot;." src="../../../_images/fig-2.3-partitionable-task-requiring-communication.png" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">Рис. 2.3 Зависимость времени от числа занятых — разделимая задача, требующая обмена данными. Fig. 2.3 Time versus number of workers—partitionable task requiring communication. The image source is "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., "Chapter 2 The Mythical Man-Month", перевод ООО Издательство "Питер".</span></p> -</figcaption> -</figure> -<p>Дополнительная нагрузка состоит из двух частей — обучения и обмена данными. Каждого работника нужно обучить технологии, целям проекта, общей стратегии и плану работы. Это обучение нельзя разбить на части, поэтому данная часть затрат изменяется линейно в зависимости от числа занятых.</p> -<p><strong>С обменом данными дело обстоит хуже. Если все части задания должны быть отдельно скоординированы между собой, то затраты возрастают как n(n-2)/2. Для трех работников требуется втрое больше попарного общения, чем для двух, для четырех — вшестеро. Если помимо этого возникает необходимость в совещаниях трех, четырех и т.д. работников для совместного решения вопросов, положение становится еще хуже. Дополнительные затраты на обмен данными могут полностью обесценить результат дробления исходной задачи и привести к положению, описываемому рисунком 2.4.</strong></p> -<figure class="align-left" id="id14"> -<a class="reference internal image-reference" href="../../../_images/fig-2.4-task-with-complex-interrelationships.png"><img alt="Рис. 2.4 Зависимость времени от числа занятых — задача со сложными взаимосвязями. Fig. 2.4 Time versus number of workers—task with complex interrelationships. The image source is &quot;The Mythical Man-Month Essays on Software Engineering Anniversary Edition&quot; by Frederick P. Brooks, Jr., &quot;Chapter 2 The Mythical Man-Month&quot;, перевод ООО Издательство &quot;Питер&quot;." src="../../../_images/fig-2.4-task-with-complex-interrelationships.png" style="width: 70%;"/></a> -<figcaption> -<p><span class="caption-text">Рис. 2.4 Зависимость времени от числа занятых — задача со сложными взаимосвязями. Fig. 2.4 Time versus number of workers—task with complex interrelationships. The image source is "The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., "Chapter 2 The Mythical Man-Month", перевод ООО Издательство "Питер".</span></p> -</figcaption> -</figure> -<p>Поскольку создание программного продукта является по сути системным проектом — практикой сложных взаимосвязей, затраты на обмен данными велики и быстро начинают преобладать над сокращением сроков, достигаемым в результате разбиения задачи на более мелкие подзадачи. В этом случае привлечение дополнительных работников не сокращает, а удлиняет график работ.</p> -<p>The second fallacious thought mode is expressed in the very unit of effort used in estimating and scheduling: the man-month. Cost does indeed vary as the product of the number of men and the number of months. Progress does not. Hence the man-month as a unit for measuring the size of a job is a dangerous and deceptive myth. It implies that men and months are interchangeable.</p> -<p>Men and months are interchangeable commodities only when a task can be partitioned among many workers with no communication among them (Fig. 2.1). This is true of reaping wheat or picking cotton; it is not even approximately true of systems programming.</p> -<p>When a task cannot be partitioned because of sequential constraints, the application of more effort has no effect on the schedule (Fig. 2.2). The bearing of a child takes nine months, no matter how many women are assigned. Many software tasks have this characteristic because of the sequential nature of debugging.</p> -<p>In tasks that can be partitioned but which require communication among the subtasks, the effort of communication must be added to the amount of work to be done. Therefore the best that can be done is somewhat poorer than an even trade of men for months (Fig. 2.3).</p> -<p>The added burden of communication is made up of two parts, training and intercommunication. Each worker must be trained in the technology, the goals of the effort, the overall strategy, and the plan of work. This training cannot be partitioned, so this part of the added effort varies linearly with the number of workers.</p> -<p><strong>Intercommunication is worse. If each part of the task must be separately coordinated with each other part/ the effort increases as n(n-I)/2. Three workers require three times as much pairwise intercommunication as two; four require six times as much as two. If, moreover, there need to be conferences among three, four, etc., workers to resolve things jointly, matters get worse yet. The added effort of communicating may fully counteract the division of the original task and bring us to the situation of Fig. 2.4.</strong></p> -<p>Since software construction is inherently a systems effort—an exercise in complex interrelationships—communication effort is great, and it quickly dominates the decrease in individual task time brought about by partitioning. Adding more men then lengthens, not shortens, the schedule."</p> -<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>Мы остановились на дилемме: с одной стороны, чем меньше численность людей, принимающих проектные решения, тем выше их продуктивность. -С другой стороны, чем больше людей задействовано в разработке, тем скорее продукт сможет выйти на рынок. -Проанализируем о том, как эту дилемму можно решить.</p> -<p>Решение этой дилеммы становится возможным с качественным отделением архитектуры от реализации (с чем отлично справляются сетевые границы Bounded Contexts):</p> -<blockquote> -<div><p>📝 "<strong>Архитектура и разработка должны быть тщательно разделены.</strong> Как сказал Блау (Blaauw), "архитектура говорит, что должно произойти, а разработка - как сделать, чтобы это произошло". В качестве простого примера он приводит часы, архитектура которых состоит из циферблата, стрелок и заводной головки. Ребенок, освоивший это архитектуру, с одинаковой легкостью может узнать время и по ручным часам, и по часам на колокольне. Исполнение же и его реализация описывают, что происходит внутри: передача усилий и управление точностью каждым из многих механизмов.</p> -<p><strong>Architecture must be carefully distinguished from implementation.</strong> As Blaauw has said, "Where architecture tells what happens, implementation tells how it is made to happen." He gives as a simple example a clock, whose architecture consists of the face, the hands, and the winding knob. When a child has learned this architecture, he can tell time as easily from a wristwatch as from a church tower. The implementation, however, and its realization, describe what goes on inside the case—powering by any of many mechanisms and accuracy control by any of many."</p> -<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> -</div></blockquote> +<section id="id7"> +<h4><a class="toc-backref" href="#id21" role="doc-backlink">Проблемы данной модели</a></h4> +<p>В существующей модели прослеживается ряд проблем. Рассмотрим их по порядку.</p> +<section id="id8"> +<h5><a class="toc-backref" href="#id22" role="doc-backlink">Вероятность утраты согласованности</a></h5> +<p>Давайте представим, что <code class="docutils literal notranslate"><span class="pre">endorserA</span></code> 2-го класса дает рекомендацию в пользу <code class="docutils literal notranslate"><span class="pre">specialistA</span></code> 2-го класса, у которого уже существует 13 рекомендаций, т.е. для присвоения нового квалификационного класса не хватает всего одной рекомендации. +В период времени с момента проверки инварианта методом <code class="docutils literal notranslate"><span class="pre">Endorser.Endorse(...)</span></code> и до декрементирования счетчика доступных рекомендаций рекомендующего методом <code class="docutils literal notranslate"><span class="pre">Endorser.DecreaseAvailableEndorsementCount()</span></code>, а также до вызова метода <code class="docutils literal notranslate"><span class="pre">Specialist.IncreaseReceivedEndorsementCount(Weight)</span></code>, другой участник <code class="docutils literal notranslate"><span class="pre">endorserB</span></code> 2-го класса может также успеть дать рекомендацию в пользу <code class="docutils literal notranslate"><span class="pre">specialistA</span></code>.</p> +<p>В результате рекомендация <code class="docutils literal notranslate"><span class="pre">endorserB</span></code> будет зачтена в пользу <code class="docutils literal notranslate"><span class="pre">specialistA</span></code> уже фактически 1-го класса, что нарушает требование о запрете на рекомендацию участников более высокого квалификационного класса.</p> +<p>Для упреждения такой ситуации достаточно наложить покрывающий (композитный) уникальный индекс на поля <code class="docutils literal notranslate"><span class="pre">Endorsement.specialistId</span></code> и <code class="docutils literal notranslate"><span class="pre">Endorsement.specialistVersion</span></code>.</p> +<p>Или рассмотрим другую ситуацию. +Участник <code class="docutils literal notranslate"><span class="pre">endorserA</span></code>, у которого оставалась всего одна доступная рекомендация в текущем году, дает рекомендацию в пользу <code class="docutils literal notranslate"><span class="pre">specialistA</span></code>, +но произошла техническая задержка доставки сообщения <code class="docutils literal notranslate"><span class="pre">EndorsementCreated</span></code> рекомендующему по техническим причинам, например, очередь "встала" (или подписчик затупил, чек-поинт в БД запустился, сеть упала...), и тогда рекомендующий может успеть раздать рекомендаций больше, чем располагает. +Упреждается такая ситуация таким же образом - покрывающим уникальным индексом на поля <code class="docutils literal notranslate"><span class="pre">Endorsement.endorserId</span></code> и <code class="docutils literal notranslate"><span class="pre">Endorsement.endorserGrade</span></code>.</p> +<p>Но это выдвигает новый вопрос - каким образом партиционировать таблицу <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>, чтобы реализовать оба уникальных индекса? +Кто хоть раз занимался партиционированием, тот знает, что уникальный индекс возможен только в пределах партиции. +Можно, конечно, партиционировать <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> по автоинкрементальному первичному ключу (или по дате создания), но тут самое время перейти к следующему требованию, которое гласит: "Допускается одна рекомендация рекомендующего за один конкретный артефакт рекомендуемого".</p> </section> -<section id="emacsway-harlan-mills-proposal"> -<span id="id5"/><h3><a class="toc-backref" href="#id20" role="doc-backlink">Предложение Харлана Миллза</a></h3> -<p>Harlan Mills' Proposal (Предложение Харлана Миллза) было опубликовано в:</p> -<ul class="simple"> -<li><p>Mills, H., "Chief programmer teams, principles, and procedures," IBM Federal Systems Division Report FSC 71-5108, Gaithersburg, Md., 1971.</p></li> -<li><p>Baker, F. T., "Chief programmer team management of production programming," IBM Sys. J., 11, 1 (1972).</p></li> -</ul> -<blockquote> -<div><p>📝 "Предложение Харлана Миллза дает свежее и творческое решение. Миллз предложил, чтобы на каждом участке работы была <strong>команда разработчиков, организованная наподобие бригады хирургов, а не мясников</strong>. Имеется в виду, что не каждый участник группы будет врезаться в задачу, но резать будет один, а остальные оказывать ему всевозможную поддержку, повышая его производительность и плодотворность.</p> -<p>При некотором размышлении ясно, что <strong>эта идея приведет к желаемому, если ее удастся осуществить</strong>. Лишь несколько голов занято проектированием и разработкой, и в то же время много работников находится на подхвате. Будет ли такая организация работать? Кто играет роль анестезиологов и операционных сестер в группе программистов, а как осуществляется разделение труда? Чтобы нарисовать картину работы такой команды с включением всех мыслимых видов поддержки, я позволю себе вольное обращение к метафорам.</p> -<p>A proposal by Harlan Mills offers a fresh and creative solution. Mills proposes that each segment of a large job be tackled by a team, but that <strong>the team be organized like a surgical team rather than a hog-butchering team</strong>. That is, instead of each member cutting away on the problem, one does the cutting and the others give him every support that will enhance his effectiveness and productivity.</p> -<p>A little thought shows that <strong>this concept meets the desiderata, if it can be made to work</strong>. Few minds are involved in design and construction, yet many hands are brought to bear. Can it work? Who are the anesthesiologists and nurses on a programming team, and how is the work divided? Let me freely mix metaphors to suggest how such a team might work if enlarged to include all conceivable support."</p> -<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>Обратите внимание на слова "эта идея приведет к желаемому, если ее удастся осуществить". -Именно эту задачу успешно решает концепция <a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard-single/#_solution_space">Bounded Context</a>, позволяя совместить большой размер коллектива и продуктивность, т.е., осуществить масштабирование команд без ущерба производительности.</p> -<blockquote> -<div><p>📝 "... мы стремимся к тому, чтобы сервисы создавались в результате разбиения системы на такие части, при которых <strong>темпы развития внутри сервисов были намного выше темпов развития между сервисами</strong>.</p> -<p>... we aim to ensure our services are decomposed such that the <strong>pace of change inside a service is much higher than the pace of change between services</strong>."</p> -<p class="attribution">—"Building Microservices. Designing Fine-Grained Systems" by Sam Newman, перевод ООО Издательство "Питер"</p> -</div></blockquote> -<blockquote> -<div><p>📝 "One case study was particularly interesting. The team had made the wrong choice, using microservices on a system that wasn't complex enough to cover the Microservice Premium. The project got in trouble and needed to be rescued, so lots more people were thrown onto the project. At this point the microservice architecture became helpful, because <strong>the system was able to absorb the rapid influx of developers and the team was able to leverage the larger team numbers much more easily than is typical with a monolith</strong>. As a result the project accelerated to a productivity greater than would have been expected with a monolith, enabling the team to catch up. The result was still a net negative, in that the software cost more staff-hours than it would have done if they had gone with a monolith, but the <strong>microservices architecture did support ramp up</strong>."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/microservice-trade-offs.html">Microservice Trade-Offs</a>" by Martin Fowler</p> -</div></blockquote> -<blockquote> -<div><p>📝 "Netflix и Amazon</p> -<p>Наверное, идея обязательной согласованности организации и архитектуры может быть неплохо проиллюстрирована на примере Amazon и Netflix. В Amazon довольно рано начали понимать преимущества владения командами полным жизненным циклом управляемых ими систем. Там решили, что команды должны всецело распоряжаться теми системами, за которые они отвечают, управляя всем жизненным циклом этих систем. Но в Amazon также знали, что <strong>небольшие команды могут работать быстрее больших</strong>. Это привело к созданию команд, которые можно было бы накормить двумя пиццами. Это стремление к созданию небольших команд, владеющих полным жизненным циклом своих сервисов, и стало основной причиной того, что в Amazon была разработана платформа Amazon Web Services. Для обеспечения самодостаточности своих команд компании понадобилось создать соответствующий инструментарий. Этот пример был взят на вооружение компанией Netflix и с самого начала определил формирование ее структуры вокруг небольших независимых команд, образуемых с прицелом на то, что создаваемые ими сервисы также будут независимы друг от друга. Тем самым обеспечивалась оптимизация скорости изменения архитектуры систем. Фактически в Netflix разработали организационную структуру для желаемой архитектуры создаваемых систем.</p> -<p>Netflix and Amazon</p> -<p>Probably the two poster children for the idea that organizations and architecture should be aligned are Amazon and Netflix. Early on, Amazon started to understand the benefits of teams owning the whole lifecycle of the systems they managed. It wanted teams to own and operate the systems they looked after, managing the entire lifecycle. But Amazon also knew that <strong>small teams can work faster than large teams</strong>. This led famously to its two-pizza teams, where no team should be so big that it could not be fed with two pizzas. This driver for small teams owning the whole lifecycle of their services is a major reason why Amazon developed Amazon Web Services. It needed to create the tooling to allow its teams to be self-sufficient. Netflix learned from this example, and ensured that from the beginning it structured itself around small, independent teams, so that the services they created would also be independent from each other. This ensured that the architecture of the system was optimized for speed of change. Effectively, Netflix designed the organizational structure for the system architecture it wanted."</p> -<p class="attribution">—"Building Microservices. Designing Fine-Grained Systems" by Sam Newman, перевод ООО Издательство "Питер"</p> -</div></blockquote> -<p>я хотел бы добавить еще одно высказывание от разработчиков популярного микросервисного фреймворка go-kit:</p> -<blockquote> -<div><p>📝 "Почему микросервисы? Практически вся современная разработка программного обеспечения ориентирована на единственную цель - улучшить время выхода на рынок. Микросервисы представляют собой эволюцию модели сервис-ориентированной архитектуры, которая элегантно устраняет организационные противоречия, <strong>предоставляя вашим инженерам и командам автономию</strong>, необходимую им для непрерывной доставки, итерации и улучшения.</p> -<p>Why microservices? Almost all of contemporary software engineering is focused on the singular goal of improving time-to-market. Microservices are an evolution of the service-oriented architecture pattern that elegantly eliminate organizational friction, <strong>giving your engineers and teams the autonomy</strong> they need to continuously ship, iterate, and improve."</p> -<p class="attribution">—"<a class="reference external" href="https://gokit.io/">Go kit. A toolkit for microservices.</a>"</p> -</div></blockquote> -<p>На самом деле, если у вас армейская дисциплина среди разработчиков, то нет необходимости укреплять сетевыми границами пределы автономности команд, поскольку границами автономности команды является Bounded Context, который не обязательно должен быть выражен микорсервисом(-ами).</p> -<blockquote> -<div><p>📝 "In theory, you don't need microservices for this if you simply have the discipline to follow clear rules and establish clear boundaries within your monolithic application; in practice, I've found this to be the case only very rarely.)"</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/dont-start-monolith.html">Don't start with a monolith</a>" by Stefan Tilkov</p> -</div></blockquote> -<p>Сетевые границы решают проблему, известную как creeping coupling или abstraction leak. А это позволяет снизить квалификационные требования к разработчикам, тем более, что Microservices First обычно имеет экономическую целесообразность только при задействовании большого количества разработчиков.</p> -<blockquote> -<div><p>📝 "Обмен данными между самими сервисами ведется через сетевые вызовы, чтобы <strong>упрочить обособленность сервисов</strong> и избежать рисков, сопряженных с тесными связями.</p> -<p>All communication between the services themselves are via network calls, <strong>to enforce separation between the services</strong> and avoid the perils of tight coupling."</p> -<p class="attribution">—"Building Microservices. Designing Fine-Grained Systems" by Sam Newman, перевод ООО Издательство "Питер"</p> -</div></blockquote> +<section id="id9"> +<h5><a class="toc-backref" href="#id23" role="doc-backlink">Уникальность артефакта</a></h5> +<p>Суть в том, что дубликаты описаний артефактов могут быть нечеткими. +Требуется вводить пре-модерацию рекомендаций. +Но это значит, что оптимистическая блокировка с помощью уникального индекса может длиться часами и днями. +Вряд ли пользователи системы будут в восторге от этого.</p> +<p>А что если выделить <code class="docutils literal notranslate"><span class="pre">Endorsement.artifactDescription</span></code> в отдельный Агрегат и сделать пре-модерацию для него? +Кажется, это предотвратит длительные блокировки по уже одобренным артефактам, а рекомендация неодобренных артефактов в принципе невозможна. +Более того, артефакты можно категоризировать, и тогда система сможет информировать не только о квалификационной классности члена Организации, но и об областях знаний его экспертности.</p> +<p>Вносим правки:</p> +<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kd">type</span><span class="w"> </span><span class="nx">Endorsement</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">endorserId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">endorserGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">endorserVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">artifactId</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Artifact</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="w"/> +<span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="nx">ArtifactStatus</span><span class="w"/> +<span class="w"> </span><span class="nx">description</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="w"/> +<span class="w"> </span><span class="nx">competenceIds</span><span class="w"> </span><span class="p">[]</span><span class="nx">CompetenceId</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Competence</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">CompetenceId</span><span class="w"/> +<span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="nx">CompetenceName</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> +</pre></div> +</div> +<p>Задача упрощается. +В момент создания Агрегата <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> мы можем удостовериться, что такой артефакт такого рекомендуемого еще пока не был рекомендован таким рекомендующим, с помощью стратегии-валидатора, передаваемой аргументом в фабричный метод, ответственный за создание этого Агрегата.</p> +<p>Но вот в чем дело. +После выделения артефакта в отдельный Агрегат, нам корневой доступ к Агрегату <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> особо-то и не нужен. +Это значит, что его можно преобразовать в Сущность.</p> </section> +<section id="endorsement"> +<h5><a class="toc-backref" href="#id24" role="doc-backlink">Преобразование Endorsement в Сущность</a></h5> +<p>С точки зрения <a class="reference external" href="https://enterprisecraftsmanship.com/posts/domain-model-purity-completeness/">DDD Trilemma</a>, учитывая относительно небольшое количество возможных рекомендаций в процессе жизни Агрегата <code class="docutils literal notranslate"><span class="pre">Specialist</span></code>, имеет смысл отдать предпочтение в пользу "Domain model purity" и "Domain model completeness".</p> +<p>Вопрос в том, в каком именно Агрегате разместить Сущность <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>? +Ответ на этот вопрос подскажет нам, по какому ключу лучше партиционировать таблицу <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>. +Сейчас становится уже очевидно, что партиционирование по автоинкрементальному первичному ключу (или по дате создания) будет приводить к просмотру всех партиций, что нас не устраивает.</p> +<p>У кого хранится в реальном мире наградной лист, почетная грамота, сертификат и т.д. - у награждаемого или у награждающего? +Для кого он имеет ценность?</p> +<p>Это наводит на мысль о том, что Сущность <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> должна принадлежать Агрегату <code class="docutils literal notranslate"><span class="pre">Specialist</span></code>. +Что подтвержается также ответом на вопрос о том, должен ли рекомендующий, т.е. Агрегат <code class="docutils literal notranslate"><span class="pre">Endorser</span></code>, хранить рекомендации удаленных из системы рекомендуемых? +Вроде бы рекомендации должны удаляться вместе с рекомендуемым (это отвечает и на вопрос о том, по какому ключу партиционировать таблицу <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code>). +А вот если из системы удаляется рекомендующий, то его рекомендации продолжают иметь значение как способ подтверждения достоверности квалификационной классности рекомендуемого. +Иными словами, квалификационная классность рекомендуемого является <a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%91%D1%80%D1%82%D0%BA%D0%B0_%D1%81%D0%BF%D0%B8%D1%81%D0%BA%D0%B0">сверткой (left fold)</a> этих рекомендаций, по-другому говоря - их проекцией.</p> +<p>Таким образом, между рекомендуемым и рекомендациями образуется строгая согласованность. +Все, что теперь требуется Агрегату <code class="docutils literal notranslate"><span class="pre">Specialist</span></code> для того, чтобы установить возможность создания рекомендации - это квалификационный класс рекомендующего и достоверность того, что он пока еще не исчерпал доступные ему рекомендации.</p> +<p>Но это так же значит, что мы не можем создать покрывающий уникальный индекс на поля <code class="docutils literal notranslate"><span class="pre">Endorsement.endorserId</span></code> и <code class="docutils literal notranslate"><span class="pre">Endorsement.endorserGrade</span></code>.</p> +<p>Иными словами, существует незначительная вероятность того, что <code class="docutils literal notranslate"><span class="pre">Endorser</span></code> успеет раздать рекомендаций больше, чем ему доступно. +Существует несколько способов решить эту проблему.</p> </section> -<section id="program-management"> -<span id="emacsway-program-management"/><h2><a class="toc-backref" href="#id21" role="doc-backlink">Program Management</a></h2> -<p>Знаете, почему не бывает больших червяков? -Любое беспозвоночное животное не может быть бесконечно большим, поскольку на определенном пороге сила его тяжести превысит предел его прочности. -Рост силы тяжести опережает рост прочности. -Чтобы увеличение массы организма стало возможным, в нем должен появиться скелет, который выполняет опорную функцию.</p> -<p>По этой же причине бумажный кораблик хорошо держит форму, но если его пропорционально увеличить в несколько раз, то он рухнет под собственной тяжестью без фермы жесткости.</p> -<p>По этой же причине невозможно фрактально увеличить село до размеров крупного города, не обеспечив в нем транспортные магистрали и узлы связи.</p> -<p>Эту проблему хорошо сформулировал Galileo Galilei в теории theory of Beam Bending:</p> -<blockquote> -<div><figure class="align-left" id="id15"> -<a class="reference internal image-reference" href="../../../_images/galileo-beam-bending.jpg"><img alt="Discorsi e dimostrazioni matematiche, intorno à due nuoue scienze. Leiden: appresso gli Elsevirii, 1638. The image source is &quot;Galileo's Beam Experiment&quot; https://civil.lindahall.org/strength.shtml" src="../../../_images/galileo-beam-bending.jpg" style="width: 200px;"/></a> -<figcaption> -<p><span class="caption-text">Discorsi e dimostrazioni matematiche, intorno à due nuoue scienze. Leiden: appresso gli Elsevirii, 1638. The image source is "<a class="reference external" href="https://civil.lindahall.org/strength.shtml">Galileo's Beam Experiment</a>"</span></p> -</figcaption> -</figure> -</div></blockquote> -<blockquote> -<div><p>📝 "Many mathematicians before Galileo had dealt with the problem of statics – how forces are transmitted by structural members. -Galileo proposed a new science, the study of the strength of materials, that considered how the size and shape of structural members affects their ability to carry and transmit loads. -He discovered that as the length of a beam increases, its strength decreases, unless you increase the thickness and breadth at an even greater rate. -You cannot, therefore, simply double or triple the dimensions of a beam, and expect it to carry double or triple the load. -This led Galileo to recognize what we now call <strong>the scaling problem – there are limits to how big nature can make a tree, or an animal, for beyond a certain limit, the branches of the tree or the limbs of the animal, will break under their own weight.</strong></p> -<p>The illustration of a cantilever beam demonstrates Galileo’s discovery that the breaking force on a beam increases as the square of its length."</p> -<p class="attribution">—"<a class="reference external" href="https://civil.lindahall.org/strength.shtml">Galileo's Beam Experiment</a>"</p> -</div></blockquote> -<p>Масса балки зависит от ее объема (кубатура), а прочность - от сечения (квадратура). Т.е. масса возрастает на одно изменение больше прочности.</p> -<p>Попытка фрактально увеличивать численность Scrum/Nexus-команд равносильна попытке создать беспозвоночное животное с массой динозавра. -Основная тяжесть, под которой рушится прочность коллектива, формируется коммуникативной нагрузкой (з-н Брукса: n(n-1)/2).</p> -<p>Если предыдущий пример показался вам неубедительным, то давайте попробуем представить себе управление воздушным движением без диспетчеров. -Ну, такие... самоорганизующиеся экипажи. -Чтобы пилоты во время полета сами между собой договаривались о том, как они будут расходиться, какие эшелоны они будут занимать, в какой очередности они будут производить посадку и взлет... -Причем, гипотетически это еще было бы осуществимо где-то в районе малозагруженных аэропортов. -Но при этом возрастет когнитивная нагрузка на пилота. -Ни один из пилотов, в условиях управления воздушным судном, не обладает ресурсами внимания достаточными для достижения целостного понимания картины воздушного движения. -Эту когнитивную нагрузку с него снимает диспетчер управления воздушным движением. -А теперь попробуйте представьте себе что-то подобное в Шереметьево. -А если какое-то одно воздушное судно терпит бедствие и нуждается в аварийной посадке?</p> -<section id="spotify"> -<h3><a class="toc-backref" href="#id22" role="doc-backlink">Spotify</a></h3> -<p>Даже в Spotify существует такой "опорный скелет":</p> -<blockquote> -<div><p>📝 "At Spotify there is a separate operations team, but their job is not to make releases for the squads -­ their job is to give the squads the support they need to release code themselves; support in the form of infrastructure, scripts, and routines. -They are, in a sense, "building the road to production".</p> -<p>&lt;...&gt;</p> -<p>We also have a chief architect role, a person who coordinates work on high-­level architectural issues that cut across multiple systems. -He reviews development of new systems to make sure they avoid common mistakes, and that they are aligned with our architectural vision. -The feedback is always just suggestions and input -­ the decision for the final design of the system still lies with the squad building it."</p> -<p class="attribution">—"<a class="reference external" href="https://www.scrumatscale.com/wp-content/uploads/2020/09/S@S_Spotify_Scaling.pdf">Scaling Agile @ Spotify with Tribes, Squads, Chapters &amp; Guilds</a>" by Henrik Kniberg &amp; Anders Ivarsson, Oct 2012</p> -</div></blockquote> -<p>Но более отчетливо этот скелет сформирован в виде Program Management в <a class="reference external" href="https://www.scaledagileframework.com/">Scaled Agile Framework (SAFe)</a> и в <a class="reference external" href="https://www.pmi.org/disciplined-agile/process/introduction-to-dad">Disciplined agile delivery (DAD)</a>.</p> -<p>SAFe создан известным автором по аналитике Dean Leffingwell, и, наверное, поэтому SAFe хорошо регламентирует процессы, предшествующие этапу реализации ПО в условиях масштабируемой Agile-разработки.</p> +<section id="id10"> +<h5><a class="toc-backref" href="#id25" role="doc-backlink">Достижение согласованности</a></h5> +<section id="data-context-and-interaction-dci"> +<h6><a class="toc-backref" href="#id26" role="doc-backlink">Data, context, and interaction (DCI)</a></h6> +<p>Первый из них - это "<a class="reference external" href="https://en.m.wikipedia.org/wiki/Data,_context_and_interaction">Data, context, and interaction (DCI)</a>". +Подробно он описан в главе "Chapter 9. Coding it Up: The DCI Architecture" книги "Lean Architecture: for Agile Software Development" 1st edition by James O. Coplien, Gertrud Bjørnvig. +Можно посмотреть на <a class="reference external" href="https://github.com/agiledragon/transfer-money-go">примере реализации перевода денежных средств</a> с одного счета на другой счет (который, в определенной мере, похож на перенос рекомендации от одного члена Организации к другому члену Организации).</p> </section> -<section id="agile-software-requirements-lean-requirements-practices-for-teams-programs-and-the-enterprise"> -<h3><a class="toc-backref" href="#id23" role="doc-backlink">Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise</a></h3> -<p>В книге "Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell, которая вышла в печать в том же году, в котором он выпустил первый релиз SAFe, Dean Leffingwell убедительно обосновывает, что аналитики и архитекторы должны быть частью системной команды.</p> -<blockquote> -<div><p>📝 "Architects: Many agile teams do not contain people with titles containing the word architect [The best architectures, requirements, and designs emerge from self-organizing teams.], and yet architecture does matter to agile teams. -In these cases, the local architecture (that of the component, service, or feature that the team is accountable for) is most often determined by the local teams in a collaborative model. -In this way, it can be said that "architecture emerges" from the activities of those teams.</p> -<p>At the system level, however, <strong>architecture is often coordinated among system architects and business analysts who are responsible for determining the overall structure (components and services) of the system</strong>, as well as the system-level use cases and performance criteria that are to be imposed on the system as a whole. -For this reason, it is likely that the <strong>agile team has a key interface to one or more architects who may live outside the team</strong>. -(We'll discuss this in depth in Chapter 20.)</p> -<p>&lt;...&gt;</p> -<p>Some of these QA personnel will live outside the team, while others (primarily testers) will have likely been dispatched to live with the product team. -There, they work daily with developers to test new code and thereby help assure new code quality on a real-time basis.</p> -<p>In addition, as we'll see later, QA personnel are involved with the development of the system-level testing required to assure overall system quality and conformance to nonfunctional, as well as functional, requirements.</p> -<p>&lt;...&gt;</p> -<p>Other specialists and supporting personnel: Other supporting roles may include user-experience designers, documentation specialists, database designers and administrators, configuration management, build and deployment specialists, and whomever else is necessary to develop and deploy a whole product solution.</p> -<p class="attribution">—Agile Software Requirements Lean Requirements Practices for Teams, Programs, and the Enterprise (Agile Software Development Series) by Dean Leffingwell</p> -</div></blockquote> -<p>Для такого решения есть несколько причин:</p> -<ol class="arabic"> -<li><p>В спринте возникают две цели (текущая и посторонняя):</p> -<ol class="arabic simple"> -<li><p>Реализация текущего системного инкремента.</p></li> -<li><p>Анализ и проектирование (т.е. <a class="reference internal" href="../sdlc/uncertainty-management/prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Prediction-активности</span></a> в виде PBR, Spike и Planning) будущего системного инкремента.</p></li> -</ol> -<p>Источником работы аналитиков являются стейкхолдеры, а результатом работы - требования (под руководством Product Owner, разумеется), т.е. <a class="reference internal" href="../sdlc/models/agile/analysis/requirements/requirements.html#emacsway-product-backlog-item"><span class="std std-ref">PBI</span></a>. -В то время как для команды разработки источником работы являются PBI (в состоянии DOR), а результатом работы - Системный Инкремент.</p> -<p>Получается, что две команды работают несинхронно, над разными целями, и производят разные артефакты. -Аналитики работают вне цикла реализации Системного Инкремента, опережая его в среднем на пару спринтов.</p> -<p>PBI, не производящий Системного Инкремента, но производящий артефакты, необходимые для доведения другого PBI до состояния DOR, традиционно называется Spike. -Spike нацелен на достижение цели будущих спринтов, поэтому его присутствие в текущем спринте отвлекает от цели текущего спринта, повышает когнитивную нагрузку и затрудняет управление Team Backlog. -Говоря архитектурным языком, налицо все признаки падения Cohesion, который восстанавливается, как известно, путем декомпозиции. -Для малочисленного коллектива (тем более, для Single Team Agile) эта нагрузка не превышает накладные расходы на содержание отдельного Program Backlog. -Но, по мере роста численности коллектива, накладные расходы на содержание отдельного Program Backlog начинают уже окупаться.</p> -</li> -<li><p>По мере роста численности коллектива растет коммуникативная нагрузка, и требуется <a class="reference internal" href="#emacsway-harlan-mills-proposal"><span class="std std-ref">повышение уровня автономности команд</span></a>.</p></li> -<li><p>Системные инкременты, производимы командами, нуждаются в интеграции. Было бы неэффективно каждой команде погружаться в подробности целостной картины потребностей интеграции, при этом дублируя друг друга.</p></li> -<li><p>Стоимость <a class="reference internal" href="../sdlc/uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">адаптации</span></a> Продукта возрастает стремительней роста численность коллектива, что создает экономическую целесообразность для смещения <a class="reference internal" href="../sdlc/uncertainty-management/balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">баланса Pridiction/Adaptation</span></a> в сторону <a class="reference internal" href="../sdlc/uncertainty-management/prediction/prediction.html#emacsway-prediction"><span class="std std-ref">Prediction</span></a>.</p></li> -</ol> -<p>Поэтому, аналитику, архитектуру и UX/UI Design, в таком случае, выводят в отдельный цикл производства, известный сегодня как Program Management (который следует отличать от Program Management в PMBoK). -Получается два каскадных цикла, при этом, первый цикл (Program Backlog) создает артефакты, необходимые для достижения DOR для второго цикла (Team Backlogs), который, в свою очередь, уже производит системный инкремент.</p> -<p>Говоря о проблемах масштабирования Agile-команд, мне очень интересной показалась ещё одна его книга, которая вышла 4-мя годами ранее:</p> +<section id="process-manager-pattern"> +<h6><a class="toc-backref" href="#id27" role="doc-backlink">Process Manager Pattern</a></h6> +<p>Второй способ описывает Vaughn Vernon в интервью "<a class="reference external" href="https://www.infoq.com/articles/modeling-uncertainty-reactive-ddd/">Modeling Uncertainty with Reactive DDD</a>" by Vaughn Vernon reviewed by Thomas Betts - путем применения <a class="reference external" href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/ProcessManager.html">Process Manager Pattern</a>.</p> +<p>Сюда же можно отнести <a class="reference external" href="https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf">SAGA pattern</a> и <a class="reference external" href="https://github.com/meirwah/awesome-workflow-engines">workflow engines</a>.</p> +</section> +<section id="pessimistic-offline-lock"> +<h6><a class="toc-backref" href="#id28" role="doc-backlink">Pessimistic Offline Lock</a></h6> +<p>Еще одним решением может быть <a class="reference external" href="https://martinfowler.com/eaaCatalog/pessimisticOfflineLock.html">пессимистическая блокировка</a> Агрегата <code class="docutils literal notranslate"><span class="pre">Endorser</span></code>. +Сценарий будет состоять из следующих этапов:</p> <ul class="simple"> -<li><p>"Scaling Software Agility: Best Practices for Large Enterprises" by Dean Leffingwell</p></li> +<li><p>блокировка Агрегата <code class="docutils literal notranslate"><span class="pre">Endorser</span></code>;</p></li> +<li><p>проверка возможности осуществления рекомендации;</p> +<ul> +<li><p>в случае неудачи - блокировка отпускается;</p></li> +<li><p>в случае успеха - порождается Доменное Событие;</p> +<ul> +<li><p>обработчик Доменного События вызывает <code class="docutils literal notranslate"><span class="pre">Specialist.ReceiveEndorsement(Endorser,</span> <span class="pre">ArtifactId,</span> <span class="pre">time.Time)</span> <span class="pre">error</span></code>;</p> +<ul> +<li><p>в случае успеха порождается Доменное Событие об успехе;</p> +<ul> +<li><p>обработчик Доменного События осуществит декрементирование счетчика доступных рекомендаций рекомендующего методом <code class="docutils literal notranslate"><span class="pre">Endorser.DecreaseAvailableEndorsementCount()</span></code> и отпустит блокировку;</p></li> </ul> -</section> -<section id="scaled-agile-framework-safe"> -<h3><a class="toc-backref" href="#id24" role="doc-backlink">Scaled Agile Framework (SAFe)</a></h3> +</li> +<li><p>в случае неудачи порождается Доменное Событие о неудаче;</p> <ul> -<li><p>"<a class="reference external" href="https://www.amazon.com/dp/B08F5HC37Z">SAFe® 5.0 Distilled: Achieving Business Agility with the Scaled Agile Framework®</a>" by Richard Knaster, Dean Leffingwell</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/program-and-solution-backlogs/">Program and Solution Backlogs</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/system-architect-engineering/">System Architect/Engineering</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/agile-teams/">Agile Teams</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/organizing-agile-teams-and-arts-team-topologies-at-scale/">Organizing Agile Teams and ARTs: Team Topologies at Scale</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/shared-services/">Shared Services</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/architectural-runway/">Architectural Runway</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/agile-architecture/">Agile Architecture in SAFe</a>"</p> -<blockquote> -<div><p>📝 "The second dimension of the team and technical agility competency is teams of Agile teams. -Even with good, local execution, building enterprise-class solutions typically requires more scope and breadth of skills than a single Agile team can provide. -Therefore, Agile teams operate in the context of an ART, which is a long-lived team of Agile teams. -The ART incrementally develops, delivers, and (where applicable) operates one or more solutions (Figure 6-5)."</p> -<p>📝 "System Architect/Engineering is an individual or team that defines the overall architecture of the system. -They work at a level of abstraction above the teams and components and define Non-Functional Requirements (NFRs), major system elements, subsystems, and interfaces."</p> -<p>📝 "System Teams typically assist in building and supporting DevOps infrastructure for development, continuous integration, automated testing, and deployment into the staging environment. -In larger systems they may do end-to-end testing, which cannot be readily accomplished by individual Agile teams."</p> -<p>📝 "Shared Services are specialists—for example, data security, information architects, Database Administrators (DBAs)—who are necessary for the success of an ART but cannot be dedicated to a specific train."</p> -<p>📝 "With the right architecture, elements of the system may be released independently. -Figure 8-8 illustrates an autonomous delivery system that was architected to enable system elements to be released independently."</p> -<p>📝 "Figure 8-8. Architecture impacts the ability to release system elements independently"</p> -<p class="attribution">—"SAFe® 5.0: The World's Leading Framework for Business Agility" by Richard Knaster, Dean Leffingwell</p> -</div></blockquote> +<li><p>обработчик Доменного События отпустит блокировку.</p></li> +</ul> </li> </ul> -</section> -<section id="agile-practice-guide-by-pmi"> -<h3><a class="toc-backref" href="#id25" role="doc-backlink">"Agile Practice Guide" by PMI</a></h3> -<p>Отдельно стоит выделить книгу "<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute, 2017, поскольку эта книга является мощным оружием в руках аналитиков и архитекторов в вопросах организации качественных процессов. -Автором книги является Project Management Institute (PMI), обладающий неоспоримым авторитетом в глазах менеджмента. -Книга достаточно грамотная, и затрагивает острые вопросы интеграции аналитической и архитектурной активности в Agile-разработку. -В общем, если вы где-то услышите фразу "Architecture vs. Agile", то самое время вспомнить об этой книге.</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://scalingsoftwareagility.files.wordpress.com/2007/03/a-lean-and-scalable-requirements-information-model-for-agile-enterprises-pdf.pdf">A Lean and Scalable Requirements Information Model for the Agile Enterprise</a>" by Dean Leffingwell with Juha‐Markus Aalto</p></li> +</li> +</ul> +</li> +</ul> +</li> </ul> +<p>Блокировка не позволит рекомендующему осуществить другую рекомендацию, пока не завершится первая.</p> </section> -<section id="disciplined-agile-delivery-dad"> -<h3><a class="toc-backref" href="#id26" role="doc-backlink">Disciplined agile delivery (DAD)</a></h3> -<p>И еще один официальный способ о том, как интегрировать работу аналитиков и архитекторов в Scrum:</p> +<section id="id11"> +<h6><a class="toc-backref" href="#id29" role="doc-backlink">Резервирование</a></h6> +<p>Повысить параллелизм можно, если заменить блокировку на резервирование рекомендации, используя счетчик <code class="docutils literal notranslate"><span class="pre">Endorser.pendingEndorsementCount</span></code>, значение которого не должно превышать значение <code class="docutils literal notranslate"><span class="pre">Endorser.availableEndorsementCount</span></code>. +Сценарий будет состоять из следующих этапов:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile/lifecycle/program">DAD Life Cycle – Program (Team of Teams)</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile/process/program-management">Program Management</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile/agility-at-scale/tactical-agility-at-scale/large-agile-teams">Large Agile Teams</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile/agility-at-scale/tactical-agility-at-scale/large-agile-teams/organizing-agile-teams#Large">Organizing Agile Teams : Large Teams/Programs</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/foundational/program-management">The Standard for Program Management – Fourth Edition</a>"</p></li> +<li><p>резервирование рекомендации инкрементированием счетчика <code class="docutils literal notranslate"><span class="pre">Endorser.pendingEndorsementCount</span></code>;</p></li> +<li><p>проверка возможности осуществления рекомендации;</p> +<ul> +<li><p>в случае неудачи - декрементирование счетчика <code class="docutils literal notranslate"><span class="pre">Endorser.pendingEndorsementCount</span></code>;</p></li> +<li><p>в случае успеха - порождается Доменное Событие;</p> +<ul> +<li><p>обработчик Доменного События вызывает <code class="docutils literal notranslate"><span class="pre">Specialist.ReceiveEndorsement(Endorser,</span> <span class="pre">ArtifactId,</span> <span class="pre">time.Time)</span> <span class="pre">error</span></code>;</p> +<ul> +<li><p>в случае успеха порождается Доменное Событие об успехе;</p> +<ul> +<li><p>обработчик Доменного События осуществит декрементирование счетчика доступных рекомендаций рекомендующего <code class="docutils literal notranslate"><span class="pre">Endorser.availableEndorsementCount</span></code> и отпустит резервирование декрементированием счетчика <code class="docutils literal notranslate"><span class="pre">Endorser.pendingEndorsementCount</span></code>;</p></li> </ul> -<p>Учитывая, что Disciplined agile delivery (DAD) сопровождается и развивается by Project Management Institute (PMI), интеграция его практик вызвает, как правило, меньше всего возражений со стороны менеджмента.</p> -<p>См. также:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="http://agilemodeling.com/essays/agileArchitecture.htm">Agile Architecture: Strategies for Scaling Agile Development</a>"</p></li> +</li> +<li><p>в случае неудачи порождается Доменное Событие о неудаче;</p> +<ul> +<li><p>обработчик Доменного События отпустит резервирование декрементированием счетчика <code class="docutils literal notranslate"><span class="pre">Endorser.pendingEndorsementCount</span></code>.</p></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +</ul> +</li> </ul> +<p>Этот вариант выглядит наиболее простым, поэтому, на нем и остановимся. +Не исключено, что в будущем появятся альтернативные реализации с использованием описанных подходов.</p> </section> -<section id="iso-iec-ieee-12207-2017"> -<h3><a class="toc-backref" href="#id27" role="doc-backlink">ISO/IEC/IEEE 12207:2017</a></h3> -<blockquote> -<div><p>📝 "Agile projects for complex systems attempt to manage cost by prioritizing the most important capabilities for early realization. -If an organization manages the development and maintenance of its entire portfolio of software systems as a single system, managed by spend rate rather than total spending, then the organization can, in principle, manage that portfolio of systems as a continuing agile development, analogous to managing a highly iterative "Kanban" maintenance effort."</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> -</div></blockquote> </section> -<section id="nexus"> -<h3><a class="toc-backref" href="#id28" role="doc-backlink">Nexus</a></h3> -<p>На scrum.org есть интересная статья, сравнивающая Nexus и SAFe:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.scrum.org/resources/blog/comparing-nexus-and-safe-similarities-differences-potential-synergies">Comparing Nexus and SAFe - Similarities, Differences, potential synergies</a>" by Yuval Yeret</p></li> -</ul> -<p>Интересна она, прежде всего, тем, что открыто говорит о проблемах Nexus, которые можно решить путем заимствования практик у SAFe.</p> -<p>Одним из наиболее узких мест Nexus является отсутствие масштабирования аналитической работы (сбор требований) в problem space. -Команды масштабируются, а бизнес-анализ, в лице единственного Product Owner, - нет. -Scrum, как известно, оставляет Product Owner с этой проблемой наедине, предлагая ему самостоятельно решать эту проблему путем делегации полномочий в случаях, когда аналитическая работа становится узким горлышком.</p> -<blockquote> -<div><p>📝 "it's hard for one Product Owner to deal with too many teams... -In real life, these Product Owners are typically accountable for the value delivered by these multiple teams and rely upon a lot of assistance from the Development Teams in order to deal with the challenge of scale."</p> -<p class="attribution">—"<a class="reference external" href="https://www.scrum.org/resources/blog/comparing-nexus-and-safe-similarities-differences-potential-synergies">Comparing Nexus and SAFe - Similarities, Differences, potential synergies</a>" by Yuval Yeret</p> -</div></blockquote> -<blockquote> -<div><p>📝 "A Nexus has a single Product Owner who manages a single Product Backlog from which the Scrum Teams work."</p> -<p class="attribution">—"<a class="reference external" href="https://www.scrum.org/resources/online-nexus-guide">The 2021 Nexus™ Guide</a></p> -</div></blockquote> -<blockquote> -<div><p>📝 "The Product Owner may do the above work or may delegate the responsibility to others. Regardless, the Product Owner remains accountable."</p> -<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> -</div></blockquote> -<blockquote> -<div><p>📝 "In multi-team programs, this one Product Owner may delegate the work to Product Owners that represent him or her on subordinate teams, but all decisions and direction come from the top-level, single Product Owner.</p> -<p class="attribution">—"Jeff Sutherland's Scrum Handbook" by Jeff Sutherland</p> -</div></blockquote> -<p>Статья подчеркивает ограниченность масштабирования Nexus по этой причине и предлагает к рассмотрению SAFe-практики:</p> -<blockquote> -<div><p>📝 "As Nexus is designed to be a lightweight framework, with a more limited scope than SAFe, its not surprising that there are a lot more elements in SAFe that Nexus doesn't say anything about. -Some of these can be useful in your context, some not necessarily. -Think Architectural Runway, Innovation and Planning iteration, Team-level Kanbans, DevOps, Continuous Delivery pipeline, System Architect, Business Owner, Features/Enablers, Epics."</p> -<p class="attribution">—"<a class="reference external" href="https://www.scrum.org/resources/blog/comparing-nexus-and-safe-similarities-differences-potential-synergies">Comparing Nexus and SAFe - Similarities, Differences, potential synergies</a>" by Yuval Yeret</p> -</div></blockquote> -<p>В числе прочего, упоминается и выделенная роль системного архитектора, поскольку в масштабируемом Agile возникают вопросы одновременного достижения как интеграции инкремента продукта, так и автономности команд.</p> -<p>В статье много лестных отзывов о Program Kanban:</p> -<blockquote> -<div><p>📝 "Program Kanban. -SAFe includes one of the most powerful techniques to help improve flow and collaboration across a team of teams - a Kanban Board that takes a cross-team perspective. -I started using this technique back in 2009 and it's one I "don't leave home without". -Nexus doesn't include a Nexus-level Kanban board but it's a very nice complementary practice to consider. -<a class="reference external" href="https://www.scrum.org/resources/blog/scaling-scrum-nexus-and-kanban">Read more here</a>"</p> -<p class="attribution">—"<a class="reference external" href="https://www.scrum.org/resources/blog/comparing-nexus-and-safe-similarities-differences-potential-synergies">Comparing Nexus and SAFe - Similarities, Differences, potential synergies</a>" by Yuval Yeret</p> -</div></blockquote> -<p>Здесь автор ссылается на другую свою статью "<a class="reference external" href="https://www.scrum.org/resources/blog/scaling-scrum-nexus-and-kanban">Scaling Scrum with Nexus and Kanban</a>" by Yuval Yeret, где предлагает интегрировать Program Management в самую легковесную scaled Scrum модель разработки Nexus, подобно тому, как это сделано в SAFe.</p> -<blockquote> -<div><p>📝 "This will include all stages of work in the Nexus - ranging from Value discovery..."</p> -<p class="attribution">—"<a class="reference external" href="https://www.scrum.org/resources/blog/scaling-scrum-nexus-and-kanban">Scaling Scrum with Nexus and Kanban</a>" by Yuval Yeret</p> -</div></blockquote> -<p>Хотя в Scrum и можно выстроить хорошо отлаженные процессы, но это требует настолько деликатной работы, что я бы предпочел рассматривать сразу SAFe даже для маленьких команд (минимальную его конфигурацию - Essential Safe):</p> +</section> +</section> +<section id="id12"> +<h3><a class="toc-backref" href="#id30" role="doc-backlink">Упрощенная реализация итоговой модели</a></h3> +<div class="highlight-go notranslate"><div class="highlight"><pre><span/><span class="kn">package</span><span class="w"> </span><span class="nx">grade_2</span><span class="w"/> + +<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="s">"errors"</span><span class="w"/> +<span class="w"> </span><span class="s">"time"</span><span class="w"/> +<span class="p">)</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="kt">uint64</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="w"> </span><span class="kt">uint64</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="w"> </span><span class="kt">string</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">ArtifactStatus</span><span class="w"> </span><span class="kt">uint8</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">CompetenceId</span><span class="w"> </span><span class="kt">uint64</span><span class="w"/> +<span class="kd">type</span><span class="w"> </span><span class="nx">CompetenceName</span><span class="w"> </span><span class="kt">string</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Weight</span><span class="w"> </span><span class="kt">uint8</span><span class="w"/> + +<span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="nx">LowerWeight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"/> +<span class="w"> </span><span class="nx">PeerWeight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="w"> </span><span class="nx">HigherWeight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">2</span><span class="w"/> + +<span class="w"> </span><span class="nx">Expert</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">Candidate</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">Grade1</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">Grade2</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">Grade3</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">WithoutGrade</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">Grade</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"/> + +<span class="w"> </span><span class="nx">Proposed</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">ArtifactStatus</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="nx">Accepted</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">ArtifactStatus</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"/> +<span class="p">)</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Specialist</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">grade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">receivedEndorsements</span><span class="w"> </span><span class="p">[]</span><span class="nx">Endorsement</span><span class="w"/> +<span class="w"> </span><span class="nx">assignments</span><span class="w"> </span><span class="p">[]</span><span class="nx">Assignment</span><span class="w"/> +<span class="w"> </span><span class="nx">version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">ReceiveEndorsement</span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">,</span><span class="w"> </span><span class="nx">aId</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">GetGrade</span><span class="p">()</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="s">"it is allowed to receive endorsements only from members with equal or higher grade"</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">!</span><span class="nx">e</span><span class="p">.</span><span class="nx">CanCompleteEndorsement</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="s">"endorser is not able to complete endorsement"</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nb">uint64</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">GetId</span><span class="p">())</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">uint64</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="w"/> +<span class="w"> </span><span class="s">"endorser can't endorse himself"</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsements</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">v</span><span class="p">.</span><span class="nx">IsEndorsedBy</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">GetId</span><span class="p">(),</span><span class="w"> </span><span class="nx">aId</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"this artifact has already been endorsed by the recogniser"</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsements</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsements</span><span class="p">,</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">GetId</span><span class="p">(),</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">GetGrade</span><span class="p">(),</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">GetVersion</span><span class="p">(),</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="nx">aId</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">})</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">actualizeGrade</span><span class="p">(</span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">actualizeGrade</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">WithoutGrade</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">6</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade3</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade3</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade2</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade2</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Grade1</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Grade1</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Candidate</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">Candidate</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">40</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">Expert</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="p">}</span><span class="w"/> +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">getReceivedEndorsementCount</span><span class="p">()</span><span class="w"> </span><span class="kt">uint</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">counter</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">receivedEndorsements</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">v</span><span class="p">.</span><span class="nx">GetSpecialistGrade</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">counter</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nb">uint</span><span class="p">(</span><span class="nx">v</span><span class="p">.</span><span class="nx">GetWeight</span><span class="p">())</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">counter</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">setGrade</span><span class="p">(</span><span class="nx">g</span><span class="w"> </span><span class="nx">Grade</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">assignments</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">assignments</span><span class="p">,</span><span class="w"> </span><span class="nx">Assignment</span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="p">,</span><span class="w"> </span><span class="nx">g</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">,</span><span class="w"/> +<span class="w"> </span><span class="p">})</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">grade</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">g</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">Specialist</span><span class="p">)</span><span class="w"> </span><span class="nx">IncreaseVersion</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">version</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Endorsement</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">endorserId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">endorserGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">endorserVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">artifactId</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">)</span><span class="w"> </span><span class="nx">IsEndorsedBy</span><span class="p">(</span><span class="nx">rId</span><span class="w"> </span><span class="nx">MemberId</span><span class="p">,</span><span class="w"> </span><span class="nx">aId</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">endorserId</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">rId</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">artifactId</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">aId</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">)</span><span class="w"> </span><span class="nx">GetSpecialistGrade</span><span class="p">()</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">specialistGrade</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorsement</span><span class="p">)</span><span class="w"> </span><span class="nx">GetWeight</span><span class="p">()</span><span class="w"> </span><span class="nx">Weight</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">endorserGrade</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">specialistGrade</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">PeerWeight</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">endorserGrade</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">specialistGrade</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">HigherWeight</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">LowerWeight</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Assignment</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistId</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">specialistVersion</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">assignedGrade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Endorser</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"/> +<span class="w"> </span><span class="nx">grade</span><span class="w"> </span><span class="nx">Grade</span><span class="w"/> +<span class="w"> </span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"/> +<span class="w"> </span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="nx">EndorsementCount</span><span class="w"/> +<span class="w"> </span><span class="nx">version</span><span class="w"> </span><span class="kt">uint</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">GetId</span><span class="p">()</span><span class="w"> </span><span class="nx">MemberId</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">id</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">GetGrade</span><span class="p">()</span><span class="w"> </span><span class="nx">Grade</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">grade</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">GetVersion</span><span class="p">()</span><span class="w"> </span><span class="kt">uint</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">canReserveEndorsement</span><span class="p">()</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">CanCompleteEndorsement</span><span class="p">()</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">ReserveEndorsement</span><span class="p">()</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">!</span><span class="nx">e</span><span class="p">.</span><span class="nx">canReserveEndorsement</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"no endorsement can be reserved"</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">ReleaseEndorsementReservation</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">CompleteEndorsement</span><span class="p">()</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"no endorsement is available"</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"there is no endorsement reservation"</span><span class="p">)</span><span class="w"/> +<span class="w"> </span><span class="p">}</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">availableEndorsementCount</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">pendingEndorsementCount</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">e</span><span class="w"> </span><span class="o">*</span><span class="nx">Endorser</span><span class="p">)</span><span class="w"> </span><span class="nx">IncreaseVersion</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">e</span><span class="p">.</span><span class="nx">version</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Artifact</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">ArtifactId</span><span class="w"/> +<span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="nx">ArtifactStatus</span><span class="w"/> +<span class="w"> </span><span class="nx">description</span><span class="w"> </span><span class="nx">ArtifactDescription</span><span class="w"/> +<span class="w"> </span><span class="nx">competenceIds</span><span class="w"> </span><span class="p">[]</span><span class="nx">CompetenceId</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> + +<span class="kd">type</span><span class="w"> </span><span class="nx">Competence</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"/> +<span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nx">CompetenceId</span><span class="w"/> +<span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="nx">CompetenceName</span><span class="w"/> +<span class="w"> </span><span class="nx">createdAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"/> +<span class="p">}</span><span class="w"/> +</pre></div> +</div> +<p>Ссылка на полную модель:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/guidance-six-safe-practices-for-s-sized-teams/">Six SAFe Practices for S-Sized Teams</a>" by Juha-Markus Aalto, Director Product Development, Qentinel Group</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/essential-safe/">Essential SAFe</a>"</p></li> +<li><p><a class="reference external" href="https://github.com/emacsway/grade/tree/main/grade/internal/domain">https://github.com/emacsway/grade/tree/main/grade/internal/domain</a></p></li> </ul> </section> -<section id="extreme-programming"> -<h3><a class="toc-backref" href="#id29" role="doc-backlink">Extreme Programming</a></h3> -<blockquote> -<div><p>📝 "With awareness and appropriate adaptations, <strong>XP does scale</strong>. -Some problems can be simplified to be easily handled by a small XP team. -For others, XP must be augmented. -The basic values and principles apply at all scales. -The practices can be modified to suit your situation."</p> -<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Chapter 15. Scaling XP :: Conclusion"</p> -</div></blockquote> -<p>Во втором издании "Extreme Programming Explained", Kent Beck предлагает механизм масштабирования команд, который в точности реализует Program Management на основе <a class="reference internal" href="#emacsway-harlan-mills-proposal"><span class="std std-ref">Harlan Mills' Proposal</span></a>.</p> -<blockquote> -<div><p>📝 "Creating and maintaining a community of one hundred is a much different job than creating and maintaining a community of twelve, but it is done all the time."</p> -<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Chapter 15. Scaling XP"</p> -</div></blockquote> -<blockquote> -<div><p>📝 "If just using a smaller team doesn't work, turn the big programming problem into several smaller problems, each solvable by a small team. -First solve a small part of the problem with a small team. -Then divide the system along its natural fracture lines and begin working on it with a few teams. -<strong>Partitioning introduces the risk that the pieces won't fit on integration, so integrate frequently to reconcile differing assumptions between teams.</strong> -This is a conquer-and-divide strategy instead of a divide-and-conquer strategy. -Sabre Airline Solutions, profiled in the next chapter, uses this strategy extensively.</p> -<p>The goal of conquer-and-divide is <strong>to have teams that can each be managed as if they are the only team to limit coordination costs</strong>. -Even so, the whole <strong>system needs to be integrated frequently</strong>. -The occasional exceptions to this illusion of independence are managed as exceptions. -<strong>If the exceptions become the norm and the teams have to spend too much time coordinating, look to the system to see if there are ways of restructuring it to return the teams to independence.</strong> -<strong>Only if this fails is the overhead of large-project management appropriate.</strong></p> -<p>In summary, faced with the apparent need for a large team, first ask if a small team can solve the problem. -If that doesn't work, <strong>begin the project with a small team, then split the work among autonomous teams.</strong>"</p> -<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Chapter 15. Scaling XP :: Number of People"</p> -</div></blockquote> </section> -<section id="scrum-of-scrums"> -<h3><a class="toc-backref" href="#id30" role="doc-backlink">Scrum of Scrums</a></h3> -<blockquote> -<div><ul class="simple"> -<li><p>Each team had an architecture representative on <strong>a Scrum of Scrum architecture team led by the Business Unit Lead Architect</strong></p></li> -<li><p>The <strong>enterprise architecture team had Business Unit Lead Architects led by the CTO</strong> who had senior management commitment to 10% of all points in every sprint dedicated to architectural improvement (technical debt remediation, integration, branding, etc.)</p></li> -</ul> -<p class="attribution">—"<a class="reference external" href="https://www.scruminc.com/wp-content/uploads/2014/06/agile-architecture.pdf">Agile Architecture Fast, Cheap, Out of Control</a>" Jeff Sutherland</p> -</div></blockquote> -<p>См. также структуру "Scrum of Scrum Team (SoS) a Core Team" на странице 5 "<a class="reference external" href="https://www.scrumatscale.com/wp-content/uploads/2020/09/Scrum_At_Scale_Case_Study_Air_Transport_Amogh.pdf">The Scrum Software Factory</a>" by Amogh Joshi.</p> +<section id="missing-chapter"> +<h2><a class="toc-backref" href="#id31" role="doc-backlink">Missing chapter</a></h2> +<p>Проектом предусматривается поддержка <a class="reference external" href="https://docs.microsoft.com/en-us/azure/architecture/guide/multitenant/overview">Multitenancy</a>. +В свете этого, возникает потребность в гибком конфигурировании количества уровней классности для каждого <code class="docutils literal notranslate"><span class="pre">Tenant</span></code>, а также количества требуемых рекомендаций для достижения каждого уровня. +По этой причине, конструктор экземпляра Объекта-значения <code class="docutils literal notranslate"><span class="pre">Grade</span></code> должен создаваться Агрегатом <code class="docutils literal notranslate"><span class="pre">Tenant</span></code>. +Соответственно, фабричные методы Агрегатов <code class="docutils literal notranslate"><span class="pre">Endorser</span></code> и <code class="docutils literal notranslate"><span class="pre">Endorsement</span></code> должны переехать в Агрегат <code class="docutils literal notranslate"><span class="pre">Tenant</span></code>, чтобы иметь возможность принимать сконфигурированный экземпляр Объекта-значения <code class="docutils literal notranslate"><span class="pre">Grade</span></code>.</p> +<p>По мере роста гибкости бизнес-правил можно рассмотреть вариант применения "<a class="reference external" href="https://martinfowler.com/bliki/RulesEngine.html">Rules Engine</a>" (aka "<a class="reference external" href="https://martinfowler.com/dslCatalog/productionRule.html">Production Rule System</a>"), например, в виде "<a class="reference external" href="https://github.com/hyperjumptech/grule-rule-engine">Grule-Rule-Engine</a>" - Rule engine implementation in Golang.</p> </section> -<section id="id6"> -<h3><a class="toc-backref" href="#id31" role="doc-backlink">Другие</a></h3> -<p>Program Management также присутствует в MSF и в FDD. -В RAD тоже аналитика является "upstream development activities". -RUP реализует <a class="reference internal" href="../sdlc/models/spiral.html#emacsway-spiral-development"><span class="std std-ref">спиральную</span></a> модель.</p> -<p>В книге "Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman особый интерес представляют собою главы:</p> +Sun, 11 Jun 2023 00:00:00 Балансирование Бизнес/Технических интересовhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/agile/analysis/concerns/balancing-business-technical-concerns.html +<span id="id1"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id2"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p>20.6 More on ADD Step 7: Perform Analysis of the Current Design and Review the Iteration Goal and Achievement of the Design Purpose</p> +<li><p><a class="reference internal" href="#emacsway-agile-balancing-business-technical-concerns" id="id13">Балансирование Бизнес/Технических интересов</a></p> <ul> -<li><p>Use of an Architectural Backlog</p></li> -<li><p>Use of a Design Kanban Board</p></li> +<li><p><a class="reference internal" href="#id3" id="id14">Поиск баланса</a></p> +<ul> +<li><p><a class="reference internal" href="#emacsway-agile-technical-concerns-predominance" id="id15">Преобладание технических интересов</a></p></li> +<li><p><a class="reference internal" href="#emacsway-agile-business-concerns-predominance" id="id16">Преобладание бизнес-интересов</a></p></li> +<li><p><a class="reference internal" href="#emacsway-agile-solution-to-balancing-business-technical-concerns" id="id17">Решение</a></p> +<ul> +<li><p><a class="reference internal" href="#extreme-programming" id="id18">Extreme Programming</a></p> +<ul> +<li><p><a class="reference internal" href="#xp" id="id19">Первая версия XP</a></p></li> +<li><p><a class="reference internal" href="#emacsway-xp2-balancing-business-technical-concerns" id="id20">Вторая версия XP</a></p></li> </ul> </li> +<li><p><a class="reference internal" href="#scrum" id="id21">Scrum</a></p> +<ul> +<li><p><a class="reference internal" href="#the-scrum-guide" id="id22">The Scrum Guide™</a></p></li> +<li><p><a class="reference internal" href="#id8" id="id23">К первоисточнику за сутью</a></p></li> </ul> -<p>Интерес они вызыват прежде всего потому, что:</p> -<blockquote> -<div><p>📝 "The drivers become part of an <strong>architectural design backlog</strong> that you should use to perform the different design iterations. -When you have made design decisions that account for all of the items in the backlog, you’ve completed this round."</p> -<p class="attribution">—"Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman</p> -</div></blockquote> -<blockquote> -<div><p>📝 "The output of ADD is not an architecture complete in every detail, but an architecture in which the main design approaches have been selected and vetted. -<strong>It produces a "workable" architecture early and quickly, one that can be given to other project teams so they can begin their work while the architect or architecture team continues to elaborate and refine.</strong>"</p> -<p class="attribution">—"Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman</p> -</div></blockquote> -<p>Humberto Cervantes и Rick Kazman, в книге "Designing Software Architectures: A Practical Approach", которая была посвящена ADD 3.0, предлагают заводить "architectural design backlog" даже в Scrum:</p> -<blockquote> -<div><p>📝 "For example, when using Scrum, the sprint backlog and the design backlog are not independent: -Some features in the sprint backlog may require architecture design to be performed, so they will generate items that go into the architectural design backlog. -These two backlogs can be managed separately, however. -The design backlog may even be managed internally, as it contains several items that are typically not discussed or prioritized by the customer (or product owner).</p> -<p>Also, additional architectural concerns may arise as decisions are made. -For example, if you choose a reference architecture, you will probably need to add specific architectural concerns, or quality attribute scenarios derived from them, to the architectural design backlog. -An example of such a concern is the management of sessions for a web application reference architecture."</p> -<p class="attribution">—"Designing Software Architectures: A Practical Approach" by Humberto Cervantes, Rick Kazman</p> -</div></blockquote> -<p>Т.е. речь идет опять же, об отдельном Backlog для активностей, предшествующих фазе реализации Системного Инкремента.</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.atlassian.com/blog/jira-align/tools-for-agile-program-management">4 tools you need to build an agile program management powerhouse</a>" by Kyle Foreman</p></li> -</ul> -</section> -</section> -<section id="emacsway-fractal-team"> -<span id="id7"/><h2><a class="toc-backref" href="#id32" role="doc-backlink">Фрактальная структура</a></h2> -<p>Хотя Program Management и выполняет роль опорного хребта коммуникативной нагрузки коллектива, момент его внедрения в процессы разработки должен быть своевременным и оправданным, т.е. издержки на его содержание должны покрываться выгодами от его внедрения. -Кроме того, концентрация всех архитектурных задач на уровне Program Management может привести к образованию узкого горлышка. -Одним из способов решения этой задачи является децентрализация архитектурных решений об интеграции ограниченных контекстов. -Карта ограниченных контекстов (<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard-single/#context-map">Context Map</a>) позволяет сократить количество возможных коммуникационных путей в коллективе и снизить коммуникативную нагрузку. -Например, если подмножество какого-то публичного интерфейса Ограниченного Контекста используется как Customer/Supplier только одним другим Ограниченным Контекстом, то команде не нужно общаться с командами остальных Ограниченных Контекстов по поводу изменения этого подмножества. -Построение топологии команд по Ограниченным Контекстам позволяет сфокусировать полезную коммуникативную нагрузку внутри команды и уменьшить контрпродуктивную коммуникативную нагрузку по интеграции между командами, тем самым повышая уровень автономности команд.</p> -<p>Более лучшего эффекта можно достигнуть используя CDC-Tests:</p> -<blockquote> -<div><p>📝 "About consumer-driven contract testing, we identified two reasons:</p> -<ol class="arabic simple"> -<li><p>development teams have communication obstacles when several people working on one microservice (e.g., over 8 people, see Figure 6 (Right)) and</p></li> -<li><p>microservices systems extensively use third party resources [118]."</p></li> -</ol> -<p class="attribution">—"<a class="reference external" href="https://www.researchgate.net/publication/337326691_Consumer-Driven_Contract_Tests_for_Microservices_A_Case_Study">Consumer-Driven Contract Tests for Microservices: A Case Study</a>" by Jyri Lehvä, Niko Mäkitalo, Tommi Mikkonen</p> -</div></blockquote> -<blockquote> -<div><p>📝 "We use some techniques from DDD, particularly event storming, to understand and model the domains in our business context. -At a more technical level, we use Pact for contract testing services and inter-team communication. -Pact has really helped us to adopt a clear, defined approach to testing services, setting expectations across all teams about how to test and interact with other teams."</p> -<p class="attribution">—"Team Topologies: Organizing Business and Technology Teams for Fast Flow" by Matthew Skelton, Manuel Pais</p> -</div></blockquote> -<blockquote> -<div><p>📝 "Contract tests are a big win when it comes to enabling teams to work and deploy independently, but they also require some level of coordination. -Consumer contract tests are of very little value unless they're verified against the provider, and a provider can't write contract tests for their system without working with the consumer team to get the tests added to the consumer project.</p> -<p>Contracts are not a replacement for good communication between or within teams. -In fact, contracts require collaboration and communication. -One could make the argument that this is one of the main reasons to leverage Pact and enforce communication pathways in large internal and external development organizations.</p> -<p>Contracts are not a magical silver bullet that will allow you to hide in your developer caves and toss built artifacts at each other until everything passes. -It is important for all teams to be invested in the process. -One of the most common reasons that Pact fails to be successfully adopted in an organisation is a lack of buy in from all parties.</p> -<p>Collaborate about the problems, collaborate over the design, and keep the communication channels open."</p> -<p class="attribution">—"<a class="reference external" href="https://docs.pact.io/pact_nirvana/step_2">CI/CD Setup Guide :: Talk</a>"</p> -</div></blockquote> -<p>Таким образом, независимо от того, существует ли у команд Program Management, или же команды имеет фрактальную структуру, CDC-Tests позволяют в значительной мере управлять коммуникативной нагрузкой на команды и минизировать Проблему Брукса.</p> -</section> -<section id="id8"> -<h2><a class="toc-backref" href="#id33" role="doc-backlink">Социальная роль архитектуры</a></h2> -<p>📝 "By keeping things team sized, we help to achieve what MacCormack and colleagues call "an '<strong>architecture for participation</strong>' that promotes ease of understanding by limiting module size, and ease of contribution by minimizing the propagation of design changes."[MacCormack et al., "Exploring the Structure of Complex Software Designs."] In other words, we need <strong>a team-first software architecture that maximizes people's ability to work with it</strong>.</p> -<p>&lt;...&gt;</p> -<p>More than ever I believe that someone who claims to be an <strong>Architect needs both technical and social skills, they need to understand people and work within the social framework</strong>. They also need a remit that is broader than pure technology—they need to have a say in <strong>organizational structures and personnel issues, i.e. they need to be a manager too</strong>.[Kelly, "Return to Conway's Law."]"</p> -<p>— "Team Topologies: Organizing Business and Technology Teams for Fast Flow" by Matthew Skelton</p> -</section> -<section id="emacsway-team-topologies-at-scale-literature"> -<span id="id9"/><h2><a class="toc-backref" href="#id34" role="doc-backlink">Литература</a></h2> -<ul class="simple"> -<li><p>"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr.</p></li> -<li><p>"Team Topologies: Organizing Business and Technology Teams for Fast Flow" by Matthew Skelton</p></li> -<li><p>"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</p></li> -<li><p>"Scaling Software Agility: Best Practices for Large Enterprises" by Dean Leffingwell</p></li> -<li><p>"SAFe® 5.0: The World's Leading Framework for Business Agility" by Richard Knaster, Dean Leffingwell</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute, 2017</p></li> -<li><p>"<a class="reference external" href="https://leanpub.com/arch-modernization-ddd">Architecture Modernization with Strategic Domain-Driven Design. A Guide for Technology Leaders.</a>" by Nick Tune</p></li> -<li><p>"<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard/">Open Agile Architecture. A Standard of The Open Group</a>"</p></li> -</ul> -</section> -<section id="id10"> -<h2><a class="toc-backref" href="#id35" role="doc-backlink">Ссылки по теме</a></h2> -<ol class="arabic simple"> -<li><p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/team-responsibility-ownership-patterns-part-1-a-business-architecture-model-63597c4e60e1">Architecture Ownership Patterns For Team Topologies. Part 1: A Business Architecture Model</a>" by Nick Tune</p></li> -<li><p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/architecture-ownership-patterns-for-team-topologies-part-2-single-team-patterns-943d31854285">Architecture Ownership Patterns for Team Topologies. Part 2: Single Team Patterns</a>" by Nick Tune</p></li> -<li><p>"<a class="reference external" href="https://medium.com/nick-tune-tech-strategy-blog/architecture-ownership-patterns-for-team-topologies-part-3-multi-team-patterns-eecc146ddb28">Architecture Ownership Patterns for Team Topologies. Part 3: Multi-Team Patterns</a>" by Nick Tune</p></li> -</ol> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://blog.avanscoperta.it/2021/04/22/about-team-topologies-and-context-mapping/">About Team Topologies and Context Mapping</a>" by Alberto Brandolini</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/articles/strong-weak-arch.html">The strong and weak forces of architecture</a>" by Evan Bottcher</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/articles/devops-compliance.html">Compliance in a DevOps Culture. Integrating Compliance Controls and Audit into CI/CD Processes</a> by Carl Nygard</p></li> -<li><p>"<a class="reference external" href="https://event-driven.io/en/how_using_events_help_in_teams_autonomy/">How using events helps in a teams' autonomy</a>" by Oskar Dudycz</p></li> -</ul> -</section> -Thu, 06 Oct 2022 00:00:00 Список психологических эффектовhttps://dckms.github.io/system-architecture/emacsway/soft-skills/cognitive-biases.html -<span id="id1"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<blockquote> -<div><p>📝 "Самая главная формула успеха — знание, как обращаться с людьми."</p> -<p class="attribution">—<a class="reference external" href="https://ru.wikiquote.org/wiki/%D0%A2%D0%B5%D0%BE%D0%B4%D0%BE%D1%80_%D0%A0%D1%83%D0%B7%D0%B2%D0%B5%D0%BB%D1%8C%D1%82">Теодор Рузвельт</a></p> -</div></blockquote> -<blockquote> -<div><p>📝 "Вежливость города берет"</p> -<p class="attribution">—Народная пословица</p> -</div></blockquote> -<p>Список психологических эффектов, с которыми приходится сталкиваться в своей деятельности IT-архитектору:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%94%D0%B0%D0%BD%D0%BD%D0%B8%D0%BD%D0%B3%D0%B0_%E2%80%94_%D0%9A%D1%80%D1%8E%D0%B3%D0%B5%D1%80%D0%B0">Эффект Даннинга — Крюгера</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC_%D1%81%D0%B0%D0%BC%D0%BE%D0%B7%D0%B2%D0%B0%D0%BD%D1%86%D0%B0">Синдром самозванца</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%BB%D0%BE%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%BA_%D0%BF%D0%BE%D0%B4%D1%82%D0%B2%D0%B5%D1%80%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D1%8E_%D1%81%D0%B2%D0%BE%D0%B5%D0%B9_%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D0%B7%D1%80%D0%B5%D0%BD%D0%B8%D1%8F">Склонность к подтверждению своей точки зрения</a>"</p></li> -<li><p>"<a class="reference internal" href="learning-spiral-phase-mismatch.html#emacsway-learning-spiral-phase-mismatch"><span class="std std-ref">Несовпадение фаз спиралей обучения</span></a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%BE%D0%B5_%D0%B2%D0%BE%D1%81%D0%BF%D1%80%D0%B8%D1%8F%D1%82%D0%B8%D0%B5">Селективное восприятие</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BF%D1%80%D0%B8%D0%B2%D1%8F%D0%B7%D0%BA%D0%B8">Эффект привязки</a>" (Эффект якоря)</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологическая защита</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%BE%D0%B5_%D1%81%D0%BE%D0%BF%D1%80%D0%BE%D1%82%D0%B8%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_(%D0%BF%D1%81%D0%B8%D1%85%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F)">Реактивное сопротивление</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BB%D0%BE%D0%B6%D0%BD%D0%BE%D0%B9_%D1%83%D0%BD%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Эффект ложной уникальности</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%BE%D0%B4%D0%BD%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Эффект неоднозначности</a>" (упоминался <a class="reference external" href="https://t.me/emacsway_log/97">здесь</a> и <a class="reference external" href="https://t.me/emacsway_log/101">здесь</a>)</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%B4%D0%BF%D0%BE%D1%87%D1%82%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D0%BE%D0%B3%D0%BE_%D1%80%D0%B8%D1%81%D0%BA%D0%B0">Предпочтение нулевого риска</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%98%D1%80%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%83%D1%81%D0%B8%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5">Закон иррационального усиления</a>" (упоминался <a class="reference internal" href="learning-spiral-phase-mismatch.html#emacsway-learning-spiral-phase-mismatch-code-review"><span class="std std-ref">здесь</span></a>)</p></li> -<li><p>"<a class="reference external" href="https://en.wikipedia.org/wiki/Sunk_cost">Sunk cost</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%98%D1%81%D0%BA%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_%D0%B2%D0%BE%D1%81%D0%BF%D1%80%D0%B8%D1%8F%D1%82%D0%B8%D0%B8_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B2%D1%8B%D0%B1%D0%BE%D1%80%D0%B0">Искажение в восприятии сделанного выбора</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%9A%D0%BE%D0%B3%D0%BD%D0%B8%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9_%D0%B4%D0%B8%D1%81%D1%81%D0%BE%D0%BD%D0%B0%D0%BD%D1%81">Когнитивный диссонанс</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%BD%D0%BE%D1%81%D1%82%D1%8C">Конформность</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%B2%D0%BB%D0%B0%D0%B4%D0%B5%D0%BD%D0%B8%D1%8F">Эффект владения</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0_%D0%B2%D1%8B%D0%B6%D0%B8%D0%B2%D1%88%D0%B5%D0%B3%D0%BE">Систематическая ошибка выжившего</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D0%BE%D1%80%D0%B8%D1%8F_%D1%80%D0%B0%D0%B7%D0%B1%D0%B8%D1%82%D1%8B%D1%85_%D0%BE%D0%BA%D0%BE%D0%BD">Теория разбитых окон</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%90%D0%BF%D0%B5%D0%BB%D0%BB%D1%8F%D1%86%D0%B8%D1%8F_%D0%BA_%D0%BB%D0%B8%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Апелляция к личности</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%B2%D1%82%D0%BE%D1%80%D0%BE%D0%B9_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B">Эффект второй системы</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/Хоторнский_эффект">Хоторнский эффект новизны</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D1%84%D0%B5%D1%81%D1%81%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%B4%D0%B5%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D1%8F">Профессиональная деформация</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BF%D1%80%D0%BE%D0%B6%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%B0">Эффект прожектора</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%BA%D1%80%D0%B0%D1%81%D1%82%D0%B8%D0%BD%D0%B0%D1%86%D0%B8%D1%8F">Прокрастинация</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D0%BC%D0%BE%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%B2%D1%8B%D0%B3%D0%BE%D1%80%D0%B0%D0%BD%D0%B8%D0%B5">Эмоциональное выгорание</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9E%D1%88%D0%B8%D0%B1%D0%BA%D0%B0_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F">Ошибка планирования</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D1%82%D0%B5%D0%BB%D0%B5%D1%81%D0%BA%D0%BE%D0%BF%D0%B0">Эффект телескопа</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%B4%D0%B0%D0%B2%D0%BD%D0%B5%D0%B3%D0%BE">Эффект недавнего</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BD%D0%BE%D0%B9_%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D0%B8">Каскад доступной информации</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D1%82%D1%80%D0%B8%D0%B2%D0%B8%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Закон тривиальности (эффект велосипедного сарая)</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD%D1%8B_%D0%9F%D0%B0%D1%80%D0%BA%D0%B8%D0%BD%D1%81%D0%BE%D0%BD%D0%B0">Первый закон Паркинсона (Работа заполняет время, отпущенное на неё)</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/Синдром_неприятия_чужой_разработки">Синдром неприятия чужой разработки</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%93%D1%80%D1%83%D0%BF%D0%BF%D0%BE%D0%B2%D0%BE%D0%B5_%D0%BC%D1%8B%D1%88%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5">Групповое мышление</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B8%D0%B2%D0%B0%D1%8F_%D0%B7%D0%B0%D0%B1%D1%8B%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F">Кривая забывания</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B8%D0%B2%D0%B0%D1%8F_%D0%BE%D0%B1%D1%83%D1%87%D0%B0%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D0%B8">Кривая обучаемости</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BA%D1%80%D0%B0%D1%8F_(%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D1%8C)">Эффект края (память)</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D1%87%D0%B5%D1%82%D1%8B%D1%80%D1%91%D1%85_%D0%BA%D0%B0%D0%BD%D0%B0%D0%BB%D0%BE%D0%B2">Модель четырёх каналов</a>"</p></li> -</ul> -<p>Обзорные (агрегированные) статьи:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9B%D0%BE%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0">Логическая ошибка</a>"</p></li> -<li><p>"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BA%D0%BE%D0%B3%D0%BD%D0%B8%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D1%85_%D0%B8%D1%81%D0%BA%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9">Список когнитивных искажений</a>"</p></li> -<li><p>"<a class="reference external" href="https://en.wikipedia.org/wiki/Decision-making">Decision-making</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.atlassian.com/blog/productivity/cognitive-bias-examples">5 cognitive bias examples and how to avoid them in decision-making</a>" by Ben Crothers</p></li> +</li> +<li><p><a class="reference internal" href="#atam-in-agile" id="id24">ATAM in Agile</a></p></li> +<li><p><a class="reference internal" href="#emacsway-agile-balancing-business-technical-concerns-with-fixed-iteration-ratio" id="id25">Фиксированная часть итерации на технические задачи</a></p></li> +<li><p><a class="reference internal" href="#open-agile-architecture" id="id26">Open Agile Architecture™</a></p></li> +<li><p><a class="reference internal" href="#id10" id="id27">Системное мышление</a></p></li> </ul> -<p>А вот следующая статья очень интересна. -Научное биологическое обоснование того, почему процесс Knowledge Crunching неизбежен. -Иными словами, почему требуется время на вызревание концептуальных контуров доменного моделирования, что и является основной причиной появления Monolith First:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.hindawi.com/journals/np/2009/482696/">A Plastic Temporal Brain Code for Conscious State Generation</a>"</p></li> +</li> </ul> -<p>На эту тему была неплохая статья на Хабре:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://habr.com/ru/company/web_payment_ru/blog/246081/">О медленном программировании</a>"</p></li> +</li> +<li><p><a class="reference internal" href="#id11" id="id28">Психологическая сторона вопроса</a></p></li> </ul> -<p>Шпаргалки по теме:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://play.google.com/store/apps/details?id=ru.free_coding.biascs">Шпаргалка по когнитивным искажениям в виде мобильного приложения</a>"</p></li> +</li> </ul> -<p>В виде JSON:</p> +</nav> +<p>Существует довольно распространенная проблема поиска баланса между краткосрочными бизнес-интересами и долгосрочными техническими интересами проекта.</p> +<blockquote> +<div><p>📝 "Краткосрочные индивидуальные цели часто конфликтуют с долгосрочными социальными целями. +Общество решает эту проблему при помощи набора ценностей, подкрепленных мифами, ритуалами, наказаниями и наградами. +Без уважения к этим ценностям люди забывают о социальных нуждах и стремятся реализовать свой собственный индивидуальный краткосрочный интерес. +Четыре ценности для ХР — это: коммуникация (communication), простота (simplicity), обратная связь (feedback), храбрость (courage).</p> +<p>Short-term individual goals often conflict with long-term social goals. +Societies have learned to deal with this problem by developing shared sets of values, backed up by myths, rituals, punishments, and rewards. +Without these values, humans tend to revert to their own short-term best interest. +The four values of XP are: Communication, Simplicity, Feedback, Courage."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 7. Four Values", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Спустя 23 года Kent Beck продолжает говорить об актуальности проблемы, упоминув среди ее причин когнитивные искажения:</p> +<blockquote> +<div><p>💬 "I've always been puzzled why the balance between structure &amp; behavior investment seems so hard to maintain. +I'm also puzzled why the balance we see in the wild is so heavily tilted towards behavior changes when as I geek I think it should be more balanced.</p> +<p>If "behavior change = revenue" &amp; "structure change = option", then the struggle for balance makes more sense. +It's not about the personalities of Product versus Engineering. +It's not about short-sighted versus visionary thinking. +The struggle is economic — <strong>do we make some money now or more money later</strong>? +The answer is always "both". We have to make some money now to survive. +We want to make more money later. +<strong>Fear versus greed. No wonder it's so hard to get time to refactor.</strong>"</p> +<p class="attribution">—"<a class="reference external" href="https://tidyfirst.substack.com/p/behavior-change-revenue-versus-structure">Behavior Change = Revenue Versus Structure Change = Option</a>" by Kent Beck</p> +</div></blockquote> +<p>Решение этой проблемы было одной из целей создания Agile:</p> +<blockquote> +<div><p>📝 "During the <a class="reference external" href="https://martinfowler.com/articles/agileStory.html">Snowbird meeting</a>, Kent Beck said that the goal of Agile was to heal the divide between business and development. To that end, the following bill of rights was developed by Kent, Ward Cunningham, and Ron Jeffries, among others."</p> +<p class="attribution">—"Clean Agile: Back to Basics" by Robert C. Martin</p> +</div></blockquote> +<blockquote> +<div><p>📝 "There is <strong>always a tension between advancing product functionality and raising product quality</strong>.</p> +<p>Business pressures tend to make us view engineering problems, software bugs, and manufacturing line irregularities as necessary evils. +We see them as distractions that lie outside the Sprint. +And because developers really like to do new stuff, they often smooth over current product problems, or they postpone resolving them until <strong>the tomorrow that never comes</strong>.</p> +<p>&lt;...&gt;</p> +<p>Fixing issues takes time, so we often defer such work. +We believe that the market benefit is not worth the effort to fix them, or that they displace the "more important," revenue-generating work. +However, McConnell (Software Development 4 [McC96]) has shown that bugs in software <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">slow down the Development Team</span></a> because they cause "stumbling" and work-arounds that create a drag on development. +These impediments actually <strong>slow down other development that isn't directly related to fixing bugs</strong>.</p> +<p>[McC96]Steve McConnell. The XP Customer Role in Practice: Three Studies. Software Development. 4[8]:38—42, 1996, August."</p> +<p class="attribution">—"A Scrum Book: The Spirit of the Game" by Jeff Sutherland, James Coplie, chapter "81 Whack the Mole"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "A frequent frustration amongst software developers is the perception that their management team only values things that can be sold. To management, they believe, architectural refactoring is wasted money, occupying development teams for months at a time without a single additional thing being produced that can be sold. And for that matter, why does it take so long for them to add a feature? (Possible answer: that would be because the architecture has not been refactored in years.)</p> +<p>Management teams do have a business to run and customers do not typically hand over money for architectural refactorings, no matter how elegant they are; so without shiny new things to sell, there may be no money to continue to employ the development teams who want to do the refactoring.</p> +<p>As such, this issue has two aspects: firstly, development teams need to learn how to justify such investment; and secondly, such non-functional investment will always have to be balanced with functional requirements."</p> +<p class="attribution">—"Open Agile Architecture™" by The Open Group, Chapter "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard-single/#KLP-CAR-justifying">6.5.1. Justifying Ongoing Investment in Architectural Refactoring</a>"</p> +</div></blockquote> +<section id="id3"> +<h2><a class="toc-backref" href="#id14" role="doc-backlink">Поиск баланса</a></h2> +<p>В первой версии XP управление разработкой осуществлялось посредством четырех переменных:</p> <ul class="simple"> -<li><p><a class="reference external" href="https://www.dropbox.com/s/8l49rx8ig9i4za3/cognitive-bias-cheat-sheet-ru.json">https://www.dropbox.com/s/8l49rx8ig9i4za3/cognitive-bias-cheat-sheet-ru.json</a></p></li> -<li><p><a class="reference external" href="http://ezh.li/cbcs-json">http://ezh.li/cbcs-json</a></p></li> -<li><p><a class="reference external" href="https://github.com/busterbenson/public/blob/master/cognitive-bias-cheat-sheet.json">https://github.com/busterbenson/public/blob/master/cognitive-bias-cheat-sheet.json</a></p></li> +<li><p>затраты (cost)</p></li> +<li><p>время (time)</p></li> +<li><p>качество (quality)</p></li> +<li><p>объем работ (scope)</p></li> </ul> -<p>Статьи по теме:</p> +<p>Иногда эти четыре переменные можно встретить в виде Iron Triangle, где <a class="reference external" href="https://en.m.wikipedia.org/wiki/Project_management_triangle">Quality ограничено тремя переменными</a>:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://betterhumans.pub/cognitive-bias-cheat-sheet-55a472476b18">Cognitive bias cheat sheet</a>" by Buster Benson</p></li> -<li><p>"<a class="reference external" href="https://medium.com/russian/cognitive-bias-cheat-sheet-5bb0664b67b5">Памятка по когнитивным искажениям</a>" / Alexey Ezhikov</p></li> -<li><p>"<a class="reference external" href="https://www.talent-management.com.ua/3467-shpargalka-po-kognitivnym-iskazheniyam/">Шпаргалка по когнитивным искажениям</a>"</p></li> +<li><p>затраты (cost)</p></li> +<li><p>время (time)</p></li> +<li><p>объем работ (scope)</p></li> </ul> -<p>Простой и доходчивый видеокурс по SoftSkills:</p> +<p>Хотя сам Martin Barnes, PhD говорил, что:</p> +<blockquote> +<div><p>💬 I sketched a diagram to make the point – a triangle with time, cost and quality at the corners.</p> +<p class="attribution">—"<a class="reference external" href="https://pmworldlibrary.net/wp-content/uploads/2018/11/pmwl-barnes-how-it-all-began-pmwt-july-2006.pdf">HOW IT ALL BEGAN</a>" by Martin Barnes, PhD</p> +</div></blockquote> +<p>Иными словами, Quality было тождественно (или рассматривалось как составная часть) Scope.</p> +<p>Так или иначе, но на заре Agile качество имело такое существенное и нелинейное влияние на разработку, что Iron Triangle стал квадратом, известным также как The "Project Diamond" model, см.:</p> <ul class="simple"> -<li><p>"<a class="reference external" href="https://youtube.com/channel/UCSN7G8syJUaRiXrw1l0qk_g">Soft Skills Pro</a>"</p></li> +<li><p>"<a class="reference external" href="http://www.betterprojects.net/2009/03/it-used-to-be-iron-triangle.html">It used to be the Iron Triangle</a>". Better Project. by Brown, Craig</p></li> +<li><p>"<a class="reference external" href="https://www.projectsmart.co.uk/lifecycle-and-methodology/introduction-to-project-management.php">Introduction to Project Management</a>" by Duncan Haughey</p></li> </ul> -Fri, 23 Sep 2022 00:00:00 SAGAhttps://dckms.github.io/system-architecture/emacsway/it/concurrency/saga.html -<span id="emacsway-saga"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -Mon, 29 Aug 2022 00:00:00 Transactionhttps://dckms.github.io/system-architecture/emacsway/it/concurrency/transaction.html -<span id="emacsway-transaction"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -Mon, 29 Aug 2022 00:00:00 Event Sourcinghttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/event-sourcing.html -<span id="emacsway-golang-event-sourcing"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> +<p>И только во второй версии XP он превратился в треугольник, но уже без Quality. +Но обо всем по порядку.</p> +<blockquote> +<div><p>📝 "Одним из основополагающих правил нашей стратегии является то, что технари концентрируются на решении технических проблем, а бизнесмены — на решении бизнес-проблем. +Проект должен управляться бизнес-решениями, однако для принятия бизнес-решений должна использоваться информация о затратах и риске, предоставляемая техническими специалистами.</p> +<p>Эта информация является результатом технических решений. +<strong>Существуют два широко распространенных неправильных режима взаимоотношений между бизнесом и разработчиками: когда либо бизнес, либо разработчики получают слишком большую власть над проектом, проект начинает страдать.</strong></p> +<p>One key to our strategy is to keep technical people focused on technical problems and business people focused on business problems. +The project must be driven by business decisions, but the business decisions must be informed by technical decisions about cost and risk.</p> +<p>There are two common failure modes in the relationship between Business and Development. +<strong>If either Business or Development gains too much power, the project suffers.</strong>"</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 14. Splitting Business and Technical Responsibility", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<section id="emacsway-agile-technical-concerns-predominance"> +<span id="id4"/><h3><a class="toc-backref" href="#id15" role="doc-backlink">Преобладание технических интересов</a></h3> +<p>Начнем с преобладания технических интересов.</p> +<p id="emacsway-second-system-effect">Frederick Brooks в своем бестселлере "Мифический человеко-месяц" говорит об "<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%B2%D1%82%D0%BE%D1%80%D0%BE%D0%B9_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B">Эффекте второй системы</a>". +Я приведу небольшой фрагмент:</p> +<blockquote> +<div><p>📝 "Если ответственность за спецификацию функций отделить от ответственности за быстрое создание недорогого продукта, то <strong>чем сдержать изобретательский энтузиазм архитектора</strong>?</p> +<p>If one separates responsibility for functional specification from responsibility for building a fast, cheap product, <strong>what discipline bounds the architect's inventive enthusiasm</strong>?"</p> +<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Похожую проблему описывает и Kent Beck в "Extreme Programming" 1st edition:</p> +<blockquote> +<div><p>📝 "Когда разработчикам предоставляется чрезмерная свобода, они начинают использовать все те новые технологии и процессы, для которых у них никогда не хватает времени, если "эти белые воротнички" постоянно подгоняют их. +Когда разработчикам предоставляется свобода, они устанавливают и начинают использовать новые инструменты разработки, новые языки программирования, новые технологии. +При этом инструменты, языки и технологии выбираются исходя из того, что они очень интересны и суперсовременны. +Все только что появившееся на рынке связано с риском. +(Если мы не попробуем это сейчас, то когда же еще?)</p> +<p>Таким образом, в результате предоставления разработчикам слишком широких полномочий, они прикладывают слишком много усилий и генерируют слишком много риска, при этом <strong>они обеспечивают слишком незначительную отдачу</strong>.</p> +<p>When Development is in charge, they put in place all the process and technology that they never had time for when "those suits" were pushing them around. +They install new tools, new languages, new technologies. +And the tools, languages, and technologies are chosen because they are interesting and cutting edge. +Cutting edge implies risk. +(If we haven't learned that by now, when will we?)</p> +<p>So, the net result of the "Development in Charge" scenario is too much effort and way, way <strong>too much risk for too little return</strong>."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 14. Splitting Business and Technical Responsibility", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Doing infrastructure without customer function leads to the following risks:</p> <ul class="simple"> -<li><p><a class="reference internal" href="#event-sourcing" id="id2">Event Sourcing</a></p></li> +<li><p>You spend a lot of time not delivering things that are valuable to the customer, which strains the relationship with the customer.</p></li> +<li><p>You try to make the infrastructure cover everything you think you might need, which leads to an overly complex infrastructure."</p></li> </ul> -</nav> -<p>Термины StreamId/StreamName, StreamType, StreamPosition не несут информативности в домене, и должны появляться в домене только <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples/blob/05d95572f2ad6b85357b216d7d617b27359a360d/iddd_collaboration/src/main/java/com/saasovation/collaboration/port/adapter/persistence/repository/EventStoreCalendarRepository.java#L54">на стадии сохранения</a>.</p> -<p>Иными словами, они не несут информации обработчикам доменных событий, которым нужен первичный идентификатор Агрегата, а не его сериализованное в строку представление.</p> -Sun, 07 Aug 2022 00:00:00 Использовать ли в проекте CanExecute pattern?https://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/why-no-can-execute.html -<span id="emacsway-golang-can-execute"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<p>CanExecute pattern был описан в статье "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/validation-and-ddd/">Validation and DDD</a>" by Vladimir Khorikov.</p> -<p>Vladimir Khorikov - авторитетный специалист, смело принимающий на себя все риски первопроходца, который существенным образом повлиял на развитие индустрии, а также на мое становление как специалиста, за что я ему очень признателен.</p> -<p>CanExecute pattern, продемонстрированный Владимиром, является, действительно, очень удобным подходом, без которого очень сложно обойтись там, где это вызвано объективной необходимостью:</p> -<ol class="arabic simple"> -<li><p>в распределенных процедурах (процессах);</p></li> -<li><p>там, где существует вероятность установления частично-валидного состояния композитного объекта, т.е. для обеспечения атомарности валидации с целью осуществимости атомарности изменения состояния.</p></li> +<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 10. Release Planning :: How Do You Plan Infrastructure?"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Программист является сердцем ХР. +На самом деле если бы программисты могли всегда принимать решения, в которых тщательно балансировались краткосрочные и долгосрочные приоритеты, в рамках проекта не нужны были бы никакие другие технические работники, кроме программистов. +Конечно же если заказчику не требуется программное обеспечение для того, чтобы поддерживать функционирование бизнеса, то никакой надобности в программистах не было бы.</p> +<p>The programmer is the heart of XP. +Actually, if programmers could always make decisions that carefully balanced short-term and long-term priorities, there would be no need for any other technical people on the project besides programmers. +Of course, if the customer didn't absolutely need software to keep the business running, there would be no need for the programmers, so it won't do to get too big-headed about being the vital programmer."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 22. Roles for People", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Есть масса примеров, подсказанных другими искусствами и ремеслами, которые +подводят к мнению, что дисциплина идет на пользу. +Действительно, афоризм художника гласит, что "форма освобождает". +Самые ужасные строения — это те, бюджет которых был слишком велик для поставленных целей. +Творческую активность Баха едва ли могла подавлять еженедельная необходимость изготавливать кантату определенного вида. +Я уверен, что архитектура компьютера Stretch стала бы лучше, если бы на нее наложили более жесткие ограничения; так, ограничения, наложенные бюджетом на System/360 Model 30, по моему мнению, принесли лишь пользу архитектуре Model 75.</p> +<p>Аналогично, я считаю, что получение архитектуры извне усиливает, а не подавляет творческую активность группы исполнителей. +Они сразу сосредоточиваются на той части задачи, которой никто не занимался, и в результате изобретательность бьет ключом. +В не ограничиваемой группе большая часть обдумывания и обсуждения посвящена архитектурным решениям в ущерб реализации. [5]</p> +<p>There are many examples from other arts and crafts that lead one to believe that discipline is good for art. +Indeed, an artist's aphorism asserts, "Form is liberating." +The worst buildings are those whose budget was too great for the purposes to be served. +Bach's creative output hardly seems to have been squelched by the necessity of producing a limited-form cantata each week. +I am sure that the Stretch computer would have had a better architecture had it been more tightly constrained; the constraints imposed by the System/360 Model 30's budget were in my opinion entirely beneficial for the Model 75's architecture.</p> +<p>Similarly, I observe that the external provision of an architecture enhances, not cramps, the creative style of an implementing group. +They focus at once on the part of the problem no one has addressed, and inventions begin to flow. +In an unconstrained implementing group, most thought and debate goes into architectural decisions, and implementation proper gets short shrift. [5]"</p> +<ol class="arabic simple" start="5"> +<li><p>Englebart, D., and W. English, "A research center for augmenting human intellect," AFIPS Conference Proceedings, Fall Joint Computer Conference, San Francisco (Dec. 9-11, 1968), pp. 395-410.</p></li> </ol> -<p>В этом я убедился на собственной практике.</p> -<p>В других случаях, ключевой аргумент использования CanExecute pattern, приводимый в статье, сводится к CQS principle.</p> -<p>Я обсудил с ним этот вопрос, и он согласился с тем, что этот вопрос не совсем однозначный.</p> -<p>В этом подходе меня смущает тот факт, что образуется логическая зависимость - клиент класса действует исходя из предположения о том, что оба метода используют один и тот же инвариант.</p> -<p>В заметке "<a class="reference internal" href="../../tactical-design/cqrs/cqrs-command-and-result.html#emacsway-cqs-command-status-code"><span class="std std-ref">Может ли Command возвращать служебную информацию (код ошибки или успешность выполнения)?</span></a>" этот вопрос уже затрагивался, поэтому, повторюсь:</p> +<p class="attribution">—"The Mythical Man-Month Essays on Software Engineering Anniversary Edition" by Frederick P. Brooks, Jr., перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>К этой же категории относится и т.н. Resume-Driven Development, когда разработчики безобоснованно переусложняют проект сложными технологиями ради очередной отметки о достижении в резюме.</p> +</section> +<section id="emacsway-agile-business-concerns-predominance"> +<span id="id5"/><h3><a class="toc-backref" href="#id16" role="doc-backlink">Преобладание бизнес-интересов</a></h3> +<p>Но есть и обратная проблема - когда технические специалисты ущемлены в своих полномочиях в пользу представителей бизнеса, проект неизменно загнивает, а <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">экономика разработки деградирует с зависимостью, приближенной к экспоненциальной</span></a>.</p> +<blockquote> +<div><p>📝 "Когда бизнесмены получают слишком много полномочий, они начинают диктовать разработчикам значения для всех четырех переменных. +"Вот то, что ты должен сделать. +Это должно быть сделано тогда-то и тогда-то. +Нет, тебе не дадут ни одной дополнительной рабочей станции. +И для тебя будет лучше, если ты сделаешь эту работу с наивысшим возможным качеством, иначе у тебя будут проблемы. +Ты меня хорошо понял? Скотина ленивая!"</p> +<p>В такой ситуации бизнес предписывает слишком многое. +Некоторые элементы в списке требований абсолютно обязательны, но некоторые — нет. +И если у разработчиков не будет никаких полномочий, они не смогут возразить. +Они не смогут принудить бизнес выбрать правильный вариант. +И тогда разработчики, понурив голову, идут работать над невыполнимой задачей, которую перед ними поставили.</p> +<p>Как правило, наименее важные требования являются причиной наибольшего риска. +Похоже, это является следствием их природы. +Они меньше всего обдумываются, меньше всего анализируются и меньше всего осмысливаются, поэтому вероятность того, что именно они изменятся в процессе разработки, выше всего. +Очень часто такие требования оказываются также наиболее рискованными с технической точки зрения.</p> +<p><strong>В результате, если бизнес получает слишком большие полномочия, проект требует слишком много усилий и генерирует слишком много риска, при этом он</strong> <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">обеспечивает слишком незначительную отдачу</span></a>.</p> +<p>If Business has the power, they feel fit to dictate all four variables to Development. +"Here is what you will do. +Here is when it will be done. +No, you can't have any new workstations. +And it better be of the highest quality or you're in trouble, buster."</p> +<p>In this scenario, Business always specifies too much. +Some of the items on the list of requirements are absolutely essential. +But some are not. +And if Development doesn't have any power, they can't object; they can't force Business to choose which is which. +So Development dutifully goes to work, heads down, on the impossible task they have been given.</p> +<p>It seems to be in the nature of the less important requirements that they entail the greatest risk. +They are typically the poorest understood, so there is great risk that the requirements will change all during development. +Somehow, they also tend to be technically riskier.</p> +<p><strong>The result of the "Business in Charge" scenario, then, is that the project takes on too much effort and way, way too much risk for</strong> <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">too little return</span></a>."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 14. Splitting Business and Technical Responsibility", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Закон Вайнберга-Брукса: От действий менеджеров, основанных на неправильных моделях системы, пострадало больше проектов, чем от всех остальных причин вместе взятых.</p> +<p>Weinberg-Brooks' Law: More software projects have gone awry from management's taking action based on incorrect system models than for all other causes combined."</p> +<p class="attribution">—"<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems Thinking</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">на русском</a>)</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Scrum is by far the most widely used agile framework in the world, but we've also found that 58% of Scrum implementations fail."</p> +<p class="attribution">—"<a class="reference external" href="https://www.scruminc.com/better-scrum-with-essence/">Better Scrum with Essence</a>" Jeff Sutherland</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Мы попробовали различные варианты работы с техническими историями. +Мы пробовали считать их самыми обычными user story. +Это была неудачная идея: для product owner'а приоритезировать их в product backlog'е было всё равно, что сравнить тёплое с мягким. +По очевидным причинам технические истории получали самый низкий приоритет с объяснением: +"Да, ребята, несомненно, ваш сервер непрерывной интеграции – очень важная штука, но давайте сперва реализуем кое-какие прибыльные функции? +После этого вы можете прикрутить вашу техническую конфетку, окей?"</p> +<p>В некоторых случаях product owner действительно прав, но чаще все-таки нет. +Мы пришли к выводу, что product owner не всегда компетентен, чтобы идти на компромисс.</p> +<p>We've experimented a lot with different ways of handling tech stories. +We tried treating them as first-class stories, just like any others. +That was no good; when the product owner prioritized the product backlog, it was like comparing apples with oranges. +In fact, for obvious reasons, the tech stories were often given low priority with the motivation like +"Yeah guys, I'm sure a continuous-build server is important and all, but let's build some revenue-driving features first shall we? +Then you can add your tech candy later, OK?"</p> +<p>In some cases the product owner is right, but often not. +We've concluded that the product owner is not always qualified to be making that tradeoff."</p> +<p class="attribution">—"Scrum and XP from the Trenches: How We Do Scrum" 2nd edition by Henrik Kniberg, перевод под редакцией Алексея Кривицкого</p> +</div></blockquote> +</section> +<section id="emacsway-agile-solution-to-balancing-business-technical-concerns"> +<span id="id6"/><h3><a class="toc-backref" href="#id17" role="doc-backlink">Решение</a></h3> <blockquote> -<div><p>💬️ "It is important here two deal with two common objections to the side-effect-free style.</p> -<p>The first has to do with error handling. -Sometimes a function with side effects is really a procedure, which in addition to doing its job returns a status code indicating how things went. -But there are better ways to do this; roughly speaking, the proper O-O technique is to <strong>enable the client, after an operation on an object, to perform a query on the status, represented for example by an attribute of the object</strong>, as in</p> -<p>target.some_operation(...)</p> -<p>how_did_it_go := target.status</p> -<p>Note that the technique of returning a status as function result is lame anyway. -It transforms a procedure into a function by adding the status as a result; -<strong>but it does not work if the routine was already a function, which already has a result of its own</strong>. -It is also problematic if you need more than one status indicator. -In such cases the C approach is either to return a "structure" (the equivalent of an object) with several components, which is getting close to the above scheme, or to use global variables — which raises a whole set of new problems, especially in a large system where many modules can trigger errors."</p> -<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +<div><p>📝 "You notice we have two different criteria set by two different groups of people. +How do we resolve the two of them? +Programmers want to tackle high-risk stories first, and customers want to tackle high-value stories first. +There are plenty of times when these conflicting priorities have to be resolved."</p> +<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 13. Ordering the Stories :: Negotiating Between the Two"</p> </div></blockquote> -<p>Единственная причина, по которой Bertrand Meyer избегал возврата ошибок в то время, заключается в том, что тогда было невозможно возвратить одновременно и результат, и ошибку. -Сегодня таких проблем нет. -В Golang это поддерживается на уровне синтаксиса языка, а в других языках поддерживается объект Result.</p> -<p>Но даже если и разделять, то Bertrand Meyer рекомендует проверять ошибки после попытки, а не перед попыткой.</p> -Wed, 03 Aug 2022 00:00:00 Role of Software Design in Agilehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/software-design.html -<span id="emacsway-agile-software-design"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<figure class="align-center" id="id7"> -<a class="reference internal image-reference" href="../../../../../../_images/ouroboros.jpg"><img alt="Уроборос. Иллюстрация из открытых источников неизвестного автора." src="../../../../../../_images/ouroboros.jpg" style="width: 40%;"/></a> -<figcaption> -<p><span class="caption-text">Уроборос. Иллюстрация из открытых источников неизвестного автора.</span></p> -</figcaption> -</figure> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> +<blockquote> +<div><p>📝 "Our planning process relies on clearly separating the roles of business people and software people. +This ensures that business people make all the business decisions and software people make all the technical decisions.</p> +<p>The key to project management is balancing power between the business people and the programmers. +Done right, software project management has</p> <ul class="simple"> -<li><p><a class="reference internal" href="#role-of-software-design-in-agile" id="id12">Role of Software Design in Agile</a></p> -<ul> -<li><p><a class="reference internal" href="#emacsway-who-reads-the-code" id="id13">Кто читает код?</a></p></li> -<li><p><a class="reference internal" href="#primary-technical-imperative" id="id14">Primary Technical Imperative</a></p></li> -<li><p><a class="reference internal" href="#id3" id="id15">Оправдано ли качество?</a></p> -<ul> -<li><p><a class="reference internal" href="#martin-fowler" id="id16">Martin Fowler</a></p></li> -<li><p><a class="reference internal" href="#kent-beck" id="id17">Kent Beck</a></p></li> -<li><p><a class="reference internal" href="#robert-martin" id="id18">Robert Martin</a></p></li> -<li><p><a class="reference internal" href="#agile-manifesto" id="id19">Agile Manifesto</a></p></li> -<li><p><a class="reference internal" href="#ralph-johnson" id="id20">Ralph Johnson</a></p></li> -<li><p><a class="reference internal" href="#steve-mcconnell" id="id21">Steve McConnell</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id22">Сергей Тепляков</a></p></li> -<li><p><a class="reference internal" href="#id5" id="id23">Народное творчество</a></p></li> -<li><p><a class="reference internal" href="#randy-shoup" id="id24">Randy Shoup</a></p></li> -</ul> -</li> -</ul> -</li> +<li><p>Business people making business decisions</p></li> +<li><p>Technical people making technical decisions"</p></li> </ul> -</nav> -<section id="emacsway-who-reads-the-code"> -<span id="id2"/><h2><a class="toc-backref" href="#id13" role="doc-backlink">Кто читает код?</a></h2> -<p>Среди малоопытных разработчиков иногда можно услышать, что им некогда писать качественный код, так как у них мало времени, а этот код все равно читать никто не будет.</p> -<p>Истина в том, что в процессе конструирования кода, 91% времени занимает именно чтение кода и борьба со сложностью, и только 9% времени (1:10) занимает ввод символов с клавиатуры. -И это соотношение дано еще для качественного кода.</p> -<p>Причем, разработчик пишет код в одиночку и лишь единожды. -Зато читают код все разработчики команды и по много раз.</p> -<p>Таким образом, плохо написанный код более чем на 91% (т.е. более чем на порядок!) влияет на снижение темпов разработки всей команды.</p> -<p>Кстати, этот момент хорошо объясняет то, почему <a class="reference internal" href="../../../../tdd/tdd.html#emacsway-why-is-tdd-faster"><span class="std std-ref">при TDD разработка осуществляется быстрее</span></a>, хотя объема кода пишется больше.</p> +<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 4. Balancing Power"</p> +</div></blockquote> <blockquote> -<div><p>📝 "Кто-то спросит: так ли уж часто читается наш код? -Разве большая часть времени не уходит на его написание?</p> -<p>Вам когда-нибудь доводилось воспроизводить запись сеанса редактирования? -В 80-х и 90-х годах существовали редакторы, записывавшие все нажатия клавиш (например, Emacs). Вы могли проработать целый час, а потом воспроизвести весь сеанс, словно ускоренное кино. -Когда я это делал, результаты оказывались просто потрясающими.</p> -<p>Большинство операций относилось к прокрутке и переходу к другим модулям!</p> +<div><p>📝 "Это достаточно сложно — разработать процесс, в рамках которого краткосрочные личные интересы служат долгосрочным интересам всей команды. +Вы можете сколько угодно рассуждать на тему, насколько та или иная методика способствует достижению долгосрочной всеобщей цели, однако как только вы оказываетесь под давлением, вы обнаруживаете, что если методика не способствует решению конкретной проблемы, стоящей перед вами в настоящий момент, вы отбрасываете ее в сторону. +Если дисциплина ХР не будет удовлетворять краткосрочным личным интересам людей, она обречена на провал.</p> +<p>It's been tricky, designing a process where following short-term self-interest also serves long-term team interest. +You can expound all you want on how some practice or other is in everybody's best interest long-term, but when the pressure mounts, if the practice doesn't solve an immediate problem it will be discarded. +If XP can't work with people's short-term interest, it is doomed to the outer methodological darkness."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 8. Basic Principles", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<p>Хорошая организация процессов должна взаимокомпенсировать эти перекосы.</p> +<p>Под техническими интересами в данном случае понимаются, в первую очередь, такие Quality Attributes, как <a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=8299">Modifiability</a>, Evolvability, Flexibility, Modularity, Testabilty, Deployability etc.</p> +<p>Разрешение противоречий требований различных групп стейкхолдеров хорошо изучены анализом и архитектурой.</p> +<blockquote> +<div><p>📝 "Stakeholder Priority. The <strong>priority of each requirement</strong> should be identified. +This may be established through a consensus process among potential stakeholders. +As appropriate, a scale such as 1-5 or a simple scheme such as High, Medium or Low, could be used for identifying the priority of each requirement. +The priority is not intended to imply that some requirements are not necessary, but it may indicate what <strong>requirements are candidates for the trade space when decisions regarding alternatives are necessary</strong>. +Prioritization needs to consider the stakeholders who need the requirements. +This <strong>facilitates trading off requirements</strong> and balancing the impact of changes among stakeholders."</p> +<p>📝 "trade-off - decision-making actions that select from various requirements (3.1.19) and alternative solutions on the basis of net benefit to the stakeholders (3.1.28)"</p> +<p>📝 "It is important to continue to perform requirements negotiation during the analysis and allocation of requirements, <strong>because conflicts will occur</strong>. +Negotiation might be needed among stakeholders requiring mutually incompatible features, or due to <strong>conflicts between desired performance requirements, constraints, available budget, and delivery schedule</strong>. +In most cases, it is necessary to consult with the stakeholder(s) <strong>to reach a consensus on an appropriate trade-off</strong>. +It is often important for contractual reasons that such decisions are traceable to the stakeholder. +<strong>Various analysis methods and conflict resolution techniques may be applicable to facilitate the resolution and are dependent on the specific situation.</strong> +Some organizations consider requirements negotiation to be part of requirements validation. +The specific process subcategory is not important as long as the conflict resolution occurs as early as possible in the requirements analysis task."</p> +<p class="attribution">—"ISO/IEC/IEEE 29148:2018 Systems and software engineering — Life cycle processes — Requirements engineering", "6.2.3.3 Analyze and maintain stakeholder requirements."</p> +</div></blockquote> +<p>Существует целый ряд достаточно зрелых методик, направленных на достижение сбалансированных решений. +Четвертое издание книги "Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman наглядно демонстрирует, как можно интегрировать их в итеративную (agile) разработку.</p> +<p>Появились легковесные варианты этих методик: Lightweight Architecture Evaluation (LAE), Mini-QAW etc. +Многие из этих методик описаны в "<a class="reference external" href="https://www.iso.org/standard/73436.html">ISO/IEC/IEEE 42030:2019 Software, systems and enterprise — Architecture evaluation framework</a>".</p> +<p>Однако, легковесные реализации agile-модели разработки предлагают свои, предельно упрощенные, процессы достижения баланса между краткосрочными бизнес-интересами и долгосрочными техническими интересами.</p> +<p>Если разобраться во всех этих обстоятельствах, то можно убедиться в невозможности избежать конфликта интересов. +Это нормально, так как это отражает неизбежный конфликт ресурсов и невозможность одновременного удовлетворения всех требований различных групп стейкхолдеров, которые зачастую обратно коррелируют. +Нужно не предотвращать этот конфликт, - эта задача есть невозможная, а управлять им путем разрешения противоречий. +В противном случае, вполне естественный конфликт интересов может перерасти в неестественный конфликт межличностный (в лучшем случае), или даже привести к <a class="reference internal" href="business-concerns/developer-motivation.html#emacsway-developer-motivation"><span class="std std-ref">потере кадров</span></a> (в худшем случае).</p> +<section id="extreme-programming"> +<span id="emacsway-xp-balancing-business-technical-concerns"/><h4><a class="toc-backref" href="#id18" role="doc-backlink">Extreme Programming</a></h4> +<section id="xp"> +<span id="emacsway-xp1-balancing-business-technical-concerns"/><h5><a class="toc-backref" href="#id19" role="doc-backlink">Первая версия XP</a></h5> +<p>Решение этой проблемы хорошо описано в главе "Chapter 14. Splitting Business and Technical Responsibility" книги "Extreme Programming Explained" 1st edition by Kent Beck. +Решение слишком объемное, чтобы поместить его сюда полностью, поэтому, я приведу только ключевые его моменты.</p> +<blockquote> +<div><p>📝 "Что делать?</p> +<p>Решение состоит в том, чтобы определенным образом <strong>разделить полномочия и ответственность между бизнесом и разработчиками</strong>. +<strong>Бизнесмены должны принимать решения в своей области компетенции, а программисты должны принимать решения в своей области компетенции.</strong> +Решения, принятые одной стороной, должны стать базой для решений, принимаемых другой стороной. +Ни одна сторона не должна в одностороннем порядке решать абсолютно все.</p> +<p>What to Do?</p> +<p>The solution is to somehow <strong>split the responsibility and power between Business and Development</strong>. +<strong>Business people should make the decisions for which they are suited.</strong> +<strong>Programmers should make the decisions for which they are suited.</strong> +Each party's decisions should inform the other's. +Neither party should be able to unilaterally decide anything."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 14. Splitting Business and Technical Responsibility", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "В данной главе я расскажу вам о модели разработки программного обеспечения, которая представляет собой систему контролируемых переменных. +В рамках данной модели разработка программного обеспечения определяется с использованием следующих четырех переменных:</p> <ul class="simple"> -<li><p>Боб открывает модуль.</p></li> -<li><p>Он находит функцию, которую необходимо изменить.</p></li> -<li><p>Задумывается о последствиях.</p></li> -<li><p>Ой, теперь он переходит в начало модуля, чтобы проверить инициализацию переменной.</p></li> -<li><p>Снова возвращается вниз и начинает вводить код.</p></li> -<li><p>Стирает то, что только что ввел.</p></li> -<li><p>Вводит заново.</p></li> -<li><p>Еще раз стирает!</p></li> -<li><p>Вводит половину чего-то другого, но стирает и это!</p></li> -<li><p>Прокручивает модуль к другой функции, которая вызывает изменяемую функцию, чтобы посмотреть, как она вызывается.</p></li> -<li><p>Возвращается обратно и восстанавливает только что стертый код.</p></li> -<li><p>Задумывается.</p></li> -<li><p>Снова стирает!</p></li> -<li><p>Открывает другое окно и просматривает код субкласса. Переопределяется ли в нем эта функция?</p></li> +<li><p>затраты (cost);</p></li> +<li><p>время (time);</p></li> +<li><p>качество (quality);</p></li> +<li><p>объем работ (scope).</p></li> </ul> -<p>&lt;...&gt;</p> -<p>В общем, вы поняли. -На самом деле соотношение времени чтения и написания кода превышает 10:1. -Мы постоянно читаем свой старый код, поскольку это необходимо для написания нового кода.</p> -<p>Из-за столь высокого соотношения наш код должен легко читаться, даже если это затрудняет его написание. -Конечно, написать код, не прочитав его, невозможно, так что упрощение чтения в действительности упрощает и написание кода. -Уйти от этой логики невозможно. -Невозможно написать код без предварительного чтения окружающего кода. -Код, который вы собираетесь написать сегодня, будет легко или тяжело писаться в зависимости от того, насколько легко или тяжело читается окружающий код. -Если вы хотите быстро справиться со своей задачей, если вы хотите, чтобы ваш код было легко писать — позаботьтесь о том, чтобы он легко читался.</p> -<p>You might ask: How much is code really read? Doesn't most of the effort go into writing it?</p> -<p>Have you ever played back an edit session? In the 80s and 90s we had editors like Emacs that kept track of every keystroke. -You could work for an hour and then play back your whole edit session like a high-speed movie. -When I did this, the results were fascinating.</p> -<p>The vast majority of the playback was scrolling and navigating to other modules!</p> +<p>В данном случае игра в разработку программного обеспечения выглядит следующим образом: <strong>внешние силы (заказчики, менеджеры) должны определить значения для любых трех переменных из указанного набора, при этом команда разработчиков должна выбрать результирующее значение для оставшейся переменной</strong>.</p> +<p>Некоторые менеджеры и заказчики полагают, что они обладают правом с успехом установить значение для всех четырех переменных. +"Вы обязаны реализовать все, что указано в техническом задании к первому числу следующего месяца, работая в текущем составе, то есть без увеличения численности, при этом качество должно стоять на первом месте и не уступать нашим обычным стандартам". +Когда происходит подобное, <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">качество, как правило, летит ко всем чертям</span></a> (и это, к сожалению, как раз и является общераспространенным стандартом), потому что никто не в состоянии хорошо делать свою работу под слишком большим давлением. +Помимо качества, время, как правило, также выходит из-под контроля. +Таким образом, вы производите некачественное программное обеспечение, не успевая при этом сдать работу к сроку.</p> +<p>Чтобы решить проблему, необходимо сделать все четыре переменные наблюдаемыми. +Если все — программисты, заказчики и менеджеры — смогут наблюдать за поведением всех четырех переменных, будет легче сознательно выбрать, какие из четырех переменных следует контролировать. +Если результирующее значение четвертой переменной окажется неприемлемым, можно будет либо изменить входные значения, либо выбрать для контроля другие три переменные.</p> +<p>Here is a model of software development from the perspective of a system of control variables. +In this model, there are four variables in software development:</p> <ul class="simple"> -<li><p>Bob enters the module.</p></li> -<li><p>He scrolls down to the function needing change.</p></li> -<li><p>He pauses, considering his options.</p></li> -<li><p>Oh, he's scrolling up to the top of the module to check the initialization of a variable.</p></li> -<li><p>Now he scrolls back down and begins to type.</p></li> -<li><p>Ooops, he's erasing what he typed!</p></li> -<li><p>He types it again.</p></li> -<li><p>He erases it again!</p></li> -<li><p>He types half of something else but then erases that!</p></li> -<li><p>He scrolls down to another function that calls the function he's changing to see how it is called.</p></li> -<li><p>He scrolls back up and types the same code he just erased.</p></li> -<li><p>He pauses.</p></li> -<li><p>He erases that code again!</p></li> -<li><p>He pops up another window and looks at a subclass. Is that function overridden?</p></li> +<li><p>Cost</p></li> +<li><p>Time</p></li> +<li><p>Quality</p></li> +<li><p>Scope</p></li> </ul> +<p>The way the software development game is played in this model is that <strong>external forces (customers, managers) get to pick the values of any three of the variables</strong>. +<strong>The development team gets to pick the resultant value of the fourth variable.</strong></p> +<p>Some managers and customers believe they can pick the value of all four variables. +"You are going to get all these requirements done by the first of next month with exactly this team. +And quality is job one here, so it will be up to our usual standards." +When this happens, <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">quality always goes out the window</span></a> (this is generally up to the usual standards, though), since nobody does good work under too much stress. +Also likely to go out of control is time. +You get crappy software late.</p> +<p>The solution is to make the four variables visible. +If everyone—programmers, customers, and managers—can see all four variables, they can consciously choose which variables to control. +If they don't like the result implied for the fourth variable, they can change the inputs, or they can pick a different three variables to control."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 4. Four Variables", перевод ООО Издательство "Питер"</p> +</div></blockquote> +</section> +<section id="emacsway-xp2-balancing-business-technical-concerns"> +<span id="id7"/><h5><a class="toc-backref" href="#id20" role="doc-backlink">Вторая версия XP</a></h5> +<p>Сам же Kent Beck и преобразовал позже квадрат (Quality, Cost, Time, Scope) в треугольник (Cost, Time, Scope), путем преобразования качества (Quality) из переменной в константу.</p> +<p>Если в первой версии XP он боролся за то, чтобы Quality (или хотя бы любую одну из 4-х переменных управления разработкой) контролировали технические специалисты, то во второй версии он и вовсе преобразовал качество в константу.</p> +<p>Вот что он пишет во втором издании:</p> +<blockquote> +<div><p>📝 "Quality</p> +<p>Sacrificing quality is not effective as a means of control. +<strong>Quality is not a control variable.</strong> +Projects don't go faster by accepting lower quality. +They don't go slower by demanding higher quality. +Pushing quality higher often results in faster delivery; while lowering quality standards often results in later, less predictable delivery.</p> +<p>One of my biggest surprises since the first edition of Extreme Programming Explained was released has been just how far teams have been able to push quality as measured in defects, design quality, and the experience of development. +Each increase in quality leads to improvements in other desirable project properties, like productivity and effectiveness, as well. +<strong>There is no apparent limit to the benefits of quality, only limits in our ability to understand how to achieve higher quality.</strong></p> +<p>Quality isn't a purely economic factor. +People need to do work <a class="reference internal" href="business-concerns/developer-motivation.html#emacsway-developer-motivation"><span class="std std-ref">they are proud of</span></a>. +I remember talking to the manager of a mediocre team. +He went home on the weekends and made fancy ironwork as a blacksmith. +He met his need for quality; he just met it outside of work.</p> +<p><strong>If you can't control projects by controlling quality, how can you control them?</strong> +Time and cost are most often fixed. +XP chooses scope as the primary means of planning, tracking, and steering projects. +Since scope is never known precisely in advance, it makes a good lever. +The weekly and quarterly cycles provide explicit points for tracking and choosing scope.</p> +<p>A concern for quality is no excuse for inaction. +If you don't know a clean way to do a job that has to be done, do it the best way you can. +If you know a clean way but it would take too long, do the job as well as you have time for now. +Resolve to finish doing it the clean way later. +This often occurs during architectural evolution, where you have to live with two architectures solving the same problem while you transition from one to the other. +Then the transition itself becomes a demonstration of quality: making a big change efficiently in small, safe steps."</p> +<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck</p> +</div></blockquote> +<p>Кроме того, во втором издании Kent Beck упоминает книгу "Joint Application Development", и сопровождает её таким комментарием:</p> +<blockquote> +<div><p>📝 "Annotated Bibliography</p> +<p>Reading a wide range of books around a topic adds to the richness of my understanding. Here are a few suggestions for interesting reading on ideas related to XP."</p> +<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Annotated Bibliography :: Project Management"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Jane Wood and Denise Silver , Joint Application Development, 2nd edition, John Wiley and Sons, 1995; ISBN 0471042994.</p> +<p>JAD facilitators facilitate without directing, give power to people who know best how to make a decision, and eventually fade away. +<strong>JAD is focused on creating a requirements document that the developers and customers agree can and should be implemented.</strong>"</p> +<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Annotated Bibliography :: Project Management"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "The facilitated <strong>JAD workshop brings key users (stakeholders) and systems professionals together to resolve their differences in a neutral, non-hostile atmosphere</strong>. +<strong>Key to the workshop is a specially trained, unbiased facilitator who is not a member of the project team and therefore has no political stake in the outcome of the workshop.</strong> +The workshop will build a team that will stay together, psychologically at least, for the life of the project.</p> <p>&lt;...&gt;</p> -<p>You get the drift. Indeed, the ratio of time spent reading vs. writing is well over 10:1. -We are constantly reading old code as part of the effort to write new code.</p> -<p>Because this ratio is so high, we want the reading of code to be easy, even if it makes the writing harder. -Of course there's no way to write code without reading it, so making it easy to read actually makes it easier to write.</p> -<p>There is no escape from this logic. -You cannot write code if you cannot read the surrounding code. -The code you are trying to write today will be hard or easy to write depending on how hard or easy the surrounding code is to read. -So if you want to go fast, if you want to get done quickly, if you want your code to be easy to write, make it easy to read."</p> -<p class="attribution">—"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin, перевод: Е.Матвеев, ООО Издательство "Питер"</p> +<p>The Key Players</p> +<ol class="arabic simple"> +<li><p>The Facilitator</p></li> +</ol> +<p>The facilitator is in charge of the workshop - the guardian of the process. +It is the facilitator's responsibility to ensure that the expected workshop deliverables are produced and the expected consensus is achieved. +The facilitator is an unbiased leader who has no ties to the project. +He can come from some other department or from outside the company. +Some companies are training facilitators who work out of a facilitation center attached to the human resources department."</p> +<p class="attribution">—"<a class="reference external" href="https://web.archive.org/web/20090221042620/http://www.bee.net/bluebird/jaddoc.htm">Joint Application Design. Business Requirements Analysis for Successful Re-engineering</a>" by Bill Jennerich</p> +</div></blockquote> +<p>Баланс краткосрочных бизнес-интересов и долгосрочных технических интересов Kent Beck теперь уже находит в сглаживании по времени "<a class="reference external" href="https://martinfowler.com/bliki/DesignPayoffLine.html">Design Payoff Line</a>" посредством применения принципа <a class="reference internal" href="../../../../uncertainty-management/adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>, см. "<a class="reference internal" href="../../../../uncertainty-management/adaptation/crash-course-in-software-development-economics.html#emacsway-software-development-economics-literature"><span class="std std-ref">Краткий курс по экономике разработки программного обеспечения</span></a>". +Иными словами, вопрос поиска баланса краткосрочных бизнес-интересов и долгосрочных технических интересов перешел полностью под контроль технических специалистов, и вместо разрешения противоречия между двумя группами стейкхолдеров превратился в вопрос минимизации ущерба краткосрочным бизнес-интересам от осуществления технических решений.</p> +<blockquote> +<div><p>📝 "You have the right to produce quality work at all times."</p> +<p class="attribution">—"Programmer Bill of Rights", "Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 2. Fear"</p> +</div></blockquote> +<p>Вот как комментирует эту фразу организатор создания Agile Manifesto:</p> +<blockquote> +<div><p>📝</p> +<blockquote> +<div><p>"Developers have the right to produce high-quality work at all times." — Kent Beck</p> +</div></blockquote> +<p>This may be the most profound of all these rights. Developers have the right to do good work. +The business has no right to tell developers to cut corners or do low-quality work. +Or, to say this differently, the business has no right to force developers to ruin their professional reputations or violate their professional ethics.</p> +<p class="attribution">—"Clean Agile: Back to Basics" by Robert C. Martin</p> </div></blockquote> </section> -<section id="primary-technical-imperative"> -<span id="emacsway-primary-technical-imperative"/><h2><a class="toc-backref" href="#id14" role="doc-backlink">Primary Technical Imperative</a></h2> +</section> +<section id="scrum"> +<span id="emacsway-scrum-balancing-business-technical-concerns"/><h4><a class="toc-backref" href="#id21" role="doc-backlink">Scrum</a></h4> +<section id="the-scrum-guide"> +<h5><a class="toc-backref" href="#id22" role="doc-backlink">The Scrum Guide™</a></h5> +<p>Dean Leffingwell возлагает на Product Owner обязанность по разрешению противоречий требований:</p> <blockquote> -<div><p>📝 "There are two ways of constructing a software design: one way is to make it so simple that there are obviously no deficiencies, and the other is to make it so complicated that there are no obvious deficiencies."</p> -<p class="attribution">—C. A. R. Hoare</p> +<div><p>📝 "Each project stakeholder will have their own vision, requirements, and priorities. As the primary representative to all those stakeholders, this provides a particular challenge to product owners—because all those requirements must be aligned and expectations must be managed toward a single solution.</p> +<p><strong>The product owner's primary job is to merge these diverse stakeholder voices into a single prioritized backlog for the team.</strong> +They can do this by facilitating or leading, or some appropriate mix of each."</p> +<p class="attribution">—"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</p> </div></blockquote> +<p>Но обладает ли Product Owner достаточным нейтралитетом для этого, или же он сам находится в сфере интересов одной из групп стейкхолдеров? +Ответственнен ли он за финансовую успешность продукта?</p> +<p>Официальный "The 2020 Scrum Guide™" возлагает на Product Owner обязанность по "<em>maximizing the value of the product</em>". +Слово "value" - полисемантическое, которое слишком часто встречается в тексте гайда, в т.ч. и в обязанностях Scrum Master и Scrum Team. +Из гайда установить значение этого слова весьма затруднительно.</p> +<p>Из других источников можно сделать вывод о том, что ответственнен, по крайней мере, был ответственным, ибо в 2020 году модель ролей существенно изменилась, и, вероятно, еще продолжит меняться.</p> <blockquote> -<div><p>📝 "Управление сложностью — самый важный технический аспект разработки ПО. -По-моему, управление сложностью настолько важно, что оно должно быть Главным Техническим Императивом Разработки ПО.</p> -<p>Managing complexity is the most important technical topic in software development. -In my view, it's so important that Software's Primary Technical Imperative has to be managing complexity."</p> -<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell, перевод: Издательско-торговый дом "Русская Редакция"</p> +<div><p>📝 "The Product Owner is responsible to those funding the project for delivering the vision in a manner that maximizes their ROI.</p> +<p>&lt;...&gt;</p> +<p>The Product Owner's focus is return on investment (ROI)."</p> +<p class="attribution">—"Agile Project Management with Scrum" by Ken Schwaber</p> </div></blockquote> <blockquote> -<div><p>📝 "Дейкстра пишет, что ни один человек не обладает интеллектом, способным вместить все детали современной компьютерной программы (Dijkstra, 1972), поэтому нам - разработчикам ПО — не следует пытаться охватить всю программу сразу. -Вместо этого мы должны попытаться организовать программы так, чтобы можно было безопасно работать с их отдельными фрагментами по очереди. -Целью этого является минимизация объема программы, о котором нужно думать в конкретный момент времени. -Можете считать это своеобразным умственным жонглированием: чем больше умственных шаров программа заставляет поддерживать в воздухе, -тем выше вероятность того, что вы уроните один из них и допустите ошибку при проектировании или кодировании.</p> -<p>На уровне архитектуры ПО сложность проблемы можно снизить, разделив систему на подсистемы. -Несколько несложных фрагментов информации понять проще, чем один сложный. -В разбиении сложной проблемы на простые фрагменты и заключается цель всех методик проектирования ПО. -Чем более независимы подсистемы, тем безопаснее сосредоточиться на одном аспекте сложности в конкретный момент времени. -Грамотно определенные объекты разделяют аспекты проблемы так, чтобы вы могли решать их по очереди. -Пакеты обеспечивают такое же преимущество на более высоком уровне агрегации.</p> -<p>Стремление к краткости методов программы помогает снизить нагрузку на интеллект. -Этому же способствует написание программы в терминах проблемной области, а не низкоуровневых деталей реализации, -а также работа на самом высоком уровне абстракции.</p> -<p>Суть сказанного в том, что программисты, компенсирующие изначальные ограничения человеческого ума, -пишут более понятный и содержащий меньшее число ошибок код.</p> -<p>Dijkstra pointed out that no one's skull is really big enough to contain a modern computer program (Dijkstra 1972), -which means that we as software developers shouldn't try to cram whole programs into our skulls at once; -we should try to organize our programs in such a way that we can safely focus on one part of it at a time. -The goal is to minimize the amount of a program you have to think about at any one time. -You might think of this as mental juggling—the more mental balls the program requires you -to keep in the air at once, the more likely you'll drop one of the balls, leading to a design or coding error.</p> -<p>At the software-architecture level, the complexity of a problem is reduced by dividing the system into subsystems. -Humans have an easier time comprehending several simple pieces of information than one complicated piece. -The goal of all software-design techniques is to break a complicated problem into simple pieces. -The more independent the subsystems are, the more you make it safe to focus on one bit of complexity at a time. -Carefully defined objects separate concerns so that you can focus on one thing at a time. -Packages provide the same benefit at a higher level of aggregation.</p> -<p>Keeping routines short helps reduce your mental workload. -Writing programs in terms of the problem domain, rather than in terms of low-level implementation details, and -working at the highest level of abstraction reduce the load on your brain.</p> -<p>The bottom line is that programmers who compensate for inherent human limitations -write code that's easier for themselves and others to understand and that has fewer errors."</p> -<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell, перевод: Издательско-торговый дом "Русская Редакция"</p> +<div><p>📝 "Four, the Product Owner needs to be accountable for value. +In a business context what matters is revenue. +I measure a Product Owner by how much revenue they deliver per "point" of effort."</p> +<p class="attribution">—"Scrum: The Art of Doing Twice the Work in Half the Time" by Jeffrey Sutherland</p> </div></blockquote> <blockquote> -<div><p>📝 "<strong>Главным Техническим Императивом Разработки ПО является управление сложностью.</strong> -Управлять сложностью будет гораздо легче, если при проектировании вы будете стремиться к простоте.</p> -<p>Есть два общих способа достижения простоты: -минимизация объема существенной сложности, с которой приходится иметь дело в любой конкретный момент времени, -и подавление необязательного роста несущественной сложности.</p> -<p><strong>Software's Primary Technical Imperative is managing complexity.</strong> -This is greatly aided by a design focus on simplicity.</p> -<p>Simplicity is achieved in two general ways: -minimizing the amount of essential complexity that anyone's brain has to deal with at any one time, -and keeping accidental complexity from proliferating needlessly."</p> -<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell, перевод: Издательско-торговый дом "Русская Редакция"</p> +<div><p>📝 "The Product Owner is responsible for maximizing return on investment (ROI) by identifying product features, translating these into a prioritized feature list, deciding which should be at the top of the list for the next Sprint, and continually re-prioritizing and refining the list.</p> +<p>The Product Owner has profit and loss responsibility for the product, assuming it is a commercial product. +In the case of an internal application, the Product Owner is not responsible for ROI in the sense of a commercial product (that will generate revenue), but they are still responsible for maximizing ROI in the sense of choosing – each Sprint – the highest-business-value lowest-cost items."</p> +<p class="attribution">—"Jeff Sutherland's Scrum Handbook" by Jeff Sutherland</p> </div></blockquote> <blockquote> -<div><p>📝 "При выполнении других заданий человек может удерживать в памяти 7±2 дискретных элементов [Miller, 1956]. -Если класс содержит более семи элементов данных-членов, подумайте, не разделить ли его на несколько менее крупных классов [Riel, 1996].</p> -<p>The number "7±2" has been found to be a number of discrete items a person can remember while performing other tasks [Miller 1956]. -If a class contains more than about seven data members, consider whether the class should be decomposed into multiple smaller classes [Riel 1996].</p> -<dl class="simple"> -<dt>[Miller, 1956]</dt><dd><p>Miller, G. A. 1956. "The Magical Number Seven, Plus or Minus Two: Some Limits on Our Capacity for Processing Information." -The Psychological Review 63, no. 2 (2): 81–97.</p> -</dd> -<dt>[Riel 1996]</dt><dd><p>Riel, Arthur J. 1996. Object-Oriented Design Heuristics. Reading, MA: Addison-Wesley."</p> -</dd> -</dl> -<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell, перевод: Издательско-торговый дом "Русская Редакция"</p> +<div><p>📝 "The product owner is responsible for ensuring that good economic decisions are continuously being made at the release, sprint, and product backlog levels."</p> +<p class="attribution">—"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin</p> </div></blockquote> -<p>По поводу последнего изречения - лучше один раз увидеть на примере метафоры в виде картинки со схожим эффектом:</p> -<figure class="align-left" id="id8"> -<a class="reference internal image-reference" href="../../../../../../_images/12-points.jpg"><img alt="Просто ваши глаза не могут увидеть все 12 точек одновременно. Ninio's extinction illusion. Twelve black dots cannot be seen at once. Ninio, J. and Stevens, K. A. (2000) Variations on the Hermann grid: an extinction illusion. Perception, 29, 1209-1217. The image source is a post by Akiyoshi Kitaoka https://www.facebook.com/akiyoshi.kitaoka/posts/10207806663219295" src="../../../../../../_images/12-points.jpg" style="width: 90%;"/></a> -<figcaption> -<p><span class="caption-text">Просто ваши глаза не могут увидеть все 12 точек одновременно. -Ninio's extinction illusion. Twelve black dots cannot be seen at once. -Ninio, J. and Stevens, K. A. (2000) Variations on the Hermann grid: an extinction illusion. Perception, 29, 1209-1217. -The image source is "<a class="reference external" href="https://www.facebook.com/akiyoshi.kitaoka/posts/10207806663219295">a post</a>" by Akiyoshi Kitaoka.</span></p> -</figcaption> -</figure> -<p>Как и в "Законе Миллера", суть картинки сводится к тому, что у человека есть предел способности <strong>воспринимать</strong> информацию, и если количество единиц поступающей информации превышает этот предел (не зависимо от его природы, будь то особенность работы рецепторов сетчатки или предел возможностей краткосрочной памяти), то начинается "жонглирование", т.е. неспособность рассмотреть (в прямом и в переносном смыслах) всю информацию единовременно и изолированно.</p> -<p>Вероятное объяснение этого явления заключается в том, что:</p> <blockquote> -<div><p>💬 "Your eye's receptors are stimulated and influenced by the activity of neighboring receptors. In a complex, repetitive grid like this, one receptor can have trouble perceiving the dots accurately because of stimulation occurring in a nearby receptor."</p> -<p class="attribution">—<a class="reference external" href="https://www.brainhq.com/brain-resources/brain-teasers/ninios-extinction-illusion/">источник</a></p> +<div><p>📝 "The Product Owner is responsible for maximizing return on investment (ROI)"</p> +<p class="attribution">—"<a class="reference external" href="https://less.works/less/scrum/roles">Scrum Roles</a>" by Craig Larman</p> </div></blockquote> -<p><strong>Внимание</strong> - это избирательная направленность <strong>восприятия</strong>. -Периферийное зрение - это способность видеть те предметы, которые выходят за <strong>фокус</strong> основного <strong>внимания</strong>. -Слово "сфокусировать" - означает "сосредоточить", как в прямом (оптическом), так и в переносном (сконцентрироваться) смыслах. -Основной принцип управления сложностью - это её декомпозиция до такого уровня, над которым обеспечивается перевес умственных возможностей человека. Т.е. когда объем рассматриваемой изолированно сложности "вмещается" в <strong>фокус</strong> внимания человека.</p> -<p>См. также "<a class="reference internal" href="../../../../../soft-skills/icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Принцип ледокола</span></a>".</p> -<blockquote id="emacsway-kent-beck-constantine-s-law"> -<div><p>📝 "These were elucidated in the mid-70s by Yourdon &amp; Constantine in <a class="reference external" href="https://amzn.to/2GsuXvQ">Structured Design</a> and haven't changed. -Their argument goes like this:</p> -<ol class="arabic simple"> -<li><p>We design software to reduce its cost.</p></li> -<li><p>The cost of software is ≈ the cost of changing the software.</p></li> -<li><p>The cost of changing the software is ≈ the cost of the expensive changes (power laws and all that).</p></li> -<li><p>The cost of the expensive changes is generated by cascading changes — if I change this then I have to change that and that, and if I change that then…</p></li> -<li><p>Coupling between elements of a design is this propensity for a change to propagate.</p></li> -<li><p>So, design ≈ cost ≈ change ≈ big change ≈ coupling. Transitively, software design ≈ managing coupling.</p></li> -</ol> -<p>(This skips loads of interesting stuff, but I'm just trying to set up the argument for why rapid decomposition of a monolith into micro-services is counter-productive.)"</p> -<p>Managing Coupling</p> -<p>Note I don't say, "Eliminating coupling." -Decoupling comes with its own costs, both the cost of the decoupling itself and the future costs of unanticipated changes. -The more perfectly a design is adapted to one set of changes, the more likely it is to be blind-sided by novel changes. And so we have the classic tradeoff curve:</p> -<figure class="align-left" id="id9"> -<a class="reference internal image-reference" href="../../../../../../_images/balancing-coupling-decoupling.jpeg"><img alt="Classic tradeoff curve of balancing cost of Coupling vs. cost of Decoupling. The image source is article &quot;Monolith -&gt; Services: Theory &amp; Practice&quot; by Kent Beck https://medium.com/@kentbeck_7670/monolith-services-theory-practice-617e4546a879" src="../../../../../../_images/balancing-coupling-decoupling.jpeg" style="width: 90%;"/></a> -<figcaption> -<p><span class="caption-text">Classic tradeoff curve of balancing cost of Coupling vs. cost of Decoupling. The image source is article "<a class="reference external" href="https://medium.com/@kentbeck_7670/monolith-services-theory-practice-617e4546a879">Monolith -&gt; Services: Theory &amp; Practice</a>" by Kent Beck.</span></p> -</figcaption> -</figure> -<p>You manage coupling one of two ways:</p> -<ol class="arabic simple"> -<li><p>Eliminate coupling. A client and server with hard-coded read() and write() functions are coupled with respect to protocol changes. Change a write() and you'll have to change the read(). Introduce an interface definition language, though, and you can add to the protocol in one place and have the change propagate automatically to read() and write().</p></li> -<li><p>Reduce coupling's scope. If changing one element implies changing ten others, then it's better if those elements are together than if they are scattered all over the system —less to navigate, less to examine, less to test. The number of elements to change is the same, but the cost per change is smaller. (This is also known as the "manure in one pile" principle, or less-aromatically "cohesion".)</p></li> +<p>Однако, значение термина Value гораздо шире, о чем пишет Ken Schwaber в статье "<a class="reference external" href="https://kenschwaber.wordpress.com/2014/03/28/evidence-of-softwares-value-to-an-organization/">Evidence of Software's Value to an Organization</a>", где Value состоит из трех составляющих:</p> +<blockquote> +<div><ol class="arabic simple"> +<li><p>Current value</p></li> +<li><p>Time-to-market</p></li> +<li><p>Ability to innovate</p></li> </ol> -<p class="attribution">—"<a class="reference external" href="https://medium.com/@kentbeck_7670/monolith-services-theory-practice-617e4546a879">Monolith -&gt; Services: Theory &amp; Practice</a>" by Kent Beck</p> </div></blockquote> -<p>Eric Evans дает неплохое определение Constantine's Law нетехническим языком:</p> +<p>Интересно, что таким образом они пытались решить другую проблему, которая тоже связана с балансированием долгосрочных и краткосрочных интересов:</p> <blockquote> -<div><p>💬 "МОДУЛИ дают возможность посмотреть на модель с разных сторон: -во-первых, можно изучить подроб­ности устройства модуля, не вникая в сложное целое; -во-вторых, удобно рассматривать взаимоотношения между модулями, не вдаваясь в детали их внутреннего устройства.</p> -<p>&lt;...&gt;</p> -<p>То, что при делении на модули должна соблюдаться низкая внешняя зависимость (low coupling) при высокой внутренней связности (high cohesion)- это общие слова. -Определения зависимости и связности грешат уклоном в чисто технические, количест­венные критерии, по которым их якобы можно измерить, подсчитав количество ассо­циаций и взаимодействий. -Но это не просто механические характеристики подразде­ления кода на модули, а идейные концепции. -Человек не может одновременно удер­живать в уме слишком много предметов (отсюда низкая внешняя зависимость). -А плохо связанные между собой фрагменты информации так же трудно понять, как неструктурированную "кашу" из идей (отсюда высокая внутренняя связность).</p> -<p>MODULES give people two views of the model: -They can look at detail within a MODULE without being overwhelmed by the whole, or they can look at relationships between MODULES in views that exclude interior detail.</p> -<p>&lt;...&gt;</p> -<p>It is a truism that there should be low coupling between MODULES and high cohesion within them. -Explanations of coupling and cohesion tend to make them sound like technical metrics, to be judged mechanically based on the distributions of associations and interactions. Yet it isn't just code being divided into MODULES, but concepts. -There is a limit to how many things a person can think about at once (hence low coupling). -Incoherent fragments of ideas are as hard to understand as an undifferentiated soup of ideas (hence high cohesion)."</p> -<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> +<div><p>📝 "One common approach is to hire a project manager to oversee the team's day-to-day work. +The project manager does the work that management may feel is too important to ignore but not important enough to distract from their own pressing agendas. +Though this is very common—almost ubiquitous—the approach in fact slows product delivery and may reduce quality and profitability. +First, the organization is building a product rather than carrying out a project. +When project development completes, the product is still in the field and questions of maintenance and added feature development find only awkward answers. +<strong>Organizationally separating product creation from ongoing development ("maintenance") creates many problems.</strong> +Secondly, the company rarely gives the project manager responsibility for value such as ROI or net present value (see Value and ROI), so his or her incentive is to deliver as fast as possible within the financial constraints. +<strong>Without this responsibility, the project manager is more likely to make short-term decisions with long-term consequences, and short-term decisions tend not to have positive long-term consequences.</strong>"</p> +<p class="attribution">—"A Scrum Book: The Spirit of the Game" by Jeff Sutherland, James Coplie, chapter "11 Product Owner"</p> +</div></blockquote> +<p>Какие выводы можно сделать?</p> +<p>Решая одну проблему, они создали другую (см. другие цитаты Jeff Sutherland на этой же странице). +С точки зрения архитектуры, Product Owner становится заинтересованным лицом и теряет нейтралитет своей позиции, а значит, в силу когнитивных искажений и давления обстоятельств, он всегда будет предвзят, и будет руководствоваться краткосрочными бизнес-интересами в ущерб долгосрочным техническим, если только не обладает развитым <a class="reference internal" href="business-concerns/common-planning-errors.html#emacsway-planning-technical-task"><span class="std std-ref">системным мышлением и волей</span></a>.</p> +<p>Ну а поскольку никаких методик разрешения противоречий требований стейкхолдеров Scrum не предлагает, то в ранней версии "The 2011 Scrum Guide™" этот конфликт разрешался тем, что Product Owner не мог навязывать конкретную реализацию, оставляя переменную управления разработкой Quality на усмотрение разработчиков, <a class="reference internal" href="#emacsway-xp1-balancing-business-technical-concerns"><span class="std std-ref">как и в XP1</span></a>:</p> +<blockquote> +<div><p>📝 "They [The Development Team] are self-organizing. +No one (not even the Scrum Master) tells the Development Team how to turn Product Backlog into Increments of potentially releasable functionality;"</p> +<p class="attribution">—"The 2011 Scrum Guide™"</p> +</div></blockquote> +<p>Именно об этом говорит Jeffrey Sutherland в высказывании, к которому мы скоро вернемся.</p> +<p>А вот в гайде 2020 года это звучит уже так:</p> +<blockquote> +<div><p>📝 "They [Scrum Team] are also self-managing, meaning they internally decide who does what, when, and how."</p> +<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> +</div></blockquote> +<p>, где Scrum Team уже включает в себя и Product Owner тоже, что вносит путаницу в распределение обязанностей, так как получается, что Product Owner теперь уже может влиять на реализацию (how). +Причем, сделано это было, как можно догадаться, из-за сложности достижения консенсуса между Product Owner и Development Teams:</p> +<blockquote> +<div><p>📝 "One Team, Focused on One Product</p> +<blockquote> +<div><p>The goal was to eliminate the concept of a separate team within a team that has led to "proxy" or "us and them" behavior between the PO and Dev Team. +There is now just one Scrum Team focused on the same objective, with three different sets of accountabilities: PO, SM, and Developers."</p> </div></blockquote> -</section> -<section id="id3"> -<h2><a class="toc-backref" href="#id15" role="doc-backlink">Оправдано ли качество?</a></h2> -<section id="martin-fowler"> -<h3><a class="toc-backref" href="#id16" role="doc-backlink">Martin Fowler</a></h3> +<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/revisions.html">Changes between 2017 and 2020 Scrum Guides</a>"</p> +</div></blockquote> +<p>Однако, при этом Quality сделали константой, <a class="reference internal" href="#emacsway-xp2-balancing-business-technical-concerns"><span class="std std-ref">как и в XP2</span></a>:</p> <blockquote> -<div><p>📝 "In most contexts higher quality ⇒ expensive. But high internal quality of software allows us to develop features faster and cheaper."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/TradableQualityHypothesis.html">Tradable Quality Hypothesis</a>" by Martin Fowler</p> +<div><p>📝 "During the Sprint: Quality does not decrease;"</p> +<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> </div></blockquote> -<figure class="align-left" id="id10"> -<span id="emacsway-design-stamina-graph"/><a class="reference internal image-reference" href="../../../../../../_images/design-stamina-graph.png"><img alt="The pseudo-graph plots delivered functionality (cumulative) versus time for two imaginary stereotypical projects: one with good design and one with no design. The image from &quot;Design Stamina Hypothesis&quot; by Martin Fowler. https://martinfowler.com/bliki/DesignStaminaHypothesis.html" src="../../../../../../_images/design-stamina-graph.png" style="width: 90%;"/></a> -<figcaption> -<p><span class="caption-text">The pseudo-graph plots delivered functionality (cumulative) versus time for two imaginary stereotypical projects: one with good design and one with no design. The image from "<a class="reference external" href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>" by Martin Fowler.</span></p> -</figcaption> -</figure> +<p>А все отклонения продукта должны устраняться как можно скорее:</p> <blockquote> -<div><p>📝 "... the true value of internal quality - that it's the enabler to speed. The purpose of internal quality is to go faster."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/TradableQualityHypothesis.html">Tradable Quality Hypothesis</a>" by Martin Fowler</p> +<div><p>📝 "If any aspects of a process deviate outside acceptable limits or if the resulting <strong>product is unacceptable</strong>, the process being applied or the <strong>materials being produced must be adjusted</strong>. +The adjustment must be made <strong>as soon as possible to minimize further deviation</strong>".</p> +<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> </div></blockquote> +<p>И предупредили о проблеме дисбаланса интересов:</p> <blockquote> -<div><p>📝 "The value of good software design is economic: you can continue to add new functionality quickly even as the code-base grows in size."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>" by Martin Fowler</p> +<div><p>📝 "Adaptation becomes more difficult when the people involved are not empowered or self-managing."</p> +<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> </div></blockquote> +<p>Сам Ken Schwaber под "прозрачностью" понимает полное отсутствие Technical Debt:</p> <blockquote> -<div><p>📝 "We usually perceive that it costs more to get higher quality, but software internal quality actually reduces costs."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/is-quality-worth-cost.html">Is High Quality Software Worth the Cost?</a>" by Martin Fowler</p> +<div><p>📝 "Transparency means the software is ready. +It can either be immediately deployed or built upon without regression. +<strong>It has no technical debt.</strong>"</p> +<p class="attribution">—"<a class="reference external" href="https://kenschwaber.wordpress.com/2014/04/09/can-software-developers-meet-the-needs/">Can Software Developers Meet the Need?</a>" by Ken Schwaber</p> </div></blockquote> <blockquote> -<div><p>📝 "The fundamental role of internal quality is that it lowers the cost of future change. -But there is some extra effort required to write good software, which does impose some cost in the short term."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/is-quality-worth-cost.html">Is High Quality Software Worth the Cost?</a>" by Martin Fowler</p> +<div><p>📝 "I also reminded the team members that Scrum requires transparency. +When the Team demonstrates functionality to the Product Owner and stakeholders at the Sprint review, those viewing the functionality have a right to presume that the code is complete, meaning not only that the code is written but also that it is written according to standards, easy to read, refactored, unit tested, harness tested, and even functionality tested. +If this isn't true, the Team isn't allowed to demonstrate the functionality, because in that case, the viewer's assumption would be incorrect."</p> +<p class="attribution">—"Agile Project Management with Scrum" by Ken Schwaber</p> </div></blockquote> +<p>Jeff Sutherland возлагает устранение Technical Debt на Definition of Done:</p> <blockquote> -<div><p>📝 "The whole point of good design and clean code is to make you go faster - if it didn't people like Uncle Bob, Kent Beck, and Ward Cunningham wouldn't be spending time talking about it."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebtQuadrant.html">Technical Debt Quadrant</a>" by Martin Fowler</p> +<div><p>📝 "In the long run, Definition of Done helps to remove technical debt."</p> +<p>&lt;...&gt;</p> +<p>With a good Definition of Done, the team will avoid technical debt."</p> +<p class="attribution">—"A Scrum Book: The Spirit of the Game" by Jeff Sutherland, James Coplie, chapter "82 Definition of Done"</p> </div></blockquote> +<p>Jeff Sutherland так же советует устранять технические проблемы немедленно, в главе "81 Whack the Mole" книги "A Scrum Book: The Spirit of the Game" by Jeff Sutherland, James Coplie (текст слишком объемный для его цитирования).</p> +<p>А баланс бизнес и технических интересов обеспечивается тем, что решения Product Owner инспектируемы:</p> <blockquote> -<div><p>📝 "Sadly, software developers usually don't do a good job of explaining this situation. -Countless times I've talked to development teams who say "they (management) won't let us write good quality code because it takes too long". -Developers often justify attention to quality by justifying through the need for proper professionalism. -But this moralistic argument implies that this quality comes at a cost - dooming their argument. -The annoying thing is that the resulting crufty code both makes developers' lives harder, and costs the customer money. -When thinking about internal quality, I stress that we should only approach it as an economic argument. -High internal quality reduces the cost of future features, meaning that putting the time into writing good code actually reduces cost.</p> -<p>This is why the question that heads this article misses the point. -The "cost" of high internal quality software is negative. -The usual trade-off between cost and quality, one that we are used to for most decisions in our life, does not make sense with the internal quality of software. -(It does for external quality, such as a carefully crafted user-experience.) -Because the relationship between cost and internal quality is an unusual and counter-intuitive relationship, it's usually hard to absorb. -But understanding it is critical to developing software at maximum efficiency."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/is-quality-worth-cost.html">Is High Quality Software Worth the Cost?</a>" by Martin Fowler</p> +<div><p>📝 "For Product Owners to succeed, the entireorganization must respect their decisions. +These decisions are visible in the content and ordering of the Product Backlog, +and through the <strong>inspectable</strong> Increment at the Sprint Review."</p> +<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> </div></blockquote> +<p>А инспектирует их сбалансированный круг внутренних (команда) и внешних стейкхолдеров:</p> <blockquote> -<div><p>📝 "Рефакторинг ускоряет написание программ</p> -<p>В конечном итоге все сказанное сводится к одному: рефакторинг ускоряет написание программ.</p> -<p>Создается впечатление внутреннего противоречия. -Когда я рассказываю о рефакторинге, становится очевидно, что он повышает качество кода. -Улучшение проекта, повышение удобочитаемости, уменьшение количества ошибок — все это способствует качеству кода. -Но разве скорость разработки не снижается из-за всего этого?</p> -<p>Когда я общаюсь с разработчиками программного обеспечения, которые какое-то время работали над системой, я часто слышу, что сначала им удалось быстро продвинуться вперед, но теперь добавление новых функциональных возможностей занимает гораздо больше времени. -Каждая новая функция требует все больше и больше времени, чтобы понять, как вписать ее в существующую кодовую базу, а после ее добавления часто возникают ошибки, исправление которых занимает еще больше времени. -Кодовая база начинает выглядеть как серия исправлений, исправляющих предыдущие исправления, и требуются навыки археолога, чтобы выяснить, как все это работает. -Все это замедляет добавление новых функциональных возможностей до такой степени, что зачастую разработчики хотят начать все заново с чистого листа.</p> -<p>Визуализировать это положение вещей можно с помощью следующего псевдографика.</p> -<p>Но некоторые команды сообщают о другом опыте. -Они утверждают, что могут добавлять новые функциональные возможности быстрее, потому что они могут использовать уже существующий код, опираясь на то, что уже имеется в наличии.</p> -<p>Разница между этими проектами заключается во внутреннем качестве программного обеспечения. -Программное обеспечение с хорошим внутренним проектом позволяет легко найти, какие нужно внести изменения, чтобы добавить новую функциональную возможность, и где. -Хорошая модульность позволяет понять только небольшое подмножество кода, в которое нужно вносить изменения. -Если код понятен, меньше вероятность внести ошибку, а если это и произойдет, процесс отладки будет намного проще. -Так кодовая база превращается в платформу для создания новых функциональных возможностей для своей предметной области.</p> -<p>Я называю этот эффект гипотезой стойкости проекта (<a class="reference external" href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>): -создавая хороший внутренний проект, мы повышаем стойкость программного обеспечения, позволяющую двигаться быстрее. -Я не могу доказать, что это так, поэтому называю это утверждение гипотезой. -Но так подсказывает мой опыт, а также опыт сотен отличных программистов, с которыми я познакомился за свою карьеру.</p> -<p>Двадцать лет назад общепринятым было мнение, что для создания хорошего проекта нужно завершить проектирование до начала кодирования, потому что, как только мы написали код, мы можем столкнуться только с ухудшением и упадком. -Рефакторинг меняет эту картину. -Теперь мы знаем, что можем улучшить проект существующего кода, так что мы можем формировать и улучшать проект с течением времени, даже когда меняются потребности программы. -Поскольку очень сложно сделать хороший проект заранее, рефакторинг становится жизненно важным.</p> -<p>Refactoring Helps Me Program Faster</p> -<p>In the end, all the earlier points come down to this: Refactoring helps me develop code more quickly.</p> -<p>This sounds counterintuitive. -When I talk about refactoring, people can easily see that it improves quality. -Better internal design, readability, reducing bugs—all theseimprove quality. -But doesn't the time I spend on refactoring reduce the speed of development?</p> -<p>When I talk to software developers who have been working on a system for a while, I often hear that they were able to make progress rapidly at first, but now it takes much longer to add new features. -Every new feature requires more and more time to understand how to fit it into the existing code base, and once it's added, bugs often crop up that take even longer to fix. -The code base starts looking like a series of patches covering patches, and it takes an exercise in archaeology to figure out how things work. -This burden slows down adding new features — to the point that developers wish they could start again from a blank slate.</p> -<p>I can visualize this state of affairs with <a class="reference internal" href="#emacsway-design-stamina-graph"><span class="std std-ref">the following pseudograph</span></a>.</p> -<p>But some teams report a different experience. -They find they can add new features faster because they can leverage the existing things by quickly building on what's already there.</p> -<p>The difference between these two is the internal quality of the software. -Software with a good internal design allows me to easily find how and where I need to make changes to add a new feature. -Good modularity allows me to only have to understand a small subset of the code base to make a change. -If the code is clear, I'm less likely to introduce a bug, and if I do, the debugging effort is much easier. -Done well, my code base turns into a platform for building new features for its domain.</p> -<p>I refer to this effect as the <a class="reference external" href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>: -By putting our effort into a good internal design, we increase the stamina of the software effort, allowing us to go faster for longer. -I can't prove that this is the case, which is why I refer to it as a hypothesis. -But it explains my experience, together with the experience of hundreds of great programmers that I've got to know over my career.</p> -<p>Twenty years ago, the conventional wisdom was that to get this kind of good design, it had to be completed before starting to program — because once we wrote the code, we could only face decay. -Refactoring changes this picture. -We now know we can improve the design of existing code—so we can form and improve a design over time, even as the needs of the program change. -Since it is very difficult to do a good design up front, refactoring becomes vital to achieving that virtuous path of rapid functionality."</p> -<p class="attribution">—"Refactoring: Improving the Design of Existing Code" 2nd edition by Martin Fowler, Kent Beck, перевод И.В. Красикова под редакцией С.Н. Тригуб</p> +<div><p>📝 "Scrum Definition: The <strong>Scrum Team and its stakeholders inspect</strong> the results and adjust for the next Sprint.</p> +<p>&lt;...&gt;</p> +<p>Sprint Review: During the event, the <strong>Scrum Team and stakeholders review</strong> what was accomplished in the Sprint +and what has changed in their environment."</p> +<p class="attribution">—"<a class="reference external" href="https://scrumguides.org/scrum-guide.html">The 2020 Scrum Guide™</a>"</p> </div></blockquote> +<p>Это работает для маленьких команд. +В больших коллективах лучше работают практики для работы со стейкхолдерами типа QAW, Mini-QAW, etc.</p> +</section> +<section id="id8"> +<h5><a class="toc-backref" href="#id23" role="doc-backlink">К первоисточнику за сутью</a></h5> +<p>Bertrand Meyer был прав - лучший способ понять суть вещей - это обратиться к первоисточнику. +Jeffrey Sutherland о том, как и зачем он ввел роль Product Owner:</p> <blockquote> -<div><p>📝 "In its common usage, evolutionary design is a disaster. -The design ends up being the aggregation of a bunch of ad-hoc tactical decisions, each of which makes the code harder to alter. -In many ways you might argue this is no design, certainly it usually leads to a poor design. -As Kent puts it, <strong>design is there to enable you to keep changing the software easily in the long term.</strong> -<strong>As design deteriorates, so does your ability to make changes effectively.</strong> -You have the state of software entropy, over time the design gets worse and worse. -Not only does this make the software harder to change, it also makes bugs both easier to breed and harder to find and safely kill. -This is the "code and fix" nightmare, where the bugs become exponentially more expensive to fix as the project goes on."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler</p> +<div><p>📝 "When I started the first Scrum team in 1993, I didn't have a Product Owner. +I was part of the leadership team and had a bunch of other responsibilities besides figuring out exactly what the team should do in each Sprint. +I carried out management and marketing duties, dealt with customers, and plotted strategy. +But in that first Sprint I figured I could handle the Backlog. +I just needed to make sure I had enough "stories" and features for the team to work on during the next Sprint. +The problem was, after the second Sprint we introduced the Daily Stand-up meeting. +Velocity went up 400 percent in the next Sprint, and the team finished in a week what we thought would take us a month. +There was no more Backlog for them to work on! I thought I'd have a month to create more "stories." A great problem to have, admittedly, but one that had to be addressed. +So I thought about this role of Product Owner and what qualities someone would need to execute it properly.</p> +<p>My inspiration for the role came from Toyota's Chief Engineer. +A Chief Engineer at Toyota is responsible for a whole product line, such as the Corolla or the Camry. +To do this, they have to draw on the talents of groups specializing in body engineering, or chassis, or electrical, or whatever. +The Chief Engineer has to draw from all those groups to create a cross-functional team capable of creating a car. +Outside of Toyota everyone thinks of these legendary Chief Engineers (or Shusas, as they were originally called) as all-powerful leaders of the "Toyota Way." And in a way they are. +But what they don't have is authority. +No one reports to them—rather, they report to their own groups. +People can tell Chief Engineers that they're wrong, so they have to make sure they're right. +They don't give anyone performance appraisals or promotions or raises. +But they do decide on the vision of the car, and how the car will be made—by persuasion, not coercion.</p> +<p>It's this idea that I wanted to embody within Scrum. +John Shook of the Lean Enterprise Institute once began his description of the Chief Engineer role by quoting the US Marine Corps leadership manual:</p> +<p>"An individual's responsibility for leadership is not dependent on authority.… the deep-rooted assumption that authority should equal responsibility is the root of much organizational evil. +I believe misunderstanding around this issue is rampant, problematic, and runs so deep in our consciousness that we don't even realize it." [Shook, John. "The Remarkable Chief Engineer." Lean Enterprise Institute, February 3, 2009]</p> +<p>Reflecting on my time at West Point and in Vietnam, I found myself agreeing that leadership has nothing to do with authority. +Rather, it has to do with—among other things—knowledge and being a servant-leader. +The Chief Engineer can't simply say something has to be done a particular way. +He has to persuade, cajole, and demonstrate that his way is the right way, the best way. +It usually takes someone with thirty years of experience to fill the role. +I wanted that in Scrum, but I'm also well aware that very few people have that level of skill and experience. +So I split the role in two, giving the Scrum Master the how and the Product Owner the what.</p> +<p>Even in those early days of Scrum I knew that I needed someone who was deeply connected to the customer. +The Product Owner needed to be able to deliver feedback to the team from the customer each and every Sprint. +They needed to spend half their time talking to the people buying the product (getting their thoughts on the latest incremental release and how it delivered value) and half their time with the team creating the Backlog (showing them what the customers valued and what they didn't)."</p> +<p class="attribution">—"Scrum: The Art of Doing Twice the Work in Half the Time" by Jeffrey Sutherland</p> </div></blockquote> +<p>Отдельно следует выделить два критически важных момента, непонимание которых является корнем проблем большинства Scrum-проектов:</p> <blockquote> -<div><p>📝 "If you're a manager or customer how can you tell if the software is well designed? -It matters to you because poorly designed software will be more expensive to modify in the future."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler</p> +<div><p>📝 "So I split the role in two, giving the Scrum Master the <strong>how</strong> and the Product Owner the <strong>what</strong>.</p> +<p>&lt;...&gt;</p> +<p>The Scrum Master and the team are responsible for <strong>how fast they're going and how much faster they can get</strong>. +The Product Owner is accountable for <strong>translating the team's productivity into value</strong>."</p> +<p class="attribution">—"Scrum: The Art of Doing Twice the Work in Half the Time" by Jeffrey Sutherland</p> +</div></blockquote> +<p>Иными словами, Product Owner отвечает за то, что нужно сделать (problem space), а команда отвечает за правильный выбор надлежащей реализации (solution space).</p> +<p>С команды не снимается ответственность за ухудшение темпов разработки, если причиной этого ухудшения стали технические решения о реализации, на которые команда согласилась против своего желания под давлением Product Owner, полагая, что тем самым она делегирует ему свою ответственность. +Именно эту ошибку я нередко наблюдал у малоопытных разработчиков, и, увы, когда падение внутреннего качества программы начинало вызывать проблемы со сроками, то аргументы типа "Вы же сами так решили" и "Вас же предупреждали" не помогали им переложить вину на Product Owner. +Как правило, за этим следовали кадровые решения. +Зачастую Product Owner уверен в том, что, если команда согласилась, то она знает что делает и трезво оценивает ситуацию.</p> +<p>Тут нужно заметить, что Product Owner в Scrum отвечает как за функциональные, так и за нефункциональные требования, в отличии от, например, SAFe, где за NFR отвечает системный архитектор.</p> +<p>Другое проявление этой же ловушки - это когда все думают, что "<a class="reference internal" href="business-concerns/common-planning-errors.html#emacsway-agile-common-planning-errors"><span class="std std-ref">позже исправим</span></a>". +Однако, самый выгодный момент для исправления, если смотреть сугубо с математической точки зрения, - это именно сейчас, пока величина технического долга наименьшая. +Чем больше накапливается <a class="reference internal" href="business-concerns/compound-interest.html#emacsway-compound-interest"><span class="std std-ref">технический долг</span></a>, тем больше <a class="reference internal" href="../../agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">падает скорость разработки</span></a>, и тем меньше остается ресурсов на технические задачи. +Потом будет менее выгодное положение, чем сейчас.</p> +<blockquote> +<div><div class="line-block"> +<div class="line">- We don't have time to do it right!</div> +<div class="line">- Do you have time to do it twice?</div> +</div> +<p class="attribution">—<a class="reference external" href="https://www.infoq.com/presentations/microservices-data-centric">Randy Shoup</a>, VP Engineering at Stitch Fix in San Francisco</p> +</div></blockquote> +<p>Эту ситуацию следует отличать от принципа <a class="reference internal" href="../../../../uncertainty-management/adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>, который отличается тем, что:</p> +<ol class="arabic simple"> +<li><p>YAGNI управляет неопределенностью в отношении востребованности реализации.</p></li> +<li><p>YAGNI оправдан лишь в том случае, когда стоимость реализации в будущем не будет существенно дороже, чем сейчас.</p></li> +<li><p>YAGNI имеет целью сгладить "<a class="reference external" href="https://martinfowler.com/bliki/DesignPayoffLine.html">Design Payoff Line</a>" верного решения, а не подменить его неверным.</p></li> +<li><p>YAGNI имеет целью достигнуть наилучшей экономики разработки в балансе краткосрочных и долгосрочных интересов, а не пожертвовать долгосрочными интересами в угоду краткосрочным.</p></li> +<li><p>YAGNI должен способствовать эволюции программы, а не препятствовать ей.</p></li> +</ol> +<p>YAGNI как раз и является тем самым инструментом, который позволяет максимально удовлетворить требования Product Owner, не жертвуя при этом качеством программы.</p> +</section> +</section> +<section id="atam-in-agile"> +<span id="emacsway-agile-atam"/><h4><a class="toc-backref" href="#id24" role="doc-backlink">ATAM in Agile</a></h4> +<p>Использование ATAM в Agile-разработке (скачивание свободное):</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.researchgate.net/publication/276317148_Insights_from_15_Years_of_ATAM_Data_Towards_Agile_Architecture">Insights from 15 Years of ATAM Data: Towards Agile Architecture</a>" by Stephany Bellomo, Ian Gorton, and Rick Kazman, IEEE Software, September/October, 2015, 32:5, 38-45</p></li> +</ul> +<blockquote> +<div><p>📝 "Agile teams strive to <strong>balance short term feature development with longer term quality concerns</strong>. +These evolutionary approaches often hit a "complexity wall" from the cumulative effects of unplanned changes, resulting in unreliable, poorly performing software. +Consequently, there is renewed focus on approaches to address architectural concerns within the Agile community. +We present an analysis of quality attribute concerns from 15 years of Architecture Trade-off Analysis Method data, gathered from 31 projects. +We found that modifiability is the dominant concern across all project types; additionally there was considerable focus on performance, availability, and interoperability. +For information technology projects, a relatively new quality—deployability—has emerged as a key concern. +Our results provide insights for Agile teams allocating architecture-related tasks to iterations. +For example they can use these results to create checklists for release planning or retrospectives to help assess whether a given quality should be addressed to support future needs.</p> +<p>&lt;...&gt;</p> +<p>One of the major challenges Agile teams face in building an architecture foundation is balancing the competing concerns of delivery of near-term functional requirements (based on the Agile philosophy of delivering user value early and often) and near and long term quality attribute goals (without which the project can grind to a halt as system complexity makes efficient modifications impossible). +In particular, quality attribute (QA) prioritization can be especially difficult in early increments, and a wrong decision can have serious ramifications resulting in hard-to-modify, unreliable, slow, or insecure systems [5].</p> +<ol class="arabic simple" start="5"> +<li><ol class="upperalpha simple" start="19"> +<li><p>Bellomo, R. Nord, and I. Ozkaya. A Study of Enabling Factors for Rapid Fielding; Combined Practices to Balance Tension between Speed and Stability Proceedings of International Conference on Software Engineering 2013."</p></li> +</ol> +</li> +</ol> +<p class="attribution">—"<a class="reference external" href="https://www.researchgate.net/publication/276317148_Insights_from_15_Years_of_ATAM_Data_Towards_Agile_Architecture">Insights from 15 Years of ATAM Data: Towards Agile Architecture</a>" by Stephany Bellomo, Ian Gorton, and Rick Kazman, IEEE Software, September/October, 2015</p> </div></blockquote> +<p>Подробнее про ATAM можно узнать здесь:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=5177">ATAM: Method for Architecture Evaluation</a>" by Rick Kazman, Mark H. Klein, Paul C. Clements (<a class="reference external" href="https://resources.sei.cmu.edu/asset_files/TechnicalReport/2000_005_001_13706.pdf">pdf</a>, <a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=513908">collection</a>)</p></li> +</ul> +<p>Интересно, что обе эти статьи упоминаются в стандарте "<a class="reference external" href="https://www.iso.org/standard/73436.html">ISO/IEC/IEEE 42030:2019 Software, systems and enterprise — Architecture evaluation framework</a>".</p> +<p>Смотрите также статьи про Mini-QAW в Agile:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://re-magazine.ireb.org/articles/discover-quality-requirements-with-the-mini-qaw">Discover Quality Requirements with the Mini-QAW. A short and fun elicitation workshop for Agile teams and architects.</a>" by Thijmen de Gooijer Michael Keeling Will Chaparro</p></li> +<li><p>"<a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=4995">Quality Attribute Workshop Participants Handbook</a>" by Mario R. Barbacci, Robert J. Ellison, Charles B. Weinstock, William G. Wood (<a class="reference external" href="https://resources.sei.cmu.edu/asset_files/SpecialReport/2000_003_001_13640.pdf">pdf</a>)</p></li> +<li><p>"<a class="reference external" href="https://resources.sei.cmu.edu/asset_files/Presentation/2014_017_101_89563.pdf">Facilitating the Mini-Quality Attributes Workshop. A Lightweight, Architecture-Focused Method.</a>" by Will Chaparro IBM, Michael Keeling IBM</p></li> +</ul> +<p>Смотрите также о "Lightweight Architecture Evaluation (LAE)" в "Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman.</p> +</section> +<section id="emacsway-agile-balancing-business-technical-concerns-with-fixed-iteration-ratio"> +<span id="id9"/><h4><a class="toc-backref" href="#id25" role="doc-backlink">Фиксированная часть итерации на технические задачи</a></h4> <blockquote> -<div><p>📝 "From the very earliest days of agile methods, people have asked what role there is for architectural or design thinking. -A common misconception is that since agile methods drop the notion of a detailed up-front design artifact, that there is no room for architecture in an agile project. -In my keynote at the first-ever agile conference, I pointed out that design was every bit as important for agile projects, but it manifests itself differently, becoming an evolutionary approach."</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/agile.html">Agile Software Development</a>" by Martin Fowler</p> +<div><p>📝 "Business should sequence stories. +Business people understand uncertainty in estimates. +They face risk all the time with financial projections. +They also understand the cost of reworking in the cases where reworking is an issue. +If they wish to run a risk in order to get better value now, it is really their call. +It is the programmers' task to make the risk visible, not to make the decision for the customer.</p> +<p>While this arrangement is the ideal, sometimes you need something extra to make it work, perhaps allowing developers to choose a certain amount of [technical high-risk] stories per iteration so that they can bring the risk forward."</p> +<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 13. Ordering the Stories :: Negotiating Between the Two"</p> </div></blockquote> -</section> -<section id="kent-beck"> -<h3><a class="toc-backref" href="#id17" role="doc-backlink">Kent Beck</a></h3> <blockquote> -<div><p>📝 "Nothing kills speed more effectively than poor internal quality."</p> -<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler</p> +<div><p>📝 "Я всё еще считаю технику технических историй классной и часто её использую. +Мелкие тех-истории, просто встраиваются в ежедневную работу, в то время как большие записываются в тех беклог, видимый product owner'у, но управляемый командой. +Команда и product owner договариваются о правиле, к примеру: 10-20% нашего времени мы используем на тех-истории. +Такой подход не требует придумывать сложные схемы, как focus factor или time reports, просто используйте интуицию. +Спросите на ретроспективе: "Грубо, сколько нашей ёмкости спринта ушло на тех-истории, и кажется ли, что это была хорошая инвестиция?</p> +<p>I still find tech stories to be a great pattern and use it a lot. +Smaller tech stories are just embedded into the day-to-day work, while larger stories are written down and placed in a tech backlog, visible to the product owner but managed by the team. +The team and product owner agree on a guideline such as "10-20% of our time is spent on tech stories". +No need for elaborate tracking schemes like focus factor or time reports, just use gut feel. +Ask at the retro, "Roughly how much of our sprint capacity did we spend on tech stories, and did that feel about right?"".</p> +<p class="attribution">—"Scrum and XP from the Trenches: How We Do Scrum" 2nd edition by Henrik Kniberg, перевод под редакцией Алексея Кривицкого</p> </div></blockquote> +</section> +<section id="open-agile-architecture"> +<h4><a class="toc-backref" href="#id26" role="doc-backlink">Open Agile Architecture™</a></h4> <blockquote> -<div><p>📝 "... the activity of design is not an option. It must be given serious thought for software development to be effective."</p> -<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> +<div><p>📝 "It is worth, at this point, returning to Fowler's distinction [Fowler 2019] between code refactoring and architectural restructuring. Fowler would strongly promote the view that code refactoring requires no justification; rather it is part of a developer's "day job". This does not mean that we have to take on a massive code restructuring exercise for a legacy codebase; on the contrary, there may be no reason whatsoever to restructure the code for a stable legacy project. However, that said, developers should refactor their code when the opportunity arises. Such activity constitutes a "Type 2" decision as documented in [Ries 2011].</p> +<p>Architectural refactoring (restructuring), however, often requires explicit investment because the required effort is significant. In such cases, it is incumbent on development teams and architects to "sell" the refactoring in monetary, time, or customer success terms. For example, "if we perform refactoring A, the build for Product B will be reduced by seven minutes, resulting in us being able to deploy C times more frequently per day"; or, "implementing refactoring D will directly address key Customer E's escalated pain point; their annual subscription and support fee is $12 million per annum". Note, however, that claims that "refactoring F will make us G% more productive" should be avoided as software productivity is notoriously difficult to measure."</p> +<ul class="simple"> +<li><p>[Fowler 2019] Refactoring: Improving the Design of Existing Code, by Martin Fowler, January 2019, published by Addison-Wesley</p></li> +<li><p>[Ries 2011] The Lean Startup: How Constant Innovation Creates Radically Successful Businesses, by Eric Ries, October 2011, published by Portfolio Penguin</p></li> +</ul> +<p class="attribution">—"Open Agile Architecture™" by The Open Group, Chapter "<a class="reference external" href="https://pubs.opengroup.org/architecture/o-aa-standard-single/#KLP-CAR-justifying">6.5.1. Justifying Ongoing Investment in Architectural Refactoring</a>"</p> </div></blockquote> +</section> +<section id="id10"> +<h4><a class="toc-backref" href="#id27" role="doc-backlink">Системное мышление</a></h4> +<p>См. "<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems Thinking</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">на русском</a>).</p> +</section> +</section> +</section> +<section id="id11"> +<h2><a class="toc-backref" href="#id28" role="doc-backlink">Психологическая сторона вопроса</a></h2> +<p>Проблеме достижения понимания между представителями бизнеса и техническими специалистами посвятили свои статьи даже такие всемирно-известные светила, как Gregor Hohpe, который пытался объяснить бизнесу важность архитектурных решений на примере <a class="reference internal" href="business-concerns/architecture-options.html#emacsway-architecture-options"><span class="std std-ref">фондовых опционов</span></a>.</p> +<p>А Ward Cunningham предложил использовать метафору <a class="reference internal" href="business-concerns/compound-interest.html#emacsway-compound-interest"><span class="std std-ref">сложного процента (TechnicalDebt)</span></a>, хорошо демонстрирующую экспоненциальную деградацию velocity при дисбалансе решений в пользу краткосрочных бизнес-интересов.</p> +<p>Даже основатели Agile, такие, как Ron Jeffries, имели сложности в достижении понимания с представителями бизнеса, и термин Story Point возник именно потому, что они <a class="reference external" href="https://twitter.com/RonJeffries/status/1052858860539658240?s=20">не смогли объяснить представителю бизнеса, почему 2 идеальных дня занимали 5 календарных дней</a>:</p> <blockquote> -<div><p>📝 "Качество — это еще одна весьма странная переменная. -Зачастую, настаивая на улучшении качества, мы можете завершить проект быстрее, чем запланировано. -Или вы можете успеть сделать больше за заданный интервал времени. -Именно это случилось со мной, когда я приступил к разработке тестов для программного модуля, работа над которым описывалась в главе 2. -Как только я закончил работу над всеми тестами, я был настолько уверен в своем коде, что смог разработать код модуля существенно быстрее, без каких-либо липших сомнений и размышлений. -Я смог подчистить мою систему с меньшим количеством усилий, в результате я существенно упростил дальнейшую разработку. -Мне часто приходится наблюдать, как подобное происходит с целыми командами разработчиков. -Как только они приступают к тестированию или как только они разрабатывают общие для всех стандарты кодирования, работа начинает идти существенно быстрее.</p> -<p>Существует весьма странная зависимость между внутренним и внешним качеством. -Внешнее качество — это качество, измерением которого занимается заказчик. -Внутреннее качество оценивается программистами. -Если вы намерены временно пожертвовать внутренним качеством для того, чтобы сократить время разработки, и при этом надеетесь на то, что внешнее качество не пострадает слишком сильно, имейте в виду, что вы стремитесь к достижению краткосрочной цели. -Возможно, закрыв глаза на качество внутренней отделки, вам удастся сэкономить пару недель или даже месяц, однако с течением времени количество внутренних проблем может увеличиться настолько, что разрабатываемую вами систему будет чрезвычайно сложно сопровождать и развивать; -кроме того, возможно, вам не удастся достичь приемлемого уровня внешнего качества.</p> -<p>Quality is another strange variable. -Often, by insisting on better quality you can get projects done sooner, or you can get more done in a given amount of time. -This happened to me when I started writing unit tests (as described in Chapter 2, A Development Episode, page 7). -As soon as I had my tests, I had so much more confidence in my code that I wrote faster, without stress. -I could clean up my system more easily, which made further development easier. -I've also seen this happen with teams. -As soon as they start testing, or as soon as they agree on coding standards, they start going faster.</p> -<p>There is a strange relationship between internal and external quality. -External quality is quality as measured by the customer. -Internal quality is quality as measured by the programmers. -Temporarily sacrificing internal quality to reduce time to market in hopes that external quality won't suffer too much is a tempting short-term play. -And you can often get away with making a mess for a matter of weeks or months. -Eventually, though, internal quality problems will catch up with you and make your software prohibitively expensive to maintain, or unable to reach a competitive level of external quality."</p> -<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 4. Four Variables :: Interactions Between the Variables", перевод ООО Издательство "Питер"</p> +<div><p>📝 "we estimated stories initially in "ideal time", later in points, tracked number accomplished to adjust how many to pull each iteration. +switched to points because ideal time confused people (why did 2 day story take 5 days).</p> +<p>it worked, i think, because we had low politics."</p> +<p class="attribution">—<a class="reference external" href="https://twitter.com/RonJeffries/status/1052858860539658240?s=20">Ron Jeffries</a></p> </div></blockquote> +<p>По словам Craig Larman, проблемы могут возникать даже в таких компаниях, как Microsoft, являющихся "колыбелью архитектуры" (откуда вышли такие авторы, как Steve McConnell), см. "<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems Thinking</a>" by Craig Larman (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">на русском</a>).</p> +<p>Нужно учитывать еще и психологическую составляющую.</p> +<p>Технарь всегда будет отстаивать внутреннее качество программы потому, что от этого зависит его velocity. +Он понимает, что за сорванные сроки виноватым будет именно он. +И даже, если руководство не обвинит его явно, но оно может это запомнить ("взять на карандаш") и учесть это в будущем при принятии кадровых решений (что вызывает еще больше ежедневного страха из-за неопределенности будущего).</p> +<p>Наконец, представитель бизнеса, который сегодня выдает индульгенции на снижение внутреннего качества программы, завтра может быть заменен другим представителем, который эти индульгенции может легко отозвать, и технари останутся с проблемой наедине. +Качество кода не исправляется так же быстро, как отзываются индульгенции, что ставит разработчиков в зависимое положение от конкретной персоны, которая, вероятно, не будет работать в одной и той же должности вечно.</p> +<p>Эти риски создают неопределенность, которая, в результате действия психологического "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%BE%D0%B4%D0%BD%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Эффекта Неоднозначности</a>", вынуждает технаря отстаивать решение, обладающее наименьшей неопределенностью (т.е. настаивать на выполнении технической задачи). +Возникает "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологическая Защита</a>", которая может перерасти в открытый конфликт. +Этот эффект дополнительно еще мультиплицируется распространенным среди технарей "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC_%D1%81%D0%B0%D0%BC%D0%BE%D0%B7%D0%B2%D0%B0%D0%BD%D1%86%D0%B0">Эффектом Самозванца</a>".</p> +<p>Страх неопределенности возникает и у представителя бизнеса. +Зачастую он не уверен в том, хватит ли команде квалификации, чтобы эффективно использовать выделенные ресурсы на технические задачи, и зачастую эта неуверенность подкреплена негативным опытом в прошлом. +Эти страхи, действительно, обоснованы, поскольку на рынке не так уж и много специалистов, способных писать экономически высокоэффективный код. +В силу психологического "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%BE%D0%B4%D0%BD%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">Эффекта Неоднозначности</a>", возникает стремление к варианту, обладающему наименьшей неопределенностью, т.е. лучше "запилить еще одну осязаемую бизнес-фичу" вместо того, чтобы потратить ресурсы на призрачную возможность повысить velocity.</p> +<p>Также нужно учитывать и "<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%BD%D0%B5%D0%B4%D0%B0%D0%B2%D0%BD%D0%B5%D0%B3%D0%BE">Эффект Недавнего</a>". +Психолог, нобелевский лауреат Даниэль Канеман выделил «правило пик-конец» нашей памяти. +Мы помним прошлое неравномерно. +Наибольший вес мы придаем двум видам событий: тем, что вызвали максимальные эмоции и тем, которые произошли недавно.</p> +<p>В силу <a class="reference internal" href="../../../../../../soft-skills/cognitive-biases.html#emacsway-cognitive-biases"><span class="std std-ref">когнитивных искажений</span></a>, технарь всегда будет недооценивать бизнес-потребности, а бизнесмен - технические потребности. +Это нормально. +К тому же, представители бизнеса всегда находится под давлением других стейкхолдеров бизнес-группы. +Хорошая организация процессов должна взаимокомпенсировать эти перекосы.</p> <blockquote> -<div><p>📝 "Why can't you just listen, write a test case, make it run, listen, write a test case, make it run indefinitely? -Because we know it doesn't work that way. -You can do that for a while. -In a forgiving language you may even be able to do that for a long while. -Eventually, though, you get stuck. -The only way to make the next test case run is to break another. -Or the only way to make the test case run is far more trouble than it is worth. -Entropy claims another victim.</p> -<p>The only way to avoid this is to design. -Designing is creating a structure that organizes the logic in the system. -Good design organizes the logic so that a change 45 in one part of the system doesn't always require a change in another part of the system. -Good design ensures that every piece of logic in the system has one and only one home. -Good design puts the logic near the data it operates allows the extension of the system with changes in only one place."</p> -<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> +<div><p>📝 "Software development is risky. +<strong>People involved have many fears of what may go wrong.</strong> +To develop effectively we must acknowledge these fears.</p> +<p><strong>Why do we need a software process? For the same reason that we need laws, governments, and taxes: fear.</strong></p> +<p>&lt;...&gt;</p> +<p>Unacknowledged Fear Is the Source of All Software Project Failures</p> +<p>&lt;...&gt;</p> +<p><strong>In order to be successful, a development process must be instituted among customers and developers that secures certain inalienable rights.</strong></p> +<p>&lt;...&gt;</p> +<p>If we are going to develop well, we must create a culture that makes it possible for programmers and customers to acknowledge their fears and accept their rights and responsibilities. +Without such guarantees, we cannot be courageous. +We huddle in fear behind fortress walls, building them ever stronger, adding ever more weight to the development processes we have adopted. +We continually add cannonades and battlements, documents and reviews, procedures and sign-offs, moats with crocodiles, +torture chambers, and huge pots of boiling oil.</p> +<p>But when our fears are acknowledged and our rights are accepted, then we can be courageous. +We can set goals that are hard to reach and collaborate to make those goals. +We can tear down the structures that we built out of fear and that impede us. +We will have the courage to do only what is necessary and no more, to spend our time on what's important rather than on protecting ourselves."</p> +<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler, "Chapter 2. Fear"</p> </div></blockquote> +<p>Глава "Chapter 2. Fear" книги "Planning Extreme Programming" by Kent Beck, Martin Fowler обладает уникальной ценностью, но немного великовата для того, чтобы поместить её сюда полностью.</p> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference internal" href="../requirements/nonfunctional-requirements.html#emacsway-agile-nonfunctional-requirements"><span class="std std-ref">Agile nonfunctional Requirements</span></a>"</p></li> +<li><p>"<a class="reference internal" href="business-concerns/compound-interest.html#emacsway-compound-interest"><span class="std std-ref">Technical Debt и сложный процент</span></a>"</p></li> +<li><p>"<a class="reference internal" href="business-concerns/architecture-options.html#emacsway-architecture-options"><span class="std std-ref">Architecture: Selling Options</span></a>"</p></li> +<li><p>"<a class="reference internal" href="business-concerns/common-planning-errors.html#emacsway-agile-common-planning-errors"><span class="std std-ref">Наиболее частые ошибки планирования</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../../../../soft-skills/cognitive-biases.html#emacsway-cognitive-biases"><span class="std std-ref">Список психологических эффектов</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../../uncertainty-management/adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../../uncertainty-management/adaptation/crash-course-in-software-development-economics.html#emacsway-software-development-economics-literature"><span class="std std-ref">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> +<li><p>"<a class="reference internal" href="technical-concerns/when-to-refactor.html#emacsway-when-to-refactor"><span class="std std-ref">Когда делать refactoring в legacy</span></a>"</p></li> +<li><p>"<a class="reference internal" href="technical-concerns/when-to-write-unit-tests.html#emacsway-when-to-write-unit-tests"><span class="std std-ref">Когда писать Unit Tests в legacy</span></a>"</p></li> +</ul> +</div> </section> -<section id="robert-martin"> -<h3><a class="toc-backref" href="#id18" role="doc-backlink">Robert Martin</a></h3> +Tue, 17 Jan 2023 00:00:00 Как стать успешным разработчикомhttps://dckms.github.io/system-architecture/emacsway/it/self-education/success-roadmap.html<span class="target" id="index-0"/><section id="emacsway-success-roadmap"> +<span id="id1"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> <blockquote> -<div><p>💬 "The only way to make the deadline — the only way to go fast — is to keep the code as clean as possible at all times."</p> -<p class="attribution">—"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p> +<div><p>"My career mission is to help geeks feel safe in the world."</p> +<p class="attribution">—Kent Beck, description of his Linkedin profile</p> </div></blockquote> +<nav class="contents" id="id2"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#emacsway-success-roadmap" id="id10">Как стать успешным разработчиком</a></p> +<ul> +<li><p><a class="reference internal" href="#id3" id="id11">Несколько исторических примеров</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id12">Дорожная карта</a></p> +<ul> +<li><p><a class="reference internal" href="#id5" id="id13">1. Учимся писать экономически эффективный код</a></p></li> +<li><p><a class="reference internal" href="#id6" id="id14">2. Обучаем команду</a></p></li> +<li><p><a class="reference internal" href="#id7" id="id15">3. Организовываем процессы</a></p></li> +<li><p><a class="reference internal" href="#id8" id="id16">4. Изменяем коллектив</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#id9" id="id17">Если хочется все бросить...</a></p></li> +</ul> +</li> +</ul> +</nav> +<p>По поводу "<a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC_%D1%81%D0%B0%D0%BC%D0%BE%D0%B7%D0%B2%D0%B0%D0%BD%D1%86%D0%B0">Эффекта Самозванца</a>" (ощущение того, что человек не заслуживает профессиональной позиции, полагая, что окружающие ошибочно думают иначе). +Видно, что эта тема многих беспокоит. +Мне даже известны люди, которые не выдержали напряжения и бросили разработку.</p> +<p>Хотя этот термин здесь не совсем корректно употреблен, и означает он немного другую проблему, но в индустрии этот термин хорошо закрепился и многим понятен.</p> +<p>Наверное, каждого разработчика волнует вопрос его эффективности. +Чаще всего собственная недооценка провоцируется хронической неуспеваемостью, о чем и пойдет речь далее.</p> +<p>Нужно учитывать, что через "Долину Отчаяния" на графике <a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%94%D0%B0%D0%BD%D0%BD%D0%B8%D0%BD%D0%B3%D0%B0_%E2%80%94_%D0%9A%D1%80%D1%8E%D0%B3%D0%B5%D1%80%D0%B0">Даннинга-Крюгера</a> проходят все. +Если вы относите причины неуспеваемости на свой счет, то, вероятно, в вашей компании что-то не так с процессами, которые искажают это восприятие. +Впрочем, подобный уровень организации процессов является, скорее, правилом на рынке труда, чем исключением.</p> +<section id="id3"> +<h2><a class="toc-backref" href="#id11" role="doc-backlink">Несколько исторических примеров</a></h2> +<p>Фрагмент биографии легендарного летчика-аса Ивана Кожедуба:</p> <blockquote> -<div><p>📝 "The way to go fast, and to keep the deadlines at bay, is to stay clean. -Professionals do not succumb to the temptation to create a mess in order to move quickly. -Professionals realize that "quick and dirty" is an oxymoron. -Dirty always means slow!"</p> -<p class="attribution">—"Clean Coder" by Robert Martin</p> +<div><p>📝 "В начале военной карьеры Ивана Никитовича преследовали неудачи, его даже чуть было не перевели на пост оповещения. +Только заступничество командира полка майора И. Солдатенко помогло ему остаться в полку. +Свою первую победу летчик одержал в ходе 40-го боевого вылета, сбив немецкий пикировщик."</p> +<p class="attribution">—"<a class="reference external" href="https://w.histrf.ru/articles/article/show/kozhiedub_ivan_nikitovich_08_06_1920_08_08_1991_ghgh">Кожедуб Иван Никитович</a>" / Киселев О. Н.</p> </div></blockquote> +<p>Каждая ошибка - это ориентир на пути к успеху. +Неважно, сколько ошибок было сделано, важно сколько выводов из них было вынесено. +Правильные решения возникают из опыта. +Опыт возникает из неправильных решений.</p> +<p>Еще один назидательный пример - Кубинец Лопес стал первым в истории четырехкратным олимпийским чемпионом в греко-римской борьбе, превзойдя достижение Александра Карелина.</p> <blockquote> -<div><p>📝 "The goal of good software design? That goal is nothing less than my utopian description:</p> -<blockquote> -<div><p>The goal of software architecture is to minimize the human resources required to build and maintain the required system.</p> -</div></blockquote> -<p>The measure of design quality is simply the measure of the effort required to meet the needs of the customer. -If that effort is low, and stays low throughout the lifetime of the system, the design is good. -If that effort grows with each new release, the design is bad. -It's as simple as that."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +<div><p>📝 В 13 лет его карьера могла завершиться досрочно — он получил страшный двойной перелом ноги...</p> +<p>Лопес уже в 17 лет попал в сборную Кубы, но не все шло гладко. На своем первом крупном соревновании — чемпионате мира 2002 года — молодой Лопес с треском провалился. Он финишировал 13-м в весовой категории до 120 кг. А на следующий год выступил и того хуже — занял 16-е место.</p> +<p>Не заладилось и на Олимпиаде в Афинах — в четвертьфинале кубинца остановил россиянин Хасан Бароев, ставший впоследствии Олимпийским чемпионом и лишенный медали.</p> +<p>"Не понимаю, что я тогда делал не так. Я был готов, был заряжен. Но медали не шли ко мне", — вспоминал об этом впоследствии Лопес.</p> +<p>Но начиная с 2005 года результаты упорного и упрямого кубинца пошли вверх. Он стал чемпионом мира в 2005, 2007, 2009 и 2010 годах.</p> +<p class="attribution">—"<a class="reference external" href="https://tass.ru/opinions/12047595">Скромный кубинский гигант. Кто побил рекорд Карелина в борьбе?</a>" / Лазорин Игорь, ТАСС</p> </div></blockquote> +<p>Кстати, сам Александр Карелин говорил:</p> <blockquote> -<div><p>📝 "Напомню, что целью архитектора является минимизация трудозатрат на создание и сопровождение системы. -Что может помешать достижению этой цели? -Зависимость — и особенно зависимость от преждевременных решений.</p> -<p>Recall that the goal of an architect is to minimize the human resources required to build and maintain the required system. -What it is that saps this kind of peoplepower? -Coupling—and especially coupling to premature decisions."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin, перевод ООО Издательство "Питер"</p> +<div><p>💬 "В успехе только 5% таланта, а остальное - это пот и трудолюбие. +Поэтому нужно захотеть стать чемпионом и не бояться преодолевать трудности. +Самое главное - сделать первый шаг, не бояться наступать на леность, трусость и самовосприятие. +Нужно встать с дивана, поднять сначала свою "тушу", а потом тело соперника на ковре..."</p> +<p class="attribution">—Александр Карелин</p> </div></blockquote> +<p>Нередко импульс волевых усилий, необходимый для решения неудач в начале своего профессионального пути, обретает момент инерции уже на всю жизнь, помогая <a class="reference internal" href="../../soft-skills/planning-in-psychology.html#emacsway-planning-in-psychology"><span class="std std-ref">достигнуть уровень высококлассного специалиста</span></a>. Таких примеров история знает немало, в самых различных отраслях.</p> +<p>Юрий Никулин не был принят во ВГИК, т.к. в нем не обнаружили актерских способностей. +Примерно по этой же причине он не поступил в ГИТИС. +Приняли его лишь в школу-студию разговорных жанров при Московском цирке на Цветном бульваре. +Вот такие дела с талантами бывают у людей, оказавшимися позже наиболее талантливыми.</p> +<p>Sylvester Stallone в свое время пришлось даже написать собственный сценарий, чтоб получить роль.</p> +</section> +<section id="id4"> +<h2><a class="toc-backref" href="#id12" role="doc-backlink">Дорожная карта</a></h2> +<section id="id5"> +<h3><a class="toc-backref" href="#id13" role="doc-backlink">1. Учимся писать экономически эффективный код</a></h3> +<p>Первым важным навыком на пути к обретению успеваемости является умение писать <a class="reference internal" href="../sdlc/uncertainty-management/adaptation/crash-course-in-software-development-economics.html#emacsway-software-development-economics-literature"><span class="std std-ref">экономически эффективный код</span></a> с <a class="reference internal" href="../sdlc/models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">пологим характером роста стоимости его изменения</span></a>. +На эту тему было написано <a class="reference internal" href="self-education-for-software-engineer.html"><span class="doc">немало книг</span></a>. +Не понимая истинных причин снижения velocity, человек склонен относить это на свой счет, что препятствует их обнаружению и устранению.</p> +</section> +<section id="id6"> +<h3><a class="toc-backref" href="#id14" role="doc-backlink">2. Обучаем команду</a></h3> +<p>Второй важный навык выводится исходя из модели коллективного владения кодом. +Вы работаете по большей части с кодом, написанным другими участниками команды. +Вы тратите на его чтение, понимание и изменение основную часть времени. +От его качества зависит и ваша персональная успеваемость.</p> +<p>Здесь есть несколько вариантов:</p> +<ol class="arabic simple"> +<li><p>Попасть в струю коллектива, которая работает с качественным кодом. Для этого нужно уметь их собой заинтересовать, поэтому см. п.1.</p></li> +<li><p>Изолироваться от командного legacy и начать формировать новую кодовую базу под себя (вариант кажется фантастическим, но, тем не менее, вполне реальнен).</p></li> +<li><p>Влиять на коллектив, и вместе с коллективом изменять код. Этот вариант тоже возможен, но требует обладания совокупностью качеств. Больше всего мне в этом вопросе помогла книга "Extreme Programming Explained" 1st edition by Kent Beck.</p></li> +</ol> +<p>Полученные знания нужно умело применять. +Здесь важно понять, с какой стороны начать. +Этот вопрос хорошо освещает статья "<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">Системное мышление</a> by Craig Larman.</p> </section> -<section id="agile-manifesto"> -<h3><a class="toc-backref" href="#id19" role="doc-backlink">Agile Manifesto</a></h3> -<blockquote> -<div><p>📝 "Continuous attention to technical excellence and good design enhances agility."</p> -<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/principles.html">Principles behind the Agile Manifesto</a>"</p> -</div></blockquote> +<section id="id7"> +<h3><a class="toc-backref" href="#id15" role="doc-backlink">3. Организовываем процессы</a></h3> +<p>Итак. Теперь вы можете писать высокоэффективный код вместе с командой. +Но это еще не победа. +Успешность во многом зависит от качества организации процессов. +Одно неверное управленческое решение, и команда демотивирована, уходят ключевые специалисты, возникают разногласия и конфликты.</p> +<p>Попасть работать к хорошему менедженту хотя и возможно, но это сложнее, чем попасть работать в хорошую команду. +А это значит, что вы можете рассчитывать только на себя.</p> +<p>Наиболее частые проблемы исходят из-за неверного распределения обязанностей, например, когда продакт занимается не требованиями, а реализацией. +Или методика оценивания задач не соответствует уровню культуры коллектива - индивидуальная оценка задачи может повысить точность планирования в зрелом коллективе, а может напрочь убить взаимопомощь и распространение знаний в развивающемся коллективе, и разогнать комплекс неполноценности до уровня психологического предела (см. "Agile Estimating and Planning" by Mike Cohn), особенно, если при этом еще и путают оценку с обязательством. +Непонимание того, чем является макет UX/UI дизайна (problem vs. solution space) приводит конфликту между продактом и командой. +Неудачная топология заблокирует автономность команд, и команды будут бОльшую часть времени потопать в дискуссиях. +Список можно продолжать. +Вообще, по моим наблюдением, качество организации процессов является основной причиной увольнения значимых специалистов.</p> +<p>Собственно, даже Steve McConnell советовал в некоторых случаях "голосовать ногами". +Вот только вероятность того, что на новом месте менеджмент будет поставлен получше, не сильно высокая.</p> +<p>Поскольку процессы влияют на вас, то вы можете изменить свое положение, влияя на процессы. +Поэтому, грамотный специалист должен уметь <a class="reference internal" href="../sdlc/sdlc-reference.html#emacsway-sdlc-literature"><span class="std std-ref">разбираться в процессах</span></a>.</p> </section> -<section id="ralph-johnson"> -<h3><a class="toc-backref" href="#id20" role="doc-backlink">Ralph Johnson</a></h3> -<blockquote> -<div><p>📝 "In most successful software projects, the expert developers working on that project have -a shared understanding of the system design. -<strong>This shared understanding is called 'architecture.'</strong> -This understanding includes how the system is divided into components and how the components interact through interfaces. -These components are usually composed of smaller components, but the architecture only -includes the components and interfaces that are understood by all the developers."</p> -<p class="attribution">—<a class="reference external" href="https://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf">Ralph Johnson</a></p> -</div></blockquote> +<section id="id8"> +<h3><a class="toc-backref" href="#id16" role="doc-backlink">4. Изменяем коллектив</a></h3> +<p>И, наконец, мы подходим к самой сложной карьерной проблеме - это <a class="reference internal" href="../../soft-skills/change-making.html"><span class="doc">осуществление изменений в коллективе</span></a> с точки зрения <a class="reference internal" href="../../soft-skills/cognitive-biases.html"><span class="doc">коммуникативной, социальной и управленческой психологии</span></a>. +Мало знать, что нужно изменить, нужно еще иметь понимание как это осуществить.</p> </section> -<section id="steve-mcconnell"> -<h3><a class="toc-backref" href="#id21" role="doc-backlink">Steve McConnell</a></h3> -<blockquote> -<div><p>📝 "The General Principle of Software Quality is that improving quality reduces development costs.</p> -<p>Understanding this principle depends on understanding a key observation: the best way -to improve productivity and quality is to reduce the time spent reworking code, whether -the rework arises from changes in requirements, changes in design, or debugging. -The industry-average productivity for a software product is about 10 to 50 of lines of -delivered code per person per day (including all noncoding overhead). -It takes only a matter of minutes to type in 10 to 50 lines of code, so how is the rest of the day spent? -Part of the reason for these seemingly low productivity figures is that industry average -numbers like these factor nonprogrammer time into the lines-of-code-per-day figure. -Tester time, project manager time, and administrative support time are all included. -Noncoding activities, such as requirements development and architecture work, are also -typically factored into those lines-of-code-per-day figures. -But none of that is what takes up so much time.</p> -<p>The single biggest activity on most projects is debugging and correcting code that -doesn't work properly. -Debugging and associated refactoring and other rework consume -about 50 percent of the time on a traditional, naive software-development cycle. -(See Section 3.1, "Importance of Prerequisites," for more details.) Reducing debugging by -preventing errors improves productivity. -Therefore, the most obvious method of shortening a development schedule is to improve the quality of the product and decrease -the amount of time spent debugging and reworking the software. -This analysis is confirmed by field data. -In a review of 50 development projects involving over 400 work-years of effort and -almost 3 million lines of code, a study at NASA's Software -Engineering Laboratory found that increased quality assurance was -associated with decreased error rate but did not increase overalldevelopment cost (Card 1987).</p> -<p>A study at IBM produced similar findings:</p> +</section> +<section id="id9"> +<h2><a class="toc-backref" href="#id17" role="doc-backlink">Если хочется все бросить...</a></h2> <blockquote> -<div><p>Software projects with the lowest levels of defects had the shortest development -schedules and the highest development productivity.... software defect removal is -actually the most expensive and time-consuming form of work for software (Jones 2000).</p> -<p class="attribution">—Jones, Capers. 2000. Software Assessments, Benchmarks, and Best Practices. Reading, MA: Addison-Wesley.</p> -</div></blockquote> -<p>The same effect holds true at the small end of the scale. -In a 1985 study, 166 professional programmers wrote programs from the -same specification. -The resulting programs averaged 220 lines of -code and a little under five hours to write. -The fascinating result was that programmers who took the median time to complete their -programs produced programs with the greatest number of errors. -The programmers who took more or less than the median time -produced programs with significantly fewer errors (DeMarco and Lister 1985).</p> -<p>The two slowest groups took about five times as long to achieve roughly the same -defect rate as the fastest group. -It's not necessarily the case that writing software without -defects takes more time than writing software with defects. -As the graph shows, it can take less."</p> -<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell</p> +<div><p>📝 "Чтобы жить честно, надо рваться, путаться, ошибаться, начинать и бросать... и вечно бороться и лишаться. +А спокойствие — душевная подлость".</p> +<p class="attribution">—Лев Николаевич Толстой</p> </div></blockquote> <blockquote> -<div><p>📝 "Watts Humphrey reports that teams using the Team Software Process -(TSP) have achieved defect levels of about 0.06 defects per 1000 lines of code. -TSP focuses on training developers not to create defects in the first place (Weber 2003). -[Morales, Alexandra Weber. 2003. "The Consummate Coach: Watts Humphrey, Father of Cmm and Author of Winning with Software, Explains How to Get Better at What You Do," SD Show Daily, September 16, 2003.]</p> -<p>The results of the TSP and cleanroom projects confirm another version of the General -Principle of Software Quality: it's cheaper to build high-quality software than it is to build and fix low-quality software. -Productivity for a fully checked-out, 80,000-line cleanroom project was 740 lines of code per work-month. -The industry average rate for fully checked-out code is closer to 250–300 lines per work-month, including all noncoding overhead (Cusumano et al 2003). -[Cusumano, Michael , et al. 2003. "Software Development Worldwide: The State of the Practice," IEEE Software, November/ December 2003, 28–34.] -The cost savings and productivity come from the fact that virtually no time is devoted to debugging on TSP or cleanroom projects. -No time spent on debugging? -That is truly a worthy goal!"</p> -<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell</p> +<div><p>📝 "Никогда не ошибается тот, кто ничего не делает."</p> +<p>📝 "Лучше осмеливаться на могучие дела, добиваться славных триумфов, пусть и перемежающихся с неудачами, чем стоять в одном ряду со слабыми духом, которые не могут ни наслаждаться от души, ни сильно страдать, потому что живут в серых сумерках, где нет ни побед, ни поражений.</p> +<p>📝 "Мужество, это когда продолжаешь, хотя сил уже нет.</p> +<p>📝 "Не критик имеет значение, не человек, указывающий, где сильный споткнулся, или где тот, кто делает дело, мог бы справиться с ним лучше. +Уважения достоин тот, кто сам стоит на арене, у кого лицо покрыто потом, кровью и грязью; кто отважно борется; +кто совершает промахи и ошибки, потому что никакой труд не обходится без них; +кто познал великий энтузиазм и великую преданность, кто посвящает себя достойной цели; +кто, при лучшем исходе, достигает высочайшего триумфа, а при худшем, если его постигает неудача, это по крайней мере неудача в великом дерзновении; +и потому никогда он не будет среди тех холодных и робких душ, которым не знакомы ни победа, ни поражение." (Париж, Сорбонна, 1910)</p> +<p class="attribution">—<a class="reference external" href="https://ru.wikiquote.org/wiki/%D0%A2%D0%B5%D0%BE%D0%B4%D0%BE%D1%80_%D0%A0%D1%83%D0%B7%D0%B2%D0%B5%D0%BB%D1%8C%D1%82">Теодор Рузвельт</a></p> </div></blockquote> <blockquote> -<div><p>📝 "A six-month study conducted by IBM found that maintenance programmers "most often said that <strong>understanding the original programmer's intent was the most difficult problem</strong>" (Fjelstad and Hamlen 1979). -[Fjelstad, R. K. , and W. T. Hamlen. 1979. "Applications Program Maintenance Study: Report to our Respondents." Proceedings Guide 48, Philadelphia. Reprinted in Tutorial on Software Maintenance, G. Parikh and N. Zvegintzov eds. Los Alamitos, CA: CS Press, 1983: 13–27.]"</p> -<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell</p> +<div><p>📝 "Лучше иногда падать, чем никогда не летать."</p> +<p>📝 "Никогда не бойся делать то, что ты не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник."</p> +<p>📝 "Конь о четырех ногах и то спотыкается."</p> +<p class="attribution">—Народная мудрость (автор неизвестен)</p> </div></blockquote> -</section> -<section id="id4"> -<h3><a class="toc-backref" href="#id22" role="doc-backlink">Сергей Тепляков</a></h3> <blockquote> -<div><p>📝 "Хороший дизайн заключается в простом решении, когда изменения требований ведут к линейным трудозатратам."</p> -<p class="attribution">—"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>", Сергей Тепляков</p> +<div><p>📝 "Лучше зажечь одну свечу, чем проклинать темноту."</p> +<p class="attribution">—Махатма Ганди</p> </div></blockquote> -</section> -<section id="id5"> -<h3><a class="toc-backref" href="#id23" role="doc-backlink">Народное творчество</a></h3> -<p>Старый программистский анекдот:</p> <blockquote> -<div><p>💬 Идет мужик по лесу. Смотрит, другой мужик лес рубит. -| - Привет, что делаешь? -| - Не видишь? Лес рублю... -| - Так бензопила же лежит рядом. Возьми её - быстрее будет. -| - Я не умею. -| - Так инструкция же рядом лежит. Возьми, прочти... -| - Мне некогда её читать - мне лес рубить надо.</p> +<div><p>📝 "Солнцу безразлично, почитает его светлячок или нет."</p> +<p>📝 "Избегайте тех, кто старается подорвать вашу веру в себя. +Великий человек, наоборот, внушает чувство, что вы можете стать великим."</p> +<p>📝 "Смелость — это сопротивление страху и господство над страхом, а не отсутствие страха."</p> +<p>📝 "Главное — верить. Если веришь, то всё обязательно будет хорошо — даже лучше, чем ты сам можешь устроить."</p> +<p class="attribution">—Марк Твен</p> </div></blockquote> -</section> -<section id="randy-shoup"> -<h3><a class="toc-backref" href="#id24" role="doc-backlink">Randy Shoup</a></h3> <blockquote> -<div><div class="line-block"> -<div class="line">- We don't have time to do it right!</div> -<div class="line">- Do you have time to do it twice?</div> -</div> -<p class="attribution">—<a class="reference external" href="https://www.infoq.com/presentations/microservices-data-centric">Randy Shoup</a>, VP Engineering at Stitch Fix in San Francisco</p> +<div><p>📝 "Если ты не научишься управлять собой, тобой будут управлять другие."</p> +<p class="attribution">—Хасай Алиев</p> </div></blockquote> -<figure class="align-left" id="id11"> -<a class="reference internal image-reference" href="../../../../../../_images/do-it-right.png"><img alt="Do it right! Иллюстрация из открытых источников неизвестного автора." src="../../../../../../_images/do-it-right.png" style="width: 90%;"/></a> -<figcaption> -<p><span class="caption-text">Do it right! Иллюстрация из открытых источников неизвестного автора.</span></p> -</figcaption> -</figure> <div class="admonition seealso"> <p class="admonition-title">См.также</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="../crash-course-in-software-development-economics.html"><span class="doc">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../../../soft-skills/icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Принцип ледокола</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">Что такое Agile Development</span></a>"</p></li> -<li><p>"<a class="reference internal" href="patterns.html#emacsway-agile-patterns"><span class="std std-ref">Role of Design Patterns in Agile</span></a>"</p></li> +<li><p>"<a class="reference internal" href="self-education-for-software-engineer.html#emacsway-self-education-literature"><span class="std std-ref">Список литературы для самообучения разработчика программного обеспечения</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../soft-skills/planning-in-psychology.html#emacsway-planning-in-psychology"><span class="std std-ref">Психологическое значение планирования</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../soft-skills/learning.html#emacsway-learning-in-psychology"><span class="std std-ref">Кристаллизация знаний. Как читать и не превратиться в коллекционера информации.</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../README.html"><span class="doc">Как пользоваться</span></a>"</p></li> +</ul> +</div> +</section> +</section> +Sat, 31 Dec 2022 00:00:00 Краткий курс по экономике разработки программного обеспеченияhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/crash-course-in-software-development-economics.html<span class="target" id="index-0"/><section id="emacsway-software-development-economics-literature"> +<span id="id1"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<p>Краткий курс по экономике разработки программного обеспечения:</p> +<ul class="simple"> +<li><p>"Extreme Programming Explained" 1st edition by Kent Beck</p> +<ul> +<li><p>"Chapter 3. Economics of Software Development"</p></li> +<li><p>"Chapter 17. Design Strategy"</p></li> +<li><p>"Chapter 20. Retrofitting XP"</p></li> +<li><p>"Chapter 24. What Makes XP Hard"</p></li> +</ul> +</li> +<li><p>"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin</p> +<ul> +<li><p>"Chapter 3. Agile Principles"</p></li> +<li><p>"Chapter 8. Technical Debt"</p></li> +</ul> +</li> +<li><p>"Software Engineering: A Practitioner's Approach" 9th edition by Roger S. Pressman, Bruce Maxim</p> +<ul> +<li><p>"3.2 Agility and the cost of change"</p></li> +</ul> +</li> +<li><p>"Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman</p> +<ul> +<li><p>"Chapter 7. Modifiability"</p></li> +<li><p>"Chapter 23. Economic analysis of architectures"</p></li> +</ul> +</li> +<li><p>"Refactoring: Improving the Design of Existing Code" 1st (and 2nd) edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p> +<ul> +<li><p>"Chapter 2. Principles in Refactoring"</p></li> +</ul> +</li> +<li><p>"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +<ul> +<li><p>"Chapter 1. What Is Design and Architecture?"</p></li> +</ul> +</li> +<li><p>"<a class="reference external" href="https://www.computer.org/education/bodies-of-knowledge/software-engineering">Software Engineering Body of Knowledge (SWEBOK) v.3</a>" (<a class="reference external" href="https://github.com/ligurio/swebok-2004-in-russian">на русском</a>)</p> +<ul> +<li><p>"Chapter 12: Software Engineering Economics"</p></li> +</ul> +</li> +<li><p>"<a class="reference external" href="https://waseda.app.box.com/v/ieee-cs-swebok">Software Engineering Body of Knowledge (SWEBOK) v.4 (draft)</a>"</p> +<ul> +<li><p>"Chapter 15: Software Engineering Economics"</p></li> +</ul> +</li> +<li><p>"Working Effectively with Legacy Code" by Michael C. Feathers</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/Yagni.html">Yagni</a>" (хорошо разъясняет виды экономических ущербов: "cost of build", "cost of delay", "cost of carry", "cost of repair", "cost of removing")</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebt.html">Technical Debt</a>"</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebtQuadrant.html">Technical Debt Quadrant</a>"</p></li> +<li><p>"<a class="reference external" href="https://architectelevator.com/architecture/architecture-options/">Architecture: Selling Options</a>" by Gregor Hohpe. How do you explain the value of architecture to business stakeholders? Deferring to the Nobel-prize winning economists Black and Scholes can work surprisingly well.</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/DesignPayoffLine.html">Design Payoff Line</a>"</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>"</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/articles/is-quality-worth-cost.html">Is High Quality Software Worth the Cost?</a>"</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>" / Сергей Тепляков</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2012/04/blog-post_19.html">О повторном использовании кода</a>" / Сергей Тепляков</p></li> +<li><p>"<a class="reference external" href="https://less.works/less/principles/systems-thinking.html">Systems thinking</a>" (<a class="reference external" href="https://less.works/ru/less/principles/systems-thinking.html">на русском</a>)</p></li> +<li><p>"<a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=8299">Modifiability</a>"</p></li> +<li><p>"<a class="reference external" href="https://youtu.be/DngAZyWMGR0">Making Architecture Matter - Martin Fowler Keynote</a>" - превосходное 14-ти минутное видео.</p></li> +<li><p>"<a class="reference external" href="https://doi.org/10.1155/2020/2976564">Comparing Maintainability Index, SIG Method, and SQALE for Technical Debt Identification</a>" by Peter Strecansky, Stanislav Chren, and Bruno Rossi</p></li> +</ul> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference internal" href="software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a></p></li> +<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/technical-concerns/when-to-refactor.html#emacsway-when-to-refactor"><span class="std std-ref">Когда делать refactoring в legacy</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/technical-concerns/when-to-write-unit-tests.html#emacsway-when-to-write-unit-tests"><span class="std std-ref">Когда писать Unit Tests в legacy</span></a>"</p></li> +<li><p>"<a class="reference internal" href="software-design/software-design.html#emacsway-agile-software-design"><span class="std std-ref">Role of Software Design in Agile</span></a>"</p></li> +<li><p>"<a class="reference internal" href="software-design/patterns.html#emacsway-agile-patterns"><span class="std std-ref">Role of Design Patterns in Agile</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../../soft-skills/icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Принцип ледокола</span></a>"</p></li> +<li><p>"<a class="reference internal" href="adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">Что такое Agile Development</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/balancing-business-technical-concerns.html#emacsway-agile-balancing-business-technical-concerns"><span class="std std-ref">Балансирование Бизнес/Технических интересов</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/business-concerns/common-planning-errors.html#emacsway-agile-common-planning-errors"><span class="std std-ref">Наиболее частые ошибки планирования</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/business-concerns/compound-interest.html#emacsway-compound-interest"><span class="std std-ref">Technical Debt и сложный процент</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../models/agile/analysis/concerns/business-concerns/architecture-options.html#emacsway-architecture-options"><span class="std std-ref">Architecture: Selling Options</span></a>"</p></li> </ul> </div> </section> -</section> -Sat, 23 Jul 2022 00:00:00 Role of Design Patterns in Agilehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/patterns.html -<span id="emacsway-agile-patterns"/> +Wed, 02 Nov 2022 00:00:00 Что такое Predictionhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/prediction/prediction.html +<span id="emacsway-prediction"/> <p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> +<blockquote> +<div><p>📝 A second common style of definition for architecture is that it's "the design decisions that need to be made early in a project", but Ralph complained about this too, saying that it was more like the decisions you wish you could get right early in a project.</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/architecture/">Software Architecture Guide</a>" by Martin Fowler</p> +</div></blockquote> +<p>К Prediction (Прогнозированию) относится ряд активностей на основе правил логического вывода, предшествующих производству Системного Инкремента и направленных на заблаговременное разрешение неопределенности. +К ним относятся Business/System Requirements Definition and Analysis, Architecture Definition, Design Definition, разработка макетов UX/UI-Design, Estimation и Planning. +Но главным образом к ним относится разрешение неопределенности в problem-space (т.е. требований), что оказывает существенное влияние на выбор SDLC-модели.</p> +<p>В Scrum эти активности традиционно выражаются в событиях, предшествующих Definition Of Ready (DOR):</p> <ul class="simple"> -<li><p><a class="reference internal" href="#role-of-design-patterns-in-agile" id="id5">Role of Design Patterns in Agile</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id6">Составляющие экономического эффекта применения паттернов</a></p> -<ul> -<li><p><a class="reference internal" href="#id3" id="id7">Индивидуальная составляющая</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id8">Коллективная составляющая</a></p></li> +<li><dl class="simple"> +<dt>Со стороны Product Owner:</dt><dd><ul> +<li><p>Reveal needs of stakeholders</p></li> +<li><p>Creating PBI</p></li> </ul> +</dd> +</dl> </li> +<li><dl class="simple"> +<dt>Со стороны Team:</dt><dd><ul> +<li><p>PBR</p></li> +<li><p>Planning</p></li> +<li><p>Spike</p></li> </ul> +</dd> +</dl> </li> </ul> -</nav> -<p>Немного о Паттернах Проектирования. -Нужны ли они?</p> -<p>Паттерны могут приносить пользу экономике разработки, а могут приносить и вред, если не понимать их назначения и злоупотреблять ими. -Как говорится, молотком можно гвоздь забить, а можно и пальцы отбить.</p> -<p>Любое проектное решение должно исходить из <a class="reference internal" href="software-design.html#emacsway-primary-technical-imperative"><span class="std std-ref">принципов управления сложностью</span></a>. -Добавление паттерна может увеличивать уровень косвенности системы, что тоже имеет свою стоимость.</p> -<p>Посмотрим, к примеру, мотивацию Mediator pattern:</p> +<p>Основная проблема Prediction заключается в том, что характер роста стоимости Прогнозирования, в зависимости от его точности, близок к экспоненциальному. +В то время как характер роста бизнес-выгод от точности Прогнозирования близок к логарифмическому. +Пересечение этих графиков образует предел экономической целесообразности разрешения неопределенности путем Прогнозирования. +Здесь подразумевается, что стоимость самой реализации уже вычтена из бизнес-выгод.</p> <blockquote> -<div><p>📝 "Mediator promotes loose <strong>coupling</strong> by keeping objects from referring to each other explicitly, -and it lets you vary their interaction independently."</p> -<p class="attribution">—"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides</p> +<div><p>💬 "WaterFall is based on the empirical observation of 30 years ago (ref: BarryBoehm, Software Engineering Economics, Prentice Hall, 1981.) that the cost of change rises exponentially (base 10) by phases. The conclusion is that you should make the big decisions up front, because changing them is so expensive."</p> +<p class="attribution">—"<a class="reference external" href="https://wiki.c2.com/?WaterFall">Water Fall</a>" at c2.com</p> </div></blockquote> -<p>Лекарство не должно быть хуже болезни. -А цель должна оправдывать средства. -Внося сложность в систему, мы должны обретать возможность управлять еще большим уровнем сложности, т.е. решение должно быть оправданным.</p> -<p>По этому поводу хорошо <a class="reference internal" href="software-design.html#emacsway-kent-beck-constantine-s-law"><span class="std std-ref">рассуждал Kent Beck</span></a>.</p> -<p>И по этому поводу хорошо <a class="reference internal" href="../../../../../soft-skills/learning-spiral-phase-mismatch.html#emacsway-martin-fowler-16-patterns-in-32-lines"><span class="std std-ref">говорил Martin Fowler о 16 Паттернах в 32 строках кода</span></a>.</p> -<p>Вопрос применения паттернов - это вопрос поиска баланса между уровнем управляемой ими сложности и уровнем привносимой ими сложности. -При дисбалансе бизнес и технических интересов, злоупотребление паттернами может привести к <a class="reference internal" href="../../../models/agile/analysis/concerns/balancing-business-technical-concerns.html#emacsway-second-system-effect"><span class="std std-ref">экономически неоправданному переусложению системы</span></a>.</p> -<p>Тем не менее, Паттерны Проектирования являются <a class="reference internal" href="../../../../../soft-skills/knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">обобщением и систематизацией практики</span></a>. -Их не выдумывают - их обобщают. -Это значит, что незнание конкретного паттерна еще не означает неосознанного его применения.</p> -<section id="id2"> -<h2><a class="toc-backref" href="#id6" role="doc-backlink">Составляющие экономического эффекта применения паттернов</a></h2> -<p>Паттерны способны значительно улучшить экономику разработки при разумном их применении. -Экономическая их эффективность складывается из двух составляющих:</p> -<ol class="arabic simple"> -<li><p>Индивидуальная</p></li> -<li><p>Коллективная</p></li> -</ol> -<p>Рассмотрим каждый из них по отдельности.</p> -<section id="id3"> -<h3><a class="toc-backref" href="#id7" role="doc-backlink">Индивидуальная составляющая</a></h3> -<p>Начнем с первой, индивидуальной составляющей. -Каким образом применение паттернов может повысить персональную эффективность разработчика? Вот что говорит по этому поводу автор книг "Implementation Patterns" и "Smalltalk Best Practice Patterns" Kent Beck:</p> <blockquote> -<div><p>📝 "Я обратил внимание на один важный эффект, который, я надеюсь, смогут принять во внимание и другие. -Если на основе постоянно повторяющихся действий формулируются правила, дальнейшее применение этих правил становится неосознанным и автоматическим. -Естественно, ведь это проще, чем обдумывать все за и все против того или иного действия с самого начала. -Благодаря этому повышается скорость работы, и если в дальнейшем вы сталкиваетесь с исключением или проблемой, которая не вписывается ни в какие правила, у вас появляется дополнительное время и энергия для того, чтобы в полной мере применить свои творческие способности.</p> -<p>Именно это произошло со мной, когда я писал книгу Smalltalk Best Practice Patterns (Лучшие паттерны Smalltalk). -В какой-то момент я решил просто следовать правилам, описываемым в моей книге. -В начале это несколько замедлило скорость моей работы, — мне требовалось дополнительное время, чтобы вспомнить то или иное правило, или написать новое правило. -Однако по прошествии недели я заметил, что с моих пальцев почти мгновенно слетает код, над разработкой которого ранее мне приходилось некоторое время размышлять. -Благодаря этому у меня появилось дополнительное время для анализа и важных размышлений о дизайне.</p> -<p>Существует еще одна связь между TDD и паттернами: TDD является методом реализации дизайна, основанного на паттернах. -Предположим, что в определенном месте разрабатываемой системы мы хотим реализовать паттерн Strategy (Стратегия). -Мы пишем тест для первого варианта и реализуем его, создав метод. -После этого мы намеренно пишем тест для второго варианта, ожидая, что на стадии рефакторинга мы придем к паттерну Strategy (Стратегия). -Мы с Робертом Мартином (Robert Martin) занимались исследованием подобного стиля TDD. -Проблема состоит в том, что дизайн продолжает вас удивлять. -Идеи, которые на первый взгляд кажутся вам вполне уместными, позже оказываются неправильными. -Поэтому я не рекомендую целиком и полностью доверять своим предчувствиям относительно паттернов. -Лучше думайте о том, что, по-вашему, должна делать система, позвольте дизайну оформиться так, как это необходимо.</p> -<p>The effect that I have noticed, and which I hope others find, is that by reducing repeatable behavior to rules, applying the rules becomes rote and mechanical. -This is quicker than redebating everything from first principles all the time. -When along comes an exception, or a problem that just doesn't fit any of the rules, you have more time and energy to generate and apply creativity.</p> -<p>This happened to me when writing the Smalltalk Best Practice Patterns. -At some point I decided just to follow the rules I was writing. -It was much slower at first, to be looking up the rules, or to be stopping to write a new rule. -After a week, however, I discovered that code was ripping off my fingertips that would have required a pause for thought before. -This gave me more time and attention for bigger thoughts about design and analysis. -Another relationship between TDD and patterns is TDD as an implementation method for pattern-driven design. -Say we decide we want a Strategy for something. -We write a test for the first variant and implement it as a method. -Then we consciously write a test for the second variant, expecting the refactoring phase to drive us to a Strategy. -Robert Martin and I did some research into this style of TDD. -The problem is that the design keeps surprising you. -Perfectly sensible design ideas turn out to be wrong. -Better just to think about what you want the system to do, and let the design sort itself out later."</p> -<p class="attribution">—"Test-Driven Development By Example" by Kent Beck, перевод П. Анджан</p> +<div><p>💬 "There is a fundamental truth to work breakdown structure estimation - the only way to estimate using a work breakdown structure to really accurately to get the number right is to implement the project. +Then you'll have the estimate.</p> +<p>The cost of improving the estimate, the initial work breakdown estimation, the cost of refining that grows exponentially. +With every next layer you want to take it down. +And the benefit of doing that does not grow exponentially. +It grows logarithmically.</p> +<p>Managers understand there is an extremely high cost involved with refining the estimate."</p> +<p class="attribution">—<a class="reference external" href="https://youtu.be/eisuQefYw_o?t=1995">"YOW! 2016 Robert C. Martin - Effective Estimation (or: How not to Lie)" at 33:15</a></p> </div></blockquote> -</section> -<section id="id4"> -<h3><a class="toc-backref" href="#id8" role="doc-backlink">Коллективная составляющая</a></h3> -<p>Перейдем ко второй, коллективной составляющей. -Каким именно образом паттерны могут повысить экономическую эффективность разработки?</p> -<p>Когда в печать вышла книга "Patterns of Enterprise Application Architecture" (PoEAA) by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford, то David Heinemeier Hansson прочитал ее одним из первых, и реализовал эти паттерны в виде Ruby On Rails (RoR). -Использование этого фреймворка, и реализованных им паттернов, позволило:</p> +<p>Robert C. Martin упомянул о таком способе обработки неопределенности, как реализовать Проект (или Системный Инкремент). +Это уже другой, эмпирический (т.е. опытным путем) способ обработки неопределенности, который называется <a class="reference internal" href="../adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Adaptation</span></a> и составляет основу итеративной разработки. +Чем сложнее предметная область Проекта, тем раньше наступает предел экономической целесообразности Prediction.</p> +Thu, 27 Oct 2022 00:00:00 Borrowing troublehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/borrowing-trouble.html +<span id="emacsway-borrowing-trouble"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p>снизить негативный эффект "<a class="reference internal" href="../../../../team-topologies/harlan-mills%27-proposal.html#emacsway-brooks-s-law"><span class="std std-ref">Закона Брукса</span></a>"</p></li> -<li><p>уменьшить порог вхождения новых разработчиков в проект</p></li> -<li><p>переместить фокус внимания разработчиков от Domain-independent knowledge к <a class="reference external" href="https://en.wikipedia.org/wiki/Domain_knowledge">Domain knowledge</a></p></li> +<li><p><a class="reference internal" href="#borrowing-trouble" id="id2">Borrowing trouble</a></p></li> </ul> -<p>В итоге, разработка на RoR дала многократный (на то время) прирост темпов разработки, что вызвало вирусный интерес к PoEAA и массовое клонирование RoR на многие языки программирования.</p> -<p>Иными словами, паттерны осуществляют унификацию решений типовых проблем, что способствует удешевлению достижения коллективного понимания устройства системы, путем минимизации затрат времени на синхронизацию и обобщение мнений.</p> -<p>По мере формирования коллективной знаний в области системной архитектуры, стали обнажаться архитектурные недостатки RoR, и по этому поводу даже были сняты два поучительных и заслуживающих внимания сериала:</p> -<ol class="arabic simple"> -<li><p>"<a class="reference external" href="https://martinfowler.com/articles/is-tdd-dead/">Is TDD Dead?</a>"</p></li> -<li><p>"<a class="reference external" href="https://martinfowler.com/articles/badri-hexagonal/">A Conversation with Badri Janakiraman about Hexagonal Rails</a>"</p></li> -</ol> -<p>Однако, сам факт достижения высокой экономической эффективности от использования паттернов PoEAA был очевиден, и этот факт оказал существенное влияние на формирование современного состояния области знаний системной архитектуры.</p> +</nav> +<p>Чем выше интеллект человека, тем больше он склонен продумывать все заблаговременно в условиях недостаточной информированности. +Это приводит к тому, что его продуктивность зачастую становится ниже продуктивности рядовых разработчиков (которые сильно не парятся). +Выгодней принимать решение в момент наибольшей полноты информированности (чем позже - тем лучше).</p> <blockquote> -<div><p>📝 "In most successful software projects, the expert developers working on that project have a shared understanding of the system design. -<strong>This shared understanding is called 'architecture.'</strong> -This understanding includes how the system is divided into components and how the components interact through interfaces. -These components are usually composed of smaller components, but the architecture only includes the components and interfaces that are understood by all the developers."</p> -<p class="attribution">—<a class="reference external" href="https://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf">Ralph Johnson</a></p> +<div><p>📝 "Иногда очень умные программисты с трудом овладевают ХР. +Для очень умных людей тяжело поменять их умение делать правильные дальновидные предположения на тесную коммуникацию и постоянную эволюцию системы.</p> +<p>Really smart programmers sometimes have a hard time with XP. +Sometimes the smart people have the hardest time trading the "Guess Right" game for close communication and continuous evolution."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 25. When You Shouldn't Try XP", перевод ООО Издательство "Питер"</p> </div></blockquote> <blockquote> -<div><p>📝 ""Programming would be more effective if programmers spent less time on the mundane, repetitive parts of their job so they had more time to spend doing a good job of solving truly unique problems.</p> -<p>Most programs follow a small set of laws:</p> -<ul class="simple"> -<li><p>Programs are read more often than they are written.</p></li> -<li><p>There is no such thing as “done”. Much more investment will be spent modifying programs than developing them initially.</p></li> -<li><p>They are structured using a basic set of state and control flow concepts.</p></li> -<li><p>Readers need to understand programs in detail and in concept. Sometimes they move from detail to concept, sometimes from concept to detail. Patterns are based on this commonality. For example, every programmer has to decide how to structure iteration. By the time you are thinking about how to write a loop, most of the domain-specific questions have been resolved for the moment and you are left with purely technical issues: the loop should be easy to read, easy to write, easy to verify, easy to modify, and efficient."</p></li> -</ul> -<p class="attribution">—"Implementation Patterns" by Kent Beck</p> +<div><p>📝 "Не надо обладать ученой степенью в области компьютерных наук для того, чтобы участвовать в ХР-проекте (в действительности ученая степень частенько является одним из серьезных мешающих факторов).</p> +<p>It doesn't take a Ph.D. in computer science to contribute to an XP project (in fact, the Ph.D.'s sometimes have the most trouble)."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 24. What Makes XP Hard", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "ХР работает против многих программистских инстинктов. +Мы, программисты, привыкли ожидать появления проблем. +Если проблемы откладываются на более позднее время, мы счастливы. +Если проблемы не появляются, мы не обращаем на это внимания. +Поэтому наша стратегия проектирования должна увести нас в сторону от этих "размышлений о будущем". +К счастью, большинство разработчиков способно отучится от этой привычки "брать неприятности взаймы" (как про это говорила моя бабушка). +К сожалению, чем вы умнее, тем сложнее вам отучиться от этого.</p> +<p>XP works against many programmers' instincts. +As programmers, we get in the habit of anticipating problems. +When they appear later, we're happy. +When they don't appear, we don't notice. +So the design strategy will have to go sideways of this "guessing at the future" behavior. +Fortunately, most folks can unlearn the habit of "borrowing trouble" (as my grandmother called it). +Unfortunately, the smarter you are, the harder it will be to unlearn."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 17. Design Strategy", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "We often forget that it is also best to postpone decisions until the last possible moment. +This isn’t lazy or irresponsible; it lets us make informed choices with the best possible information. +A premature decision is a decision made with suboptimal knowledge. +We will have that much less customer feedback, mental reflection on the project, and experience with our implementation choices if we decide too soon."</p> +<p class="attribution">—"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p> </div></blockquote> <div class="admonition seealso"> <p class="admonition-title">См.также</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="../../../../../soft-skills/knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">Разрешение конфликтов на почве недостатка знаний</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../../../../team-topologies/harlan-mills%27-proposal.html#emacsway-brooks-s-law"><span class="std std-ref">Закон Брукса</span></a>"</p></li> +<li><p>"<a class="reference internal" href="yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../crash-course-in-software-development-economics.html#emacsway-software-development-economics-literature"><span class="std std-ref">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">Balancing Prediction/Adaptation</span></a>"</p></li> </ul> </div> -</section> -</section> -Fri, 22 Jul 2022 00:00:00 TDD - Разработка через тестированиеhttps://dckms.github.io/system-architecture/emacsway/it/tdd/tdd.html -<span id="emacsway-tdd"/> -<p>Вокруг TDD (Test-Driven Development) сложилось немало мифов и заблуждений, и здесь я попытаюсь восстановить изначальный его смысл. -Для этого придется обратиться к первоисточникам.</p> +Thu, 06 Oct 2022 00:00:00 SAGAhttps://dckms.github.io/system-architecture/emacsway/it/concurrency/saga.html +<span id="emacsway-saga"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +Mon, 29 Aug 2022 00:00:00 Transactionhttps://dckms.github.io/system-architecture/emacsway/it/concurrency/transaction.html +<span id="emacsway-transaction"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +Mon, 29 Aug 2022 00:00:00 Event Sourcinghttps://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/event-sourcing.html +<span id="emacsway-golang-event-sourcing"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#event-sourcing" id="id2">Event Sourcing</a></p></li> +</ul> +</nav> +<p>Термины StreamId/StreamName, StreamType, StreamPosition не несут информативности в домене, и должны появляться в домене только <a class="reference external" href="https://github.com/VaughnVernon/IDDD_Samples/blob/05d95572f2ad6b85357b216d7d617b27359a360d/iddd_collaboration/src/main/java/com/saasovation/collaboration/port/adapter/persistence/repository/EventStoreCalendarRepository.java#L54">на стадии сохранения</a>.</p> +<p>Иными словами, они не несут информации обработчикам доменных событий, которым нужен первичный идентификатор Агрегата, а не его сериализованное в строку представление.</p> +Sun, 07 Aug 2022 00:00:00 Использовать ли в проекте CanExecute pattern?https://dckms.github.io/system-architecture/emacsway/it/ddd/grade/domain/why-no-can-execute.html +<span id="emacsway-golang-can-execute"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<p>CanExecute pattern был описан в статье "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/validation-and-ddd/">Validation and DDD</a>" by Vladimir Khorikov.</p> +<p>Vladimir Khorikov - авторитетный специалист, смело принимающий на себя все риски первопроходца, который существенным образом повлиял на развитие индустрии, а также на мое становление как специалиста, за что я ему очень признателен.</p> +<p>CanExecute pattern, продемонстрированный Владимиром, является, действительно, очень удобным подходом, без которого очень сложно обойтись там, где это вызвано объективной необходимостью:</p> +<ol class="arabic simple"> +<li><p>в распределенных процедурах (процессах);</p></li> +<li><p>там, где существует вероятность установления частично-валидного состояния композитного объекта, т.е. для обеспечения атомарности валидации с целью осуществимости атомарности изменения состояния.</p></li> +</ol> +<p>В этом я убедился на собственной практике.</p> +<p>В других случаях, ключевой аргумент использования CanExecute pattern, приводимый в статье, сводится к CQS principle.</p> +<p>Я обсудил с ним этот вопрос, и он согласился с тем, что этот вопрос не совсем однозначный.</p> +<p>В этом подходе меня смущает тот факт, что образуется логическая зависимость - клиент класса действует исходя из предположения о том, что оба метода используют один и тот же инвариант.</p> +<p>В заметке "<a class="reference internal" href="../../tactical-design/cqrs/cqrs-command-and-result.html#emacsway-cqs-command-status-code"><span class="std std-ref">Может ли Command возвращать служебную информацию (код ошибки или успешность выполнения)?</span></a>" этот вопрос уже затрагивался, поэтому, повторюсь:</p> +<blockquote> +<div><p>💬️ "It is important here two deal with two common objections to the side-effect-free style.</p> +<p>The first has to do with error handling. +Sometimes a function with side effects is really a procedure, which in addition to doing its job returns a status code indicating how things went. +But there are better ways to do this; roughly speaking, the proper O-O technique is to <strong>enable the client, after an operation on an object, to perform a query on the status, represented for example by an attribute of the object</strong>, as in</p> +<p>target.some_operation(...)</p> +<p>how_did_it_go := target.status</p> +<p>Note that the technique of returning a status as function result is lame anyway. +It transforms a procedure into a function by adding the status as a result; +<strong>but it does not work if the routine was already a function, which already has a result of its own</strong>. +It is also problematic if you need more than one status indicator. +In such cases the C approach is either to return a "structure" (the equivalent of an object) with several components, which is getting close to the above scheme, or to use global variables — which raises a whole set of new problems, especially in a large system where many modules can trigger errors."</p> +<p class="attribution">—"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"</p> +</div></blockquote> +<p>Единственная причина, по которой Bertrand Meyer избегал возврата ошибок в то время, заключается в том, что тогда было невозможно возвратить одновременно и результат, и ошибку. +Сегодня таких проблем нет. +В Golang это поддерживается на уровне синтаксиса языка, а в других языках поддерживается объект Result.</p> +<p>Но даже если и разделять, то Bertrand Meyer рекомендует проверять ошибки после попытки, а не перед попыткой.</p> +Wed, 03 Aug 2022 00:00:00 Role of Software Design in Agilehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/software-design.html +<span id="emacsway-agile-software-design"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<figure class="align-center" id="id7"> +<a class="reference internal image-reference" href="../../../../../../_images/ouroboros.jpg"><img alt="Уроборос. Иллюстрация из открытых источников неизвестного автора." src="../../../../../../_images/ouroboros.jpg" style="width: 40%;"/></a> +<figcaption> +<p><span class="caption-text">Уроборос. Иллюстрация из открытых источников неизвестного автора.</span></p> +</figcaption> +</figure> <nav class="contents" id="id1"> <p class="topic-title">Содержание</p> <ul class="simple"> -<li><p><a class="reference internal" href="#tdd" id="id32">TDD - Разработка через тестирование</a></p> +<li><p><a class="reference internal" href="#role-of-software-design-in-agile" id="id12">Role of Software Design in Agile</a></p> <ul> -<li><p><a class="reference internal" href="#id2" id="id33">Что такое TDD?</a></p> +<li><p><a class="reference internal" href="#emacsway-who-reads-the-code" id="id13">Кто читает код?</a></p></li> +<li><p><a class="reference internal" href="#primary-technical-imperative" id="id14">Primary Technical Imperative</a></p></li> +<li><p><a class="reference internal" href="#id3" id="id15">Оправдано ли качество?</a></p> <ul> -<li><p><a class="reference internal" href="#tdd-software-design" id="id34">TDD - это о Software Design</a></p></li> -<li><p><a class="reference internal" href="#id8" id="id35">TDD - это способ управления сложностью</a></p></li> -<li><p><a class="reference internal" href="#emacsway-why-is-tdd-faster" id="id36">Почему TDD быстрее</a></p></li> -<li><p><a class="reference internal" href="#tdd-clean-code" id="id37">TDD - основной катализатор Clean Code</a></p></li> +<li><p><a class="reference internal" href="#martin-fowler" id="id16">Martin Fowler</a></p></li> +<li><p><a class="reference internal" href="#kent-beck" id="id17">Kent Beck</a></p></li> +<li><p><a class="reference internal" href="#robert-martin" id="id18">Robert Martin</a></p></li> +<li><p><a class="reference internal" href="#agile-manifesto" id="id19">Agile Manifesto</a></p></li> +<li><p><a class="reference internal" href="#ralph-johnson" id="id20">Ralph Johnson</a></p></li> +<li><p><a class="reference internal" href="#steve-mcconnell" id="id21">Steve McConnell</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id22">Сергей Тепляков</a></p></li> +<li><p><a class="reference internal" href="#id5" id="id23">Народное творчество</a></p></li> +<li><p><a class="reference internal" href="#randy-shoup" id="id24">Randy Shoup</a></p></li> </ul> </li> -<li><p><a class="reference internal" href="#id25" id="id38">Влияние TDD на темпы разработки</a></p></li> -<li><p><a class="reference internal" href="#black-box-or-white-box" id="id39">Black Box or White Box?</a></p></li> -<li><p><a class="reference internal" href="#sociable-or-solitary" id="id40">Sociable or Solitary?</a></p></li> -<li><p><a class="reference internal" href="#tdd-design-patterns" id="id41">TDD и Design Patterns</a></p></li> -<li><p><a class="reference internal" href="#one-assertion-per-test" id="id42">One assertion per test?</a></p></li> </ul> </li> </ul> </nav> -<section id="id2"> -<h2><a class="toc-backref" href="#id33" role="doc-backlink">Что такое TDD?</a></h2> -<p>Прежде всего, что такое TDD (Test-Driven Development)?</p> +<section id="emacsway-who-reads-the-code"> +<span id="id2"/><h2><a class="toc-backref" href="#id13" role="doc-backlink">Кто читает код?</a></h2> +<p>Среди малоопытных разработчиков иногда можно услышать, что им некогда писать качественный код, так как у них мало времени, а этот код все равно читать никто не будет.</p> +<p>Истина в том, что в процессе конструирования кода, 91% времени занимает именно чтение кода и борьба со сложностью, и только 9% времени (1:10) занимает ввод символов с клавиатуры. +И это соотношение дано еще для качественного кода.</p> +<p>Причем, разработчик пишет код в одиночку и лишь единожды. +Зато читают код все разработчики команды и по много раз.</p> +<p>Таким образом, плохо написанный код более чем на 91% (т.е. более чем на порядок!) влияет на снижение темпов разработки всей команды.</p> +<p>Кстати, этот момент хорошо объясняет то, почему <a class="reference internal" href="../../../../tdd/tdd.html#emacsway-why-is-tdd-faster"><span class="std std-ref">при TDD разработка осуществляется быстрее</span></a>, хотя объема кода пишется больше.</p> <blockquote> -<div><p>Чистый код, который работает (clean code that works), — в этой короткой, но содержательной фразе, придуманной Роном Джеффризом (Ron Jeffries), кроется весь смысл методики Test-Driven Development (TDD). -Чистый код, который работает, — это цель, к которой стоит стремиться, и этому есть причины.</p> -<p>Clean code that works - now. -This is the seeming contradiction that lies behind much of the pain of programming. -Test-driven development replies to this contradiction with a paradox-test the program before you write it.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id3" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "Кто-то спросит: так ли уж часто читается наш код? +Разве большая часть времени не уходит на его написание?</p> +<p>Вам когда-нибудь доводилось воспроизводить запись сеанса редактирования? +В 80-х и 90-х годах существовали редакторы, записывавшие все нажатия клавиш (например, Emacs). Вы могли проработать целый час, а потом воспроизвести весь сеанс, словно ускоренное кино. +Когда я это делал, результаты оказывались просто потрясающими.</p> +<p>Большинство операций относилось к прокрутке и переходу к другим модулям!</p> +<ul class="simple"> +<li><p>Боб открывает модуль.</p></li> +<li><p>Он находит функцию, которую необходимо изменить.</p></li> +<li><p>Задумывается о последствиях.</p></li> +<li><p>Ой, теперь он переходит в начало модуля, чтобы проверить инициализацию переменной.</p></li> +<li><p>Снова возвращается вниз и начинает вводить код.</p></li> +<li><p>Стирает то, что только что ввел.</p></li> +<li><p>Вводит заново.</p></li> +<li><p>Еще раз стирает!</p></li> +<li><p>Вводит половину чего-то другого, но стирает и это!</p></li> +<li><p>Прокручивает модуль к другой функции, которая вызывает изменяемую функцию, чтобы посмотреть, как она вызывается.</p></li> +<li><p>Возвращается обратно и восстанавливает только что стертый код.</p></li> +<li><p>Задумывается.</p></li> +<li><p>Снова стирает!</p></li> +<li><p>Открывает другое окно и просматривает код субкласса. Переопределяется ли в нем эта функция?</p></li> +</ul> +<p>&lt;...&gt;</p> +<p>В общем, вы поняли. +На самом деле соотношение времени чтения и написания кода превышает 10:1. +Мы постоянно читаем свой старый код, поскольку это необходимо для написания нового кода.</p> +<p>Из-за столь высокого соотношения наш код должен легко читаться, даже если это затрудняет его написание. +Конечно, написать код, не прочитав его, невозможно, так что упрощение чтения в действительности упрощает и написание кода. +Уйти от этой логики невозможно. +Невозможно написать код без предварительного чтения окружающего кода. +Код, который вы собираетесь написать сегодня, будет легко или тяжело писаться в зависимости от того, насколько легко или тяжело читается окружающий код. +Если вы хотите быстро справиться со своей задачей, если вы хотите, чтобы ваш код было легко писать — позаботьтесь о том, чтобы он легко читался.</p> +<p>You might ask: How much is code really read? Doesn't most of the effort go into writing it?</p> +<p>Have you ever played back an edit session? In the 80s and 90s we had editors like Emacs that kept track of every keystroke. +You could work for an hour and then play back your whole edit session like a high-speed movie. +When I did this, the results were fascinating.</p> +<p>The vast majority of the playback was scrolling and navigating to other modules!</p> +<ul class="simple"> +<li><p>Bob enters the module.</p></li> +<li><p>He scrolls down to the function needing change.</p></li> +<li><p>He pauses, considering his options.</p></li> +<li><p>Oh, he's scrolling up to the top of the module to check the initialization of a variable.</p></li> +<li><p>Now he scrolls back down and begins to type.</p></li> +<li><p>Ooops, he's erasing what he typed!</p></li> +<li><p>He types it again.</p></li> +<li><p>He erases it again!</p></li> +<li><p>He types half of something else but then erases that!</p></li> +<li><p>He scrolls down to another function that calls the function he's changing to see how it is called.</p></li> +<li><p>He scrolls back up and types the same code he just erased.</p></li> +<li><p>He pauses.</p></li> +<li><p>He erases that code again!</p></li> +<li><p>He pops up another window and looks at a subclass. Is that function overridden?</p></li> +</ul> +<p>&lt;...&gt;</p> +<p>You get the drift. Indeed, the ratio of time spent reading vs. writing is well over 10:1. +We are constantly reading old code as part of the effort to write new code.</p> +<p>Because this ratio is so high, we want the reading of code to be easy, even if it makes the writing harder. +Of course there's no way to write code without reading it, so making it easy to read actually makes it easier to write.</p> +<p>There is no escape from this logic. +You cannot write code if you cannot read the surrounding code. +The code you are trying to write today will be hard or easy to write depending on how hard or easy the surrounding code is to read. +So if you want to go fast, if you want to get done quickly, if you want your code to be easy to write, make it easy to read."</p> +<p class="attribution">—"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin, перевод: Е.Матвеев, ООО Издательство "Питер"</p> </div></blockquote> -<section id="tdd-software-design"> -<h3><a class="toc-backref" href="#id34" role="doc-backlink">TDD - это о Software Design</a></h3> -<p>Классическое заблуждение заключается в том, что TDD - это методика тестирования. -На самом же деле, TDD - это, прежде всего, методика разработки и проектирования:</p> +</section> +<section id="primary-technical-imperative"> +<span id="emacsway-primary-technical-imperative"/><h2><a class="toc-backref" href="#id14" role="doc-backlink">Primary Technical Imperative</a></h2> <blockquote> -<div><p>Ирония TDD состоит в том, что это вовсе не методика тестирования. -Это методика анализа, методика проектирования, фактически методика структурирования всей деятельности, связанной с разработкой программного кода.</p> -<p>One of the ironies of TDD is that it isn't a testing technique (the Cunningham Koan). -It's an analysis technique, a design technique, really a technique for structuring all the activities of development.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id4" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "There are two ways of constructing a software design: one way is to make it so simple that there are obviously no deficiencies, and the other is to make it so complicated that there are no obvious deficiencies."</p> +<p class="attribution">—C. A. R. Hoare</p> </div></blockquote> <blockquote> -<div><p>Если сравнивать со средним уровнем индустрии разработки программного обеспечения, методика TDD позволяет вам писать код, содержащий значительно меньше дефектов и формировать значительно более чистый дизайн. Те, кто стремится к изяществу, могут найти в TDD средство для достижения цели.</p> -<p>It lets you write code with far fewer defects and a much cleaner design than is common in the industry. However, those whose souls are healed by the balm of elegance can find in TDD a way to do well by doing good.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id5" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "Управление сложностью — самый важный технический аспект разработки ПО. +По-моему, управление сложностью настолько важно, что оно должно быть Главным Техническим Императивом Разработки ПО.</p> +<p>Managing complexity is the most important technical topic in software development. +In my view, it's so important that Software's Primary Technical Imperative has to be managing complexity."</p> +<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell, перевод: Издательско-торговый дом "Русская Редакция"</p> </div></blockquote> <blockquote> -<div><p>TDD базируется на очаровательно-наивном предположении программиста о том, что чем красивее код, тем вероятнее успех. -TDD помогает вам обращать внимание на правильные вопросы в подходящие для этого моменты времени. Благодаря этому вы можете делать дизайн чище и модифицировать его по мере того, как перед вами встают новые обстоятельства.</p> -<p>TDD rests on a charmingly naive geekoid assumption that if you write better code, you'll be more successful. -TDD helps you to pay attention to the right issues at the right time so you can make your designs cleaner, you can refine your designs as you learn.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id6" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "Дейкстра пишет, что ни один человек не обладает интеллектом, способным вместить все детали современной компьютерной программы (Dijkstra, 1972), поэтому нам - разработчикам ПО — не следует пытаться охватить всю программу сразу. +Вместо этого мы должны попытаться организовать программы так, чтобы можно было безопасно работать с их отдельными фрагментами по очереди. +Целью этого является минимизация объема программы, о котором нужно думать в конкретный момент времени. +Можете считать это своеобразным умственным жонглированием: чем больше умственных шаров программа заставляет поддерживать в воздухе, +тем выше вероятность того, что вы уроните один из них и допустите ошибку при проектировании или кодировании.</p> +<p>На уровне архитектуры ПО сложность проблемы можно снизить, разделив систему на подсистемы. +Несколько несложных фрагментов информации понять проще, чем один сложный. +В разбиении сложной проблемы на простые фрагменты и заключается цель всех методик проектирования ПО. +Чем более независимы подсистемы, тем безопаснее сосредоточиться на одном аспекте сложности в конкретный момент времени. +Грамотно определенные объекты разделяют аспекты проблемы так, чтобы вы могли решать их по очереди. +Пакеты обеспечивают такое же преимущество на более высоком уровне агрегации.</p> +<p>Стремление к краткости методов программы помогает снизить нагрузку на интеллект. +Этому же способствует написание программы в терминах проблемной области, а не низкоуровневых деталей реализации, +а также работа на самом высоком уровне абстракции.</p> +<p>Суть сказанного в том, что программисты, компенсирующие изначальные ограничения человеческого ума, +пишут более понятный и содержащий меньшее число ошибок код.</p> +<p>Dijkstra pointed out that no one's skull is really big enough to contain a modern computer program (Dijkstra 1972), +which means that we as software developers shouldn't try to cram whole programs into our skulls at once; +we should try to organize our programs in such a way that we can safely focus on one part of it at a time. +The goal is to minimize the amount of a program you have to think about at any one time. +You might think of this as mental juggling—the more mental balls the program requires you +to keep in the air at once, the more likely you'll drop one of the balls, leading to a design or coding error.</p> +<p>At the software-architecture level, the complexity of a problem is reduced by dividing the system into subsystems. +Humans have an easier time comprehending several simple pieces of information than one complicated piece. +The goal of all software-design techniques is to break a complicated problem into simple pieces. +The more independent the subsystems are, the more you make it safe to focus on one bit of complexity at a time. +Carefully defined objects separate concerns so that you can focus on one thing at a time. +Packages provide the same benefit at a higher level of aggregation.</p> +<p>Keeping routines short helps reduce your mental workload. +Writing programs in terms of the problem domain, rather than in terms of low-level implementation details, and +working at the highest level of abstraction reduce the load on your brain.</p> +<p>The bottom line is that programmers who compensate for inherent human limitations +write code that's easier for themselves and others to understand and that has fewer errors."</p> +<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell, перевод: Издательско-торговый дом "Русская Редакция"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "<strong>Главным Техническим Императивом Разработки ПО является управление сложностью.</strong> +Управлять сложностью будет гораздо легче, если при проектировании вы будете стремиться к простоте.</p> +<p>Есть два общих способа достижения простоты: +минимизация объема существенной сложности, с которой приходится иметь дело в любой конкретный момент времени, +и подавление необязательного роста несущественной сложности.</p> +<p><strong>Software's Primary Technical Imperative is managing complexity.</strong> +This is greatly aided by a design focus on simplicity.</p> +<p>Simplicity is achieved in two general ways: +minimizing the amount of essential complexity that anyone's brain has to deal with at any one time, +and keeping accidental complexity from proliferating needlessly."</p> +<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell, перевод: Издательско-торговый дом "Русская Редакция"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "При выполнении других заданий человек может удерживать в памяти 7±2 дискретных элементов [Miller, 1956]. +Если класс содержит более семи элементов данных-членов, подумайте, не разделить ли его на несколько менее крупных классов [Riel, 1996].</p> +<p>The number "7±2" has been found to be a number of discrete items a person can remember while performing other tasks [Miller 1956]. +If a class contains more than about seven data members, consider whether the class should be decomposed into multiple smaller classes [Riel 1996].</p> +<dl class="simple"> +<dt>[Miller, 1956]</dt><dd><p>Miller, G. A. 1956. "The Magical Number Seven, Plus or Minus Two: Some Limits on Our Capacity for Processing Information." +The Psychological Review 63, no. 2 (2): 81–97.</p> +</dd> +<dt>[Riel 1996]</dt><dd><p>Riel, Arthur J. 1996. Object-Oriented Design Heuristics. Reading, MA: Addison-Wesley."</p> +</dd> +</dl> +<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell, перевод: Издательско-торговый дом "Русская Редакция"</p> +</div></blockquote> +<p>По поводу последнего изречения - лучше один раз увидеть на примере метафоры в виде картинки со схожим эффектом:</p> +<figure class="align-left" id="id8"> +<a class="reference internal image-reference" href="../../../../../../_images/12-points.jpg"><img alt="Просто ваши глаза не могут увидеть все 12 точек одновременно. Ninio's extinction illusion. Twelve black dots cannot be seen at once. Ninio, J. and Stevens, K. A. (2000) Variations on the Hermann grid: an extinction illusion. Perception, 29, 1209-1217. The image source is a post by Akiyoshi Kitaoka https://www.facebook.com/akiyoshi.kitaoka/posts/10207806663219295" src="../../../../../../_images/12-points.jpg" style="width: 90%;"/></a> +<figcaption> +<p><span class="caption-text">Просто ваши глаза не могут увидеть все 12 точек одновременно. +Ninio's extinction illusion. Twelve black dots cannot be seen at once. +Ninio, J. and Stevens, K. A. (2000) Variations on the Hermann grid: an extinction illusion. Perception, 29, 1209-1217. +The image source is "<a class="reference external" href="https://www.facebook.com/akiyoshi.kitaoka/posts/10207806663219295">a post</a>" by Akiyoshi Kitaoka.</span></p> +</figcaption> +</figure> +<p>Как и в "Законе Миллера", суть картинки сводится к тому, что у человека есть предел способности <strong>воспринимать</strong> информацию, и если количество единиц поступающей информации превышает этот предел (не зависимо от его природы, будь то особенность работы рецепторов сетчатки или предел возможностей краткосрочной памяти), то начинается "жонглирование", т.е. неспособность рассмотреть (в прямом и в переносном смыслах) всю информацию единовременно и изолированно.</p> +<p>Вероятное объяснение этого явления заключается в том, что:</p> +<blockquote> +<div><p>💬 "Your eye's receptors are stimulated and influenced by the activity of neighboring receptors. In a complex, repetitive grid like this, one receptor can have trouble perceiving the dots accurately because of stimulation occurring in a nearby receptor."</p> +<p class="attribution">—<a class="reference external" href="https://www.brainhq.com/brain-resources/brain-teasers/ninios-extinction-illusion/">источник</a></p> +</div></blockquote> +<p><strong>Внимание</strong> - это избирательная направленность <strong>восприятия</strong>. +Периферийное зрение - это способность видеть те предметы, которые выходят за <strong>фокус</strong> основного <strong>внимания</strong>. +Слово "сфокусировать" - означает "сосредоточить", как в прямом (оптическом), так и в переносном (сконцентрироваться) смыслах. +Основной принцип управления сложностью - это её декомпозиция до такого уровня, над которым обеспечивается перевес умственных возможностей человека. Т.е. когда объем рассматриваемой изолированно сложности "вмещается" в <strong>фокус</strong> внимания человека.</p> +<p>См. также "<a class="reference internal" href="../../../../../soft-skills/icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Принцип ледокола</span></a>".</p> +<blockquote id="emacsway-kent-beck-constantine-s-law"> +<div><p>📝 "These were elucidated in the mid-70s by Yourdon &amp; Constantine in <a class="reference external" href="https://amzn.to/2GsuXvQ">Structured Design</a> and haven't changed. +Their argument goes like this:</p> +<ol class="arabic simple"> +<li><p>We design software to reduce its cost.</p></li> +<li><p>The cost of software is ≈ the cost of changing the software.</p></li> +<li><p>The cost of changing the software is ≈ the cost of the expensive changes (power laws and all that).</p></li> +<li><p>The cost of the expensive changes is generated by cascading changes — if I change this then I have to change that and that, and if I change that then…</p></li> +<li><p>Coupling between elements of a design is this propensity for a change to propagate.</p></li> +<li><p>So, design ≈ cost ≈ change ≈ big change ≈ coupling. Transitively, software design ≈ managing coupling.</p></li> +</ol> +<p>(This skips loads of interesting stuff, but I'm just trying to set up the argument for why rapid decomposition of a monolith into micro-services is counter-productive.)"</p> +<p>Managing Coupling</p> +<p>Note I don't say, "Eliminating coupling." +Decoupling comes with its own costs, both the cost of the decoupling itself and the future costs of unanticipated changes. +The more perfectly a design is adapted to one set of changes, the more likely it is to be blind-sided by novel changes. And so we have the classic tradeoff curve:</p> +<figure class="align-left" id="id9"> +<a class="reference internal image-reference" href="../../../../../../_images/balancing-coupling-decoupling.jpeg"><img alt="Classic tradeoff curve of balancing cost of Coupling vs. cost of Decoupling. The image source is article &quot;Monolith -&gt; Services: Theory &amp; Practice&quot; by Kent Beck https://medium.com/@kentbeck_7670/monolith-services-theory-practice-617e4546a879" src="../../../../../../_images/balancing-coupling-decoupling.jpeg" style="width: 90%;"/></a> +<figcaption> +<p><span class="caption-text">Classic tradeoff curve of balancing cost of Coupling vs. cost of Decoupling. The image source is article "<a class="reference external" href="https://medium.com/@kentbeck_7670/monolith-services-theory-practice-617e4546a879">Monolith -&gt; Services: Theory &amp; Practice</a>" by Kent Beck.</span></p> +</figcaption> +</figure> +<p>You manage coupling one of two ways:</p> +<ol class="arabic simple"> +<li><p>Eliminate coupling. A client and server with hard-coded read() and write() functions are coupled with respect to protocol changes. Change a write() and you'll have to change the read(). Introduce an interface definition language, though, and you can add to the protocol in one place and have the change propagate automatically to read() and write().</p></li> +<li><p>Reduce coupling's scope. If changing one element implies changing ten others, then it's better if those elements are together than if they are scattered all over the system —less to navigate, less to examine, less to test. The number of elements to change is the same, but the cost per change is smaller. (This is also known as the "manure in one pile" principle, or less-aromatically "cohesion".)</p></li> +</ol> +<p class="attribution">—"<a class="reference external" href="https://medium.com/@kentbeck_7670/monolith-services-theory-practice-617e4546a879">Monolith -&gt; Services: Theory &amp; Practice</a>" by Kent Beck</p> </div></blockquote> +<p>Eric Evans дает неплохое определение Constantine's Law нетехническим языком:</p> <blockquote> -<div><p>Мы с Робертом Мартином (Robert Martin) занимались исследованием подобного стиля TDD. -Проблема состоит в том, что дизайн продолжает вас удивлять. -Идеи, которые на первый взгляд кажутся вам вполне уместными, позже оказываются неправильными. -Поэтому я не рекомендую целиком и полностью доверять своим предчувствиям относительно паттернов. -Лучше думайте о том, что, по-вашему, должна делать система, позвольте дизайну оформиться так, как это необходимо.</p> -<p>Robert Martin and I did some research into this style of TDD. The problem is that the design keeps surprising you. -Perfectly sensible design ideas turn out to be wrong. -Better just to think about what you want the system to do, and let the design sort itself out later.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id7" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>💬 "МОДУЛИ дают возможность посмотреть на модель с разных сторон: +во-первых, можно изучить подроб­ности устройства модуля, не вникая в сложное целое; +во-вторых, удобно рассматривать взаимоотношения между модулями, не вдаваясь в детали их внутреннего устройства.</p> +<p>&lt;...&gt;</p> +<p>То, что при делении на модули должна соблюдаться низкая внешняя зависимость (low coupling) при высокой внутренней связности (high cohesion)- это общие слова. +Определения зависимости и связности грешат уклоном в чисто технические, количест­венные критерии, по которым их якобы можно измерить, подсчитав количество ассо­циаций и взаимодействий. +Но это не просто механические характеристики подразде­ления кода на модули, а идейные концепции. +Человек не может одновременно удер­живать в уме слишком много предметов (отсюда низкая внешняя зависимость). +А плохо связанные между собой фрагменты информации так же трудно понять, как неструктурированную "кашу" из идей (отсюда высокая внутренняя связность).</p> +<p>MODULES give people two views of the model: +They can look at detail within a MODULE without being overwhelmed by the whole, or they can look at relationships between MODULES in views that exclude interior detail.</p> +<p>&lt;...&gt;</p> +<p>It is a truism that there should be low coupling between MODULES and high cohesion within them. +Explanations of coupling and cohesion tend to make them sound like technical metrics, to be judged mechanically based on the distributions of associations and interactions. Yet it isn't just code being divided into MODULES, but concepts. +There is a limit to how many things a person can think about at once (hence low coupling). +Incoherent fragments of ideas are as hard to understand as an undifferentiated soup of ideas (hence high cohesion)."</p> +<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> </div></blockquote> </section> -<section id="id8"> -<h3><a class="toc-backref" href="#id35" role="doc-backlink">TDD - это способ управления сложностью</a></h3> -<p>Согласно закономерности <a class="reference external" href="https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two">Магического числа семь плюс-минус два</a>, обнаруженной американским учёным-психологом Джорджем Миллером, кратковременная человеческая память, как правило, не может запомнить и повторить более 7 ± 2 элементов. -Превышение этого порога замедляет темпы разработки, так как мозг не может преодолеть высокую концентрацию сложности.</p> -<p>Тут можно провести аналогию с народной пословицей: веник сложно поломать пока он связан, но, развязав его на отдельные прутики, их можно легко переломать по отдельности. -TDD именно именно это и делает - декомпозирует (перемалывает) сложность в процессе разработки.</p> -<p id="index-0">Здесь хорошо прослеживается аналогия с рефакторингом, который, в значительной мере, был основан тем же самым человеком - Кент Беком.</p> +<section id="id3"> +<h2><a class="toc-backref" href="#id15" role="doc-backlink">Оправдано ли качество?</a></h2> +<section id="martin-fowler"> +<h3><a class="toc-backref" href="#id16" role="doc-backlink">Martin Fowler</a></h3> <blockquote> -<div><p>Мой первый опыт проведения дисциплинированного "поэтапного" рефакторинга связан с программированием на пару с Кентом Беком (Kent Beck) на высоте 30 000 футов.</p> -<p>My first experience with disciplined, "one step at a time" refactoring was when I was pair-programming at 30,000 feet with Kent Beck.</p> -<p class="attribution">—Martin Fowler, the key author of "Refactoring: Improving the Design of Existing Code" <a class="footnote-reference brackets" href="#fnrefactoring" id="id9" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts, перевод С. Маккавеева</p> +<div><p>📝 "In most contexts higher quality ⇒ expensive. But high internal quality of software allows us to develop features faster and cheaper."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/TradableQualityHypothesis.html">Tradable Quality Hypothesis</a>" by Martin Fowler</p> </div></blockquote> -<p>К тому же, рефакторинг является необъемлемой частью цикла TDD:</p> +<figure class="align-left" id="id10"> +<span id="emacsway-design-stamina-graph"/><a class="reference internal image-reference" href="../../../../../../_images/design-stamina-graph.png"><img alt="The pseudo-graph plots delivered functionality (cumulative) versus time for two imaginary stereotypical projects: one with good design and one with no design. The image from &quot;Design Stamina Hypothesis&quot; by Martin Fowler. https://martinfowler.com/bliki/DesignStaminaHypothesis.html" src="../../../../../../_images/design-stamina-graph.png" style="width: 90%;"/></a> +<figcaption> +<p><span class="caption-text">The pseudo-graph plots delivered functionality (cumulative) versus time for two imaginary stereotypical projects: one with good design and one with no design. The image from "<a class="reference external" href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>" by Martin Fowler.</span></p> +</figcaption> +</figure> <blockquote> -<div><p>Красный—зеленый—рефакторинг — это мантра TDD.</p> -<p>Red/green/refactor - the TDD mantra.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id10" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "... the true value of internal quality - that it's the enabler to speed. The purpose of internal quality is to go faster."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/TradableQualityHypothesis.html">Tradable Quality Hypothesis</a>" by Martin Fowler</p> </div></blockquote> -<p>По основной версии, слово "refactoring" происходит от математического термина "factoring", и дословно переводится как "факторизация" или "декомпозиция", о чем говорит на своем сайте ключевой автор известной книги "Refactoring: Improving the Design of Existing Code" <a class="footnote-reference brackets" href="#fnrefactoring" id="id11" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> (благодаря которой, рефакторинг, собственно, и стал популярным):</p> <blockquote> -<div><p>The obvious answer comes from the notion of factoring in mathematics. You can take an expressions such as x^2 + 5x + 6 and factor it into (x+2)(x+3). By factoring it you can make a number of mathematical operations much easier. Obviously this is much the same as representing 18 as 2*3^2. I've certainly often heard of people talking about a program as well factored once it's broken out into similarly logical chunks.</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/EtymologyOfRefactoring.html">Etymology Of Refactoring</a>" by Martin Fowler</p> +<div><p>📝 "The value of good software design is economic: you can continue to add new functionality quickly even as the code-base grows in size."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>" by Martin Fowler</p> </div></blockquote> -<p>Такое же мнение можно увидеть и на сайте Ward Cunningham:</p> <blockquote> -<div><p>Refactoring is a kind of reorganization. <strong>Technically, it comes from mathematics when you factor an expression into an equivalence - the factors are cleaner ways of expressing the same statement.</strong> Refactoring implies equivalence; the beginning and end products must be functionally identical. You can view refactoring as a special case of reworking (see WhatIsReworking).</p> -<p>Practically, refactoring means making code clearer and cleaner and simpler and elegant. Or, in other words, clean up after yourself when you code. Examples would run the range from renaming a variable to introducing a method into a third-party class that you don't have source for.</p> -<p><strong>Refactoring is not rewriting, although many people think they are the same.</strong> There are many good reasons to distinguish them, such as regression test requirements and knowledge of system functionality. The technical difference between the two is that refactoring, as stated above, doesn't change the functionality (or information content) of the system whereas rewriting does. Rewriting is reworking. See WhatIsReworking.</p> -<p>Refactoring is a good thing because complex expressions are typically built from simpler, more grokable components. Refactoring either exposes those simpler components or reduces them to the more efficient complex expression (depending on which way you are going).</p> -<p>For an example of efficiency, count the terms and operators: (x - 1) * (x + 1) = x^2 - 1. Four terms versus three. Three operators versus two. However, the left hand side expression is (arguably) simpler to understand because it uses simpler operations. Also, it provides you more information about the structure of the function f(x) = x^2 - 1, like the roots are +/- 1, that would be difficult to determine just by "looking" at the right hand side.</p> -<p class="attribution">—"<a class="reference external" href="http://wiki.c2.com/?WhatIsRefactoring">What Is Refactoring</a>" on wiki.c2.com</p> +<div><p>📝 "We usually perceive that it costs more to get higher quality, but software internal quality actually reduces costs."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/is-quality-worth-cost.html">Is High Quality Software Worth the Cost?</a>" by Martin Fowler</p> </div></blockquote> -<p>Если кому-то имя Ward Cunningham ни о чем не говорит, то вот как представил его сам Kent Beck в книге "Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id12" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>:</p> <blockquote> -<div><p>Я начал свою жизнь настоящего программиста благодаря наставничеству и в рамках постоянного сотрудничества с Уордом Каннингэмом (Ward Cunningham). -Иногда я рассматриваю разработку, основанную на тестах, как попытку предоставить каждому программисту, работающему в произвольной среде, ощущение комфорта и тесной дружбы, которое было у нас с Уордом, когда мы вместе разрабатывали программы Smalltalk в среде Smalltalk. -He существует способа определить первоначальный источник идей, если два человека обладают одним общим мозгом. -Если вы предположите, что все хорошие идеи на самом деле изначально придумал Уорд, вы не будете далеки от истины.</p> -<p>My life as a real programmer started with patient mentoring from and continuing collaboration -with Ward Cunningham. Sometimes I see Test-Driven Development (TDD) as an attempt to -give any software engineer, working in any environment, the sense of comfort and intimacy -we had with our Smalltalk environment and our Smalltalk programs. There is no way to sort -out the source of ideas once two people have shared a brain. If you assume that all of the -good ideas here are Ward's, then you won't be far wrong.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id13" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "The fundamental role of internal quality is that it lowers the cost of future change. +But there is some extra effort required to write good software, which does impose some cost in the short term."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/is-quality-worth-cost.html">Is High Quality Software Worth the Cost?</a>" by Martin Fowler</p> </div></blockquote> -<p>Ну и Википедия о факторизации:</p> <blockquote> -<div><p>Factorization (or factoring) may also refer to more general decompositions of a mathematical object into the product of smaller or simpler objects. -For example, every function may be factored into the composition of a surjective function with an injective function.</p> -<p class="attribution">—"<a class="reference external" href="https://en.wikipedia.org/wiki/Factorization">Factorization</a>", Wikipedia</p> +<div><p>📝 "The whole point of good design and clean code is to make you go faster - if it didn't people like Uncle Bob, Kent Beck, and Ward Cunningham wouldn't be spending time talking about it."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/TechnicalDebtQuadrant.html">Technical Debt Quadrant</a>" by Martin Fowler</p> </div></blockquote> <blockquote> -<div><p>Decomposition in computer science, also known as factoring, is breaking a complex problem or system into parts that are easier to conceive, understand, program, and maintain.</p> -<p class="attribution">—"<a class="reference external" href="https://en.wikipedia.org/wiki/Decomposition_(computer_science)">Decomposition</a>", Wikipedia</p> +<div><p>📝 "Sadly, software developers usually don't do a good job of explaining this situation. +Countless times I've talked to development teams who say "they (management) won't let us write good quality code because it takes too long". +Developers often justify attention to quality by justifying through the need for proper professionalism. +But this moralistic argument implies that this quality comes at a cost - dooming their argument. +The annoying thing is that the resulting crufty code both makes developers' lives harder, and costs the customer money. +When thinking about internal quality, I stress that we should only approach it as an economic argument. +High internal quality reduces the cost of future features, meaning that putting the time into writing good code actually reduces cost.</p> +<p>This is why the question that heads this article misses the point. +The "cost" of high internal quality software is negative. +The usual trade-off between cost and quality, one that we are used to for most decisions in our life, does not make sense with the internal quality of software. +(It does for external quality, such as a carefully crafted user-experience.) +Because the relationship between cost and internal quality is an unusual and counter-intuitive relationship, it's usually hard to absorb. +But understanding it is critical to developing software at maximum efficiency."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/is-quality-worth-cost.html">Is High Quality Software Worth the Cost?</a>" by Martin Fowler</p> </div></blockquote> <blockquote> -<div><p>В математике факториза́ция или фа́кторинг — это декомпозиция объекта (например, числа, полинома или матрицы) в произведение других объектов или факторов, которые, будучи перемноженными, дают исходный объект. -Например, число 15 факторизуется на простые числа 3 и 5, а полином x2 − 4 факторизуется на (x − 2)(x + 2). -В результате факторизации во всех случаях получается произведение более простых объектов, чем исходный.</p> -<p class="attribution">—"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F">Факторизация</a>", Wikipedia</p> +<div><p>📝 "Рефакторинг ускоряет написание программ</p> +<p>В конечном итоге все сказанное сводится к одному: рефакторинг ускоряет написание программ.</p> +<p>Создается впечатление внутреннего противоречия. +Когда я рассказываю о рефакторинге, становится очевидно, что он повышает качество кода. +Улучшение проекта, повышение удобочитаемости, уменьшение количества ошибок — все это способствует качеству кода. +Но разве скорость разработки не снижается из-за всего этого?</p> +<p>Когда я общаюсь с разработчиками программного обеспечения, которые какое-то время работали над системой, я часто слышу, что сначала им удалось быстро продвинуться вперед, но теперь добавление новых функциональных возможностей занимает гораздо больше времени. +Каждая новая функция требует все больше и больше времени, чтобы понять, как вписать ее в существующую кодовую базу, а после ее добавления часто возникают ошибки, исправление которых занимает еще больше времени. +Кодовая база начинает выглядеть как серия исправлений, исправляющих предыдущие исправления, и требуются навыки археолога, чтобы выяснить, как все это работает. +Все это замедляет добавление новых функциональных возможностей до такой степени, что зачастую разработчики хотят начать все заново с чистого листа.</p> +<p>Визуализировать это положение вещей можно с помощью следующего псевдографика.</p> +<p>Но некоторые команды сообщают о другом опыте. +Они утверждают, что могут добавлять новые функциональные возможности быстрее, потому что они могут использовать уже существующий код, опираясь на то, что уже имеется в наличии.</p> +<p>Разница между этими проектами заключается во внутреннем качестве программного обеспечения. +Программное обеспечение с хорошим внутренним проектом позволяет легко найти, какие нужно внести изменения, чтобы добавить новую функциональную возможность, и где. +Хорошая модульность позволяет понять только небольшое подмножество кода, в которое нужно вносить изменения. +Если код понятен, меньше вероятность внести ошибку, а если это и произойдет, процесс отладки будет намного проще. +Так кодовая база превращается в платформу для создания новых функциональных возможностей для своей предметной области.</p> +<p>Я называю этот эффект гипотезой стойкости проекта (<a class="reference external" href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>): +создавая хороший внутренний проект, мы повышаем стойкость программного обеспечения, позволяющую двигаться быстрее. +Я не могу доказать, что это так, поэтому называю это утверждение гипотезой. +Но так подсказывает мой опыт, а также опыт сотен отличных программистов, с которыми я познакомился за свою карьеру.</p> +<p>Двадцать лет назад общепринятым было мнение, что для создания хорошего проекта нужно завершить проектирование до начала кодирования, потому что, как только мы написали код, мы можем столкнуться только с ухудшением и упадком. +Рефакторинг меняет эту картину. +Теперь мы знаем, что можем улучшить проект существующего кода, так что мы можем формировать и улучшать проект с течением времени, даже когда меняются потребности программы. +Поскольку очень сложно сделать хороший проект заранее, рефакторинг становится жизненно важным.</p> +<p>Refactoring Helps Me Program Faster</p> +<p>In the end, all the earlier points come down to this: Refactoring helps me develop code more quickly.</p> +<p>This sounds counterintuitive. +When I talk about refactoring, people can easily see that it improves quality. +Better internal design, readability, reducing bugs—all theseimprove quality. +But doesn't the time I spend on refactoring reduce the speed of development?</p> +<p>When I talk to software developers who have been working on a system for a while, I often hear that they were able to make progress rapidly at first, but now it takes much longer to add new features. +Every new feature requires more and more time to understand how to fit it into the existing code base, and once it's added, bugs often crop up that take even longer to fix. +The code base starts looking like a series of patches covering patches, and it takes an exercise in archaeology to figure out how things work. +This burden slows down adding new features — to the point that developers wish they could start again from a blank slate.</p> +<p>I can visualize this state of affairs with <a class="reference internal" href="#emacsway-design-stamina-graph"><span class="std std-ref">the following pseudograph</span></a>.</p> +<p>But some teams report a different experience. +They find they can add new features faster because they can leverage the existing things by quickly building on what's already there.</p> +<p>The difference between these two is the internal quality of the software. +Software with a good internal design allows me to easily find how and where I need to make changes to add a new feature. +Good modularity allows me to only have to understand a small subset of the code base to make a change. +If the code is clear, I'm less likely to introduce a bug, and if I do, the debugging effort is much easier. +Done well, my code base turns into a platform for building new features for its domain.</p> +<p>I refer to this effect as the <a class="reference external" href="https://martinfowler.com/bliki/DesignStaminaHypothesis.html">Design Stamina Hypothesis</a>: +By putting our effort into a good internal design, we increase the stamina of the software effort, allowing us to go faster for longer. +I can't prove that this is the case, which is why I refer to it as a hypothesis. +But it explains my experience, together with the experience of hundreds of great programmers that I've got to know over my career.</p> +<p>Twenty years ago, the conventional wisdom was that to get this kind of good design, it had to be completed before starting to program — because once we wrote the code, we could only face decay. +Refactoring changes this picture. +We now know we can improve the design of existing code—so we can form and improve a design over time, even as the needs of the program change. +Since it is very difficult to do a good design up front, refactoring becomes vital to achieving that virtuous path of rapid functionality."</p> +<p class="attribution">—"Refactoring: Improving the Design of Existing Code" 2nd edition by Martin Fowler, Kent Beck, перевод И.В. Красикова под редакцией С.Н. Тригуб</p> </div></blockquote> -<p>Таким образом, рефакторинг - это способ управления сложностью, который делает программу более читаемой и понимаемой за счет декомпозиции сложности, что снижает нагрузку на краткосрочную память. -Процесс рефакторинга подобен факторизации математического выражения, в результате которого выводится более легкое эквивалентное выражение, т.е. сохраняется функциональная идентичность. -Именно поэтому рефакторинг оставляет неизменным внешнее поведение системы:</p> <blockquote> -<div><p>Рефакторинг представляет собой процесс такого изменения программной системы, при котором не меняется внешнее поведение кода, но улучшается его внутренняя структура.</p> -<p>Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure.</p> -<p class="attribution">—Martin Fowler in "Refactoring: Improving the Design of Existing Code" <a class="footnote-reference brackets" href="#fnrefactoring" id="id14" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts, перевод С. Маккавеева</p> +<div><p>📝 "In its common usage, evolutionary design is a disaster. +The design ends up being the aggregation of a bunch of ad-hoc tactical decisions, each of which makes the code harder to alter. +In many ways you might argue this is no design, certainly it usually leads to a poor design. +As Kent puts it, <strong>design is there to enable you to keep changing the software easily in the long term.</strong> +<strong>As design deteriorates, so does your ability to make changes effectively.</strong> +You have the state of software entropy, over time the design gets worse and worse. +Not only does this make the software harder to change, it also makes bugs both easier to breed and harder to find and safely kill. +This is the "code and fix" nightmare, where the bugs become exponentially more expensive to fix as the project goes on."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler</p> </div></blockquote> -<p>TDD, как и рефакторинг, расщепляет сложность таким образом, чтобы минимизировать объем сложности, рассматриваемый разработчиком в единицу времени. -Это как песочные часы - одна песчинка в единицу времени. -Именно этим объясняется повышение темпов разработки при использовании TDD.</p> <blockquote> -<div><p>Каким образом можно модифицировать одну часть метода или объекта, состоящего из нескольких частей? -Вначале изолируйте изменяемую часть. -Мне приходит в голову аналогия с хирургической операцией: фактически все тело оперируемого пациента покрыто специальной простыней за исключением места, в котором, собственно, осуществляется операция. -<strong>Благодаря такому покрытию хирург имеет дело с фиксированным набором переменных.</strong> -Перед выполнением операции врачи сколь угодно долго могут обсуждать, какое влияние на здоровье пациента оказывает тот или иной орган, однако во время операции внимание хирурга должно быть сфокусировано.</p> -<p>How do you change one part of a multi-part method or object? First, isolate the part that has to change. -The picture that comes to my mind is surgery: The entire patient except the part to be operated on is draped. -<strong>The draping leaves the surgeon with only a fixed set of variables.</strong> -Now, we could have long arguments over whether this abstraction of a person to a lower left quadrant abdomen leads to good health care, but at the moment of surgery, I'm kind of glad the surgeon can focus.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id15" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "If you're a manager or customer how can you tell if the software is well designed? +It matters to you because poorly designed software will be more expensive to modify in the future."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html">Is Design Dead?</a>" by Martin Fowler</p> </div></blockquote> -<p>В этом отношении, TDD можно сравнить с <a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A8%D0%BE%D1%80%D1%8B">шорами</a>.</p> <blockquote> -<div><p>Несмотря на множество появившихся в последнее время мощных инструментов, программирование по-прежнему остается сложной работой. -Я часто ощущаю себя в ситуации, когда мне кажется, что я жонглирую шариками, и мне приходится следить за несколькими шариками в воздухе в одно и то же время: малейшая потеря внимания, и все сыпется на пол. -Методика TDD позволяет избавиться от этого ощущения.</p> -<p><strong>Когда вы работаете в стиле TDD, в воздухе постоянно находится лишь один шарик.</strong> -<strong>Вы можете сконцентрироваться на нем, а значит, хорошо справиться со своей работой.</strong> -Когда я добавляю в программу новую функциональность, я не думаю о том, какой дизайн должен быть реализован в данной функции. -Я просто пытаюсь добиться срабатывания тестов самым простым из доступных мне способов. -Когда я переключаюсь в режим рефакторинга, я не беспокоюсь о добавлении в программу новых функций, я думаю только о правильном дизайне. -На каждом из этих этапов я концентрируюсь на единственной задаче, благодаря этому мое внимание не распыляется.</p> -<p>Despite all the fancy tools that we have, programming is still hard. -I can remember many programming times when I feel like I was trying to keep several balls in the air at once, any lapse of concentration and everything would come tumbling down. -Test-driven development helps reduce that feeling, and as a result you get this rapid unhurriedness.</p> -<p><strong>I think the reason for this is that working in a test-driven development style gives you this sense of keeping just one ball in the air at once, so you can concentrate on that ball properly and do a really good job with it.</strong> -When I'm trying to add some new functionality, I'm not worried about what really makes a good design for this piece of function, I'm just trying to get a test to pass as easily as I can. -When I switch to refactoring mode, I'm not worried about adding some new function, I'm just worried about getting the right design. -With both of these I'm just focused on one thing at a time, and as a result I can concentrate better on that one -thing.</p> -<p class="attribution">—Martin Fowler, Afterword, "Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id16" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>, перевод П. Анджан</p> +<div><p>📝 "From the very earliest days of agile methods, people have asked what role there is for architectural or design thinking. +A common misconception is that since agile methods drop the notion of a detailed up-front design artifact, that there is no room for architecture in an agile project. +In my keynote at the first-ever agile conference, I pointed out that design was every bit as important for agile projects, but it manifests itself differently, becoming an evolutionary approach."</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/agile.html">Agile Software Development</a>" by Martin Fowler</p> </div></blockquote> +</section> +<section id="kent-beck"> +<h3><a class="toc-backref" href="#id17" role="doc-backlink">Kent Beck</a></h3> <blockquote> -<div><p>Снижение количества дефектов приводит к возникновению множества вторичных психологических и социальных эффектов. -После того как я начал работать в стиле TDD, программирование стало для меня значительно менее нервным занятием. -<strong>Когда я работаю в стиле TDD, мне не надо беспокоиться о множестве вещей.</strong> -<strong>Вначале я могу заставить paботать только один тест, потом — все остальные.</strong> -Уровень стресса существенно снизился. -Взаимоотношения с партнерами по команде стали более позитивными. -Разработанный мною код перестал быть причиной сбоев, люди стали в большей степени рассчитывать на него. -У заказчиков тоже повысилось настроение. -Теперь выпуск очередной версии системы означает новую функциональность, а не набор новых дефектов, которые добавляются к уже существующим.</p> -<p>Part of the effect certainly comes from reducing defects. -The sooner you find and fix a defect, the cheaper it is, often dramatically so (just ask the Mars Lander). -There are plenty of secondary psychological and social effects from reduced defects. My own practice of programming became much less stressful when I started with TDD. -<strong>No longer did I have to worry about everything at once.</strong> -<strong>I could make this test run, and then all the rest.</strong> -Relationships with my teammates became more positive. -I stopped breaking builds, andpeople could rely on my software to work. -Customers of my systems became more positive, too. -A new release of the system just meant more functionality, not a host of new defects to identify among all of their old favorite bugs.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id17" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> -</div></blockquote> -<p>Иногда мозгу сложно удержать все в голове, и разработчик берется за листочек и ручку. -При TDD, вместо листочка и ручки используется файловый редактор. -TDD позволяет сфокусировать мозг на минимально возможной единице сложности, которую можно рассмотреть изолированно, что приводит к перераспределению умственных ресурсов. -Кстати, именно это является одной из ключевых особенностей, благодаря которой, практикование TDD делает код чище.</p> -<p>Если рефакторинг помогает сосредоточиться на одной обязанности, выполняемой функцией, то TDD идет еще дальше, и помогает сосредоточиться на одном конкретном значении функции, а значит, - на одном из ее внутренних состояний. -Это позволяет выводить алгоритм функции путем обобщения пересекаемых триангуляцией ее внутренних состояний (и поведений, производящих эти состояния). -А это, в свою очередь, позволяет моделировать поведение функции небольшими законченными фрагментами, удовлетворяющими конкретным значениям функции, и визуализировать формирование поведения функции прямо в редакторе. -Наглядно это демонстрируется на примере <a class="reference download internal" download="" href="../../../_downloads/ab3bcac3e843b3925d3fa4bcadf08fbe/tdd-fibonacci.txt"><code class="xref download docutils literal notranslate"><span class="pre">выведения</span> <span class="pre">функции</span> <span class="pre">Фибоначи</span></code></a> в приложении книги, см. Appendix II. Fibonacci <a class="footnote-reference brackets" href="#fntdd" id="id18" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>.</p> +<div><p>📝 "Nothing kills speed more effectively than poor internal quality."</p> +<p class="attribution">—"Planning Extreme Programming" by Kent Beck, Martin Fowler</p> +</div></blockquote> <blockquote> -<div><p>Это еще один паттерн рефакторинга: <strong>разработать код, который работает с некоторым конкретным экземпляром, и обобщить этот код так, чтобы он мог работать со всеми остальными экземплярами</strong>, для этого константы заменяются переменными. -В данном случае роль константы играет не некоторое значение, а жестко фиксированный код (имя конкретного метода). -Однако принцип остается одним и тем же. -В рамках TDD эта проблема решается очень легко: <strong>методика TDD снабжает вас конкретными работающими примерами, исходя из которых вы можете выполнить обобщение</strong>. -Это значительно проще, чем выполнять обобщение исходя только из собственных умозаключений.</p> -<p>Here is another general pattern of refactoring: <strong>take code that works in one instance and generalize it to work in many</strong> by replacing constants with variables. -Here the constant was hardwired code, not a data value, but the principle is the same. -<strong>TDD makes this work well by giving you running concrete examples from which to generalize</strong>, instead of having to generalize purely with reasoning.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id19" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "... the activity of design is not an option. It must be given serious thought for software development to be effective."</p> +<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> </div></blockquote> <blockquote> -<div><p>Контроль над объемом работы. -Программисты привыкли пытаться предвидеть возникновение в будущем самых разнообразных проблем. -Если вы начинаете с конкретного примера и затем осуществляете <strong>обобщение кода</strong>, это помогает вам избавиться от излишних опасений. -Вы можете <strong>сконцентрироваться на решении конкретной проблемы</strong> и поэтому выполнить работу лучше. -При переходе к следующему тесту вы опять же концентрируетесь на нем, так как знаете, что предыдущий тест гарантированно работает.</p> -<p>Scope control - Programmers are good at imagining all sorts of future problems. -Starting with one concrete example and <strong>generalizing</strong> from there prevents you from prematurely confusing yourself with extraneous concerns. -You can do a better job of solving the immediate problem <strong>because you are focused</strong>. -When you go to implement the next test case, you can focus on that one, too, knowing that the previous test is guaranteed to work.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id20" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "Качество — это еще одна весьма странная переменная. +Зачастую, настаивая на улучшении качества, мы можете завершить проект быстрее, чем запланировано. +Или вы можете успеть сделать больше за заданный интервал времени. +Именно это случилось со мной, когда я приступил к разработке тестов для программного модуля, работа над которым описывалась в главе 2. +Как только я закончил работу над всеми тестами, я был настолько уверен в своем коде, что смог разработать код модуля существенно быстрее, без каких-либо липших сомнений и размышлений. +Я смог подчистить мою систему с меньшим количеством усилий, в результате я существенно упростил дальнейшую разработку. +Мне часто приходится наблюдать, как подобное происходит с целыми командами разработчиков. +Как только они приступают к тестированию или как только они разрабатывают общие для всех стандарты кодирования, работа начинает идти существенно быстрее.</p> +<p>Существует весьма странная зависимость между внутренним и внешним качеством. +Внешнее качество — это качество, измерением которого занимается заказчик. +Внутреннее качество оценивается программистами. +Если вы намерены временно пожертвовать внутренним качеством для того, чтобы сократить время разработки, и при этом надеетесь на то, что внешнее качество не пострадает слишком сильно, имейте в виду, что вы стремитесь к достижению краткосрочной цели. +Возможно, закрыв глаза на качество внутренней отделки, вам удастся сэкономить пару недель или даже месяц, однако с течением времени количество внутренних проблем может увеличиться настолько, что разрабатываемую вами систему будет чрезвычайно сложно сопровождать и развивать; +кроме того, возможно, вам не удастся достичь приемлемого уровня внешнего качества.</p> +<p>Quality is another strange variable. +Often, by insisting on better quality you can get projects done sooner, or you can get more done in a given amount of time. +This happened to me when I started writing unit tests (as described in Chapter 2, A Development Episode, page 7). +As soon as I had my tests, I had so much more confidence in my code that I wrote faster, without stress. +I could clean up my system more easily, which made further development easier. +I've also seen this happen with teams. +As soon as they start testing, or as soon as they agree on coding standards, they start going faster.</p> +<p>There is a strange relationship between internal and external quality. +External quality is quality as measured by the customer. +Internal quality is quality as measured by the programmers. +Temporarily sacrificing internal quality to reduce time to market in hopes that external quality won't suffer too much is a tempting short-term play. +And you can often get away with making a mess for a matter of weeks or months. +Eventually, though, internal quality problems will catch up with you and make your software prohibitively expensive to maintain, or unable to reach a competitive level of external quality."</p> +<p class="attribution">—"Extreme Programming Explained" 1st edition by Kent Beck, "Chapter 4. Four Variables :: Interactions Between the Variables", перевод ООО Издательство "Питер"</p> +</div></blockquote> +<blockquote> +<div><p>📝 "Why can't you just listen, write a test case, make it run, listen, write a test case, make it run indefinitely? +Because we know it doesn't work that way. +You can do that for a while. +In a forgiving language you may even be able to do that for a long while. +Eventually, though, you get stuck. +The only way to make the next test case run is to break another. +Or the only way to make the test case run is far more trouble than it is worth. +Entropy claims another victim.</p> +<p>The only way to avoid this is to design. +Designing is creating a structure that organizes the logic in the system. +Good design organizes the logic so that a change 45 in one part of the system doesn't always require a change in another part of the system. +Good design ensures that every piece of logic in the system has one and only one home. +Good design puts the logic near the data it operates allows the extension of the system with changes in only one place."</p> +<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> </div></blockquote> -<p>Математическое объяснение этого явления можно найти в главе "1. Recurrent Problems : 1.1. The Tower of Hanoi" книги "Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik.</p> -<p>Кроме того, при TDD хорошо отслеживается ниточка, за которую можно распутать клубок сложности, и вопрос "с какого конца подступиться" решается сам собой.</p> -</section> -<section id="emacsway-why-is-tdd-faster"> -<span id="id21"/><h3><a class="toc-backref" href="#id36" role="doc-backlink">Почему TDD быстрее</a></h3> -<p>При TDD разработка осуществляется быстрее, хотя объема кода пишется больше. -Суть в том, что в процессе конструирования кода, <a class="reference internal" href="../sdlc/uncertainty-management/adaptation/software-design/software-design.html#emacsway-who-reads-the-code"><span class="std std-ref">91% времени занимает чтение кода и борьба со сложностью, и только 9% времени (1:10) занимает ввод символов с клавиатуры</span></a>.</p> -<p>TDD является эффективным средством управления сложностью и снижения когнитивной нагрузки. -А поскольку чтение кода и борьба со сложностью (обдумывание) занимает более 91% времени конструирования кода, то время на написание тестов полностью перекрывается повышением темпов разработки, т.е. разработка с тестами получается даже быстрей. -Пальцы работают больше, а голова меньше. -Происходит перераспределение составляющих разработки.</p> -<p>Допустим, что разработчику нужно написать вдвое больше кода без роста когнитивной нагрузки (написание тестов не требует борьбы со сложностью). -Т.е. вместо соотношения 1:10 (где 1 - это часть времени ввода символов с клавиатуры, а 10 - это часть времени чтения кода и борьбы со сложностью) получится соотношение 2:10, что равно 17%:83% вместо 9%:91%. -Совокупное время увеличится на <code class="docutils literal notranslate"><span class="pre">100%*(12</span> <span class="pre">-</span> <span class="pre">11)/11</span> <span class="pre">=</span> <span class="pre">9%</span></code> - ровно столько времени потребуется свеху для того, чтобы написать вдвое больше кода без роста когнитивной нагрузки.</p> -<p>А теперь представим, что удалось снизить когнитивную нагрузку вдвое. -Т.е. вместо соотношения 1:10 (где 1 - это часть времени ввода символов с клавиатуры, а 10 - это часть времени чтения кода и борьбы со сложностью) получится соотношение 1:5, что равно 17%:83% вместо 9%:91%. -Совокупное время уменьшится на <code class="docutils literal notranslate"><span class="pre">100%*(6</span> <span class="pre">-</span> <span class="pre">11)/11</span> <span class="pre">=</span> <span class="pre">-45%</span></code> - ровно столько времени сэкономится, если разработчик будет тратить вдвое меньше времени на борьбу со сложностью.</p> -<p>9% (вдвое больше кода) против 45% (вдвое меньше думать).</p> -<p>Конечно, коэффициенты в этом примере сильно завышены, но они хорошо раскрывают механизм ускорения темпов разработки с использованием TDD. -На практике TDD дает прирост разработки около 10% - Jason Gorman публиковал свою статистику многократного прохождения кат как по TDD, так и без TDD (см. главу "Chapter 1. What Is Design and Architecture? :: What went wrong?" книги "Clean Architecture: A Craftsman's Guide to Software Structure and Design" <a class="footnote-reference brackets" href="#fncarch" id="id22" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Robert C. Martin).</p> -<p>Я перепроверял эту особенность на личном опыте, и убедился в том, что это, действительно, работает.</p> -<p>Кроме того, время на написание тестов можно прогнозировать, в отличии от отладки.</p> </section> -<section id="tdd-clean-code"> -<h3><a class="toc-backref" href="#id37" role="doc-backlink">TDD - основной катализатор Clean Code</a></h3> -<p>Каким образом тестирование улучшает качество кода?</p> +<section id="robert-martin"> +<h3><a class="toc-backref" href="#id18" role="doc-backlink">Robert Martin</a></h3> <blockquote> -<div><p>"The problem with testing code is that you have to isolate that code. -It is often difficult to test a function if that function calls other functions. -To write that test you've got to figure out some way to decouple the function from all the others. -In other words, the need to test first forces you to think about good design.</p> -<p>If you don't write your tests first, there is no force preventing you from coupling the functions together into an untestable mass. -If you write your tests later, you may be able to test the inputs and the outputs of the total mass, but it will probably be quite difficult to test the individual functions."</p> -<p class="attribution">—"Clean Coder" <a class="footnote-reference brackets" href="#fnccoder" id="id23" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Robert Martin</p> +<div><p>💬 "The only way to make the deadline — the only way to go fast — is to keep the code as clean as possible at all times."</p> +<p class="attribution">—"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p> </div></blockquote> -<p>Однако, нужно учитывать:</p> <blockquote> -<div><p>Я сказал, что предположение наивное, однако, скорее всего, я преувеличил. -На самом деле наивно предполагать, что чистый код — это все, что необходимо для успеха. -Мне кажется, что хорошее проектирование — это лишь 20% успеха. -Безусловно, если проектирование будет плохим, вы можете быть на 100% уверены в том, что проект провалится. -Однако приемлемый дизайн сможет обеспечить успех проекта только в случае, если остальные 80% будут там, где им полагается быть.</p> -<p>I say "naive," but that's perhaps overstating. -What's naive is assuming that clean code is all there is to success. -Good engineering is maybe 20 percent of a project's success. -Bad engineering will certainly sink projects, but modest engineering can enable project success as long as the other 80 percent lines up right.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id24" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "The way to go fast, and to keep the deadlines at bay, is to stay clean. +Professionals do not succumb to the temptation to create a mess in order to move quickly. +Professionals realize that "quick and dirty" is an oxymoron. +Dirty always means slow!"</p> +<p class="attribution">—"Clean Coder" by Robert Martin</p> </div></blockquote> -</section> -</section> -<section id="id25"> -<h2><a class="toc-backref" href="#id38" role="doc-backlink">Влияние TDD на темпы разработки</a></h2> -<p>Я уже перечислял <a class="reference external" href="https://emacsway.github.io/ru/it/agile/easily-about-agile-way-to-rapid-development/#self-testing-code-for-agile-ru">превосходства TDD для быстрой разработки</a>, поэтому повторяться не буду.</p> -<p>Однако, перечислю основные методики, которые используются для быстрой разработки:</p> -<ul class="simple"> -<li><p>Emergent Design</p></li> -<li><p>Evolutionary (Incremental, Continuous) Design</p></li> -<li><p><a class="reference internal" href="../sdlc/uncertainty-management/adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a></p></li> -<li><p>Очевидная Реализация (Obvious Implementation)</p></li> -<li><p>Копирование Паттернов (Pattern Copying)</p></li> -</ul> -<p>Первые два хорошо подходят для начинающих специалистов, поскольку они позволяют эффективно обрабатывать случаи неполной информированности. -Последние два - для опытных специалистов.</p> -<p>Несмотря на то, что Martin Fowler (как редактор статьи Jim Shore) объединяет смысл Emergent Design и Continuous Design:</p> <blockquote> -<div><p>Continuous design is also known as evolutionary or emergent design. -I prefer the term continuous design because it emphasizes the core of the process: continuously taking advantage of opportunities to improve your design.</p> -<p class="attribution">—"<a class="reference external" href="https://www.martinfowler.com/ieeeSoftware/continuousDesign.pdf">Continuous Design</a>" by Jim Shore</p> +<div><p>📝 "The goal of good software design? That goal is nothing less than my utopian description:</p> +<blockquote> +<div><p>The goal of software architecture is to minimize the human resources required to build and maintain the required system.</p> +</div></blockquote> +<p>The measure of design quality is simply the measure of the effort required to meet the needs of the customer. +If that effort is low, and stays low throughout the lifetime of the system, the design is good. +If that effort grows with each new release, the design is bad. +It's as simple as that."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> </div></blockquote> -<p>Существует точка зрения, что они, все-таки, отличаются:</p> <blockquote> -<div><p>We distinguish between emergent and evolutionary architecture, and this distinction is an important one.</p> -<p class="attribution">—"<a class="reference external" href="https://www.thoughtworks.com/insights/blog/microservices-evolutionary-architecture">Microservices as an Evolutionary Architecture</a>" by Neal Ford, Rebecca Parsons</p> +<div><p>📝 "Напомню, что целью архитектора является минимизация трудозатрат на создание и сопровождение системы. +Что может помешать достижению этой цели? +Зависимость — и особенно зависимость от преждевременных решений.</p> +<p>Recall that the goal of an architect is to minimize the human resources required to build and maintain the required system. +What it is that saps this kind of peoplepower? +Coupling—and especially coupling to premature decisions."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin, перевод ООО Издательство "Питер"</p> </div></blockquote> </section> -<section id="black-box-or-white-box"> -<span id="emacsway-tdd-black-box"/><h2><a class="toc-backref" href="#id39" role="doc-backlink">Black Box or White Box?</a></h2> -<p>Тесты по возможности должны быть черным ящиком, т.е. тестируем поведение, а не реализацию. -Это позволяет безболезненно подменять реализацию при рефакторинге. -Опускаться в глубь реализации нужно тогда, когда это требуется для сокращения комбинаций условий тестирования, например, класс использует несколько подключаемых стратегий, и нам проще протестировать стратегии по одной. -Но при этом мы должны минимизировать зависимость от реализации. -Нарушение этого принципа, в сочетании со стремлением к высокому уровню покрытия кода тестами, накладывает на код оковы и ставит крест на дальнейшей эволюции программы. -Эту тему раскрывает Бек в первой и второй серии сериала "<a class="reference external" href="https://martinfowler.com/articles/is-tdd-dead/">Is TDD dead?</a>".</p> +<section id="agile-manifesto"> +<h3><a class="toc-backref" href="#id19" role="doc-backlink">Agile Manifesto</a></h3> <blockquote> -<div><p>My personal practice - I mock almost nothing. -If I can't figure out how to test efficiently with the real stuff, I find another way of creating a feedback loop for myself. -I have to have feedback loop and the feedback loop has to be repeatable, but like I just don't go very far down the mock path. -I look at a code where you have mocks returning mocks returning mocks and my experience is if I use TDD I can refactor stuff. -And then I heard these stories people say well I use TDD and now I can't refactor anything and I feel like I couldn't understand that and I started looking at their tests well. -If you have mocks returning mocks returning mocks your test is completely coupled to the implementation, not the interface, but the exact implementation of some object you know three streets away. -Of course you can't change anything without breaking the test. -So that for me is too high a price to pay. -That's not a trade-off I'm willing to make just to get piecemeal development.</p> -<p class="attribution">—Kent Beck, "<a class="reference external" href="https://youtu.be/z9quxZsLcfo?t=1269">Is TDD Dead? Part 1 at 21:10</a></p> +<div><p>📝 "Continuous attention to technical excellence and good design enhances agility."</p> +<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/principles.html">Principles behind the Agile Manifesto</a>"</p> </div></blockquote> +</section> +<section id="ralph-johnson"> +<h3><a class="toc-backref" href="#id20" role="doc-backlink">Ralph Johnson</a></h3> <blockquote> -<div><p>Думать об объектах, как о черных ящиках, достаточно тяжело. -Представим, что у нас есть объект Contract, состояние которого содержится в поле status, которое может принадлежать либо классу Offered, либо классу Running. -В этом случае можно написать тест, исходя из предполагаемой реализации:</p> -<div class="highlight-java notranslate" id="code-1-ru"><div class="highlight"><pre><span/><span class="linenos">1</span><span class="n">Contract</span><span class="w"> </span><span class="n">contract</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Contract</span><span class="p">();</span><span class="w"/> -<span class="linenos">2</span><span class="c1">// по умолчанию состояние Offered</span><span class="w"/> -<span class="linenos">3</span><span class="n">contract</span><span class="p">.</span><span class="na">begin</span><span class="p">();</span><span class="w"/> -<span class="linenos">4</span><span class="c1">// состояние меняется на Running</span><span class="w"/> -<span class="linenos">5</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">Running</span><span class="p">.</span><span class="na">class</span><span class="p">,</span><span class="w"> </span><span class="n">contract</span><span class="p">.</span><span class="na">status</span><span class="p">.</span><span class="na">class</span><span class="p">);</span><span class="w"/> -</pre></div> -</div> -<p>Этот тест слишком сильно зависит от текущей реализации объекта status. -Однако тест должен срабатывать даже в случае, если поле status станет булевским значением. -Может быть, когда status меняется на Running, можно протестировать дату начала работы над контрактом:</p> -<div class="highlight-java notranslate" id="code-2-ru"><div class="highlight"><pre><span/><span class="linenos">1</span><span class="n">assertEquals</span><span class="p">(...,</span><span class="w"> </span><span class="n">contract</span><span class="p">.</span><span class="na">startDate</span><span class="p">());</span><span class="w"/> -<span class="linenos">2</span><span class="c1">// генерирует исключение, если status равен Offered</span><span class="w"/> -</pre></div> -</div> -<p>Я признаю, что пытаюсь плыть против течения, когда настаиваю на том, что все тесты должны быть написаны только с использованием публичного (public) протокола. -Существует специальный пакет JXUnit, который является расширением JUnit и позволяет тестировать значения переменных, даже тех, которые объявлены как закрытые.</p> -<p>Желание протестировать объект в рамках концепции белого ящика — это не проблема тестирования, это проблема проектирования. -Каждый раз, когда у меня возникает желание протестировать значение переменной-члена для того, чтобы убедиться в работоспособности кода, я получаю возможность улучшить дизайн системы. -Если я забываю о своих опасениях и просто проверяю значение переменной, я теряю такую возможность. -Иначе говоря, если идея об улучшении дизайна не приходит мне в голову, ничего не поделаешь. -Я проверяю значение переменной, смахиваю непрошеную слезу, вношу соответствующую отметку в список задач и продолжаю двигаться вперед, надеясь, что наступит день, когда смогу найти подходящее решение.</p> -<p>Thinking about objects as black boxes is hard. If I have a Contract with a Status that can be an instance of either Offered or Running , I might feel like writing a test based on my expected implementation:</p> -<div class="highlight-java notranslate" id="code-1-en"><div class="highlight"><pre><span/><span class="linenos">1</span><span class="n">Contract</span><span class="w"> </span><span class="n">contract</span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Contract</span><span class="p">();</span><span class="w"/> -<span class="linenos">2</span><span class="c1">// Offered status by default</span><span class="w"/> -<span class="linenos">3</span><span class="n">contract</span><span class="p">.</span><span class="na">begin</span><span class="p">();</span><span class="w"/> -<span class="linenos">4</span><span class="c1">// Changes status to Running</span><span class="w"/> -<span class="linenos">5</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">Running</span><span class="p">.</span><span class="na">class</span><span class="p">,</span><span class="w"> </span><span class="n">contract</span><span class="p">.</span><span class="na">status</span><span class="p">.</span><span class="na">class</span><span class="p">);</span><span class="w"/> -</pre></div> -</div> -<p>This test is too dependent on the current implementation of status. -The test should pass even if the representation of status changed to a boolean. -Perhaps once the status changes to Running, it is possible to ask for the actual start date.</p> -<div class="highlight-java notranslate" id="code-2-en"><div class="highlight"><pre><span/><span class="linenos">1</span><span class="n">assertEquals</span><span class="p">(...,</span><span class="w"> </span><span class="n">contract</span><span class="p">.</span><span class="na">startDate</span><span class="p">());</span><span class="w"/> -<span class="linenos">2</span><span class="c1">// Throws an exception if the status is Offered</span><span class="w"/> -</pre></div> -</div> -<p>I'm aware that I am swimming against the tide in insisting that all tests be written using only public protocol. -There is even a package that extends JUnit called JXUnit, which allows testing the value of variables, even those declared private.</p> -<p>Wishing for white box testing is not a testing problem, it is a design problem. -Anytime I want to use a variable as a way of checking to see whether code ran correctly or not, I have an opportunity to improve the design. -If I give in to my fear and just check the variable, then I lose that opportunity. -That said, if the design idea doesn't come, it doesn't come. I'll check the variable, shed a tear, make a note to come back on one of my smarter days, and move on.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id26" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +<div><p>📝 "In most successful software projects, the expert developers working on that project have +a shared understanding of the system design. +<strong>This shared understanding is called 'architecture.'</strong> +This understanding includes how the system is divided into components and how the components interact through interfaces. +These components are usually composed of smaller components, but the architecture only +includes the components and interfaces that are understood by all the developers."</p> +<p class="attribution">—<a class="reference external" href="https://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf">Ralph Johnson</a></p> </div></blockquote> +</section> +<section id="steve-mcconnell"> +<h3><a class="toc-backref" href="#id21" role="doc-backlink">Steve McConnell</a></h3> <blockquote> -<div><p>Взгляд на тестирование в рамках TDD прагматичен. -В TDD тесты являются средством достижения цели. -Целью является код, в корректности которого мы в достаточной степени уверены. -Если знание особенностей реализации без какого-либо теста дает нам уверенность в том, что код работает правильно, мы не будем писать тест. -Тестирование черного ящика (когда мы намеренно игнорируем реализацию) обладает рядом преимуществ. -Если мы игнорируем код, мы наблюдаем другую систему ценностей: тесты сами по себе представляют для нас ценность. -В некоторых ситуациях это вполне оправданный подход, однако он отличается от TDD.</p> -<p>TDD's view of testing is pragmatic. -In TDD, the tests are a means to an end—the end being code in which we have great confidence. -If our knowledge of the implementation gives us confidence even without a test, then we will not write that test. -Black box testing, where we deliberately choose to ignore the implementation, has some advantages. -By ignoring the code, it demonstrates a different value system—the tests are valuable alone. -It's an appropriate attitude to take in some circumstances, but that is different from TDD.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id27" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> -</div></blockquote> +<div><p>📝 "The General Principle of Software Quality is that improving quality reduces development costs.</p> +<p>Understanding this principle depends on understanding a key observation: the best way +to improve productivity and quality is to reduce the time spent reworking code, whether +the rework arises from changes in requirements, changes in design, or debugging. +The industry-average productivity for a software product is about 10 to 50 of lines of +delivered code per person per day (including all noncoding overhead). +It takes only a matter of minutes to type in 10 to 50 lines of code, so how is the rest of the day spent? +Part of the reason for these seemingly low productivity figures is that industry average +numbers like these factor nonprogrammer time into the lines-of-code-per-day figure. +Tester time, project manager time, and administrative support time are all included. +Noncoding activities, such as requirements development and architecture work, are also +typically factored into those lines-of-code-per-day figures. +But none of that is what takes up so much time.</p> +<p>The single biggest activity on most projects is debugging and correcting code that +doesn't work properly. +Debugging and associated refactoring and other rework consume +about 50 percent of the time on a traditional, naive software-development cycle. +(See Section 3.1, "Importance of Prerequisites," for more details.) Reducing debugging by +preventing errors improves productivity. +Therefore, the most obvious method of shortening a development schedule is to improve the quality of the product and decrease +the amount of time spent debugging and reworking the software. +This analysis is confirmed by field data. +In a review of 50 development projects involving over 400 work-years of effort and +almost 3 million lines of code, a study at NASA's Software +Engineering Laboratory found that increased quality assurance was +associated with decreased error rate but did not increase overalldevelopment cost (Card 1987).</p> +<p>A study at IBM produced similar findings:</p> <blockquote> -<div><p>Many people make bad trade-offs, especially with heavy mocking. -Kent thinks it's about trade-offs: is it worth making intermediate results testable? -He used the example of a compiler where an intermediate parse-tree makes a good test point, and is also a better design.</p> -<p class="attribution">—Kent Beck, "<a class="reference external" href="https://martinfowler.com/articles/is-tdd-dead/">Is TDD Dead?</a>"</p> +<div><p>Software projects with the lowest levels of defects had the shortest development +schedules and the highest development productivity.... software defect removal is +actually the most expensive and time-consuming form of work for software (Jones 2000).</p> +<p class="attribution">—Jones, Capers. 2000. Software Assessments, Benchmarks, and Best Practices. Reading, MA: Addison-Wesley.</p> </div></blockquote> -<blockquote> -<div><p>Separate interface from implementation thinking. -I have a tendency to pollute API design decisions with implementation speculation. -I need to find a new way to separate the two levels of thinking while still providing rapid feedback between them.</p> -<p class="attribution">—Kent Beck, "<a class="reference external" href="https://www.facebook.com/notes/kent-beck/rip-tdd/750840194948847/">RIP TDD</a>"</p> +<p>The same effect holds true at the small end of the scale. +In a 1985 study, 166 professional programmers wrote programs from the +same specification. +The resulting programs averaged 220 lines of +code and a little under five hours to write. +The fascinating result was that programmers who took the median time to complete their +programs produced programs with the greatest number of errors. +The programmers who took more or less than the median time +produced programs with significantly fewer errors (DeMarco and Lister 1985).</p> +<p>The two slowest groups took about five times as long to achieve roughly the same +defect rate as the fastest group. +It's not necessarily the case that writing software without +defects takes more time than writing software with defects. +As the graph shows, it can take less."</p> +<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell</p> </div></blockquote> <blockquote> -<div><p>Структурная зависимость</p> -<p>Структурная зависимость - одна из самых сильных и наиболее коварных форм зависимости тестов. -Представьте набор тестов, в котором имеются тестовые классы для всех прикладных классов и тестовые методы для всех прикладных методов. -Такой набор очень тесно связан со структурой приложения.</p> -<p>Изменение в одном из прикладных методов или классов может повлечь необходимость изменить большое количество тестов. -Следовательно, тесты слишком хрупкие и могут сделать прикладной код слишком жестким.</p> -<p>Роль API тестирования - скрыть структуру приложения от тестов. -Это позволит развивать прикладной код, не влияя на тесты. Это также позволит развивать тесты, не влияя на прикладной код.</p> -<p>Такая возможность независимого развития абсолютно необходима, потому что с течением времени тесты становятся все более конкретными, а прикладной код, напротив, — все более абстрактным и обобщенным. -Тесная структурная зависимость препятствует такому развитию - или, по меньшей мере, затрудняет его - и мешает прикладному коду становиться все более обобщенным и гибким.</p> -<p>STRUCTURAL COUPLING</p> -<p>Structural coupling is one of the strongest, and most insidious, forms of test coupling. -Imagine a test suite that has a test class for every production class, and a set of test methods for every production method. -Such a test suite is deeply coupled to the structure of the application.</p> -<p>When one of those production methods or classes changes, a large number of tests must change as well. -Consequently, the tests are fragile, and they make the production code rigid.</p> -<p>The role of the testing API is to hide the structure of the application from the tests.</p> -<p>This allows the production code to be refactored and evolved in ways that don't affect the tests. -It also allows the tests to be refactored and evolved in ways that don't affect the production code.</p> -<p>This separation of evolution is necessary because as time passes, the tests tend to become increasingly more concrete and specific. -In contrast, the production code tends to become increasingly more abstract and general. -Strong structural coupling prevents - or at least impedes - this necessary evolution, and prevents the production code from being as general, and flexible, as it could be.</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" <a class="footnote-reference brackets" href="#fncarch" id="id28" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Robert C. Martin</p> +<div><p>📝 "Watts Humphrey reports that teams using the Team Software Process +(TSP) have achieved defect levels of about 0.06 defects per 1000 lines of code. +TSP focuses on training developers not to create defects in the first place (Weber 2003). +[Morales, Alexandra Weber. 2003. "The Consummate Coach: Watts Humphrey, Father of Cmm and Author of Winning with Software, Explains How to Get Better at What You Do," SD Show Daily, September 16, 2003.]</p> +<p>The results of the TSP and cleanroom projects confirm another version of the General +Principle of Software Quality: it's cheaper to build high-quality software than it is to build and fix low-quality software. +Productivity for a fully checked-out, 80,000-line cleanroom project was 740 lines of code per work-month. +The industry average rate for fully checked-out code is closer to 250–300 lines per work-month, including all noncoding overhead (Cusumano et al 2003). +[Cusumano, Michael , et al. 2003. "Software Development Worldwide: The State of the Practice," IEEE Software, November/ December 2003, 28–34.] +The cost savings and productivity come from the fact that virtually no time is devoted to debugging on TSP or cleanroom projects. +No time spent on debugging? +That is truly a worthy goal!"</p> +<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell</p> </div></blockquote> <blockquote> -<div><p>"Mock across architecturally significant boundaries, but not within those boundaries."</p> -<p class="attribution">—"<a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2014/05/10/WhenToMock.html">When to Mock</a>" by Robert C. Martin</p> +<div><p>📝 "A six-month study conducted by IBM found that maintenance programmers "most often said that <strong>understanding the original programmer's intent was the most difficult problem</strong>" (Fjelstad and Hamlen 1979). +[Fjelstad, R. K. , and W. T. Hamlen. 1979. "Applications Program Maintenance Study: Report to our Respondents." Proceedings Guide 48, Philadelphia. Reprinted in Tutorial on Software Maintenance, G. Parikh and N. Zvegintzov eds. Los Alamitos, CA: CS Press, 1983: 13–27.]"</p> +<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell</p> </div></blockquote> </section> -<section id="sociable-or-solitary"> -<span id="index-1"/><h2><a class="toc-backref" href="#id40" role="doc-backlink">Sociable or Solitary?</a></h2> -<p>Наверное, самое часто заблуждение, которое мне приходилось слышать, это то, тесты должны быть полностью изолированы, и должны взаимодействовать только с <a class="reference external" href="https://martinfowler.com/bliki/TestDouble.html">дублерами</a>. -Этот вопрос известен как "Solitary or Sociable?".</p> +<section id="id4"> +<h3><a class="toc-backref" href="#id22" role="doc-backlink">Сергей Тепляков</a></h3> <blockquote> -<div><p>Indeed using sociable unit tests was one of the reasons we were criticized for our use of the term "unit testing". I think that the term "unit testing" is appropriate because these tests are tests of the behavior of a single unit. We write the tests assuming everything other than that unit is working correctly.</p> -<p>As xunit testing became more popular in the 2000's the notion of solitary tests came back, at least for some people. We saw the rise of Mock Objects and frameworks to support mocking. Two schools of xunit testing developed, which I call the classic and mockist styles. One of the differences between the two styles is that mockists insist upon solitary unit tests, while classicists prefer sociable tests. Today I know and respect xunit testers of both styles <strong>(personally I've stayed with classic style)</strong>.</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/UnitTest.html#SolitaryOrSociable">Unit Test</a>" by Martin Fowler</p> +<div><p>📝 "Хороший дизайн заключается в простом решении, когда изменения требований ведут к линейным трудозатратам."</p> +<p class="attribution">—"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>", Сергей Тепляков</p> </div></blockquote> +</section> +<section id="id5"> +<h3><a class="toc-backref" href="#id23" role="doc-backlink">Народное творчество</a></h3> +<p>Старый программистский анекдот:</p> <blockquote> -<div><p>At the end of the day it's not important to decide if you go for solitary or sociable unit tests. Writing automated tests is what's important. Personally, I find myself using both approaches all the time.</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/practical-test-pyramid.html#SociableAndSolitary">The Practical Test Pyramid</a>" by Ham Vocke with support of Martin Fowler.</p> +<div><p>💬 Идет мужик по лесу. Смотрит, другой мужик лес рубит. +| - Привет, что делаешь? +| - Не видишь? Лес рублю... +| - Так бензопила же лежит рядом. Возьми её - быстрее будет. +| - Я не умею. +| - Так инструкция же рядом лежит. Возьми, прочти... +| - Мне некогда её читать - мне лес рубить надо.</p> </div></blockquote> +</section> +<section id="randy-shoup"> +<h3><a class="toc-backref" href="#id24" role="doc-backlink">Randy Shoup</a></h3> <blockquote> -<div><p>TestDrivenDevelopment produces Developer Tests. The failure of a test case implicates only the developer's most recent edit. <strong>This implies that developers don't need to use Mock Objects to split all their code up into testable units</strong>. And it implies a developer may always avoid debugging by reverting that last edit.</p> -<p class="attribution">—"<a class="reference external" href="https://wiki.c2.com/?UnitTest">Unit Test</a>" on c2.com</p> +<div><div class="line-block"> +<div class="line">- We don't have time to do it right!</div> +<div class="line">- Do you have time to do it twice?</div> +</div> +<p class="attribution">—<a class="reference external" href="https://www.infoq.com/presentations/microservices-data-centric">Randy Shoup</a>, VP Engineering at Stitch Fix in San Francisco</p> </div></blockquote> -<p>Недостатки и достоинства обоих подходов описаны в статье "<a class="reference external" href="https://martinfowler.com/articles/mocksArentStubs.html">Mocks Aren't Stubs</a>".</p> -<p>Мнение самого основателя TDD:</p> +<figure class="align-left" id="id11"> +<a class="reference internal image-reference" href="../../../../../../_images/do-it-right.png"><img alt="Do it right! Иллюстрация из открытых источников неизвестного автора." src="../../../../../../_images/do-it-right.png" style="width: 90%;"/></a> +<figcaption> +<p><span class="caption-text">Do it right! Иллюстрация из открытых источников неизвестного автора.</span></p> +</figcaption> +</figure> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference internal" href="../crash-course-in-software-development-economics.html"><span class="doc">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../../../soft-skills/icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Принцип ледокола</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">Что такое Agile Development</span></a>"</p></li> +<li><p>"<a class="reference internal" href="patterns.html#emacsway-agile-patterns"><span class="std std-ref">Role of Design Patterns in Agile</span></a>"</p></li> +</ul> +</div> +</section> +</section> +Sat, 23 Jul 2022 00:00:00 Role of Design Patterns in Agilehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/patterns.html +<span id="emacsway-agile-patterns"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#role-of-design-patterns-in-agile" id="id5">Role of Design Patterns in Agile</a></p> +<ul> +<li><p><a class="reference internal" href="#id2" id="id6">Составляющие экономического эффекта применения паттернов</a></p> +<ul> +<li><p><a class="reference internal" href="#id3" id="id7">Индивидуальная составляющая</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id8">Коллективная составляющая</a></p></li> +</ul> +</li> +</ul> +</li> +</ul> +</nav> +<p>Немного о Паттернах Проектирования. +Нужны ли они?</p> +<p>Паттерны могут приносить пользу экономике разработки, а могут приносить и вред, если не понимать их назначения и злоупотреблять ими. +Как говорится, молотком можно гвоздь забить, а можно и пальцы отбить.</p> +<p>Любое проектное решение должно исходить из <a class="reference internal" href="software-design.html#emacsway-primary-technical-imperative"><span class="std std-ref">принципов управления сложностью</span></a>. +Добавление паттерна может увеличивать уровень косвенности системы, что тоже имеет свою стоимость.</p> +<p>Посмотрим, к примеру, мотивацию Mediator pattern:</p> <blockquote> -<div><p>"My personal practice - I mock almost nothing."</p> -<p class="attribution">—Kent Beck, "<a class="reference external" href="https://youtu.be/z9quxZsLcfo?t=1269">Is TDD Dead? Part 1 at 21:10</a></p> +<div><p>📝 "Mediator promotes loose <strong>coupling</strong> by keeping objects from referring to each other explicitly, +and it lets you vary their interaction independently."</p> +<p class="attribution">—"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides</p> </div></blockquote> -<p>Лично я считаю что нужно ограничивать использование современных средства мокирования, активно эксплуатирующих Monkey Patch, поскольку они позволяют создавать и тестировать низкокачественный код.</p> -</section> -<section id="tdd-design-patterns"> -<span id="index-2"/><h2><a class="toc-backref" href="#id41" role="doc-backlink">TDD и Design Patterns</a></h2> -<p>Почему-то многие начинающие программисты, не знакомые с первоисточниками по TDD, думают, что TDD подразумевает только Evolutionary Design, а Simple Design противопоставляется паттернам программирования.</p> +<p>Лекарство не должно быть хуже болезни. +А цель должна оправдывать средства. +Внося сложность в систему, мы должны обретать возможность управлять еще большим уровнем сложности, т.е. решение должно быть оправданным.</p> +<p>По этому поводу хорошо <a class="reference internal" href="software-design.html#emacsway-kent-beck-constantine-s-law"><span class="std std-ref">рассуждал Kent Beck</span></a>.</p> +<p>И по этому поводу хорошо <a class="reference internal" href="../../../../../soft-skills/learning-spiral-phase-mismatch.html#emacsway-martin-fowler-16-patterns-in-32-lines"><span class="std std-ref">говорил Martin Fowler о 16 Паттернах в 32 строках кода</span></a>.</p> +<p>Вопрос применения паттернов - это вопрос поиска баланса между уровнем управляемой ими сложности и уровнем привносимой ими сложности. +При дисбалансе бизнес и технических интересов, злоупотребление паттернами может привести к <a class="reference internal" href="../../../models/agile/analysis/concerns/balancing-business-technical-concerns.html#emacsway-second-system-effect"><span class="std std-ref">экономически неоправданному переусложению системы</span></a>.</p> +<p>Тем не менее, Паттерны Проектирования являются <a class="reference internal" href="../../../../../soft-skills/knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">обобщением и систематизацией практики</span></a>. +Их не выдумывают - их обобщают. +Это значит, что незнание конкретного паттерна еще не означает неосознанного его применения.</p> +<section id="id2"> +<h2><a class="toc-backref" href="#id6" role="doc-backlink">Составляющие экономического эффекта применения паттернов</a></h2> +<p>Паттерны способны значительно улучшить экономику разработки при разумном их применении. +Экономическая их эффективность складывается из двух составляющих:</p> +<ol class="arabic simple"> +<li><p>Индивидуальная</p></li> +<li><p>Коллективная</p></li> +</ol> +<p>Рассмотрим каждый из них по отдельности.</p> +<section id="id3"> +<h3><a class="toc-backref" href="#id7" role="doc-backlink">Индивидуальная составляющая</a></h3> +<p>Начнем с первой, индивидуальной составляющей. +Каким образом применение паттернов может повысить персональную эффективность разработчика? Вот что говорит по этому поводу автор книг "Implementation Patterns" и "Smalltalk Best Practice Patterns" Kent Beck:</p> <blockquote> -<div><p>Я обратил внимание на один важный эффект, который, я надеюсь, смогут принять во внимание и другие. +<div><p>📝 "Я обратил внимание на один важный эффект, который, я надеюсь, смогут принять во внимание и другие. Если на основе постоянно повторяющихся действий формулируются правила, дальнейшее применение этих правил становится неосознанным и автоматическим. Естественно, ведь это проще, чем обдумывать все за и все против того или иного действия с самого начала. Благодаря этому повышается скорость работы, и если в дальнейшем вы сталкиваетесь с исключением или проблемой, которая не вписывается ни в какие правила, у вас появляется дополнительное время и энергия для того, чтобы в полной мере применить свои творческие способности.</p> @@ -10219,1019 +10214,1270 @@ Then we consciously write a test for the second variant, expecting the refactori Robert Martin and I did some research into this style of TDD. The problem is that the design keeps surprising you. Perfectly sensible design ideas turn out to be wrong. -Better just to think about what you want the system to do, and let the design sort itself out later.</p> -<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id29" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +Better just to think about what you want the system to do, and let the design sort itself out later."</p> +<p class="attribution">—"Test-Driven Development By Example" by Kent Beck, перевод П. Анджан</p> </div></blockquote> -<blockquote> -<div><p>Добавление новой функциональности при помощи тестов и рефакторинг — это две монологические разновидности программирования. -Совсем недавно я открыл еще одну разновидность: копирование паттерна. -Я занимался разработкой сценария на языке Ruby, выполняющего извлечение информации из базы данных. -Я начал с создания класса, являющегося оболочкой таблицы базы данных, а затем сказал себе, что раз я только что закончил книгу о паттернах работы с базами данных, я должен использовать паттерн. -Примеры программ в книге были написаны на Java, поэтому нужный мне код легко можно было перенести на Ruby. -Когда я программировал, я не думал о решении проблемы, я думал лишь о том, каким образом лучше всего адаптировать паттерн для условий, в рамках которых я работал.</p> -<p>Копирование паттернов само по себе не является хорошим программированием, — я всегда подчеркиваю этот факт, когда говорю о паттернах. -Любой паттерн — это полуфабрикат, — вы должны адаптировать его для условий своего проекта. -Однако чтобы сделать это, лучше всего вначале, особо не задумываясь, скопировать паттерн, а затем, воспользовавшись смесью рефакторинга и TDD, выполнить адаптацию. -В этом случае в процессе копирования паттерна вы также концентрируетесь только на одной вещи — на паттерне. -Сообщество ХР интенсивно работает над тем, чтобы добавить в общую картину паттерны. -Со всей очевидностью можно сказать, что сообщество ХР любит паттерны. -В конце концов, между множеством приверженцев ХР и множеством приверженцев паттернов существует значительное пересечение: Уорд и Кент являются лидерами обоих направлений. -Наверное, копирование паттерна — это третий монологический режим программирования наряду с разработкой в стиле "тесты вначале" и рефакторингом. -Как и первые два режима, копирование паттерна — опасная штука, если ее использовать отдельно от двух других режимов. -Все три вида программирования проявляют свою мощь только тогда, когда используются совместно друг с другом.</p> -<p>Adding features test-first and refactoring are two of these monological flavors of programming. -At a recent stint at the keyboard I experienced another one: pattern copying. -I was writing a little Ruby script that pulled some data out of a database. -As I did this I started on a class to wrap the database table and thought to myself that since I'd just finished off a book of database patterns I should use a pattern. -Although the sample code was Java, it wasn't difficult to adapt it to Ruby. -While I programmed it I didn't really think about the problem, I just thought about making a fair adaptation of the pattern to the language and specific data I was manipulating. -Pattern copying on its own isn't good programming—a fact I always stress when talking about patterns. -Patterns are always half baked, and need to be adapted in the oven of your own project. -But a good way to do this is to first copy the pattern fairly blindly, and then use some mix of refactoring or test-first, to perform the adaptation. -That way when you're doing the pattern-copying, you can concentrate on just the pattern—one thing at a time. -The XP community has struggled with where patterns fit into the picture. -Clearly the XP community is in favor of patterns, after all there is huge intersection between XP advocates and patterns advocates — Ward and Kent were leaders in both. -Perhaps pattern copying is a third monological mode to go with test-first and refactoring, and like those two is dangerous on its own but powerful in concert.</p> -<p class="attribution">—Martin Fowler, Afterword, "Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id30" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>, перевод П. Анджан</p> +</section> +<section id="id4"> +<h3><a class="toc-backref" href="#id8" role="doc-backlink">Коллективная составляющая</a></h3> +<p>Перейдем ко второй, коллективной составляющей. +Каким именно образом паттерны могут повысить экономическую эффективность разработки?</p> +<p>Когда в печать вышла книга "Patterns of Enterprise Application Architecture" (PoEAA) by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford, то David Heinemeier Hansson прочитал ее одним из первых, и реализовал эти паттерны в виде Ruby On Rails (RoR). +Использование этого фреймворка, и реализованных им паттернов, позволило:</p> +<ul class="simple"> +<li><p>снизить негативный эффект "<a class="reference internal" href="../../../../team-topologies/harlan-mills%27-proposal.html#emacsway-brooks-s-law"><span class="std std-ref">Закона Брукса</span></a>"</p></li> +<li><p>уменьшить порог вхождения новых разработчиков в проект</p></li> +<li><p>переместить фокус внимания разработчиков от Domain-independent knowledge к <a class="reference external" href="https://en.wikipedia.org/wiki/Domain_knowledge">Domain knowledge</a></p></li> +</ul> +<p>В итоге, разработка на RoR дала многократный (на то время) прирост темпов разработки, что вызвало вирусный интерес к PoEAA и массовое клонирование RoR на многие языки программирования.</p> +<p>Иными словами, паттерны осуществляют унификацию решений типовых проблем, что способствует удешевлению достижения коллективного понимания устройства системы, путем минимизации затрат времени на синхронизацию и обобщение мнений.</p> +<p>По мере формирования коллективной знаний в области системной архитектуры, стали обнажаться архитектурные недостатки RoR, и по этому поводу даже были сняты два поучительных и заслуживающих внимания сериала:</p> +<ol class="arabic simple"> +<li><p>"<a class="reference external" href="https://martinfowler.com/articles/is-tdd-dead/">Is TDD Dead?</a>"</p></li> +<li><p>"<a class="reference external" href="https://martinfowler.com/articles/badri-hexagonal/">A Conversation with Badri Janakiraman about Hexagonal Rails</a>"</p></li> +</ol> +<p>Однако, сам факт достижения высокой экономической эффективности от использования паттернов PoEAA был очевиден, и этот факт оказал существенное влияние на формирование современного состояния области знаний системной архитектуры.</p> +<blockquote> +<div><p>📝 "In most successful software projects, the expert developers working on that project have a shared understanding of the system design. +<strong>This shared understanding is called 'architecture.'</strong> +This understanding includes how the system is divided into components and how the components interact through interfaces. +These components are usually composed of smaller components, but the architecture only includes the components and interfaces that are understood by all the developers."</p> +<p class="attribution">—<a class="reference external" href="https://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf">Ralph Johnson</a></p> </div></blockquote> <blockquote> -<div><p>Patterns and XP</p> -<p>The JUnit example leads me inevitably into bringing up patterns. The relationship between patterns and XP is interesting, and it's a common question. Joshua Kerievsky argues that patterns are under-emphasized in XP and he makes the argument eloquently, so I don't want to repeat that. But it's worth bearing in mind that for many people patterns seem in conflict to XP.</p> -<p>The essence of this argument is that patterns are often over-used. The world is full of the legendary programmer, fresh off his first reading of GOF who includes sixteen patterns in 32 lines of code. I remember one evening, fueled by a very nice single malt, running through with Kent a paper to be called "Not Design Patterns: 23 cheap tricks" We were thinking of such things as use an if statement rather than a strategy. The joke had a point, patterns are often overused, but that doesn't make them a bad idea. The question is how you use them.</p> -<p>One theory of this is that the forces of simple design will lead you into the patterns. Many refactorings do this explicitly, but even without them by following the rules of simple design you will come up with the patterns even if you don't know them already. This may be true, but is it really the best way of doing it? Surely it's better if you know roughly where you're going and have a book that can help you through the issues instead of having to invent it all yourself. I certainly still reach for GOF whenever I feel a pattern coming on. For me effective design argues that we need to know the price of a pattern is worth paying - that's its own skill. Similarly, as Joshua suggests, we need to be more familiar about how to ease into a pattern gradually. In this regard XP treats the way we use patterns differently to the way some people use them, but certainly doesn't remove their value.</p> -<p>But reading some of the mailing lists I get the distinct sense that many people see XP as discouraging patterns, despite the irony that most of the proponents of XP were leaders of the patterns movement too. Is this because they have seen beyond patterns, or because patterns are so embedded in their thinking that they no longer realize it? I don't know the answers for others, but for me patterns are still vitally important. XP may be a process for development, but patterns are a backbone of design knowledge, knowledge that is valuable whatever your process may be. Different processes may use patterns in different ways. XP emphasizes both not using a pattern until it's needed and evolving your way into a pattern via a simple implementation. But patterns are still a key piece of knowledge to acquire.</p> -<p>My advice to XPers using patterns would be</p> +<div><p>📝 ""Programming would be more effective if programmers spent less time on the mundane, repetitive parts of their job so they had more time to spend doing a good job of solving truly unique problems.</p> +<p>Most programs follow a small set of laws:</p> <ul class="simple"> -<li><p>Invest time in learning about patterns</p></li> -<li><p>Concentrate on when to apply the pattern (not too early)</p></li> -<li><p>Concentrate on how to implement the pattern in its simplest form first, then add complexity later.</p></li> -<li><p>If you put a pattern in, and later realize that it isn't pulling its weight - don't be afraid to take it out again.</p></li> +<li><p>Programs are read more often than they are written.</p></li> +<li><p>There is no such thing as “done”. Much more investment will be spent modifying programs than developing them initially.</p></li> +<li><p>They are structured using a basic set of state and control flow concepts.</p></li> +<li><p>Readers need to understand programs in detail and in concept. Sometimes they move from detail to concept, sometimes from concept to detail. Patterns are based on this commonality. For example, every programmer has to decide how to structure iteration. By the time you are thinking about how to write a loop, most of the domain-specific questions have been resolved for the moment and you are left with purely technical issues: the loop should be easy to read, easy to write, easy to verify, easy to modify, and efficient."</p></li> </ul> -<p>I think XP should emphasize learning about patterns more. I'm not sure how I would fit that into XP's practices, but I'm sure Kent can come up with a way.</p> -<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html#PatternsAndXp">Is Design Dead?</a>" by Martin Fowler</p> +<p class="attribution">—"Implementation Patterns" by Kent Beck</p> </div></blockquote> -<p>Смотрите так же:</p> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> <ul class="simple"> -<li><p>XP and Patterns Ralph Johnson's View: <a class="reference external" href="http://objectclub.jp/community/XP-jp/xp_relate/xp_patterns">http://objectclub.jp/community/XP-jp/xp_relate/xp_patterns</a></p></li> -<li><p>Joshua Kerievsky, Patterns &amp; XP: <a class="reference external" href="http://www.industriallogic.com/xp/PatternsAndXP.pdf">http://www.industriallogic.com/xp/PatternsAndXP.pdf</a></p></li> +<li><p>"<a class="reference internal" href="../../../../../soft-skills/knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">Разрешение конфликтов на почве недостатка знаний</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../../../../team-topologies/harlan-mills%27-proposal.html#emacsway-brooks-s-law"><span class="std std-ref">Закон Брукса</span></a>"</p></li> </ul> +</div> </section> -<section id="one-assertion-per-test"> -<h2><a class="toc-backref" href="#id42" role="doc-backlink">One assertion per test?</a></h2> -<p>Я часто слышу это распространенное убеждение, что один тестовый метод должен содержать только одно утверждение (assertion) и не больше. -И это интересно, потому что Кент Бек этому правилу не очень-то и следует, что заставило меня найти первоисточник этого убеждения. -Источник я нашел, и он, действительно, авторитетный - это "xUnit Test Patterns. Refactoring Test Code." by Gerard Meszaros, глава "Principle: Verify One Condition per Test", но там есть кое-что еще, о чем это широко распространенное убеждение умалчивает:</p> -<blockquote> -<div><p>One possibly contentious aspect of "Verify One Condition per Test" is what we mean by "one condition." -Some test drivers insist on one assertion per test. -This insistence may be based on using a "Testcase Class per Fixture" organization -of the "Test Methods" and naming each test based on what the one assertion is verifying. -(For example, AwaitingApprovalFlight.validApproverRequestShouldBeApproved.) -Having one assertion per test makes such naming very easy but also leads to many more test methods if we have to assert on many output fi elds. -Of course, we can often comply with this interpretation by extracting a "Custom Assertion" (page 474) -or "Verification Method" (see "Custom Assertion") that allows us to reduce the multiple assertion method calls to a single call. -Sometimes that approach makes the test more readable. -When it doesn't, I wouldn't be too dogmatic about insisting on a single assertion.</p> -<p class="attribution">—"xUnit Test Patterns. Refactoring Test Code." by Gerard Meszaros</p> -</div></blockquote> -<p>Эту же тему рассматривает и Robert C. Martin в главе "Chapter 9: Unit Tests :: One Assert per Test" книги "Clean Code: A Handbook of Agile Software Craftsmanship":</p> -<blockquote> -<div><p>Я думаю, что правило "одного assert" является хорошей рекомендацией. -Обычно я стараюсь создать предметно-ориентированный язык тестирования, который это правило поддерживает, как в листинге 9.5. -Но при этом я не боюсь включать в свои тесты более одной директивы assert. -Вероятно, лучше всего сказать, что количество директив assert в тесте должно быть сведено к минимуму.</p> -<p>I think the single assert rule is a good guideline. -I usually try to create a domainspecific testing language that supports it, as in Listing 9-5. -But I am not afraid to put more than one assert in a test. -I think the best thing we can say is that the number of asserts in a test ought to be minimized.</p> -<p class="attribution">—"Clean Code: A Handbook of Agile Software Craftsmanship" <a class="footnote-reference brackets" href="#fnccode" id="id31" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Robert C. Martin, перевод Е. Матвеев</p> -</div></blockquote> -<p>Здесь он отсылает к статье "<a class="reference external" href="https://www.artima.com/weblogs/viewpost.jsp?thread=35578">One Assertion Per Test</a>" by Dave Astels в качестве первоисточника.</p> -<p class="rubric">Footnotes</p> -<aside class="footnote-list brackets"> -<aside class="footnote brackets" id="fntdd" role="note"> -<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id3">1</a>,<a role="doc-backlink" href="#id4">2</a>,<a role="doc-backlink" href="#id5">3</a>,<a role="doc-backlink" href="#id6">4</a>,<a role="doc-backlink" href="#id7">5</a>,<a role="doc-backlink" href="#id10">6</a>,<a role="doc-backlink" href="#id12">7</a>,<a role="doc-backlink" href="#id13">8</a>,<a role="doc-backlink" href="#id15">9</a>,<a role="doc-backlink" href="#id16">10</a>,<a role="doc-backlink" href="#id17">11</a>,<a role="doc-backlink" href="#id18">12</a>,<a role="doc-backlink" href="#id19">13</a>,<a role="doc-backlink" href="#id20">14</a>,<a role="doc-backlink" href="#id24">15</a>,<a role="doc-backlink" href="#id26">16</a>,<a role="doc-backlink" href="#id27">17</a>,<a role="doc-backlink" href="#id29">18</a>,<a role="doc-backlink" href="#id30">19</a>)</span> -<p>"Test-Driven Development By Example" by Kent Beck</p> -</aside> -<aside class="footnote brackets" id="fnccoder" role="note"> -<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id23">2</a><span class="fn-bracket">]</span></span> -<p>"The Clean Coder: a code of conduct for professional programmers" by Robert C. Martin</p> -</aside> -<aside class="footnote brackets" id="fnccode" role="note"> -<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id31">3</a><span class="fn-bracket">]</span></span> -<p>"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p> -</aside> -<aside class="footnote brackets" id="fncarch" role="note"> -<span class="label"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id22">1</a>,<a role="doc-backlink" href="#id28">2</a>)</span> -<p>"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> -</aside> -<aside class="footnote brackets" id="fnrefactoring" role="note"> -<span class="label"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></span> -<span class="backrefs">(<a role="doc-backlink" href="#id9">1</a>,<a role="doc-backlink" href="#id11">2</a>,<a role="doc-backlink" href="#id14">3</a>)</span> -<p>"Refactoring: Improving the Design of Existing Code" by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p> -</aside> -</aside> </section> -Thu, 21 Jul 2022 00:00:00 Role of SOLID principles in Agilehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/solid.html -<span id="emacsway-agile-solid"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> +Fri, 22 Jul 2022 00:00:00 TDD - Разработка через тестированиеhttps://dckms.github.io/system-architecture/emacsway/it/tdd/tdd.html +<span id="emacsway-tdd"/> +<p>Вокруг TDD (Test-Driven Development) сложилось немало мифов и заблуждений, и здесь я попытаюсь восстановить изначальный его смысл. +Для этого придется обратиться к первоисточникам.</p> <nav class="contents" id="id1"> <p class="topic-title">Содержание</p> <ul class="simple"> -<li><p><a class="reference internal" href="#role-of-solid-principles-in-agile" id="id5">Role of SOLID principles in Agile</a></p> -<ul> -<li><p><a class="reference internal" href="#srp" id="id6">Ошибочная трактовка SRP</a></p> +<li><p><a class="reference internal" href="#tdd" id="id32">TDD - Разработка через тестирование</a></p> <ul> -<li><p><a class="reference internal" href="#srp-is-not-to-do-just-one-thing" id="id7">SRP is not to do just one thing</a></p></li> -<li><p><a class="reference internal" href="#srp-is-about-cohesion" id="id8">SRP is about Cohesion</a></p></li> -<li><p><a class="reference internal" href="#srp-and-conway-s-law" id="id9">SRP and "Conway's law"</a></p></li> -<li><p><a class="reference internal" href="#common-closure-principle-ccp" id="id10">Common Closure Principle (CCP)</a></p></li> -<li><p><a class="reference internal" href="#srp-and-complexity" id="id11">SRP and complexity</a></p></li> -</ul> -</li> -<li><p><a class="reference internal" href="#ad-hominem" id="id12">Ad hominem</a></p></li> -<li><p><a class="reference internal" href="#solid-and-agile" id="id13">SOLID and Agile</a></p></li> -<li><p><a class="reference internal" href="#id2" id="id14">Баланс краткосрочных и долгосрочных интересов</a></p></li> -<li><p><a class="reference internal" href="#solid" id="id15">SOLID и первоисточники</a></p> +<li><p><a class="reference internal" href="#id2" id="id33">Что такое TDD?</a></p> <ul> -<li><p><a class="reference internal" href="#ocp" id="id16">OCP</a></p></li> -<li><p><a class="reference internal" href="#id3" id="id17">SRP</a></p></li> +<li><p><a class="reference internal" href="#tdd-software-design" id="id34">TDD - это о Software Design</a></p></li> +<li><p><a class="reference internal" href="#id8" id="id35">TDD - это способ управления сложностью</a></p></li> +<li><p><a class="reference internal" href="#emacsway-why-is-tdd-faster" id="id36">Почему TDD быстрее</a></p></li> +<li><p><a class="reference internal" href="#tdd-clean-code" id="id37">TDD - основной катализатор Clean Code</a></p></li> </ul> </li> -<li><p><a class="reference internal" href="#no-silver-bullet" id="id18">No Silver Bullet</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id19">Последние определения от 2022-07-06</a></p></li> +<li><p><a class="reference internal" href="#id25" id="id38">Влияние TDD на темпы разработки</a></p></li> +<li><p><a class="reference internal" href="#black-box-or-white-box" id="id39">Black Box or White Box?</a></p></li> +<li><p><a class="reference internal" href="#sociable-or-solitary" id="id40">Sociable or Solitary?</a></p></li> +<li><p><a class="reference internal" href="#tdd-design-patterns" id="id41">TDD и Design Patterns</a></p></li> +<li><p><a class="reference internal" href="#one-assertion-per-test" id="id42">One assertion per test?</a></p></li> </ul> </li> </ul> </nav> -<section id="srp"> -<span id="emacsway-agile-solid-misunderstanding"/><h2><a class="toc-backref" href="#id6" role="doc-backlink">Ошибочная трактовка SRP</a></h2> -<section id="srp-is-not-to-do-just-one-thing"> -<h3><a class="toc-backref" href="#id7" role="doc-backlink">SRP is not to do just one thing</a></h3> -<p>Существуют две распространенные ошибки применения принципа SRP:</p> -<ol class="arabic simple"> -<li><p>SRP якобы подразумевает делать только одну вещь.</p></li> -<li><p>SRP якобы применяется к компонентам, например, к микросервисам.</p></li> -</ol> -<p>Давайте немного исследуем этот вопрос.</p> -<p>В своей книге "Clean Architecture: A Craftsman's Guide to Software Structure and Design", Robert C. Martin сожалеет о том, что выбрал такое название - SRP:</p> +<section id="id2"> +<h2><a class="toc-backref" href="#id33" role="doc-backlink">Что такое TDD?</a></h2> +<p>Прежде всего, что такое TDD (Test-Driven Development)?</p> <blockquote> -<div><p>📝 "Of all the SOLID principles, the Single Responsibility Principle (SRP) might be <strong>the least well understood</strong>. -That's likely because it has a particularly <strong>inappropriate name</strong>. -It is too easy for programmers <strong>to hear the name and then assume that it means that every module should do just one thing</strong>.</p> -<p>Make no mistake, there is a principle like that. -A function should do one, and only one, thing. -We use that principle when we are refactoring large functions into smaller functions; we use it at the lowest levels. -<strong>But it is not one of the SOLID principles—it is not the SRP</strong>.</p> -<p>Historically, the SRP has been described this way:</p> +<div><p>Чистый код, который работает (clean code that works), — в этой короткой, но содержательной фразе, придуманной Роном Джеффризом (Ron Jeffries), кроется весь смысл методики Test-Driven Development (TDD). +Чистый код, который работает, — это цель, к которой стоит стремиться, и этому есть причины.</p> +<p>Clean code that works - now. +This is the seeming contradiction that lies behind much of the pain of programming. +Test-driven development replies to this contradiction with a paradox-test the program before you write it.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id3" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +</div></blockquote> +<section id="tdd-software-design"> +<h3><a class="toc-backref" href="#id34" role="doc-backlink">TDD - это о Software Design</a></h3> +<p>Классическое заблуждение заключается в том, что TDD - это методика тестирования. +На самом же деле, TDD - это, прежде всего, методика разработки и проектирования:</p> <blockquote> -<div><p><em>A module should have one, and only one, reason to change.</em></p> +<div><p>Ирония TDD состоит в том, что это вовсе не методика тестирования. +Это методика анализа, методика проектирования, фактически методика структурирования всей деятельности, связанной с разработкой программного кода.</p> +<p>One of the ironies of TDD is that it isn't a testing technique (the Cunningham Koan). +It's an analysis technique, a design technique, really a technique for structuring all the activities of development.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id4" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> </div></blockquote> -<p>Software systems are changed to satisfy users and stakeholders; those users and stakeholders are the "reason to change" that the principle is talking about. -Indeed, we can rephrase the principle to say this:</p> <blockquote> -<div><p><em>A module should be responsible to one, and only one, user or stakeholder.</em></p> +<div><p>Если сравнивать со средним уровнем индустрии разработки программного обеспечения, методика TDD позволяет вам писать код, содержащий значительно меньше дефектов и формировать значительно более чистый дизайн. Те, кто стремится к изяществу, могут найти в TDD средство для достижения цели.</p> +<p>It lets you write code with far fewer defects and a much cleaner design than is common in the industry. However, those whose souls are healed by the balm of elegance can find in TDD a way to do well by doing good.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id5" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> </div></blockquote> -<p>Unfortunately, the words "user" and "stakeholder" aren't really the right words to use here. -There will likely be more than one user or stakeholder who wants the system changed in the same way. -Instead, we're really referring to a group—one or more people who require that change. -We'll refer to that group as an actor.</p> -<p>Thus the final version of the SRP is:</p> <blockquote> -<div><p><em>A module should be responsible to one, and only one, actor.</em></p> +<div><p>TDD базируется на очаровательно-наивном предположении программиста о том, что чем красивее код, тем вероятнее успех. +TDD помогает вам обращать внимание на правильные вопросы в подходящие для этого моменты времени. Благодаря этому вы можете делать дизайн чище и модифицировать его по мере того, как перед вами встают новые обстоятельства.</p> +<p>TDD rests on a charmingly naive geekoid assumption that if you write better code, you'll be more successful. +TDD helps you to pay attention to the right issues at the right time so you can make your designs cleaner, you can refine your designs as you learn.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id6" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> </div></blockquote> -<p>Now, what do we mean by the word "module"? The simplest definition is just a source file. -Most of the time that definition works fine. -Some languages and development environments, though, don't use source files to contain their code. -In those cases a module is just a cohesive set of functions and data structures.</p> -<p>That word "cohesive" implies the SRP. -Cohesion is the force that binds together the code responsible to a single actor.</p> -<p>Perhaps the best way to understand this principle is by looking at the symptoms of violating it..."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +<blockquote> +<div><p>Мы с Робертом Мартином (Robert Martin) занимались исследованием подобного стиля TDD. +Проблема состоит в том, что дизайн продолжает вас удивлять. +Идеи, которые на первый взгляд кажутся вам вполне уместными, позже оказываются неправильными. +Поэтому я не рекомендую целиком и полностью доверять своим предчувствиям относительно паттернов. +Лучше думайте о том, что, по-вашему, должна делать система, позвольте дизайну оформиться так, как это необходимо.</p> +<p>Robert Martin and I did some research into this style of TDD. The problem is that the design keeps surprising you. +Perfectly sensible design ideas turn out to be wrong. +Better just to think about what you want the system to do, and let the design sort itself out later.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id7" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +</div></blockquote> +</section> +<section id="id8"> +<h3><a class="toc-backref" href="#id35" role="doc-backlink">TDD - это способ управления сложностью</a></h3> +<p>Согласно закономерности <a class="reference external" href="https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two">Магического числа семь плюс-минус два</a>, обнаруженной американским учёным-психологом Джорджем Миллером, кратковременная человеческая память, как правило, не может запомнить и повторить более 7 ± 2 элементов. +Превышение этого порога замедляет темпы разработки, так как мозг не может преодолеть высокую концентрацию сложности.</p> +<p>Тут можно провести аналогию с народной пословицей: веник сложно поломать пока он связан, но, развязав его на отдельные прутики, их можно легко переломать по отдельности. +TDD именно именно это и делает - декомпозирует (перемалывает) сложность в процессе разработки.</p> +<p id="index-0">Здесь хорошо прослеживается аналогия с рефакторингом, который, в значительной мере, был основан тем же самым человеком - Кент Беком.</p> +<blockquote> +<div><p>Мой первый опыт проведения дисциплинированного "поэтапного" рефакторинга связан с программированием на пару с Кентом Беком (Kent Beck) на высоте 30 000 футов.</p> +<p>My first experience with disciplined, "one step at a time" refactoring was when I was pair-programming at 30,000 feet with Kent Beck.</p> +<p class="attribution">—Martin Fowler, the key author of "Refactoring: Improving the Design of Existing Code" <a class="footnote-reference brackets" href="#fnrefactoring" id="id9" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts, перевод С. Маккавеева</p> +</div></blockquote> +<p>К тому же, рефакторинг является необъемлемой частью цикла TDD:</p> +<blockquote> +<div><p>Красный—зеленый—рефакторинг — это мантра TDD.</p> +<p>Red/green/refactor - the TDD mantra.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id10" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +</div></blockquote> +<p>По основной версии, слово "refactoring" происходит от математического термина "factoring", и дословно переводится как "факторизация" или "декомпозиция", о чем говорит на своем сайте ключевой автор известной книги "Refactoring: Improving the Design of Existing Code" <a class="footnote-reference brackets" href="#fnrefactoring" id="id11" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> (благодаря которой, рефакторинг, собственно, и стал популярным):</p> +<blockquote> +<div><p>The obvious answer comes from the notion of factoring in mathematics. You can take an expressions such as x^2 + 5x + 6 and factor it into (x+2)(x+3). By factoring it you can make a number of mathematical operations much easier. Obviously this is much the same as representing 18 as 2*3^2. I've certainly often heard of people talking about a program as well factored once it's broken out into similarly logical chunks.</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/EtymologyOfRefactoring.html">Etymology Of Refactoring</a>" by Martin Fowler</p> +</div></blockquote> +<p>Такое же мнение можно увидеть и на сайте Ward Cunningham:</p> +<blockquote> +<div><p>Refactoring is a kind of reorganization. <strong>Technically, it comes from mathematics when you factor an expression into an equivalence - the factors are cleaner ways of expressing the same statement.</strong> Refactoring implies equivalence; the beginning and end products must be functionally identical. You can view refactoring as a special case of reworking (see WhatIsReworking).</p> +<p>Practically, refactoring means making code clearer and cleaner and simpler and elegant. Or, in other words, clean up after yourself when you code. Examples would run the range from renaming a variable to introducing a method into a third-party class that you don't have source for.</p> +<p><strong>Refactoring is not rewriting, although many people think they are the same.</strong> There are many good reasons to distinguish them, such as regression test requirements and knowledge of system functionality. The technical difference between the two is that refactoring, as stated above, doesn't change the functionality (or information content) of the system whereas rewriting does. Rewriting is reworking. See WhatIsReworking.</p> +<p>Refactoring is a good thing because complex expressions are typically built from simpler, more grokable components. Refactoring either exposes those simpler components or reduces them to the more efficient complex expression (depending on which way you are going).</p> +<p>For an example of efficiency, count the terms and operators: (x - 1) * (x + 1) = x^2 - 1. Four terms versus three. Three operators versus two. However, the left hand side expression is (arguably) simpler to understand because it uses simpler operations. Also, it provides you more information about the structure of the function f(x) = x^2 - 1, like the roots are +/- 1, that would be difficult to determine just by "looking" at the right hand side.</p> +<p class="attribution">—"<a class="reference external" href="http://wiki.c2.com/?WhatIsRefactoring">What Is Refactoring</a>" on wiki.c2.com</p> +</div></blockquote> +<p>Если кому-то имя Ward Cunningham ни о чем не говорит, то вот как представил его сам Kent Beck в книге "Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id12" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>:</p> +<blockquote> +<div><p>Я начал свою жизнь настоящего программиста благодаря наставничеству и в рамках постоянного сотрудничества с Уордом Каннингэмом (Ward Cunningham). +Иногда я рассматриваю разработку, основанную на тестах, как попытку предоставить каждому программисту, работающему в произвольной среде, ощущение комфорта и тесной дружбы, которое было у нас с Уордом, когда мы вместе разрабатывали программы Smalltalk в среде Smalltalk. +He существует способа определить первоначальный источник идей, если два человека обладают одним общим мозгом. +Если вы предположите, что все хорошие идеи на самом деле изначально придумал Уорд, вы не будете далеки от истины.</p> +<p>My life as a real programmer started with patient mentoring from and continuing collaboration +with Ward Cunningham. Sometimes I see Test-Driven Development (TDD) as an attempt to +give any software engineer, working in any environment, the sense of comfort and intimacy +we had with our Smalltalk environment and our Smalltalk programs. There is no way to sort +out the source of ideas once two people have shared a brain. If you assume that all of the +good ideas here are Ward's, then you won't be far wrong.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id13" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +</div></blockquote> +<p>Ну и Википедия о факторизации:</p> +<blockquote> +<div><p>Factorization (or factoring) may also refer to more general decompositions of a mathematical object into the product of smaller or simpler objects. +For example, every function may be factored into the composition of a surjective function with an injective function.</p> +<p class="attribution">—"<a class="reference external" href="https://en.wikipedia.org/wiki/Factorization">Factorization</a>", Wikipedia</p> </div></blockquote> -<p>Впрочем, с пониманием OCP дела обстоят ненамного лучше:</p> <blockquote> -<div><p>📝 "I've heard it said that the OCP is wrong, unworkable, impractical, and not for real programmers with real work to do. -The rise of plugin architectures makes it plain that these views are utter nonsense. -On the contrary, a strong plugin architecture is likely to be the most important aspect of future software systems."</p> -<p class="attribution">—"<a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html">The Open Closed Principle</a>" by Robert C. Martin</p> +<div><p>Decomposition in computer science, also known as factoring, is breaking a complex problem or system into parts that are easier to conceive, understand, program, and maintain.</p> +<p class="attribution">—"<a class="reference external" href="https://en.wikipedia.org/wiki/Decomposition_(computer_science)">Decomposition</a>", Wikipedia</p> </div></blockquote> -</section> -<section id="srp-is-about-cohesion"> -<h3><a class="toc-backref" href="#id8" role="doc-backlink">SRP is about Cohesion</a></h3> -<p>А в своей книге 2002 года, которая вышла в свет через год после подписания Agile Manifesto (им же и организованного), Robert C. Martin выводит определение SRP из понятия "сфокусированности" (cohesion) класса:</p> <blockquote> -<div><p>📝 "SRP: The Single-Responsibility Principle</p> -<p><strong>This principle was described in the work of Tom DeMarco [1] and Meilir Page-Jones [2].</strong> -<strong>They called it cohesion.</strong> -They defined cohesion as the functional relatedness of the elements of a module. -In this chapter we'll shift that meaning a bit and relate cohesion to the forces that cause a module, or a class, to change.</p> -<p>A class should have only one reason to change.</p> -<ol class="arabic simple"> -<li><p>[DeMarco79], p. 310.</p></li> -<li><p>[Page-Jones88], Chapter 6, p. 82.</p></li> -</ol> -<ol class="arabic simple"> -<li><p>DeMarco, Tom. Structured Analysis and System Specification. Yourdon Press Computing Series. Englewood Cliff, NJ: 1979.</p></li> -<li><p>Page-Jones, Meilir. The Practical Guide to Structured Systems Design, 2d ed. Englewood Cliff, NJ: Yourdon Press Computing Series, 1988."</p></li> -</ol> -<p class="attribution">—"Agile Software Development. Principles, Patterns, and Practices." by Robert C. Martin, James W. Newkirk, Robert S. Koss</p> +<div><p>В математике факториза́ция или фа́кторинг — это декомпозиция объекта (например, числа, полинома или матрицы) в произведение других объектов или факторов, которые, будучи перемноженными, дают исходный объект. +Например, число 15 факторизуется на простые числа 3 и 5, а полином x2 − 4 факторизуется на (x − 2)(x + 2). +В результате факторизации во всех случаях получается произведение более простых объектов, чем исходный.</p> +<p class="attribution">—"<a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F">Факторизация</a>", Wikipedia</p> </div></blockquote> -<p>Многое встает на свое место, если принимать во внимание Cohesion, т.е. использовать изначальный принцип "<a class="reference external" href="http://wiki.c2.com/?CouplingAndCohesion">Low Coupling &amp; High Cohesion</a>".</p> -<p>Часто можно слышать, что применение принципов SOLID ведет к появлению нечитаемого кода. -Очень хорошо подобную проблему (правда, возникающую по другим причинам) выразил Eric Evans:</p> +<p>Таким образом, рефакторинг - это способ управления сложностью, который делает программу более читаемой и понимаемой за счет декомпозиции сложности, что снижает нагрузку на краткосрочную память. +Процесс рефакторинга подобен факторизации математического выражения, в результате которого выводится более легкое эквивалентное выражение, т.е. сохраняется функциональная идентичность. +Именно поэтому рефакторинг оставляет неизменным внешнее поведение системы:</p> <blockquote> -<div><p>📝 "Если требования архитектурной среды к распределению обязанностей таковы, что элементы, реализующие концептуальные объекты, оказываются физически разделенными, то код больше не выражает модель.</p> -<p>Нельзя разделять до бесконечности, у человеческого ума есть свои пределы, до которых он еще способен соединять разделенное; если среда выходит за эти пределы, разработчики предметной области теряют способность расчленять модель на осмысленные фрагменты.</p> -<p>If the framework's partitioning conventions pull apart the elements implementing the conceptual objects, the code no longer reveals the model.</p> -<p>There is only so much partitioning a mind can stitch back together, and if the framework uses it all up, the domain developers lose their ability to chunk the model into meaningful pieces."</p> -<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> +<div><p>Рефакторинг представляет собой процесс такого изменения программной системы, при котором не меняется внешнее поведение кода, но улучшается его внутренняя структура.</p> +<p>Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure.</p> +<p class="attribution">—Martin Fowler in "Refactoring: Improving the Design of Existing Code" <a class="footnote-reference brackets" href="#fnrefactoring" id="id14" role="doc-noteref"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></a> by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts, перевод С. Маккавеева</p> </div></blockquote> -<p>О том, что использованием принципов SOLID можно переусложнить программу, пишет и весьма авторитетный в области программной разработки Сергей Тепляков:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>"</p></li> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2013/12/about-agile-principles-patterns-and.html">Критика книги Боба Мартина "Принципы, паттерны и методики гибкой разработки на языке C#"</a>"</p></li> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2011/11/blog-post_23.html">Идеальная архитектура</a>"</p></li> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2014/10/solid.html">Шпаргалка по SOLID принципам</a>"</p></li> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2014/10/about-design-principles.html">О принципах проектирования</a>"</p></li> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2012/07/blog-post.html">О дизайне</a>"</p></li> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2012/04/blog-post_19.html">О повторном использовании кода</a>"</p></li> -</ul> -<p>Лично мне на практике не доводилось наблюдать сложности от использования принципов SOLID, разве что только в проектах с использованием Redux. -Кстати, у Udi Dahan есть прекрасная статья "<a class="reference external" href="http://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" о том, как грамотно разделять бизнес-логику и логику приложения в CQRS-приложении (а <a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/motivation">Redux реализует принципы CQRS</a>), чтобы предотвратить фрагментирование бизнес-логики.</p> -<p>Я обнаружил еще одну причину столь широкого недопонимания этого принципа. -В переводе книги "Clean Code" термин "Single" переводится как "Единый". -А в книге "Clean Architecture" - как "Единственный".</p> -<p>Эти термины похожи, но не идентичны. -Так, например, "Единое гражданство" означает то, что административно-территориальные единицы государства не могут вводить свое собственное гражданство. -Но при этом, граждане могут иметь двойное гражданство. -А вот "Единственное гражданство" уже подразумевает запрет на двойное гражданство.</p> -<p>Таким образом, термин "Единый" подразумевает "Сфокусированный" на конкретной задаче, т.е. нефрагментированный. -Иными словами, речь идет о "High Cohesion", что восходит к Constantine's Law - "Low Coupling &amp; High Cohesion", о чем прямо говорит Robert C. Martin по приведенным выше ссылкам.</p> +<p>TDD, как и рефакторинг, расщепляет сложность таким образом, чтобы минимизировать объем сложности, рассматриваемый разработчиком в единицу времени. +Это как песочные часы - одна песчинка в единицу времени. +Именно этим объясняется повышение темпов разработки при использовании TDD.</p> <blockquote> -<div><p>📝 "<strong>That word "cohesive" implies the SRP.</strong> -Cohesion is the force that binds together the code responsible to a single actor."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +<div><p>Каким образом можно модифицировать одну часть метода или объекта, состоящего из нескольких частей? +Вначале изолируйте изменяемую часть. +Мне приходит в голову аналогия с хирургической операцией: фактически все тело оперируемого пациента покрыто специальной простыней за исключением места, в котором, собственно, осуществляется операция. +<strong>Благодаря такому покрытию хирург имеет дело с фиксированным набором переменных.</strong> +Перед выполнением операции врачи сколь угодно долго могут обсуждать, какое влияние на здоровье пациента оказывает тот или иной орган, однако во время операции внимание хирурга должно быть сфокусировано.</p> +<p>How do you change one part of a multi-part method or object? First, isolate the part that has to change. +The picture that comes to my mind is surgery: The entire patient except the part to be operated on is draped. +<strong>The draping leaves the surgeon with only a fixed set of variables.</strong> +Now, we could have long arguments over whether this abstraction of a person to a lower left quadrant abdomen leads to good health care, but at the moment of surgery, I'm kind of glad the surgeon can focus.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id15" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> </div></blockquote> -<p>Так, например, метод рефакторинга "<a class="reference external" href="https://refactoring.com/catalog/inlineClass.html">Inline Class</a>" не противоречит SRP, хотя класс и отбирает обязанность у другого класса в случае, когда её недостаточно для самостоятельного существования.</p> -<p>С другой стороны, если фрагментировать класс, понижая его Cohesion, то это будет противоречить принципу SRP, хотя мы и получим многочисленные классы с дистиллированными кусочками обязанностей без примесей.</p> -<p>Качественный Software Design должен облегчать понимание кода, а не затруднять.</p> -<p>К сожалению, сложности перевода встречаются нередко. -Так, например, до сих пор нет единого мнения о том, как правильно переводить термины "Coupling" и "Cohesion", и различные источники дают прямо противоположный перевод.</p> -</section> -<section id="srp-and-conway-s-law"> -<h3><a class="toc-backref" href="#id9" role="doc-backlink">SRP and "Conway's law"</a></h3> -<p>А здесь Robert C. Martin выводит понимание SRP исходя из "Conway's law":</p> +<p>В этом отношении, TDD можно сравнить с <a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%A8%D0%BE%D1%80%D1%8B">шорами</a>.</p> <blockquote> -<div><p>📝 "SRP: The Single Responsibility Principle</p> -<p>An active <strong>corollary to Conway's law</strong>: The best structure for a software system is heavily influenced by the social structure of the organization that uses it so that each software module has one, and only one, reason to change."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +<div><p>Несмотря на множество появившихся в последнее время мощных инструментов, программирование по-прежнему остается сложной работой. +Я часто ощущаю себя в ситуации, когда мне кажется, что я жонглирую шариками, и мне приходится следить за несколькими шариками в воздухе в одно и то же время: малейшая потеря внимания, и все сыпется на пол. +Методика TDD позволяет избавиться от этого ощущения.</p> +<p><strong>Когда вы работаете в стиле TDD, в воздухе постоянно находится лишь один шарик.</strong> +<strong>Вы можете сконцентрироваться на нем, а значит, хорошо справиться со своей работой.</strong> +Когда я добавляю в программу новую функциональность, я не думаю о том, какой дизайн должен быть реализован в данной функции. +Я просто пытаюсь добиться срабатывания тестов самым простым из доступных мне способов. +Когда я переключаюсь в режим рефакторинга, я не беспокоюсь о добавлении в программу новых функций, я думаю только о правильном дизайне. +На каждом из этих этапов я концентрируюсь на единственной задаче, благодаря этому мое внимание не распыляется.</p> +<p>Despite all the fancy tools that we have, programming is still hard. +I can remember many programming times when I feel like I was trying to keep several balls in the air at once, any lapse of concentration and everything would come tumbling down. +Test-driven development helps reduce that feeling, and as a result you get this rapid unhurriedness.</p> +<p><strong>I think the reason for this is that working in a test-driven development style gives you this sense of keeping just one ball in the air at once, so you can concentrate on that ball properly and do a really good job with it.</strong> +When I'm trying to add some new functionality, I'm not worried about what really makes a good design for this piece of function, I'm just trying to get a test to pass as easily as I can. +When I switch to refactoring mode, I'm not worried about adding some new function, I'm just worried about getting the right design. +With both of these I'm just focused on one thing at a time, and as a result I can concentrate better on that one +thing.</p> +<p class="attribution">—Martin Fowler, Afterword, "Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id16" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>, перевод П. Анджан</p> </div></blockquote> -</section> -<section id="common-closure-principle-ccp"> -<h3><a class="toc-backref" href="#id10" role="doc-backlink">Common Closure Principle (CCP)</a></h3> -<p>К компонентам применяется похожий, но другой, принцип, который называется "Common Closure Principle (CCP)":</p> <blockquote> -<div><p>📝 "THE COMMON CLOSURE PRINCIPLE</p> -<p>Gather into components those classes that change for the same reasons and at the same times. -Separate into different components those classes that change at different times and for different reasons.</p> -<p>This is the Single Responsibility Principle restated for components. -Just as the SRP says that a class should not contain multiples reasons to change, so the Common Closure Principle (CCP) says that a component should not have multiple reasons to change.</p> -<p>For most applications, maintainability is more important than reusability. -If the code in an application must change, you would rather that all of the changes occur in one component, rather than being distributed across many components. [1] -If changes are confined to a single component, then we need to redeploy only the one changed component. -Other components that don't depend on the changed component do not need to be revalidated or redeployed.</p> -<p>The CCP prompts us to gather together in one place all the classes that are likely to change for the same reasons. -If two classes are so tightly bound, either physically or conceptually, that they always change together, then they belong in the same component. -This minimizes the workload related to releasing, revalidating, and redeploying the software.</p> -<p>This principle is closely associated with the Open Closed Principle (OCP). -Indeed, it is "closure" in the OCP sense of the word that the CCP addresses. -The OCP states that classes should be closed for modification but open for extension. -Because 100% closure is not attainable, closure must be strategic. -We design our classes such that they are closed to the most common kinds of changes that we expect or have experienced.</p> -<p>The CCP amplifies this lesson by gathering together into the same component those classes that are closed to the same types of changes. -Thus, when a change in requirements comes along, that change has a good chance of being restricted to a minimal number of components."</p> -<ol class="arabic simple"> -<li><p>See the section on "The Kitty Problem" in Chapter 27, "Services: Great and Small."</p></li> -</ol> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +<div><p>Снижение количества дефектов приводит к возникновению множества вторичных психологических и социальных эффектов. +После того как я начал работать в стиле TDD, программирование стало для меня значительно менее нервным занятием. +<strong>Когда я работаю в стиле TDD, мне не надо беспокоиться о множестве вещей.</strong> +<strong>Вначале я могу заставить paботать только один тест, потом — все остальные.</strong> +Уровень стресса существенно снизился. +Взаимоотношения с партнерами по команде стали более позитивными. +Разработанный мною код перестал быть причиной сбоев, люди стали в большей степени рассчитывать на него. +У заказчиков тоже повысилось настроение. +Теперь выпуск очередной версии системы означает новую функциональность, а не набор новых дефектов, которые добавляются к уже существующим.</p> +<p>Part of the effect certainly comes from reducing defects. +The sooner you find and fix a defect, the cheaper it is, often dramatically so (just ask the Mars Lander). +There are plenty of secondary psychological and social effects from reduced defects. My own practice of programming became much less stressful when I started with TDD. +<strong>No longer did I have to worry about everything at once.</strong> +<strong>I could make this test run, and then all the rest.</strong> +Relationships with my teammates became more positive. +I stopped breaking builds, andpeople could rely on my software to work. +Customers of my systems became more positive, too. +A new release of the system just meant more functionality, not a host of new defects to identify among all of their old favorite bugs.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id17" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> </div></blockquote> -<p>Нужно учитывать, что под компонентом Robert C. Martin понимает единицу развертывания (в других источниках этот термин может иметь другое значение):</p> +<p>Иногда мозгу сложно удержать все в голове, и разработчик берется за листочек и ручку. +При TDD, вместо листочка и ручки используется файловый редактор. +TDD позволяет сфокусировать мозг на минимально возможной единице сложности, которую можно рассмотреть изолированно, что приводит к перераспределению умственных ресурсов. +Кстати, именно это является одной из ключевых особенностей, благодаря которой, практикование TDD делает код чище.</p> +<p>Если рефакторинг помогает сосредоточиться на одной обязанности, выполняемой функцией, то TDD идет еще дальше, и помогает сосредоточиться на одном конкретном значении функции, а значит, - на одном из ее внутренних состояний. +Это позволяет выводить алгоритм функции путем обобщения пересекаемых триангуляцией ее внутренних состояний (и поведений, производящих эти состояния). +А это, в свою очередь, позволяет моделировать поведение функции небольшими законченными фрагментами, удовлетворяющими конкретным значениям функции, и визуализировать формирование поведения функции прямо в редакторе. +Наглядно это демонстрируется на примере <a class="reference download internal" download="" href="../../../_downloads/ab3bcac3e843b3925d3fa4bcadf08fbe/tdd-fibonacci.txt"><code class="xref download docutils literal notranslate"><span class="pre">выведения</span> <span class="pre">функции</span> <span class="pre">Фибоначи</span></code></a> в приложении книги, см. Appendix II. Fibonacci <a class="footnote-reference brackets" href="#fntdd" id="id18" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>.</p> <blockquote> -<div><p>📝 "Components are the units of deployment. -They are the smallest entities that can be deployed as part of a system. -In Java, they are jar files. -In Ruby, they are gem files. -In .Net, they are DLLs. -In compiled languages, they are aggregations of binary files. -In interpreted languages, they are aggregations of source files. -In all languages, they are the granule of deployment."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +<div><p>Это еще один паттерн рефакторинга: <strong>разработать код, который работает с некоторым конкретным экземпляром, и обобщить этот код так, чтобы он мог работать со всеми остальными экземплярами</strong>, для этого константы заменяются переменными. +В данном случае роль константы играет не некоторое значение, а жестко фиксированный код (имя конкретного метода). +Однако принцип остается одним и тем же. +В рамках TDD эта проблема решается очень легко: <strong>методика TDD снабжает вас конкретными работающими примерами, исходя из которых вы можете выполнить обобщение</strong>. +Это значительно проще, чем выполнять обобщение исходя только из собственных умозаключений.</p> +<p>Here is another general pattern of refactoring: <strong>take code that works in one instance and generalize it to work in many</strong> by replacing constants with variables. +Here the constant was hardwired code, not a data value, but the principle is the same. +<strong>TDD makes this work well by giving you running concrete examples from which to generalize</strong>, instead of having to generalize purely with reasoning.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id19" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> +</div></blockquote> +<blockquote> +<div><p>Контроль над объемом работы. +Программисты привыкли пытаться предвидеть возникновение в будущем самых разнообразных проблем. +Если вы начинаете с конкретного примера и затем осуществляете <strong>обобщение кода</strong>, это помогает вам избавиться от излишних опасений. +Вы можете <strong>сконцентрироваться на решении конкретной проблемы</strong> и поэтому выполнить работу лучше. +При переходе к следующему тесту вы опять же концентрируетесь на нем, так как знаете, что предыдущий тест гарантированно работает.</p> +<p>Scope control - Programmers are good at imagining all sorts of future problems. +Starting with one concrete example and <strong>generalizing</strong> from there prevents you from prematurely confusing yourself with extraneous concerns. +You can do a better job of solving the immediate problem <strong>because you are focused</strong>. +When you go to implement the next test case, you can focus on that one, too, knowing that the previous test is guaranteed to work.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id20" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> </div></blockquote> +<p>Математическое объяснение этого явления можно найти в главе "1. Recurrent Problems : 1.1. The Tower of Hanoi" книги "Concrete Mathematics: A Foundation for Computer Science" 2nd edition by Ronald L. Graham, Donald E. Knuth, Oren Patashnik.</p> +<p>Кроме того, при TDD хорошо отслеживается ниточка, за которую можно распутать клубок сложности, и вопрос "с какого конца подступиться" решается сам собой.</p> </section> -<section id="srp-and-complexity"> -<h3><a class="toc-backref" href="#id11" role="doc-backlink">SRP and complexity</a></h3> -<p>Еще существует распространенное мнение, что SOLID уменьшает сложность программы.</p> +<section id="emacsway-why-is-tdd-faster"> +<span id="id21"/><h3><a class="toc-backref" href="#id36" role="doc-backlink">Почему TDD быстрее</a></h3> +<p>При TDD разработка осуществляется быстрее, хотя объема кода пишется больше. +Суть в том, что в процессе конструирования кода, <a class="reference internal" href="../sdlc/uncertainty-management/adaptation/software-design/software-design.html#emacsway-who-reads-the-code"><span class="std std-ref">91% времени занимает чтение кода и борьба со сложностью, и только 9% времени (1:10) занимает ввод символов с клавиатуры</span></a>.</p> +<p>TDD является эффективным средством управления сложностью и снижения когнитивной нагрузки. +А поскольку чтение кода и борьба со сложностью (обдумывание) занимает более 91% времени конструирования кода, то время на написание тестов полностью перекрывается повышением темпов разработки, т.е. разработка с тестами получается даже быстрей. +Пальцы работают больше, а голова меньше. +Происходит перераспределение составляющих разработки.</p> +<p>Допустим, что разработчику нужно написать вдвое больше кода без роста когнитивной нагрузки (написание тестов не требует борьбы со сложностью). +Т.е. вместо соотношения 1:10 (где 1 - это часть времени ввода символов с клавиатуры, а 10 - это часть времени чтения кода и борьбы со сложностью) получится соотношение 2:10, что равно 17%:83% вместо 9%:91%. +Совокупное время увеличится на <code class="docutils literal notranslate"><span class="pre">100%*(12</span> <span class="pre">-</span> <span class="pre">11)/11</span> <span class="pre">=</span> <span class="pre">9%</span></code> - ровно столько времени потребуется свеху для того, чтобы написать вдвое больше кода без роста когнитивной нагрузки.</p> +<p>А теперь представим, что удалось снизить когнитивную нагрузку вдвое. +Т.е. вместо соотношения 1:10 (где 1 - это часть времени ввода символов с клавиатуры, а 10 - это часть времени чтения кода и борьбы со сложностью) получится соотношение 1:5, что равно 17%:83% вместо 9%:91%. +Совокупное время уменьшится на <code class="docutils literal notranslate"><span class="pre">100%*(6</span> <span class="pre">-</span> <span class="pre">11)/11</span> <span class="pre">=</span> <span class="pre">-45%</span></code> - ровно столько времени сэкономится, если разработчик будет тратить вдвое меньше времени на борьбу со сложностью.</p> +<p>9% (вдвое больше кода) против 45% (вдвое меньше думать).</p> +<p>Конечно, коэффициенты в этом примере сильно завышены, но они хорошо раскрывают механизм ускорения темпов разработки с использованием TDD. +На практике TDD дает прирост разработки около 10% - Jason Gorman публиковал свою статистику многократного прохождения кат как по TDD, так и без TDD (см. главу "Chapter 1. What Is Design and Architecture? :: What went wrong?" книги "Clean Architecture: A Craftsman's Guide to Software Structure and Design" <a class="footnote-reference brackets" href="#fncarch" id="id22" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Robert C. Martin).</p> +<p>Я перепроверял эту особенность на личном опыте, и убедился в том, что это, действительно, работает.</p> +<p>Кроме того, время на написание тестов можно прогнозировать, в отличии от отладки.</p> +</section> +<section id="tdd-clean-code"> +<h3><a class="toc-backref" href="#id37" role="doc-backlink">TDD - основной катализатор Clean Code</a></h3> +<p>Каким образом тестирование улучшает качество кода?</p> <blockquote> -<div><dl class="simple"> -<dt>📝 сложность</dt><dd><ol class="arabic simple"> -<li><p>Составленность из нескольких частей; многообразность по составу входящих частей и связей между ними.</p></li> -<li><p>Трудность, запутанность. Противоположное понятие — простота.</p></li> -</ol> -</dd> -</dl> -<p class="attribution">—"<a class="reference external" href="https://psychology.academic.ru/2331/%D1%81%D0%BB%D0%BE%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D1%8C">Словарь практического психолога</a>". — М.: АСТ, Харвест. С. Ю. Головин. 1998.</p> +<div><p>"The problem with testing code is that you have to isolate that code. +It is often difficult to test a function if that function calls other functions. +To write that test you've got to figure out some way to decouple the function from all the others. +In other words, the need to test first forces you to think about good design.</p> +<p>If you don't write your tests first, there is no force preventing you from coupling the functions together into an untestable mass. +If you write your tests later, you may be able to test the inputs and the outputs of the total mass, but it will probably be quite difficult to test the individual functions."</p> +<p class="attribution">—"Clean Coder" <a class="footnote-reference brackets" href="#fnccoder" id="id23" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> by Robert Martin</p> +</div></blockquote> +<p>Однако, нужно учитывать:</p> +<blockquote> +<div><p>Я сказал, что предположение наивное, однако, скорее всего, я преувеличил. +На самом деле наивно предполагать, что чистый код — это все, что необходимо для успеха. +Мне кажется, что хорошее проектирование — это лишь 20% успеха. +Безусловно, если проектирование будет плохим, вы можете быть на 100% уверены в том, что проект провалится. +Однако приемлемый дизайн сможет обеспечить успех проекта только в случае, если остальные 80% будут там, где им полагается быть.</p> +<p>I say "naive," but that's perhaps overstating. +What's naive is assuming that clean code is all there is to success. +Good engineering is maybe 20 percent of a project's success. +Bad engineering will certainly sink projects, but modest engineering can enable project success as long as the other 80 percent lines up right.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id24" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> </div></blockquote> +</section> +</section> +<section id="id25"> +<h2><a class="toc-backref" href="#id38" role="doc-backlink">Влияние TDD на темпы разработки</a></h2> +<p>Я уже перечислял <a class="reference external" href="https://emacsway.github.io/ru/it/agile/easily-about-agile-way-to-rapid-development/#self-testing-code-for-agile-ru">превосходства TDD для быстрой разработки</a>, поэтому повторяться не буду.</p> +<p>Однако, перечислю основные методики, которые используются для быстрой разработки:</p> +<ul class="simple"> +<li><p>Emergent Design</p></li> +<li><p>Evolutionary (Incremental, Continuous) Design</p></li> +<li><p><a class="reference internal" href="../sdlc/uncertainty-management/adaptation/software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a></p></li> +<li><p>Очевидная Реализация (Obvious Implementation)</p></li> +<li><p>Копирование Паттернов (Pattern Copying)</p></li> +</ul> +<p>Первые два хорошо подходят для начинающих специалистов, поскольку они позволяют эффективно обрабатывать случаи неполной информированности. +Последние два - для опытных специалистов.</p> +<p>Несмотря на то, что Martin Fowler (как редактор статьи Jim Shore) объединяет смысл Emergent Design и Continuous Design:</p> <blockquote> -<div><dl class="simple"> -<dt>📝 сложный</dt><dd><ol class="arabic simple"> -<li><p>Состоящий из нескольких частей, элементов. от т. перен. Характеризующийся многими переплетающимися явлениями, признаками, отношениями.</p></li> -<li><p>перен. Представляющий трудность для понимания, разрешения, осуществления; трудный.</p></li> -<li><p>перен. Обладающий противоречивыми качествами, свойствами, особенностями.</p></li> -</ol> -</dd> -</dl> -<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/efremova/246102/%D1%81%D0%BB%D0%BE%D0%B6%D0%BD%D1%8B%D0%B9">Толковый словарь Ефремовой</a>". Т. Ф. Ефремова. 2000.</p> +<div><p>Continuous design is also known as evolutionary or emergent design. +I prefer the term continuous design because it emphasizes the core of the process: continuously taking advantage of opportunities to improve your design.</p> +<p class="attribution">—"<a class="reference external" href="https://www.martinfowler.com/ieeeSoftware/continuousDesign.pdf">Continuous Design</a>" by Jim Shore</p> </div></blockquote> +<p>Существует точка зрения, что они, все-таки, отличаются:</p> <blockquote> -<div><p>📝 Complex</p> -<p>Com"plex (kŏm"plĕks), a. [L. complexus, p. p. of complecti to entwine around, comprise; com- + plectere to twist, akin to plicare to fold. See Plait, n.]</p> -<ol class="arabic"> -<li><p>Composed of two or more parts; composite; not simple; as, a complex being; a complex idea.</p> -<blockquote> -<div><p>Ideas thus made up of several simple ones put together, I call complex; such as beauty, gratitude, a man, an army, the universe. -Locke.</p> +<div><p>We distinguish between emergent and evolutionary architecture, and this distinction is an important one.</p> +<p class="attribution">—"<a class="reference external" href="https://www.thoughtworks.com/insights/blog/microservices-evolutionary-architecture">Microservices as an Evolutionary Architecture</a>" by Neal Ford, Rebecca Parsons</p> </div></blockquote> -</li> -<li><p>Involving many parts; complicated; intricate.</p> +</section> +<section id="black-box-or-white-box"> +<span id="emacsway-tdd-black-box"/><h2><a class="toc-backref" href="#id39" role="doc-backlink">Black Box or White Box?</a></h2> +<p>Тесты по возможности должны быть черным ящиком, т.е. тестируем поведение, а не реализацию. +Это позволяет безболезненно подменять реализацию при рефакторинге. +Опускаться в глубь реализации нужно тогда, когда это требуется для сокращения комбинаций условий тестирования, например, класс использует несколько подключаемых стратегий, и нам проще протестировать стратегии по одной. +Но при этом мы должны минимизировать зависимость от реализации. +Нарушение этого принципа, в сочетании со стремлением к высокому уровню покрытия кода тестами, накладывает на код оковы и ставит крест на дальнейшей эволюции программы. +Эту тему раскрывает Бек в первой и второй серии сериала "<a class="reference external" href="https://martinfowler.com/articles/is-tdd-dead/">Is TDD dead?</a>".</p> <blockquote> -<div><p>When the actual motions of the heavens are calculated in the best possible way, the process is difficult and complex. -Whewell.</p> +<div><p>My personal practice - I mock almost nothing. +If I can't figure out how to test efficiently with the real stuff, I find another way of creating a feedback loop for myself. +I have to have feedback loop and the feedback loop has to be repeatable, but like I just don't go very far down the mock path. +I look at a code where you have mocks returning mocks returning mocks and my experience is if I use TDD I can refactor stuff. +And then I heard these stories people say well I use TDD and now I can't refactor anything and I feel like I couldn't understand that and I started looking at their tests well. +If you have mocks returning mocks returning mocks your test is completely coupled to the implementation, not the interface, but the exact implementation of some object you know three streets away. +Of course you can't change anything without breaking the test. +So that for me is too high a price to pay. +That's not a trade-off I'm willing to make just to get piecemeal development.</p> +<p class="attribution">—Kent Beck, "<a class="reference external" href="https://youtu.be/z9quxZsLcfo?t=1269">Is TDD Dead? Part 1 at 21:10</a></p> </div></blockquote> -</li> -</ol> -<p>Complex fraction. See Fraction. — Complex number (Math.), in the theory of numbers, an expression of the form a + b√-1, when a and b are ordinary integers.</p> -<p>Syn. — See Intricate.</p> -<p>Com"plex, n. [L. complexus] Assemblage of related things; collection; complication.</p> <blockquote> -<div><p>This parable of the wedding supper comprehends in it the whole complex of all the blessings and privileges exhibited by the gospel. -South.</p> +<div><p>Думать об объектах, как о черных ящиках, достаточно тяжело. +Представим, что у нас есть объект Contract, состояние которого содержится в поле status, которое может принадлежать либо классу Offered, либо классу Running. +В этом случае можно написать тест, исходя из предполагаемой реализации:</p> +<div class="highlight-java notranslate" id="code-1-ru"><div class="highlight"><pre><span/><span class="linenos">1</span><span class="n">Contract</span><span class="w"> </span><span class="n">contract</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Contract</span><span class="p">();</span><span class="w"/> +<span class="linenos">2</span><span class="c1">// по умолчанию состояние Offered</span><span class="w"/> +<span class="linenos">3</span><span class="n">contract</span><span class="p">.</span><span class="na">begin</span><span class="p">();</span><span class="w"/> +<span class="linenos">4</span><span class="c1">// состояние меняется на Running</span><span class="w"/> +<span class="linenos">5</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">Running</span><span class="p">.</span><span class="na">class</span><span class="p">,</span><span class="w"> </span><span class="n">contract</span><span class="p">.</span><span class="na">status</span><span class="p">.</span><span class="na">class</span><span class="p">);</span><span class="w"/> +</pre></div> +</div> +<p>Этот тест слишком сильно зависит от текущей реализации объекта status. +Однако тест должен срабатывать даже в случае, если поле status станет булевским значением. +Может быть, когда status меняется на Running, можно протестировать дату начала работы над контрактом:</p> +<div class="highlight-java notranslate" id="code-2-ru"><div class="highlight"><pre><span/><span class="linenos">1</span><span class="n">assertEquals</span><span class="p">(...,</span><span class="w"> </span><span class="n">contract</span><span class="p">.</span><span class="na">startDate</span><span class="p">());</span><span class="w"/> +<span class="linenos">2</span><span class="c1">// генерирует исключение, если status равен Offered</span><span class="w"/> +</pre></div> +</div> +<p>Я признаю, что пытаюсь плыть против течения, когда настаиваю на том, что все тесты должны быть написаны только с использованием публичного (public) протокола. +Существует специальный пакет JXUnit, который является расширением JUnit и позволяет тестировать значения переменных, даже тех, которые объявлены как закрытые.</p> +<p>Желание протестировать объект в рамках концепции белого ящика — это не проблема тестирования, это проблема проектирования. +Каждый раз, когда у меня возникает желание протестировать значение переменной-члена для того, чтобы убедиться в работоспособности кода, я получаю возможность улучшить дизайн системы. +Если я забываю о своих опасениях и просто проверяю значение переменной, я теряю такую возможность. +Иначе говоря, если идея об улучшении дизайна не приходит мне в голову, ничего не поделаешь. +Я проверяю значение переменной, смахиваю непрошеную слезу, вношу соответствующую отметку в список задач и продолжаю двигаться вперед, надеясь, что наступит день, когда смогу найти подходящее решение.</p> +<p>Thinking about objects as black boxes is hard. If I have a Contract with a Status that can be an instance of either Offered or Running , I might feel like writing a test based on my expected implementation:</p> +<div class="highlight-java notranslate" id="code-1-en"><div class="highlight"><pre><span/><span class="linenos">1</span><span class="n">Contract</span><span class="w"> </span><span class="n">contract</span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Contract</span><span class="p">();</span><span class="w"/> +<span class="linenos">2</span><span class="c1">// Offered status by default</span><span class="w"/> +<span class="linenos">3</span><span class="n">contract</span><span class="p">.</span><span class="na">begin</span><span class="p">();</span><span class="w"/> +<span class="linenos">4</span><span class="c1">// Changes status to Running</span><span class="w"/> +<span class="linenos">5</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">Running</span><span class="p">.</span><span class="na">class</span><span class="p">,</span><span class="w"> </span><span class="n">contract</span><span class="p">.</span><span class="na">status</span><span class="p">.</span><span class="na">class</span><span class="p">);</span><span class="w"/> +</pre></div> +</div> +<p>This test is too dependent on the current implementation of status. +The test should pass even if the representation of status changed to a boolean. +Perhaps once the status changes to Running, it is possible to ask for the actual start date.</p> +<div class="highlight-java notranslate" id="code-2-en"><div class="highlight"><pre><span/><span class="linenos">1</span><span class="n">assertEquals</span><span class="p">(...,</span><span class="w"> </span><span class="n">contract</span><span class="p">.</span><span class="na">startDate</span><span class="p">());</span><span class="w"/> +<span class="linenos">2</span><span class="c1">// Throws an exception if the status is Offered</span><span class="w"/> +</pre></div> +</div> +<p>I'm aware that I am swimming against the tide in insisting that all tests be written using only public protocol. +There is even a package that extends JUnit called JXUnit, which allows testing the value of variables, even those declared private.</p> +<p>Wishing for white box testing is not a testing problem, it is a design problem. +Anytime I want to use a variable as a way of checking to see whether code ran correctly or not, I have an opportunity to improve the design. +If I give in to my fear and just check the variable, then I lose that opportunity. +That said, if the design idea doesn't come, it doesn't come. I'll check the variable, shed a tear, make a note to come back on one of my smarter days, and move on.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id26" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> </div></blockquote> -<p>Complex of lines (Geom.), all the possible straight lines in space being considered, the entire system of lines which satisfy a single relation constitute a complex; as, all the lines which meet a given curve make up a complex. The lines which satisfy two relations constitute a congruency of lines; as, the entire system of lines, each one of which meets two given surfaces, is a congruency.</p> -<p class="attribution">—<a class="reference external" href="http://www.websters1913.com/words/Complex">webster's 1913</a>. Connoisseur's reference to American English - a dictionary for writers and wordsmiths</p> +<blockquote> +<div><p>Взгляд на тестирование в рамках TDD прагматичен. +В TDD тесты являются средством достижения цели. +Целью является код, в корректности которого мы в достаточной степени уверены. +Если знание особенностей реализации без какого-либо теста дает нам уверенность в том, что код работает правильно, мы не будем писать тест. +Тестирование черного ящика (когда мы намеренно игнорируем реализацию) обладает рядом преимуществ. +Если мы игнорируем код, мы наблюдаем другую систему ценностей: тесты сами по себе представляют для нас ценность. +В некоторых ситуациях это вполне оправданный подход, однако он отличается от TDD.</p> +<p>TDD's view of testing is pragmatic. +In TDD, the tests are a means to an end—the end being code in which we have great confidence. +If our knowledge of the implementation gives us confidence even without a test, then we will not write that test. +Black box testing, where we deliberately choose to ignore the implementation, has some advantages. +By ignoring the code, it demonstrates a different value system—the tests are valuable alone. +It's an appropriate attitude to take in some circumstances, but that is different from TDD.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id27" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> </div></blockquote> -<p>Если рассматривать термин "сложность" в значении "легкость понимания", то правильное использование принципов SOLID, наоборот, облегчает понимание.</p> -<p>Если же рассматривать этот термин в значении "многообразность по составу входящих частей", то совокупная сложность программы (в общей сложности) не уменьшается, а наоборот возрастает. -Задача архитектурных принципов сводится не к тому, чтобы уменьшить сложность, а к тому, чтобы управлять сложностью. -Это позволяет формировать структуру программы таким образом, чтобы отдельные её части можно было рассматривать изолированно, сохраняя рассматриваемый уровень сложности в пределах <a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%9C%D0%B0%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%87%D0%B8%D1%81%D0%BB%D0%BE_%D1%81%D0%B5%D0%BC%D1%8C_%D0%BF%D0%BB%D1%8E%D1%81-%D0%BC%D0%B8%D0%BD%D1%83%D1%81_%D0%B4%D0%B2%D0%B0">возможностей краткосрочной памяти человека</a>.</p> -<p>Отсюда вывод - применение любого паттерна или принципа, вносящего в систему несущественную сложность (accidental complexity), должно себя окупать, т.е. позволять управлять еще большим уровнем сложности. -Тогда применение принципов и паттернов, хотя и будет (математически) усложнять программу, но будет упрощать понимание программы, формируя такие уровни абстракции, которые человеческий мозг сможет рассматривать изолированно.</p> -<p>Методики управления сложностью позволяют предотвратить Уроборос.</p> -<p>Но есть еще одно значение этого термина:</p> <blockquote> -<div><p>📝 "Structural Complexity looks at the system elements and relationships. -In particular, structural complexity looks at how many different ways system elements can be combined. -Thus, it is related to the potential for the system to adapt to external needs."</p> -<p class="attribution">—"<a class="reference external" href="https://www.sebokwiki.org/wiki/Complexity">Guide to the Systems Engineering Body of Knowledge (SEBoK)</a>"</p> +<div><p>Many people make bad trade-offs, especially with heavy mocking. +Kent thinks it's about trade-offs: is it worth making intermediate results testable? +He used the example of a compiler where an intermediate parse-tree makes a good test point, and is also a better design.</p> +<p class="attribution">—Kent Beck, "<a class="reference external" href="https://martinfowler.com/articles/is-tdd-dead/">Is TDD Dead?</a>"</p> </div></blockquote> -<p>Если рассматривать термин в таком значении, то SOLID увеличивает сложность, но это не имеет негативного влияния на понимание устройства системы.</p> -</section> -</section> -<section id="ad-hominem"> -<h2><a class="toc-backref" href="#id12" role="doc-backlink">Ad hominem</a></h2> -<p>Еще одно распространенное мнение, которое нередко можно услышать, заключается в том, что Robert C. Martin - оторванный от практики теоретик, придумывающий в своем иллюзорном мирке всякие нежизнеспособные принципы вроде SOLID, которые на практике только ухудшают код.</p> -<p>Принципы SOLID действительно, имеют под собой теоретическое обоснование, только эта теория не связана с Robert C. Martin. -А вот, например, Bertrand Meyer, действительно, является серьезным научным теоретиком, и его авторство Robert C. Martin не скрывал в своей оригинальной статье "<a class="reference external" href="https://web.archive.org/web/20060822033314/http://www.objectmentor.com/resources/articles/ocp.pdf">The Open-Closed Principle</a>".</p> -<p>Итак, вывод первый - если кто и является теоретиком, то это не Robert C. Martin. Он-то как раз практик.</p> -<p>В архитекторских кругах отношение к Robert C. Martin можно назвать, мягко говоря, неоднозначным. -Зато к Gregor Hohpe отношение - почти единодушно уважительное.</p> -<p>Но, странное дело, первая книга в <a class="reference external" href="https://architectelevator.com/architecture/architect-bookshelf/">списке рекомендованной литературы Gregor Hohpe</a> - это именно книга "Clean Code" by Robert C. Martin.</p> -<p>Мое же мнение сводится к тому, что говорить о влиянии внутреннего качества кода на характер роста стоимости изменения кода - нужно. -Именно этим и занимается Robert C. Martin. -И это <a class="reference external" href="https://en.m.wikipedia.org/wiki/Ad_hominem">важнее манеры донесения информации</a>. -Потому что это - один из наиболее чувствительных вопросов индустрии, см. "<a class="reference internal" href="../../../models/agile/analysis/concerns/business-concerns/common-planning-errors.html#emacsway-agile-common-planning-errors"><span class="std std-ref">Наиболее частые ошибки планирования</span></a>".</p> -</section> -<section id="solid-and-agile"> -<h2><a class="toc-backref" href="#id13" role="doc-backlink">SOLID and Agile</a></h2> -<p>Принципы SOLID впервые появились в статье "Design Principles and Design Patterns" 2000 года:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://sites.google.com/site/unclebobconsultingllc/getting-a-solid-start">Источник 1</a>"</p></li> -<li><p>"<a class="reference external" href="https://web.archive.org/web/20150906155800/http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf">Источник 2</a>"</p></li> -<li><p>"<a class="reference external" href="https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf">Источник 3</a>"</p></li> -</ul> -<p>Вышла эта статья за год до того, как тот же Robert C. Martin организовал встречу 17-ти, на которой был принят Agile-Manifesto. -Как между собой связаны два этих события?</p> -<p>Все просто. -Agile - это адаптивная методика, которая имеет экономическую целесообразность только в том случае, если <a class="reference internal" href="../../../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">стоимость адаптации ниже стоимости заблаговременного проектирования (BDUF)</span></a>.</p> -<p>А стоимость адаптации, благодаря которой итеративная разработка вообще обретает смысл, определяется характером роста стоимости изменения кода. -А это уже <a class="reference internal" href="software-design.html#emacsway-agile-software-design"><span class="std std-ref">задача архитектурная</span></a>, и это объясняет, почему на подписании Agile-manifesto присутствовало столько людей из мира архитектуры. -Кстати, на этой встрече предполагалось присутствие и Grady Booch, но, не вышло.</p> -<p>И это так же объясняет, почему первая книга, которую выпустил организатор встречи Agile-Manifesto после его подписания, была посвящена не столько процессам, сколько принципам конструирования (гибкого) кода, обладающего низкой стоимостью изменения. -Это лишний раз подчеркивает <a class="reference internal" href="../../../models/agile/agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">важность технической составляющей в Agile (гибкой) разработке</span></a>.</p> -<p>Итак, следующий важный вывод: если бы принципы конструирования гибкого кода, включая SOLID, не имели бы практического улучшения экономических показателей разработки, тогда Robert C. Martin с единомышленниками никогда не смог бы доказать бизнесу, что Agile обладает экономическим превосходством перед BDUF, и рынок просто его проигнорировал бы.</p> -</section> -<section id="id2"> -<h2><a class="toc-backref" href="#id14" role="doc-backlink">Баланс краткосрочных и долгосрочных интересов</a></h2> -<p><a class="reference external" href="https://en.m.wikipedia.org/wiki/List_of_system_quality_attributes">Quality Attributes</a> противоречивы между собой, и удовлетворить их все не представляется возможным. -Поэтому, приложение не может быть лучше или хуже - оно может соответствовать или не соответствовать требуемым атрибутам качества.</p> -<p>Принципы SOLID направлены на удовлетворение атрибута качества <a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=8299">Modifiability</a> (см. "Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman) в долгосрочной перспективе. -Т.е. они призваны обеспечить пологий характер роста стоимости изменения кода, максимально приближенный к горизонтальной асимптоте. -Напомню, принципы SOLID были опубликованы в контексте Agile разработки, где это требование является критически необходимым для достижения экономического превосходства Agile-разработки перед BDUF.</p> -<p>Чтобы находить баланс наименьшей стоимости разработки как в долгосрочной, так и в краткосрочной перспективе, нужно сочетать принципы SOLID с принципом YAGNI (который отвечает за снижение стоимости в краткосрочной перспективе), о чем писал Сергей Тепляков в статьях:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>"</p></li> -<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2012/04/blog-post_19.html">О повторном использовании кода</a>"</p></li> -</ul> -<p>Сам Robert Martin дает такое определение качеству дизайна:</p> <blockquote> -<div><p>📝 "The measure of design quality is simply the measure of the effort required to meet the needs of the customer. -If that effort is low, and stays low throughout the lifetime of the system, the design is good. -If that effort grows with each new release, the design is bad. -It's as simple as that."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +<div><p>Separate interface from implementation thinking. +I have a tendency to pollute API design decisions with implementation speculation. +I need to find a new way to separate the two levels of thinking while still providing rapid feedback between them.</p> +<p class="attribution">—Kent Beck, "<a class="reference external" href="https://www.facebook.com/notes/kent-beck/rip-tdd/750840194948847/">RIP TDD</a>"</p> </div></blockquote> -<p>Ключевым здесь является "stays low throughout the lifetime of the system" (т.е. в долгосрочной перспективе), поскольку существует <a class="reference external" href="https://martinfowler.com/bliki/DesignPayoffLine.html">Design Payoff Line</a>.</p> -<p>Не должно быть принципов ради принципов, когда за деревьями леса не видно. -Если принципы применяются, а стоимость разработки возрастает, значит, применяются либо не те принципы, либо не так. -Как говорил Craig Larman:</p> <blockquote> -<div><p>📝 "в продуктовой разработке нет такого понятия как "лучшие практики" - есть только практики, применение которых целесообразно в конкретном контексте. -Практики ситуационны, и беспечное объявление их "лучшими" отрывает их от мотивации и контекста. -Они превращаются в ритуалы, и навязывание так называемых "best practices" убивает культуру обучения, задавания вопросов, вовлечения и непрерывных улучшений. -Зачем людям искать чего-то лучшего, если все уже придумано за них?"</p> -<p class="attribution">—"<a class="reference external" href="https://less.works/ru/less/framework/introduction">Знакомство с LeSS</a>"</p> +<div><p>Структурная зависимость</p> +<p>Структурная зависимость - одна из самых сильных и наиболее коварных форм зависимости тестов. +Представьте набор тестов, в котором имеются тестовые классы для всех прикладных классов и тестовые методы для всех прикладных методов. +Такой набор очень тесно связан со структурой приложения.</p> +<p>Изменение в одном из прикладных методов или классов может повлечь необходимость изменить большое количество тестов. +Следовательно, тесты слишком хрупкие и могут сделать прикладной код слишком жестким.</p> +<p>Роль API тестирования - скрыть структуру приложения от тестов. +Это позволит развивать прикладной код, не влияя на тесты. Это также позволит развивать тесты, не влияя на прикладной код.</p> +<p>Такая возможность независимого развития абсолютно необходима, потому что с течением времени тесты становятся все более конкретными, а прикладной код, напротив, — все более абстрактным и обобщенным. +Тесная структурная зависимость препятствует такому развитию - или, по меньшей мере, затрудняет его - и мешает прикладному коду становиться все более обобщенным и гибким.</p> +<p>STRUCTURAL COUPLING</p> +<p>Structural coupling is one of the strongest, and most insidious, forms of test coupling. +Imagine a test suite that has a test class for every production class, and a set of test methods for every production method. +Such a test suite is deeply coupled to the structure of the application.</p> +<p>When one of those production methods or classes changes, a large number of tests must change as well. +Consequently, the tests are fragile, and they make the production code rigid.</p> +<p>The role of the testing API is to hide the structure of the application from the tests.</p> +<p>This allows the production code to be refactored and evolved in ways that don't affect the tests. +It also allows the tests to be refactored and evolved in ways that don't affect the production code.</p> +<p>This separation of evolution is necessary because as time passes, the tests tend to become increasingly more concrete and specific. +In contrast, the production code tends to become increasingly more abstract and general. +Strong structural coupling prevents - or at least impedes - this necessary evolution, and prevents the production code from being as general, and flexible, as it could be.</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" <a class="footnote-reference brackets" href="#fncarch" id="id28" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> by Robert C. Martin</p> </div></blockquote> <blockquote> -<div><p>📝 "There are no such things as best practices in product development. -There are only practices that are adequate within a certain context. -Practices are situational; blithely claiming they are "best" disconnects them from motivation and context. -They become rituals. And pushing so-called best practices kills a culture of learning, questioning, engagement, and continuous improvement. -Why would people challenge best?"</p> -<p class="attribution">—"<a class="reference external" href="https://less.works/ru/less/framework/introduction">Introduction to LeSS</a>"</p> +<div><p>"Mock across architecturally significant boundaries, but not within those boundaries."</p> +<p class="attribution">—"<a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2014/05/10/WhenToMock.html">When to Mock</a>" by Robert C. Martin</p> </div></blockquote> -<p>Иными словами, нужно осознавать, для достижения какого именно требования применяется тот или иной принцип, следить за фидбэком от его применения, и анализировать успешность достижения этого требования. Без этого, применение принципов может легко превратиться в <a class="reference external" href="http://sergeyteplyakov.blogspot.com/2013/09/blog-post_24.html">Карго-Культ</a>.</p> </section> -<section id="solid"> -<h2><a class="toc-backref" href="#id15" role="doc-backlink">SOLID и первоисточники</a></h2> -<p>Остается еще одно распространенное мнение - Robert C. Martin исказил оригинальный смысл первоисточников. -Где-то в чем-то он может и ошибся, да он и сам об этом говорил. -Но он не присваивал себе чужие идеи, и всегда открыто отсылал к первоисточникам, таким образом, привлекая к ним внимание.</p> -<section id="ocp"> -<h3><a class="toc-backref" href="#id16" role="doc-backlink">OCP</a></h3> -<p>Вот, например, многие из ваших коллег узнали бы об OCP из оригинала в изложении Bertrand Meyer? -Даже Martin Fowler говорил, что:</p> +<section id="sociable-or-solitary"> +<span id="index-1"/><h2><a class="toc-backref" href="#id40" role="doc-backlink">Sociable or Solitary?</a></h2> +<p>Наверное, самое часто заблуждение, которое мне приходилось слышать, это то, тесты должны быть полностью изолированы, и должны взаимодействовать только с <a class="reference external" href="https://martinfowler.com/bliki/TestDouble.html">дублерами</a>. +Этот вопрос известен как "Solitary or Sociable?".</p> <blockquote> -<div><p>📝 "the second edition [of "Object Oriented Software Construction"] is good but you'll need several months in a gym before you can lift it."</p> -<p class="attribution">—M.Fowler, <a class="reference external" href="https://martinfowler.com/bliki/CommandQuerySeparation.html">Command Query Separation</a></p> +<div><p>Indeed using sociable unit tests was one of the reasons we were criticized for our use of the term "unit testing". I think that the term "unit testing" is appropriate because these tests are tests of the behavior of a single unit. We write the tests assuming everything other than that unit is working correctly.</p> +<p>As xunit testing became more popular in the 2000's the notion of solitary tests came back, at least for some people. We saw the rise of Mock Objects and frameworks to support mocking. Two schools of xunit testing developed, which I call the classic and mockist styles. One of the differences between the two styles is that mockists insist upon solitary unit tests, while classicists prefer sociable tests. Today I know and respect xunit testers of both styles <strong>(personally I've stayed with classic style)</strong>.</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/bliki/UnitTest.html#SolitaryOrSociable">Unit Test</a>" by Martin Fowler</p> </div></blockquote> -<p>При этом, Robert C. Martin, действительно возлагал на старые принципы новые задачи, исходя из исторического контекста того времени. -Очень хорошо этот вопрос рассматривается в статье "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/ocp-vs-yagni/">OCP vs YAGNI</a>" by Vladimir Khorikov.</p> <blockquote> -<div><p>📝 "There are two interpretations of the Open/Closed Principle:</p> +<div><p>At the end of the day it's not important to decide if you go for solitary or sociable unit tests. Writing automated tests is what's important. Personally, I find myself using both approaches all the time.</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/practical-test-pyramid.html#SociableAndSolitary">The Practical Test Pyramid</a>" by Ham Vocke with support of Martin Fowler.</p> +</div></blockquote> <blockquote> -<div><ol class="arabic simple"> -<li><p>The original Bertrand Meyer's one is about backward compatibility. You need to close the API of your module/library/service if it's meant for external use. Not implementation but exactly the API part of it. And only when it's used by external teams.</p></li> -<li><p>The Bob Martin's one is about avoiding ripple effects: you need to be able to extend the software behavior with modifying little or no original code. This is achieved by putting extension points to your code base."</p></li> -</ol> +<div><p>TestDrivenDevelopment produces Developer Tests. The failure of a test case implicates only the developer's most recent edit. <strong>This implies that developers don't need to use Mock Objects to split all their code up into testable units</strong>. And it implies a developer may always avoid debugging by reverting that last edit.</p> +<p class="attribution">—"<a class="reference external" href="https://wiki.c2.com/?UnitTest">Unit Test</a>" on c2.com</p> </div></blockquote> -<p class="attribution">—"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/ocp-vs-yagni/">OCP vs YAGNI</a>" by Vladimir Khorikov</p> +<p>Недостатки и достоинства обоих подходов описаны в статье "<a class="reference external" href="https://martinfowler.com/articles/mocksArentStubs.html">Mocks Aren't Stubs</a>".</p> +<p>Мнение самого основателя TDD:</p> +<blockquote> +<div><p>"My personal practice - I mock almost nothing."</p> +<p class="attribution">—Kent Beck, "<a class="reference external" href="https://youtu.be/z9quxZsLcfo?t=1269">Is TDD Dead? Part 1 at 21:10</a></p> </div></blockquote> +<p>Лично я считаю что нужно ограничивать использование современных средства мокирования, активно эксплуатирующих Monkey Patch, поскольку они позволяют создавать и тестировать низкокачественный код.</p> </section> -<section id="id3"> -<h3><a class="toc-backref" href="#id17" role="doc-backlink">SRP</a></h3> -<p>В качестве источника принципа SRP, Robert C. Martin в своей книге "Agile Software Development. Principles, Patterns, and Practices." указывает:</p> +<section id="tdd-design-patterns"> +<span id="index-2"/><h2><a class="toc-backref" href="#id41" role="doc-backlink">TDD и Design Patterns</a></h2> +<p>Почему-то многие начинающие программисты, не знакомые с первоисточниками по TDD, думают, что TDD подразумевает только Evolutionary Design, а Simple Design противопоставляется паттернам программирования.</p> <blockquote> -<div><ol class="arabic simple"> -<li><p>DeMarco, Tom. Structured Analysis and System Specification. Yourdon Press Computing Series. Englewood Cliff, NJ: 1979.</p></li> -<li><p>Page-Jones, Meilir. The Practical Guide to Structured Systems Design, 2d ed. Englewood Cliff, NJ: Yourdon Press Computing Series, 1988.</p></li> -</ol> -<p class="attribution">—"Agile Software Development. Principles, Patterns, and Practices." by Robert C. Martin</p> +<div><p>Я обратил внимание на один важный эффект, который, я надеюсь, смогут принять во внимание и другие. +Если на основе постоянно повторяющихся действий формулируются правила, дальнейшее применение этих правил становится неосознанным и автоматическим. +Естественно, ведь это проще, чем обдумывать все за и все против того или иного действия с самого начала. +Благодаря этому повышается скорость работы, и если в дальнейшем вы сталкиваетесь с исключением или проблемой, которая не вписывается ни в какие правила, у вас появляется дополнительное время и энергия для того, чтобы в полной мере применить свои творческие способности.</p> +<p>Именно это произошло со мной, когда я писал книгу Smalltalk Best Practice Patterns (Лучшие паттерны Smalltalk). +В какой-то момент я решил просто следовать правилам, описываемым в моей книге. +В начале это несколько замедлило скорость моей работы, — мне требовалось дополнительное время, чтобы вспомнить то или иное правило, или написать новое правило. +Однако по прошествии недели я заметил, что с моих пальцев почти мгновенно слетает код, над разработкой которого ранее мне приходилось некоторое время размышлять. +Благодаря этому у меня появилось дополнительное время для анализа и важных размышлений о дизайне.</p> +<p>Существует еще одна связь между TDD и паттернами: TDD является методом реализации дизайна, основанного на паттернах. +Предположим, что в определенном месте разрабатываемой системы мы хотим реализовать паттерн Strategy (Стратегия). +Мы пишем тест для первого варианта и реализуем его, создав метод. +После этого мы намеренно пишем тест для второго варианта, ожидая, что на стадии рефакторинга мы придем к паттерну Strategy (Стратегия). +Мы с Робертом Мартином (Robert Martin) занимались исследованием подобного стиля TDD. +Проблема состоит в том, что дизайн продолжает вас удивлять. +Идеи, которые на первый взгляд кажутся вам вполне уместными, позже оказываются неправильными. +Поэтому я не рекомендую целиком и полностью доверять своим предчувствиям относительно паттернов. +Лучше думайте о том, что, по-вашему, должна делать система, позвольте дизайну оформиться так, как это необходимо.</p> +<p>The effect that I have noticed, and which I hope others find, is that by reducing repeatable behavior to rules, applying the rules becomes rote and mechanical. +This is quicker than redebating everything from first principles all the time. +When along comes an exception, or a problem that just doesn't fit any of the rules, you have more time and energy to generate and apply creativity.</p> +<p>This happened to me when writing the Smalltalk Best Practice Patterns. +At some point I decided just to follow the rules I was writing. +It was much slower at first, to be looking up the rules, or to be stopping to write a new rule. +After a week, however, I discovered that code was ripping off my fingertips that would have required a pause for thought before. +This gave me more time and attention for bigger thoughts about design and analysis. +Another relationship between TDD and patterns is TDD as an implementation method for pattern-driven design. +Say we decide we want a Strategy for something. +We write a test for the first variant and implement it as a method. +Then we consciously write a test for the second variant, expecting the refactoring phase to drive us to a Strategy. +Robert Martin and I did some research into this style of TDD. +The problem is that the design keeps surprising you. +Perfectly sensible design ideas turn out to be wrong. +Better just to think about what you want the system to do, and let the design sort itself out later.</p> +<p class="attribution">—"Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id29" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> by Kent Beck, перевод П. Анджан</p> </div></blockquote> -<p>А здесь он дает более развернутую историю:</p> <blockquote> -<div><p>📝 "The 1970s and 1980s were a fertile time for principles of software architecture. -Structured Programming and Design were all the rage. -During that time the notions of Coupling and Cohesion were introduced by Larry Constantine, and amplified by Tom DeMarco, Meilir Page-Jones and many others."</p> -<p class="attribution">—"<a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html">The Single Responsibility Principle</a>" by Robert C. Martin</p> +<div><p>Добавление новой функциональности при помощи тестов и рефакторинг — это две монологические разновидности программирования. +Совсем недавно я открыл еще одну разновидность: копирование паттерна. +Я занимался разработкой сценария на языке Ruby, выполняющего извлечение информации из базы данных. +Я начал с создания класса, являющегося оболочкой таблицы базы данных, а затем сказал себе, что раз я только что закончил книгу о паттернах работы с базами данных, я должен использовать паттерн. +Примеры программ в книге были написаны на Java, поэтому нужный мне код легко можно было перенести на Ruby. +Когда я программировал, я не думал о решении проблемы, я думал лишь о том, каким образом лучше всего адаптировать паттерн для условий, в рамках которых я работал.</p> +<p>Копирование паттернов само по себе не является хорошим программированием, — я всегда подчеркиваю этот факт, когда говорю о паттернах. +Любой паттерн — это полуфабрикат, — вы должны адаптировать его для условий своего проекта. +Однако чтобы сделать это, лучше всего вначале, особо не задумываясь, скопировать паттерн, а затем, воспользовавшись смесью рефакторинга и TDD, выполнить адаптацию. +В этом случае в процессе копирования паттерна вы также концентрируетесь только на одной вещи — на паттерне. +Сообщество ХР интенсивно работает над тем, чтобы добавить в общую картину паттерны. +Со всей очевидностью можно сказать, что сообщество ХР любит паттерны. +В конце концов, между множеством приверженцев ХР и множеством приверженцев паттернов существует значительное пересечение: Уорд и Кент являются лидерами обоих направлений. +Наверное, копирование паттерна — это третий монологический режим программирования наряду с разработкой в стиле "тесты вначале" и рефакторингом. +Как и первые два режима, копирование паттерна — опасная штука, если ее использовать отдельно от двух других режимов. +Все три вида программирования проявляют свою мощь только тогда, когда используются совместно друг с другом.</p> +<p>Adding features test-first and refactoring are two of these monological flavors of programming. +At a recent stint at the keyboard I experienced another one: pattern copying. +I was writing a little Ruby script that pulled some data out of a database. +As I did this I started on a class to wrap the database table and thought to myself that since I'd just finished off a book of database patterns I should use a pattern. +Although the sample code was Java, it wasn't difficult to adapt it to Ruby. +While I programmed it I didn't really think about the problem, I just thought about making a fair adaptation of the pattern to the language and specific data I was manipulating. +Pattern copying on its own isn't good programming—a fact I always stress when talking about patterns. +Patterns are always half baked, and need to be adapted in the oven of your own project. +But a good way to do this is to first copy the pattern fairly blindly, and then use some mix of refactoring or test-first, to perform the adaptation. +That way when you're doing the pattern-copying, you can concentrate on just the pattern—one thing at a time. +The XP community has struggled with where patterns fit into the picture. +Clearly the XP community is in favor of patterns, after all there is huge intersection between XP advocates and patterns advocates — Ward and Kent were leaders in both. +Perhaps pattern copying is a third monological mode to go with test-first and refactoring, and like those two is dangerous on its own but powerful in concert.</p> +<p class="attribution">—Martin Fowler, Afterword, "Test-Driven Development By Example" <a class="footnote-reference brackets" href="#fntdd" id="id30" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>, перевод П. Анджан</p> </div></blockquote> -<p>Т.е. он отсылает к <a class="reference external" href="http://wiki.c2.com/?CouplingAndCohesion">Constantine's Law</a>.</p> -<p>Этот принцип не имеет отношения к OOP, хотя и активно используется в OOP, в частности, в книгах:</p> +<blockquote> +<div><p>Patterns and XP</p> +<p>The JUnit example leads me inevitably into bringing up patterns. The relationship between patterns and XP is interesting, and it's a common question. Joshua Kerievsky argues that patterns are under-emphasized in XP and he makes the argument eloquently, so I don't want to repeat that. But it's worth bearing in mind that for many people patterns seem in conflict to XP.</p> +<p>The essence of this argument is that patterns are often over-used. The world is full of the legendary programmer, fresh off his first reading of GOF who includes sixteen patterns in 32 lines of code. I remember one evening, fueled by a very nice single malt, running through with Kent a paper to be called "Not Design Patterns: 23 cheap tricks" We were thinking of such things as use an if statement rather than a strategy. The joke had a point, patterns are often overused, but that doesn't make them a bad idea. The question is how you use them.</p> +<p>One theory of this is that the forces of simple design will lead you into the patterns. Many refactorings do this explicitly, but even without them by following the rules of simple design you will come up with the patterns even if you don't know them already. This may be true, but is it really the best way of doing it? Surely it's better if you know roughly where you're going and have a book that can help you through the issues instead of having to invent it all yourself. I certainly still reach for GOF whenever I feel a pattern coming on. For me effective design argues that we need to know the price of a pattern is worth paying - that's its own skill. Similarly, as Joshua suggests, we need to be more familiar about how to ease into a pattern gradually. In this regard XP treats the way we use patterns differently to the way some people use them, but certainly doesn't remove their value.</p> +<p>But reading some of the mailing lists I get the distinct sense that many people see XP as discouraging patterns, despite the irony that most of the proponents of XP were leaders of the patterns movement too. Is this because they have seen beyond patterns, or because patterns are so embedded in their thinking that they no longer realize it? I don't know the answers for others, but for me patterns are still vitally important. XP may be a process for development, but patterns are a backbone of design knowledge, knowledge that is valuable whatever your process may be. Different processes may use patterns in different ways. XP emphasizes both not using a pattern until it's needed and evolving your way into a pattern via a simple implementation. But patterns are still a key piece of knowledge to acquire.</p> +<p>My advice to XPers using patterns would be</p> <ul class="simple"> -<li><p>"Code Complete" by Steve McConnell</p></li> -<li><p>"Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development" by Craig Larman, где этот принцип известен под аббревиатурой GRASP</p></li> +<li><p>Invest time in learning about patterns</p></li> +<li><p>Concentrate on when to apply the pattern (not too early)</p></li> +<li><p>Concentrate on how to implement the pattern in its simplest form first, then add complexity later.</p></li> +<li><p>If you put a pattern in, and later realize that it isn't pulling its weight - don't be afraid to take it out again.</p></li> </ul> -<p>И этот принцип является одним из самых фундаментальных в разработке ПО. -Он применяется в структурном программировании, в OOP, в DDD при моделировании агрегатов, в микросервисах при поиске границ микросервисов и т.д.</p> -<p>А Kent Beck назвал его в одной из своих недавних статей</p> -<blockquote> -<div><p>📝 "the basic forces acting on software design. -These were elucidated in the mid-70s by Yourdon &amp; Constantine in <a class="reference external" href="https://amzn.to/2GsuXvQ">Structured Design</a> and haven't changed."</p> -<p class="attribution">—"<a class="reference external" href="https://medium.com/@kentbeck_7670/monolith-services-theory-practice-617e4546a879">Monolith -&gt; Services: Theory &amp; Practice</a>" by Kent Beck</p> +<p>I think XP should emphasize learning about patterns more. I'm not sure how I would fit that into XP's practices, but I'm sure Kent can come up with a way.</p> +<p class="attribution">—"<a class="reference external" href="https://martinfowler.com/articles/designDead.html#PatternsAndXp">Is Design Dead?</a>" by Martin Fowler</p> </div></blockquote> -<p>Каким бы образом это ни сделал Robert C. Martin, но он достиг поставленной цели - привлек массовое внимание к архитектурным принципам, имеющим действительно важное значение в Agile разработке.</p> +<p>Смотрите так же:</p> +<ul class="simple"> +<li><p>XP and Patterns Ralph Johnson's View: <a class="reference external" href="http://objectclub.jp/community/XP-jp/xp_relate/xp_patterns">http://objectclub.jp/community/XP-jp/xp_relate/xp_patterns</a></p></li> +<li><p>Joshua Kerievsky, Patterns &amp; XP: <a class="reference external" href="http://www.industriallogic.com/xp/PatternsAndXP.pdf">http://www.industriallogic.com/xp/PatternsAndXP.pdf</a></p></li> +</ul> </section> +<section id="one-assertion-per-test"> +<h2><a class="toc-backref" href="#id42" role="doc-backlink">One assertion per test?</a></h2> +<p>Я часто слышу это распространенное убеждение, что один тестовый метод должен содержать только одно утверждение (assertion) и не больше. +И это интересно, потому что Кент Бек этому правилу не очень-то и следует, что заставило меня найти первоисточник этого убеждения. +Источник я нашел, и он, действительно, авторитетный - это "xUnit Test Patterns. Refactoring Test Code." by Gerard Meszaros, глава "Principle: Verify One Condition per Test", но там есть кое-что еще, о чем это широко распространенное убеждение умалчивает:</p> +<blockquote> +<div><p>One possibly contentious aspect of "Verify One Condition per Test" is what we mean by "one condition." +Some test drivers insist on one assertion per test. +This insistence may be based on using a "Testcase Class per Fixture" organization +of the "Test Methods" and naming each test based on what the one assertion is verifying. +(For example, AwaitingApprovalFlight.validApproverRequestShouldBeApproved.) +Having one assertion per test makes such naming very easy but also leads to many more test methods if we have to assert on many output fi elds. +Of course, we can often comply with this interpretation by extracting a "Custom Assertion" (page 474) +or "Verification Method" (see "Custom Assertion") that allows us to reduce the multiple assertion method calls to a single call. +Sometimes that approach makes the test more readable. +When it doesn't, I wouldn't be too dogmatic about insisting on a single assertion.</p> +<p class="attribution">—"xUnit Test Patterns. Refactoring Test Code." by Gerard Meszaros</p> +</div></blockquote> +<p>Эту же тему рассматривает и Robert C. Martin в главе "Chapter 9: Unit Tests :: One Assert per Test" книги "Clean Code: A Handbook of Agile Software Craftsmanship":</p> +<blockquote> +<div><p>Я думаю, что правило "одного assert" является хорошей рекомендацией. +Обычно я стараюсь создать предметно-ориентированный язык тестирования, который это правило поддерживает, как в листинге 9.5. +Но при этом я не боюсь включать в свои тесты более одной директивы assert. +Вероятно, лучше всего сказать, что количество директив assert в тесте должно быть сведено к минимуму.</p> +<p>I think the single assert rule is a good guideline. +I usually try to create a domainspecific testing language that supports it, as in Listing 9-5. +But I am not afraid to put more than one assert in a test. +I think the best thing we can say is that the number of asserts in a test ought to be minimized.</p> +<p class="attribution">—"Clean Code: A Handbook of Agile Software Craftsmanship" <a class="footnote-reference brackets" href="#fnccode" id="id31" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a> by Robert C. Martin, перевод Е. Матвеев</p> +</div></blockquote> +<p>Здесь он отсылает к статье "<a class="reference external" href="https://www.artima.com/weblogs/viewpost.jsp?thread=35578">One Assertion Per Test</a>" by Dave Astels в качестве первоисточника.</p> +<p class="rubric">Footnotes</p> +<aside class="footnote-list brackets"> +<aside class="footnote brackets" id="fntdd" role="note"> +<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id3">1</a>,<a role="doc-backlink" href="#id4">2</a>,<a role="doc-backlink" href="#id5">3</a>,<a role="doc-backlink" href="#id6">4</a>,<a role="doc-backlink" href="#id7">5</a>,<a role="doc-backlink" href="#id10">6</a>,<a role="doc-backlink" href="#id12">7</a>,<a role="doc-backlink" href="#id13">8</a>,<a role="doc-backlink" href="#id15">9</a>,<a role="doc-backlink" href="#id16">10</a>,<a role="doc-backlink" href="#id17">11</a>,<a role="doc-backlink" href="#id18">12</a>,<a role="doc-backlink" href="#id19">13</a>,<a role="doc-backlink" href="#id20">14</a>,<a role="doc-backlink" href="#id24">15</a>,<a role="doc-backlink" href="#id26">16</a>,<a role="doc-backlink" href="#id27">17</a>,<a role="doc-backlink" href="#id29">18</a>,<a role="doc-backlink" href="#id30">19</a>)</span> +<p>"Test-Driven Development By Example" by Kent Beck</p> +</aside> +<aside class="footnote brackets" id="fnccoder" role="note"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id23">2</a><span class="fn-bracket">]</span></span> +<p>"The Clean Coder: a code of conduct for professional programmers" by Robert C. Martin</p> +</aside> +<aside class="footnote brackets" id="fnccode" role="note"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id31">3</a><span class="fn-bracket">]</span></span> +<p>"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p> +</aside> +<aside class="footnote brackets" id="fncarch" role="note"> +<span class="label"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id22">1</a>,<a role="doc-backlink" href="#id28">2</a>)</span> +<p>"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +</aside> +<aside class="footnote brackets" id="fnrefactoring" role="note"> +<span class="label"><span class="fn-bracket">[</span>5<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id9">1</a>,<a role="doc-backlink" href="#id11">2</a>,<a role="doc-backlink" href="#id14">3</a>)</span> +<p>"Refactoring: Improving the Design of Existing Code" by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p> +</aside> +</aside> </section> -<section id="no-silver-bullet"> -<h2><a class="toc-backref" href="#id18" role="doc-backlink">No Silver Bullet</a></h2> -<p>Но правда и в том, что <a class="reference external" href="https://en.m.wikipedia.org/wiki/No_Silver_Bullet">серебряной пули нет</a>. -Нет магических пяти букв, которые волшебным образом сделают код экономически высокоэффективным, особенно, если про них узнали не из первоисточника, а из Википедии. -Зайдите на github, и вы увидите огромное многообразие взаимно-противоречивых демонстрационных приложений (reference applications), и каждое из них претендует на роль самой эталонной реализации Clean Architecture (это уже не совсем SOLID, но из этой же области). -Кто в лес, кто по дрова. -И только работы парней, обладающих <a class="reference external" href="http://www.kamilgrzybek.com/programming-and-design-resources/">широким архитектурным кругозором и литературным бэкграундом</a>, таких, как <a class="reference external" href="https://github.com/kgrzybek">Kamil Grzybek</a>, могут претендовать на роль эталонной реализации:</p> +Thu, 21 Jul 2022 00:00:00 Role of SOLID principles in Agilehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/solid.html +<span id="emacsway-agile-solid"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> <ul class="simple"> -<li><p><a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd">Full Modular Monolith application with Domain-Driven Design approach</a> by Kamil Grzybek</p></li> -<li><p><a class="reference external" href="https://github.com/kgrzybek/sample-dotnet-core-cqrs-api">Sample .NET Core REST API CQRS implementation with raw SQL and DDD using Clean Architecture</a> by Kamil Grzybek</p></li> +<li><p><a class="reference internal" href="#role-of-solid-principles-in-agile" id="id5">Role of SOLID principles in Agile</a></p> +<ul> +<li><p><a class="reference internal" href="#srp" id="id6">Ошибочная трактовка SRP</a></p> +<ul> +<li><p><a class="reference internal" href="#srp-is-not-to-do-just-one-thing" id="id7">SRP is not to do just one thing</a></p></li> +<li><p><a class="reference internal" href="#srp-is-about-cohesion" id="id8">SRP is about Cohesion</a></p></li> +<li><p><a class="reference internal" href="#srp-and-conway-s-law" id="id9">SRP and "Conway's law"</a></p></li> +<li><p><a class="reference internal" href="#common-closure-principle-ccp" id="id10">Common Closure Principle (CCP)</a></p></li> +<li><p><a class="reference internal" href="#srp-and-complexity" id="id11">SRP and complexity</a></p></li> </ul> -<p>В таком случае, SOLID уже не мешает создавать экономически высокоэффективные приложения (<a class="reference external" href="http://www.kamilgrzybek.com/design/clean-domain-model-attributes/">раз</a> и <a class="reference external" href="http://www.kamilgrzybek.com/design/grasp-explained/">два</a>).</p> -<p>Еще одно, наверное, самое популярное reference application - <a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers">eShopOnContainers</a>, было разработано при значительном участии известного авторитета в области архитектуры Cesar De La Torre, который в своем <a class="reference external" href="https://devblogs.microsoft.com/cesardelatorre/free-ebookguide-on-net-microservices-architecture-for-containerized-net-applications/">блог-посте</a> пишет:</p> +</li> +<li><p><a class="reference internal" href="#ad-hominem" id="id12">Ad hominem</a></p></li> +<li><p><a class="reference internal" href="#solid-and-agile" id="id13">SOLID and Agile</a></p></li> +<li><p><a class="reference internal" href="#id2" id="id14">Баланс краткосрочных и долгосрочных интересов</a></p></li> +<li><p><a class="reference internal" href="#solid" id="id15">SOLID и первоисточники</a></p> +<ul> +<li><p><a class="reference internal" href="#ocp" id="id16">OCP</a></p></li> +<li><p><a class="reference internal" href="#id3" id="id17">SRP</a></p></li> +</ul> +</li> +<li><p><a class="reference internal" href="#no-silver-bullet" id="id18">No Silver Bullet</a></p></li> +<li><p><a class="reference internal" href="#id4" id="id19">Последние определения от 2022-07-06</a></p></li> +</ul> +</li> +</ul> +</nav> +<section id="srp"> +<span id="emacsway-agile-solid-misunderstanding"/><h2><a class="toc-backref" href="#id6" role="doc-backlink">Ошибочная трактовка SRP</a></h2> +<section id="srp-is-not-to-do-just-one-thing"> +<h3><a class="toc-backref" href="#id7" role="doc-backlink">SRP is not to do just one thing</a></h3> +<p>Существуют две распространенные ошибки применения принципа SRP:</p> +<ol class="arabic simple"> +<li><p>SRP якобы подразумевает делать только одну вещь.</p></li> +<li><p>SRP якобы применяется к компонентам, например, к микросервисам.</p></li> +</ol> +<p>Давайте немного исследуем этот вопрос.</p> +<p>В своей книге "Clean Architecture: A Craftsman's Guide to Software Structure and Design", Robert C. Martin сожалеет о том, что выбрал такое название - SRP:</p> +<blockquote> +<div><p>📝 "Of all the SOLID principles, the Single Responsibility Principle (SRP) might be <strong>the least well understood</strong>. +That's likely because it has a particularly <strong>inappropriate name</strong>. +It is too easy for programmers <strong>to hear the name and then assume that it means that every module should do just one thing</strong>.</p> +<p>Make no mistake, there is a principle like that. +A function should do one, and only one, thing. +We use that principle when we are refactoring large functions into smaller functions; we use it at the lowest levels. +<strong>But it is not one of the SOLID principles—it is not the SRP</strong>.</p> +<p>Historically, the SRP has been described this way:</p> <blockquote> -<div><p>"Using SOLID principles and Dependency Injection"</p> +<div><p><em>A module should have one, and only one, reason to change.</em></p> </div></blockquote> -<p>Речь идет об <a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/microservice-application-layer-web-api-design">этом месте гайда</a>.</p> -<p>В качестве итога можно привести слова самого Robert C. Martin:</p> +<p>Software systems are changed to satisfy users and stakeholders; those users and stakeholders are the "reason to change" that the principle is talking about. +Indeed, we can rephrase the principle to say this:</p> <blockquote> -<div><p>📝 "<strong>Following the rules on the paint can won't teach you how to paint.</strong> -This is an important point. -Principles will not turn a bad programmer into a good programmer. -Principles have to be applied with judgement. -If they are applied by rote it is just as bad as if they are not applied at all. -Having said that, if you want to paint well, I suggest you learn the rules on the paint can. -You may not agree with them all. -You may not always apply the ones you do agree with. -But you'd better know them. -Knowledge of the principles and patterns gives you the justification to decide when and where to apply them. -If you don't know them, your decisions are much more arbitrary."</p> -<p class="attribution">—"<a class="reference external" href="https://sites.google.com/site/unclebobconsultingllc/getting-a-solid-start">Getting a SOLID start.</a>" by Robert C. Martin</p> +<div><p><em>A module should be responsible to one, and only one, user or stakeholder.</em></p> </div></blockquote> -<p>См. также:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://sites.google.com/site/unclebobconsultingllc/getting-a-solid-start">Getting a SOLID start</a>"</p></li> -<li><p>"<a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html">The Single Responsibility Principle</a>"</p></li> -<li><p>"<a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html">The Open Closed Principle</a>"</p></li> -<li><p>"<a class="reference external" href="http://blog.cleancoder.com/uncle-bob/2020/10/18/Solid-Relevance.html">Solid Relevance</a>"</p></li> -</ul> -</section> -<section id="id4"> -<h2><a class="toc-backref" href="#id19" role="doc-backlink">Последние определения от 2022-07-06</a></h2> +<p>Unfortunately, the words "user" and "stakeholder" aren't really the right words to use here. +There will likely be more than one user or stakeholder who wants the system changed in the same way. +Instead, we're really referring to a group—one or more people who require that change. +We'll refer to that group as an actor.</p> +<p>Thus the final version of the SRP is:</p> <blockquote> -<div><p>💬 "The Single Responsibility Principle (SRP):</p> -<p>Gather together those things that change for the same reasons and at the same times. Separate those things that change for different reasons or at different times."</p> -<p class="attribution">—<a class="reference external" href="https://twitter.com/unclebobmartin/status/1544652844825038850?t=KWWq9TQ9XN3w9VksSRieSA&amp;s=19">Источник</a></p> +<div><p><em>A module should be responsible to one, and only one, actor.</em></p> </div></blockquote> -<blockquote> -<div><p>💬 "The Open-Closed Principle (OCP):</p> -<p>Separate modules that frequently change from modules that change less frequently with a layer of abstraction."</p> -<p class="attribution">—<a class="reference external" href="https://twitter.com/unclebobmartin/status/1544653655047118851?t=r4bY25YMWeHpAtEDtLsVdg&amp;s=19">Источник</a></p> +<p>Now, what do we mean by the word "module"? The simplest definition is just a source file. +Most of the time that definition works fine. +Some languages and development environments, though, don't use source files to contain their code. +In those cases a module is just a cohesive set of functions and data structures.</p> +<p>That word "cohesive" implies the SRP. +Cohesion is the force that binds together the code responsible to a single actor.</p> +<p>Perhaps the best way to understand this principle is by looking at the symptoms of violating it..."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> </div></blockquote> +<p>Впрочем, с пониманием OCP дела обстоят ненамного лучше:</p> <blockquote> -<div><p>💬 "The Liskov Substitution Principle (LSP):</p> -<p>The implementation of an interface must never violate the contract between that interface and its users."</p> -<p class="attribution">—<a class="reference external" href="https://twitter.com/unclebobmartin/status/1544654145839316996?t=jsDVCEvXBlwM82JwXugdMw&amp;s=19">Источник</a></p> +<div><p>📝 "I've heard it said that the OCP is wrong, unworkable, impractical, and not for real programmers with real work to do. +The rise of plugin architectures makes it plain that these views are utter nonsense. +On the contrary, a strong plugin architecture is likely to be the most important aspect of future software systems."</p> +<p class="attribution">—"<a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html">The Open Closed Principle</a>" by Robert C. Martin</p> </div></blockquote> +</section> +<section id="srp-is-about-cohesion"> +<h3><a class="toc-backref" href="#id8" role="doc-backlink">SRP is about Cohesion</a></h3> +<p>А в своей книге 2002 года, которая вышла в свет через год после подписания Agile Manifesto (им же и организованного), Robert C. Martin выводит определение SRP из понятия "сфокусированности" (cohesion) класса:</p> <blockquote> -<div><p>💬 "The Interface Segregation Principle (ISP):</p> -<p>Don't depend on things you don’t need."</p> -<p class="attribution">—<a class="reference external" href="https://twitter.com/unclebobmartin/status/1544654493677240324?t=uGpjX6exnonCpwh5VO6WXQ&amp;s=19">Источник</a></p> +<div><p>📝 "SRP: The Single-Responsibility Principle</p> +<p><strong>This principle was described in the work of Tom DeMarco [1] and Meilir Page-Jones [2].</strong> +<strong>They called it cohesion.</strong> +They defined cohesion as the functional relatedness of the elements of a module. +In this chapter we'll shift that meaning a bit and relate cohesion to the forces that cause a module, or a class, to change.</p> +<p>A class should have only one reason to change.</p> +<ol class="arabic simple"> +<li><p>[DeMarco79], p. 310.</p></li> +<li><p>[Page-Jones88], Chapter 6, p. 82.</p></li> +</ol> +<ol class="arabic simple"> +<li><p>DeMarco, Tom. Structured Analysis and System Specification. Yourdon Press Computing Series. Englewood Cliff, NJ: 1979.</p></li> +<li><p>Page-Jones, Meilir. The Practical Guide to Structured Systems Design, 2d ed. Englewood Cliff, NJ: Yourdon Press Computing Series, 1988."</p></li> +</ol> +<p class="attribution">—"Agile Software Development. Principles, Patterns, and Practices." by Robert C. Martin, James W. Newkirk, Robert S. Koss</p> </div></blockquote> +<p>Многое встает на свое место, если принимать во внимание Cohesion, т.е. использовать изначальный принцип "<a class="reference external" href="http://wiki.c2.com/?CouplingAndCohesion">Low Coupling &amp; High Cohesion</a>".</p> +<p>Часто можно слышать, что применение принципов SOLID ведет к появлению нечитаемого кода. +Очень хорошо подобную проблему (правда, возникающую по другим причинам) выразил Eric Evans:</p> <blockquote> -<div><p>💬 "The Dependency Inversion Principle (DIP):</p> -<p>Lower level policies should depend on higher level policies."</p> -<p class="attribution">—<a class="reference external" href="https://twitter.com/unclebobmartin/status/1544655000525225985?t=gEoCa1rfs4i05snSJDZXqg&amp;s=19">Источник</a></p> +<div><p>📝 "Если требования архитектурной среды к распределению обязанностей таковы, что элементы, реализующие концептуальные объекты, оказываются физически разделенными, то код больше не выражает модель.</p> +<p>Нельзя разделять до бесконечности, у человеческого ума есть свои пределы, до которых он еще способен соединять разделенное; если среда выходит за эти пределы, разработчики предметной области теряют способность расчленять модель на осмысленные фрагменты.</p> +<p>If the framework's partitioning conventions pull apart the elements implementing the conceptual objects, the code no longer reveals the model.</p> +<p>There is only so much partitioning a mind can stitch back together, and if the framework uses it all up, the domain developers lose their ability to chunk the model into meaningful pieces."</p> +<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, перевод В.Л. Бродового</p> </div></blockquote> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> +<p>О том, что использованием принципов SOLID можно переусложнить программу, пишет и весьма авторитетный в области программной разработки Сергей Тепляков:</p> <ul class="simple"> -<li><p>"<a class="reference internal" href="../crash-course-in-software-development-economics.html"><span class="doc">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> -<li><p>"<a class="reference internal" href="../software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>"</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>"</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2013/12/about-agile-principles-patterns-and.html">Критика книги Боба Мартина "Принципы, паттерны и методики гибкой разработки на языке C#"</a>"</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2011/11/blog-post_23.html">Идеальная архитектура</a>"</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2014/10/solid.html">Шпаргалка по SOLID принципам</a>"</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2014/10/about-design-principles.html">О принципах проектирования</a>"</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2012/07/blog-post.html">О дизайне</a>"</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2012/04/blog-post_19.html">О повторном использовании кода</a>"</p></li> </ul> -</div> -</section> -Fri, 15 Jul 2022 00:00:00 Systems Development Life Cycle (SDLC) Referencehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/sdlc-reference.html -<span id="emacsway-sdlc-literature"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<p>Grady Booch выделяет два ключевых критерия, которые определяют успех или неудачу проекта:</p> +<p>Лично мне на практике не доводилось наблюдать сложности от использования принципов SOLID, разве что только в проектах с использованием Redux. +Кстати, у Udi Dahan есть прекрасная статья "<a class="reference external" href="http://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>" о том, как грамотно разделять бизнес-логику и логику приложения в CQRS-приложении (а <a class="reference external" href="https://redux.js.org/understanding/thinking-in-redux/motivation">Redux реализует принципы CQRS</a>), чтобы предотвратить фрагментирование бизнес-логики.</p> +<p>Я обнаружил еще одну причину столь широкого недопонимания этого принципа. +В переводе книги "Clean Code" термин "Single" переводится как "Единый". +А в книге "Clean Architecture" - как "Единственный".</p> +<p>Эти термины похожи, но не идентичны. +Так, например, "Единое гражданство" означает то, что административно-территориальные единицы государства не могут вводить свое собственное гражданство. +Но при этом, граждане могут иметь двойное гражданство. +А вот "Единственное гражданство" уже подразумевает запрет на двойное гражданство.</p> +<p>Таким образом, термин "Единый" подразумевает "Сфокусированный" на конкретной задаче, т.е. нефрагментированный. +Иными словами, речь идет о "High Cohesion", что восходит к Constantine's Law - "Low Coupling &amp; High Cohesion", о чем прямо говорит Robert C. Martin по приведенным выше ссылкам.</p> <blockquote> -<div><p>📝 "Traits of Successful Projects</p> -<p>A successful software project is one in which the deliverables satisfy and possibly exceed the customer's expectations, the development occurred in a timely and economical fashion, and the result is resilient to change and adaptation. By this measure, we have observed several traits that are common to virtually all of the successful object-oriented systems we have encountered and noticeably absent from the ones that we count as failures:</p> -<ul class="simple"> -<li><p>Existence of a strong architectural vision</p></li> -<li><p>Application of a well-managed iterative and incremental development lifecycle"</p></li> -</ul> -<p class="attribution">—"Object-Oriented Analysis and Design with Applications" 3rd edition by Grady Booch, Robert A. Maksimchuk, Michael W. Engle, Bobbi J. Young Ph.D., Jim Conallen, Kelli A. Houston</p> +<div><p>📝 "<strong>That word "cohesive" implies the SRP.</strong> +Cohesion is the force that binds together the code responsible to a single actor."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> </div></blockquote> -<p>Если с "architectural vision" все понятно, то с "well-managed development lifecycle" у многих могут возникать вопросы. Тем не менее, для успешности проекта процессы должны быть грамотно выбраны и качественно отлажены.</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://book4cio.ru/#page-14">Учебник 4CIO</a>" - глава 3.4. Управление разработкой ПО</p></li> -<li><p>"<a class="reference external" href="https://www.sebokwiki.org/wiki/Life_Cycle_Models">SEBoK: Life Cycle Models</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.sebokwiki.org/wiki/System_Life_Cycle_Process_Models:_Iterative">SEBoK: System Life Cycle Process Models: Iterative</a>"</p></li> -<li><p>"<a class="reference external" href="https://mellarius.ru/processes">Процессы</a>" at mellarius.ru - превосходный минималистичный и самодостаточный справочник.</p></li> -<li><p>Неплохой "<a class="reference external" href="https://www.tutorialspoint.com/sdlc/index.htm">SDLC Tutorial</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.tutorialspoint.com/sdlc/sdlc_quick_guide.htm">SDLC - Quick Guide</a>"</p></li> -<li><p>"<a class="reference external" href="https://itabok.iasaglobal.org/itabok3_0/architecture-methodologies-and-frameworks/">ITABoK: Architecture Methodologies and Frameworks</a>"</p></li> -<li><p>"<a class="reference external" href="https://itabok.iasaglobal.org/itabok3_0/digital-outcome-model/agility/">ITABoK: What is Agility</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.incose.org/products-and-publications/se-handbook">Systems engineering handbook. A guide for System Life Cycle Processes and activities</a>" by INCOSE</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/foundational/pmbok">The Project Management Body of Knowledge (PMBoK)</a>" by Project Management Institute (PMI)</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute (PMI), 2017</p></li> -<li><p>"<a class="reference external" href="https://www.iiba.org/career-resources/business-analysis-resources/iiba-bookstore/">Agile Extension to the BABOK® Guide</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/22-cpre-advanced-level-re-agile-handbook/handbook_cpre_al_re%40agile_en_v1.0.2.pdf">Handbook of RE@Agile According to the IREB Standard Education and Training for IREB Certified Professional for Requirements Engineering Advanced Level RE@Agile</a>" Version 1.0.2</p></li> -<li><p>"<a class="reference external" href="https://www.iso.org/standard/63712.html">ISO/IEC/IEEE 12207:2017 Systems and software engineering — Software life cycle processes</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.iso.org/standard/63711.html">ISO/IEC/IEEE 15288:2015 Systems and software engineering — System life cycle processes</a>"</p></li> -<li><p>"ISO/IEC/IEEE 29148:2018 Systems and software engineering — Life cycle processes — Requirements engineering"</p></li> -<li><p>"ISO/IEC/IEEE 15289:2019 Systems and software engineering — Content of life-cycle information items (documentation)"</p></li> -<li><p>"ISO/IEC/IEEE 24765:2017 Systems and software engineering — Vocabulary"</p></li> -<li><p>"ISO 9000:2005 Quality management systems — Fundamentals and vocabulary"</p></li> -<li><p>"ISO/IEC 33001:2015 Information technology — Process assessment — Concepts and terminology"</p></li> -<li><p>"ГОСТ Р ИСО/МЭК 12207-2010 Информационная технология. Системная и программная инженерия. Процессы жизненного цикла программных средств."</p></li> -<li><p>"ГОСТ Р 57193-2016 Системная и программная инженерия. Процессы жизненного цикла систем."</p></li> -<li><p>"Object-Oriented Analysis and Design with Applications" 3rd edition by Grady Booch, Robert A. Maksimchuk, Michael W. Engle, Bobbi J. Young Ph.D., Jim Conallen, Kelli A. Houston - "Chapter 6. Process"</p></li> -<li><p>"Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman - "Chapter 15. Architecture in agile projects"</p></li> -<li><p>"Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman</p></li> -<li><p>"<a class="reference external" href="https://www.amazon.com/Balancing-Agility-Discipline-Guide-Perplexed/dp/0321186125">Balancing Agility and Discipline: A Guide for the Perplexed</a>" by Barry Boehm, Richard Turner</p></li> -<li><p>"Extreme Programming Explained" 1st edition by Kent Beck (именно первое издание) - кто этой книги не читал, тот ничего в Agile не понимает.</p></li> -</ul> -<p>Три превосходные книги Dean Leffingwell:</p> -<ul class="simple"> -<li><p>"Scaling Software Agility: Best Practices for Large Enterprises" by Dean Leffingwell - о проблемах масштабирования команд.</p></li> -<li><p>"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell - о проблемах интегрирования аналитической и архитектурной работы в Agile.</p></li> -<li><p>"SAFe® 5.0: The World's Leading Framework for Business Agility" by Richard Knaster, Dean Leffingwell - наиболее удачная масштабируемая Agile-модель на сегодня.</p></li> -</ul> -<ul class="simple"> -<li><p>"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin - главы 3 и 8 просто необходимы для понимания области применения Scrum. -Очень хорошо в этой книге рассматриваются экономические аспекты разработки - выбор <a class="reference internal" href="uncertainty-management/balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">Pediction vs. Adaptation</span></a>, влияние <a class="reference internal" href="models/agile/agile.html#emacsway-agile-development-essence"><span class="std std-ref">характера роста стоимости изменения кода (Modifiability)</span></a> на экономическую целесообразность Agile.</p></li> -</ul> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.craiglarman.com/wiki/downloads/misc/history-of-iterative-larman-and-basili-ieee-computer.pdf">Краткая история итеративной разработки</a>" by Craig Larman</p></li> -<li><p>"<a class="reference external" href="https://less.works/less/framework/introduction">LeSS by Craig Larman</a>" - куча полезной информации, которую можно использовать автономно. (<a class="reference external" href="https://less.works/ru/less/framework/introduction">на русском</a>)</p></li> -</ul> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile">Disciplined Agile®</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/">SAFe - Scaled Agile Framework</a>"</p></li> -</ul> -<p>Нужно заметить, что Software является подмножеством System. -Раньше и Software, и System описывались одним стандартом ISO/IEC 12207:2008. -Потом их разделили на ISO/IEC/IEEE 12207:2017 и ISO/IEC/IEEE 15288:2015.</p> +<p>Так, например, метод рефакторинга "<a class="reference external" href="https://refactoring.com/catalog/inlineClass.html">Inline Class</a>" не противоречит SRP, хотя класс и отбирает обязанность у другого класса в случае, когда её недостаточно для самостоятельного существования.</p> +<p>С другой стороны, если фрагментировать класс, понижая его Cohesion, то это будет противоречить принципу SRP, хотя мы и получим многочисленные классы с дистиллированными кусочками обязанностей без примесей.</p> +<p>Качественный Software Design должен облегчать понимание кода, а не затруднять.</p> +<p>К сожалению, сложности перевода встречаются нередко. +Так, например, до сих пор нет единого мнения о том, как правильно переводить термины "Coupling" и "Cohesion", и различные источники дают прямо противоположный перевод.</p> +</section> +<section id="srp-and-conway-s-law"> +<h3><a class="toc-backref" href="#id9" role="doc-backlink">SRP and "Conway's law"</a></h3> +<p>А здесь Robert C. Martin выводит понимание SRP исходя из "Conway's law":</p> <blockquote> -<div><p>📝 "This document has a strong relationship with ISO/IEC/IEEE 15288:2015, Systems and Software Engineering System Life Cycle Processes, and is more applicable to software systems. -To account for situations in which both ISO/IEC/IEEE 15288:2015 and ISO/IEC/IEEE 12207:2017 are applied (e.g., a development of a system containing software, or the development of a software system containing hardware), their process structures are harmonized to be identical. -The processes of this document directly correspond to processes of ISO/IEC/IEEE 15288 with specialization for software products and services."</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> +<div><p>📝 "SRP: The Single Responsibility Principle</p> +<p>An active <strong>corollary to Conway's law</strong>: The best structure for a software system is heavily influenced by the social structure of the organization that uses it so that each software module has one, and only one, reason to change."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> </div></blockquote> -Wed, 13 Jul 2022 00:00:00 Code Reviewhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/agile/practices/collaborative-development/code-review.html -<span id="emacsway-agile-practices-code-review"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> -<ul class="simple"> -<li><p><a class="reference internal" href="#code-review" id="id4">Code Review</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id5">Возможные результаты Code Review</a></p></li> -<li><p><a class="reference internal" href="#apaptation-vs-prediction" id="id6">Apaptation vs Prediction</a></p></li> -<li><p><a class="reference internal" href="#continuous-review" id="id7">Continuous Review</a></p></li> -</ul> -</li> -</ul> -</nav> -<p>Является ли Code Review эффективной практикой?</p> -<section id="id2"> -<h2><a class="toc-backref" href="#id5" role="doc-backlink">Возможные результаты Code Review</a></h2> -<p>Давайте посмотрим, какие исходы обычно возникают в результате Code Review:</p> -<ol class="arabic"> -<li><p>Когда новый инкремент <a class="reference internal" href="../../../../../../soft-skills/knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">знаний</span></a> получен, тогда возникает:</p> +</section> +<section id="common-closure-principle-ccp"> +<h3><a class="toc-backref" href="#id10" role="doc-backlink">Common Closure Principle (CCP)</a></h3> +<p>К компонентам применяется похожий, но другой, принцип, который называется "Common Closure Principle (CCP)":</p> +<blockquote> +<div><p>📝 "THE COMMON CLOSURE PRINCIPLE</p> +<p>Gather into components those classes that change for the same reasons and at the same times. +Separate into different components those classes that change at different times and for different reasons.</p> +<p>This is the Single Responsibility Principle restated for components. +Just as the SRP says that a class should not contain multiples reasons to change, so the Common Closure Principle (CCP) says that a component should not have multiple reasons to change.</p> +<p>For most applications, maintainability is more important than reusability. +If the code in an application must change, you would rather that all of the changes occur in one component, rather than being distributed across many components. [1] +If changes are confined to a single component, then we need to redeploy only the one changed component. +Other components that don't depend on the changed component do not need to be revalidated or redeployed.</p> +<p>The CCP prompts us to gather together in one place all the classes that are likely to change for the same reasons. +If two classes are so tightly bound, either physically or conceptually, that they always change together, then they belong in the same component. +This minimizes the workload related to releasing, revalidating, and redeploying the software.</p> +<p>This principle is closely associated with the Open Closed Principle (OCP). +Indeed, it is "closure" in the OCP sense of the word that the CCP addresses. +The OCP states that classes should be closed for modification but open for extension. +Because 100% closure is not attainable, closure must be strategic. +We design our classes such that they are closed to the most common kinds of changes that we expect or have experienced.</p> +<p>The CCP amplifies this lesson by gathering together into the same component those classes that are closed to the same types of changes. +Thus, when a change in requirements comes along, that change has a good chance of being restricted to a minimal number of components."</p> <ol class="arabic simple"> -<li><p>Конесенсус (обоюдное согласие на едином решении), который формируется, как правило, новым инкрементом знаний, полученным в процессе обсуждения Pull Request.</p></li> -<li><p><a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологическая защита</a>. Чувство ущербности на фоне грамотного спикера вынуждает специалиста защищать свою зону комфорта и социальное положение путем агрессивных попыток дискредитации носителя неудобных компетенций. Увы, подобные случаи происходили даже в практике достаточно известных авторов по архитектуре. Иными словами, мало знать, нужно уметь еще донести.</p></li> +<li><p>See the section on "The Kitty Problem" in Chapter 27, "Services: Great and Small."</p></li> </ol> -</li> -<li><p>Если знание по своему определению непротиворечиво и способно привести к обоюдному согласию (пусть и не всегда), то недостаток знаний (для качественной аргументации позиции) приводит к соперничеству <a class="reference internal" href="../../../../../../soft-skills/knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">мнений</span></a> за лидерство.</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +</div></blockquote> +<p>Нужно учитывать, что под компонентом Robert C. Martin понимает единицу развертывания (в других источниках этот термин может иметь другое значение):</p> <blockquote> -<div><p>📝 "Там, где заканчивается <strong>знание</strong>, начинается <strong>мнение</strong>".</p> -<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/737/%D0%9C%D0%9D%D0%95%D0%9D%D0%98%D0%95">Философия: Энциклопедический словарь.</a>" — М.: Гардарики. Под редакцией А.А. Ивина. 2004.</p> +<div><p>📝 "Components are the units of deployment. +They are the smallest entities that can be deployed as part of a system. +In Java, they are jar files. +In Ruby, they are gem files. +In .Net, they are DLLs. +In compiled languages, they are aggregations of binary files. +In interpreted languages, they are aggregations of source files. +In all languages, they are the granule of deployment."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> </div></blockquote> -<p>Тогда возникает:</p> -<ol class="arabic simple"> -<li><p><a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%BD%D0%BE%D1%81%D1%82%D1%8C">Внешний конформизм</a>, когда одному из участников Code Review не удалось аргументированно пояснить свою позицию другому, и тот решил прекратить прения, оставшись внутри себя несогласным.</p></li> -<li><p><a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%98%D1%80%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%83%D1%81%D0%B8%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5">Эффект иррационального усиления</a> - когда психологически сложно расстаться с проделанным трудом.</p></li> -</ol> -</li> -</ol> -<p>Во всех перечисленных случаях, кроме первого, это приводит к демотивации и усиливает текучку кадров. Что, в свою очередь вызывает ущерб упущенной выгоды из-за сдвига графика выхода на рынок новых бизнес-фич в результате простаивания незаполненных вакансий, проблемы Брукса (отвлекания опытных специалистов на обучение новых, низкая эффективность новых специалистов из-за недостатка знаний и трат времени на освоение новых знаний), прямые потери (обучение, поиск соискателей) и т.п.</p> -<p>Поскольку ключевым условием достижения консенсуса ревьюера и автора Pull Request является новый инкремент знаний, резонно возникает вопрос: а нужно ли получение этого инкремента привязывать во времени к инспекции уже воплощенной реализации?</p> -</section> -<section id="apaptation-vs-prediction"> -<h2><a class="toc-backref" href="#id6" role="doc-backlink">Apaptation vs Prediction</a></h2> -<p>Можно еще провести такую аналогию: Code Review - это форма инспекции и адаптации, т.е. эмпирический (опытный) способ обработки неопределенности. Это сродни хождению на ощуп. Куда-то добраться таким образом можно, но происпектировать таким образом можно только то, что можно потрогать, т.е. когда "уже пришли".</p> -<p>Процесс можно сделать эффективней, если расширить горизонт "видения", т.е. внести определенную долю Prediction-активности, и получение основного инкремента знаний перенести с Code Review на Design Review. -Как говорится, когда ты за рулем, то уже поздно читать инструкцию по вождению. -Очень хорошо эту мысль раскрывает "<a class="reference external" href="https://www.youtube.com/watch?v=Nf431Upix3M">Эксперимент с красными бусинками - Dr. Deming's Red Bead Experiment</a>".</p> -<p>Тут возникает вопрос о том, как достигнуть Design наименьшими трудозатратами, и именно эту проблему хорошо решает Event Storming, т.к. его можно осуществлять прямо в процессе обсуждения.</p> -</section> -<section id="continuous-review"> -<h2><a class="toc-backref" href="#id7" role="doc-backlink">Continuous Review</a></h2> -<p>Можно еще обратиться к народной пословице о том, что лучше один раз увидеть, чем сто раз услышать. -Т.е. использовать Continuous Review (Pair Programming, Mobbing Programming).</p> -<p>Вопрос не в том, чтобы исключить Code Review, а в том, чтобы уменьшить его негативные последствия путем добавления других форм передачи инкремента знаний.</p> -<figure class="align-left" id="id3"> -<a class="reference internal image-reference" href="../../../../../../../_images/code-review-reason.png"><img alt="Диаграмма причин и способов проведения Code Review" src="../../../../../../../_images/code-review-reason.png" style="width: 90%;"/></a> -<figcaption> -<p><span class="caption-text">Когда-то делал на скорую руку диаграмму причин и форм проведения Code Review. Жалко выбрасывать, решил поделиться. <a class="reference download internal" download="" href="../../../../../../../_downloads/c86e4ec31cbc282fd144c5c7453f9cba/code-review-reason.archimate"><code class="xref download docutils literal notranslate"><span class="pre">Исходная</span> <span class="pre">модель</span></code></a>.</span></p> -</figcaption> -</figure> </section> -Tue, 12 Jul 2022 00:00:00 Role of Simplicity in Agilehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.html -<span id="emacsway-agile-simplicity"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> -<ul class="simple"> -<li><p><a class="reference internal" href="#role-of-simplicity-in-agile" id="id5">Role of Simplicity in Agile</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id6">Единица измерения</a></p></li> -<li><p><a class="reference internal" href="#id3" id="id7">Качественный код всегда прост!</a></p> -<ul> -<li><p><a class="reference internal" href="#eric-evans" id="id8">Eric Evans</a></p></li> -<li><p><a class="reference internal" href="#edsger-w-dijkstra" id="id9">Edsger W. Dijkstra</a></p></li> -<li><p><a class="reference internal" href="#steve-mcconnell" id="id10">Steve McConnell</a></p></li> -<li><p><a class="reference internal" href="#kent-beck" id="id11">Kent Beck</a></p></li> -<li><p><a class="reference internal" href="#martin-fowler" id="id12">Martin Fowler</a></p></li> -<li><p><a class="reference internal" href="#robert-c-martin" id="id13">Robert C. Martin</a></p></li> -<li><p><a class="reference internal" href="#bjarne-stroustrup" id="id14">Bjarne Stroustrup</a></p></li> -<li><p><a class="reference internal" href="#id4" id="id15">Другие</a></p></li> -</ul> -</li> -</ul> -</li> -</ul> -</nav> -<p>Не очень глубоко осведомленные в архитектуре люди почему-то иногда думают, что архитектурное решение всегда несет перфекционизм и overengineering. -Вероятно, они просто не знакомы с "<a class="reference internal" href="software-design.html#emacsway-primary-technical-imperative"><span class="std std-ref">The Primary Technical Imperative</span></a>".</p> -<p>На самом деле, overengineering означает решение не соответствующее контексту, т.е. когда <a class="reference internal" href="patterns.html#emacsway-agile-patterns"><span class="std std-ref">уровень привнесенной сложности превышает уровень управляемой сложности</span></a>. -С точки зрения "<a class="reference internal" href="software-design.html#emacsway-primary-technical-imperative"><span class="std std-ref">The Primary Technical Imperative</span></a>" это значит, что он ухудшает внутреннее качество программы, а не повышает его.</p> -<p>Более того, хороший архитектор стремится исключить само возникновение сложной проблемы, нежели пытаться героически ее решить.</p> +<section id="srp-and-complexity"> +<h3><a class="toc-backref" href="#id11" role="doc-backlink">SRP and complexity</a></h3> +<p>Еще существует распространенное мнение, что SOLID уменьшает сложность программы.</p> <blockquote> -<div><p>📝 "Усложнять - просто, упрощать - сложно".</p> -<p class="attribution">—"Закон Мейера"</p> +<div><dl class="simple"> +<dt>📝 сложность</dt><dd><ol class="arabic simple"> +<li><p>Составленность из нескольких частей; многообразность по составу входящих частей и связей между ними.</p></li> +<li><p>Трудность, запутанность. Противоположное понятие — простота.</p></li> +</ol> +</dd> +</dl> +<p class="attribution">—"<a class="reference external" href="https://psychology.academic.ru/2331/%D1%81%D0%BB%D0%BE%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D1%8C">Словарь практического психолога</a>". — М.: АСТ, Харвест. С. Ю. Головин. 1998.</p> </div></blockquote> -<p>Вершиной простоты авиационной инженерной мысли был, пожалуй, самолет Ил-62.</p> -<p>См. видео "<a class="reference external" href="https://youtu.be/VyrN9AJm7sk">Ил-62 - идеальный вариант</a>" / @SkyShips.</p> -<p>Его конструкция получилась настолько удачной и простой, что огромный межконтинентальный лайнер управлялся исключительно мускульной силой пилотов посредством безбустерной (т.е. без усилителей) системы управления, что стало возможным благодаря удачно выбранной балансировке. -Для этого, правда, пришлось привнести в конструкцию заднюю штангу - довольно простое решение, которое на корню исключило возникновение довольно сложной проблемы. -Идеальный пример воплощения <a class="reference external" href="https://people.apache.org/~fhanik/kiss.html">KISS-principle</a>. -Более того, этот лайнер не имел даже предкрылков, благодаря оригинальному аэродинамическому решению в виде "зуба" на передней кромки крыла.</p> -<p>Это яркий пример того, как, вместо того, чтобы создавать сложные решения для сложных проблем, можно просто не допускать самого возникновения этих сложных проблем, благодаря простым и удачным проектным решениям.</p> <blockquote> -<div><p>📝 "Вобрав в себя лучшие технологические наработки, лайнер сохранил идеологию простоты конструкции и систем, что сделало его оптимальным для магистральных перевозок в СССР и одним из лучших самолетов своего времени."</p> -<p class="attribution">—"<a class="reference external" href="https://youtu.be/VyrN9AJm7sk">Ил-62 - идеальный вариант</a>" / @SkyShips</p> +<div><dl class="simple"> +<dt>📝 сложный</dt><dd><ol class="arabic simple"> +<li><p>Состоящий из нескольких частей, элементов. от т. перен. Характеризующийся многими переплетающимися явлениями, признаками, отношениями.</p></li> +<li><p>перен. Представляющий трудность для понимания, разрешения, осуществления; трудный.</p></li> +<li><p>перен. Обладающий противоречивыми качествами, свойствами, особенностями.</p></li> +</ol> +</dd> +</dl> +<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/efremova/246102/%D1%81%D0%BB%D0%BE%D0%B6%D0%BD%D1%8B%D0%B9">Толковый словарь Ефремовой</a>". Т. Ф. Ефремова. 2000.</p> </div></blockquote> <blockquote> -<div><p>📝 Дальнейший этап в творческой деятельности Ильюшина – пассажирский трансконтинентальный лайнер Ил-62, вышедший на воздушные линии в 1967 году и его модификация Ил-62М, ставший флагманом Аэрофлота. -Примечательно, что даже такой очень большой самолет сохранил простоту и легкость управления, присущую всем "илам". -В этом – одно из проявлений творческого стиля С.В.Ильюшина, стиля, которому свойственно стремление к оптимальному проектированию, упорство в достижении максимальной надежности и безопасности самолета в сочетании с высокой экономичностью или боевой эффективностью.</p> -<p>Характерной чертой творческой деятельности Ильюшина являлась простота проектных решений. -В своих воспоминаниях генеральный конструктор, академик А.С.Яковлев особо отмечает эту черту, называя Ильюшина "мастером простых решений". -Конечно, эта "простота" требовала огромного творческого напряжения и совершенно четкого и ясного представления эксплуатационной жизни проектируемого самолета.</p> -<p>В каждом самолете, созданном в конструкторском бюро под руководством С.В.Ильюшина, воплощены творческие особенности Генерального конструктора. -Умение технически просто решать сложные, а порой противоречивые проблемы – это талант, это стиль С.В.Ильюшина, конструктора и ученого, инженера и творца авиационной техники, что позволяло создавать такие машины, которые сыграли значительную роль в развитии Военно-Воздушных Сил СССР и обеспечили выполнение большой доли работы гражданского воздушного транспорта. -Они заняли достойное место в истории отечественной авиации.</p> -<p>Успех С.В.Ильюшиным достигался в результате решения технических задач на основе последних достижений науки, путем смелого внедрения нового и благодаря его исключительной дальновидности.</p> -<p>От легкого планера с полетным весом 100 кг до межконтинентального лайнера с полетным весом 160 т прошло почти 40 лет. -Под руководством С.В.Ильюшина спроектировано, построено и испытано в полете десятки машин, многие из которых оказались непревзойденными по летным характеристикам, простоте конструкции, технологии и надежности.</p> -<p class="attribution">—"<a class="reference external" href="https://www.ilyushin.org/about/history/biography/">Биография Ильюшина</a>" / ПАО "Ил" ("Ильюшин" - группа компаний ОАК)</p> +<div><p>📝 Complex</p> +<p>Com"plex (kŏm"plĕks), a. [L. complexus, p. p. of complecti to entwine around, comprise; com- + plectere to twist, akin to plicare to fold. See Plait, n.]</p> +<ol class="arabic"> +<li><p>Composed of two or more parts; composite; not simple; as, a complex being; a complex idea.</p> +<blockquote> +<div><p>Ideas thus made up of several simple ones put together, I call complex; such as beauty, gratitude, a man, an army, the universe. +Locke.</p> </div></blockquote> -<p>Давайте послушем другого известного "мастера простых решений", оружейного конструктора, создавшего наиболее надежный и простой автомат в истории:</p> +</li> +<li><p>Involving many parts; complicated; intricate.</p> <blockquote> -<div><p>📝 "хочу сказать, что сделать простое иногда во много раз сложнее, чем сложное."</p> -<p class="attribution">—М.Т. Калашников в интервью журналисту газеты "Metro Москва", 2009 год.</p> +<div><p>When the actual motions of the heavens are calculated in the best possible way, the process is difficult and complex. +Whewell.</p> </div></blockquote> -<p>И послушаем выдающегося русского художника Илью Ефимовича Репина:</p> +</li> +</ol> +<p>Complex fraction. See Fraction. — Complex number (Math.), in the theory of numbers, an expression of the form a + b√-1, when a and b are ordinary integers.</p> +<p>Syn. — See Intricate.</p> +<p>Com"plex, n. [L. complexus] Assemblage of related things; collection; complication.</p> <blockquote> -<div><p>📝 "Сначала художник рисует плохо и просто. Потом сложно и плохо. Потом сложно и хорошо. И только потом - просто и хорошо."</p> -<p class="attribution">—И.Е. Репин</p> +<div><p>This parable of the wedding supper comprehends in it the whole complex of all the blessings and privileges exhibited by the gospel. +South.</p> +</div></blockquote> +<p>Complex of lines (Geom.), all the possible straight lines in space being considered, the entire system of lines which satisfy a single relation constitute a complex; as, all the lines which meet a given curve make up a complex. The lines which satisfy two relations constitute a congruency of lines; as, the entire system of lines, each one of which meets two given surfaces, is a congruency.</p> +<p class="attribution">—<a class="reference external" href="http://www.websters1913.com/words/Complex">webster's 1913</a>. Connoisseur's reference to American English - a dictionary for writers and wordsmiths</p> +</div></blockquote> +<p>Если рассматривать термин "сложность" в значении "легкость понимания", то правильное использование принципов SOLID, наоборот, облегчает понимание.</p> +<p>Если же рассматривать этот термин в значении "многообразность по составу входящих частей", то совокупная сложность программы (в общей сложности) не уменьшается, а наоборот возрастает. +Задача архитектурных принципов сводится не к тому, чтобы уменьшить сложность, а к тому, чтобы управлять сложностью. +Это позволяет формировать структуру программы таким образом, чтобы отдельные её части можно было рассматривать изолированно, сохраняя рассматриваемый уровень сложности в пределах <a class="reference external" href="https://ru.m.wikipedia.org/wiki/%D0%9C%D0%B0%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%87%D0%B8%D1%81%D0%BB%D0%BE_%D1%81%D0%B5%D0%BC%D1%8C_%D0%BF%D0%BB%D1%8E%D1%81-%D0%BC%D0%B8%D0%BD%D1%83%D1%81_%D0%B4%D0%B2%D0%B0">возможностей краткосрочной памяти человека</a>.</p> +<p>Отсюда вывод - применение любого паттерна или принципа, вносящего в систему несущественную сложность (accidental complexity), должно себя окупать, т.е. позволять управлять еще большим уровнем сложности. +Тогда применение принципов и паттернов, хотя и будет (математически) усложнять программу, но будет упрощать понимание программы, формируя такие уровни абстракции, которые человеческий мозг сможет рассматривать изолированно.</p> +<p>Методики управления сложностью позволяют предотвратить Уроборос.</p> +<p>Но есть еще одно значение этого термина:</p> +<blockquote> +<div><p>📝 "Structural Complexity looks at the system elements and relationships. +In particular, structural complexity looks at how many different ways system elements can be combined. +Thus, it is related to the potential for the system to adapt to external needs."</p> +<p class="attribution">—"<a class="reference external" href="https://www.sebokwiki.org/wiki/Complexity">Guide to the Systems Engineering Body of Knowledge (SEBoK)</a>"</p> </div></blockquote> +<p>Если рассматривать термин в таком значении, то SOLID увеличивает сложность, но это не имеет негативного влияния на понимание устройства системы.</p> +</section> +</section> +<section id="ad-hominem"> +<h2><a class="toc-backref" href="#id12" role="doc-backlink">Ad hominem</a></h2> +<p>Еще одно распространенное мнение, которое нередко можно услышать, заключается в том, что Robert C. Martin - оторванный от практики теоретик, придумывающий в своем иллюзорном мирке всякие нежизнеспособные принципы вроде SOLID, которые на практике только ухудшают код.</p> +<p>Принципы SOLID действительно, имеют под собой теоретическое обоснование, только эта теория не связана с Robert C. Martin. +А вот, например, Bertrand Meyer, действительно, является серьезным научным теоретиком, и его авторство Robert C. Martin не скрывал в своей оригинальной статье "<a class="reference external" href="https://web.archive.org/web/20060822033314/http://www.objectmentor.com/resources/articles/ocp.pdf">The Open-Closed Principle</a>".</p> +<p>Итак, вывод первый - если кто и является теоретиком, то это не Robert C. Martin. Он-то как раз практик.</p> +<p>В архитекторских кругах отношение к Robert C. Martin можно назвать, мягко говоря, неоднозначным. +Зато к Gregor Hohpe отношение - почти единодушно уважительное.</p> +<p>Но, странное дело, первая книга в <a class="reference external" href="https://architectelevator.com/architecture/architect-bookshelf/">списке рекомендованной литературы Gregor Hohpe</a> - это именно книга "Clean Code" by Robert C. Martin.</p> +<p>Мое же мнение сводится к тому, что говорить о влиянии внутреннего качества кода на характер роста стоимости изменения кода - нужно. +Именно этим и занимается Robert C. Martin. +И это <a class="reference external" href="https://en.m.wikipedia.org/wiki/Ad_hominem">важнее манеры донесения информации</a>. +Потому что это - один из наиболее чувствительных вопросов индустрии, см. "<a class="reference internal" href="../../../models/agile/analysis/concerns/business-concerns/common-planning-errors.html#emacsway-agile-common-planning-errors"><span class="std std-ref">Наиболее частые ошибки планирования</span></a>".</p> +</section> +<section id="solid-and-agile"> +<h2><a class="toc-backref" href="#id13" role="doc-backlink">SOLID and Agile</a></h2> +<p>Принципы SOLID впервые появились в статье "Design Principles and Design Patterns" 2000 года:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://sites.google.com/site/unclebobconsultingllc/getting-a-solid-start">Источник 1</a>"</p></li> +<li><p>"<a class="reference external" href="https://web.archive.org/web/20150906155800/http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf">Источник 2</a>"</p></li> +<li><p>"<a class="reference external" href="https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf">Источник 3</a>"</p></li> +</ul> +<p>Вышла эта статья за год до того, как тот же Robert C. Martin организовал встречу 17-ти, на которой был принят Agile-Manifesto. +Как между собой связаны два этих события?</p> +<p>Все просто. +Agile - это адаптивная методика, которая имеет экономическую целесообразность только в том случае, если <a class="reference internal" href="../../../models/agile/agile.html#emacsway-agile-development"><span class="std std-ref">стоимость адаптации ниже стоимости заблаговременного проектирования (BDUF)</span></a>.</p> +<p>А стоимость адаптации, благодаря которой итеративная разработка вообще обретает смысл, определяется характером роста стоимости изменения кода. +А это уже <a class="reference internal" href="software-design.html#emacsway-agile-software-design"><span class="std std-ref">задача архитектурная</span></a>, и это объясняет, почему на подписании Agile-manifesto присутствовало столько людей из мира архитектуры. +Кстати, на этой встрече предполагалось присутствие и Grady Booch, но, не вышло.</p> +<p>И это так же объясняет, почему первая книга, которую выпустил организатор встречи Agile-Manifesto после его подписания, была посвящена не столько процессам, сколько принципам конструирования (гибкого) кода, обладающего низкой стоимостью изменения. +Это лишний раз подчеркивает <a class="reference internal" href="../../../models/agile/agile.html#emacsway-agile-development-difficulties"><span class="std std-ref">важность технической составляющей в Agile (гибкой) разработке</span></a>.</p> +<p>Итак, следующий важный вывод: если бы принципы конструирования гибкого кода, включая SOLID, не имели бы практического улучшения экономических показателей разработки, тогда Robert C. Martin с единомышленниками никогда не смог бы доказать бизнесу, что Agile обладает экономическим превосходством перед BDUF, и рынок просто его проигнорировал бы.</p> +</section> <section id="id2"> -<h2><a class="toc-backref" href="#id6" role="doc-backlink">Единица измерения</a></h2> -<p>Посмотрим, к примеру, мотивацию Mediator pattern:</p> +<h2><a class="toc-backref" href="#id14" role="doc-backlink">Баланс краткосрочных и долгосрочных интересов</a></h2> +<p><a class="reference external" href="https://en.m.wikipedia.org/wiki/List_of_system_quality_attributes">Quality Attributes</a> противоречивы между собой, и удовлетворить их все не представляется возможным. +Поэтому, приложение не может быть лучше или хуже - оно может соответствовать или не соответствовать требуемым атрибутам качества.</p> +<p>Принципы SOLID направлены на удовлетворение атрибута качества <a class="reference external" href="https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=8299">Modifiability</a> (см. "Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman) в долгосрочной перспективе. +Т.е. они призваны обеспечить пологий характер роста стоимости изменения кода, максимально приближенный к горизонтальной асимптоте. +Напомню, принципы SOLID были опубликованы в контексте Agile разработки, где это требование является критически необходимым для достижения экономического превосходства Agile-разработки перед BDUF.</p> +<p>Чтобы находить баланс наименьшей стоимости разработки как в долгосрочной, так и в краткосрочной перспективе, нужно сочетать принципы SOLID с принципом YAGNI (который отвечает за снижение стоимости в краткосрочной перспективе), о чем писал Сергей Тепляков в статьях:</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2016/08/yagni.html">Принцип YAGNI</a>"</p></li> +<li><p>"<a class="reference external" href="http://sergeyteplyakov.blogspot.com/2012/04/blog-post_19.html">О повторном использовании кода</a>"</p></li> +</ul> +<p>Сам Robert Martin дает такое определение качеству дизайна:</p> <blockquote> -<div><p>📝 "Mediator promotes loose <strong>coupling</strong> by keeping objects from referring to each other explicitly, -and it lets you vary their interaction independently."</p> -<p class="attribution">—"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides</p> +<div><p>📝 "The measure of design quality is simply the measure of the effort required to meet the needs of the customer. +If that effort is low, and stays low throughout the lifetime of the system, the design is good. +If that effort grows with each new release, the design is bad. +It's as simple as that."</p> +<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> </div></blockquote> -<p>Конечно, тут важно найти <a class="reference internal" href="software-design.html#emacsway-kent-beck-constantine-s-law"><span class="std std-ref">баланс между стоимостью Coupling и стоимостью Decoupling</span></a>. -Но ключевой целью принципа "<a class="reference external" href="http://wiki.c2.com/?CouplingAndCohesion">Low Coupling &amp; High Cohesion</a>" является управление сложностью, т.е. упрощение, а не усложнение! -Именно это позволяет <a class="reference internal" href="../../../../../soft-skills/icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">рассматривать фрагмент кода изолированно в пределах возможностей краткосрочной памяти человека</span></a>.</p> -<p>Поэтому размер программного элемента исчисляется количеством его обязанностей, а не количеством символов. -Если кто-то считает иначе, и думает, что меньше сложности означает "меньше кода", тогда попробуйте понять, что делает этот, весьма лаконичный, код:</p> +<p>Ключевым здесь является "stays low throughout the lifetime of the system" (т.е. в долгосрочной перспективе), поскольку существует <a class="reference external" href="https://martinfowler.com/bliki/DesignPayoffLine.html">Design Payoff Line</a>.</p> +<p>Не должно быть принципов ради принципов, когда за деревьями леса не видно. +Если принципы применяются, а стоимость разработки возрастает, значит, применяются либо не те принципы, либо не так. +Как говорил Craig Larman:</p> <blockquote> -<div><div class="highlight-bash notranslate" id="emacsway-rm-rf"><div class="highlight"><pre><span/> <span class="nb">echo</span> <span class="s2">"test... test... test..."</span> <span class="p">|</span> perl -e <span class="s1">'$??s:;s:s;;$?::s;;=]=&gt;%-{&lt;-|}&lt;&amp;|{;;y; -/:-@[-{-};`-{/" -;;s;;$_;see'</span> -</pre></div> -</div> -<p>P.S.: Не вздумайте запустить! Он выполняет <code class="docutils literal notranslate"><span class="pre">rm</span> <span class="pre">-rf</span> <span class="pre">/*</span></code>.</p> -<p class="attribution">—"<a class="reference external" href="https://ru.stackoverflow.com/questions/1144804/%D0%A7%D1%82%D0%BE-%D0%B4%D0%B5%D0%BB%D0%B0%D0%B5%D1%82-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9-%D0%BE%D0%B4%D0%BD%D0%BE%D1%81%D1%82%D1%80%D0%BE%D1%87%D0%BD%D0%B8%D0%BA-%D0%BD%D0%B0-perl">Источник 1</a>", "<a class="reference external" href="https://lurkmore.to/Rm_-rf">Источник 2</a>"</p> +<div><p>📝 "в продуктовой разработке нет такого понятия как "лучшие практики" - есть только практики, применение которых целесообразно в конкретном контексте. +Практики ситуационны, и беспечное объявление их "лучшими" отрывает их от мотивации и контекста. +Они превращаются в ритуалы, и навязывание так называемых "best practices" убивает культуру обучения, задавания вопросов, вовлечения и непрерывных улучшений. +Зачем людям искать чего-то лучшего, если все уже придумано за них?"</p> +<p class="attribution">—"<a class="reference external" href="https://less.works/ru/less/framework/introduction">Знакомство с LeSS</a>"</p> </div></blockquote> -<p>Как красиво сказал Vladik Khononov: "абзац - это единица измерения мыслей, а не количества слов". -Лаконичность кода определяется уровнем его сложности на горизонте его рассмотрения (т.е. на рассматриваемом уровне абстракции), а не количеством символов.</p> -</section> -<section id="id3"> -<h2><a class="toc-backref" href="#id7" role="doc-backlink">Качественный код всегда прост!</a></h2> -<section id="eric-evans"> -<h3><a class="toc-backref" href="#id8" role="doc-backlink">Eric Evans</a></h3> <blockquote> -<div><p>📝 "Software design is a constant battle with complexity."</p> -<p class="attribution">—"Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans</p> +<div><p>📝 "There are no such things as best practices in product development. +There are only practices that are adequate within a certain context. +Practices are situational; blithely claiming they are "best" disconnects them from motivation and context. +They become rituals. And pushing so-called best practices kills a culture of learning, questioning, engagement, and continuous improvement. +Why would people challenge best?"</p> +<p class="attribution">—"<a class="reference external" href="https://less.works/ru/less/framework/introduction">Introduction to LeSS</a>"</p> </div></blockquote> +<p>Иными словами, нужно осознавать, для достижения какого именно требования применяется тот или иной принцип, следить за фидбэком от его применения, и анализировать успешность достижения этого требования. Без этого, применение принципов может легко превратиться в <a class="reference external" href="http://sergeyteplyakov.blogspot.com/2013/09/blog-post_24.html">Карго-Культ</a>.</p> </section> -<section id="edsger-w-dijkstra"> -<h3><a class="toc-backref" href="#id9" role="doc-backlink">Edsger W. Dijkstra</a></h3> +<section id="solid"> +<h2><a class="toc-backref" href="#id15" role="doc-backlink">SOLID и первоисточники</a></h2> +<p>Остается еще одно распространенное мнение - Robert C. Martin исказил оригинальный смысл первоисточников. +Где-то в чем-то он может и ошибся, да он и сам об этом говорил. +Но он не присваивал себе чужие идеи, и всегда открыто отсылал к первоисточникам, таким образом, привлекая к ним внимание.</p> +<section id="ocp"> +<h3><a class="toc-backref" href="#id16" role="doc-backlink">OCP</a></h3> +<p>Вот, например, многие из ваших коллег узнали бы об OCP из оригинала в изложении Bertrand Meyer? +Даже Martin Fowler говорил, что:</p> <blockquote> -<div><p>📝 "Simplicity and elegance are unpopular because they require hard work and discipline to achieve and education to be appreciated."</p> -<p class="attribution">—Edsger W. Dijkstra</p> +<div><p>📝 "the second edition [of "Object Oriented Software Construction"] is good but you'll need several months in a gym before you can lift it."</p> +<p class="attribution">—M.Fowler, <a class="reference external" href="https://martinfowler.com/bliki/CommandQuerySeparation.html">Command Query Separation</a></p> </div></blockquote> +<p>При этом, Robert C. Martin, действительно возлагал на старые принципы новые задачи, исходя из исторического контекста того времени. +Очень хорошо этот вопрос рассматривается в статье "<a class="reference external" href="https://enterprisecraftsmanship.com/posts/ocp-vs-yagni/">OCP vs YAGNI</a>" by Vladimir Khorikov.</p> <blockquote> -<div><p>📝 "Simplicity is prerequisite for reliability."</p> -<p class="attribution">—Edsger W. Dijkstra</p> -</div></blockquote> +<div><p>📝 "There are two interpretations of the Open/Closed Principle:</p> <blockquote> -<div><p>📝 "Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. -And to make matters worse: complexity sells better."</p> -<p class="attribution">—Edsger W. Dijkstra, 1984 <a class="reference external" href="http://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD896.html">On the nature of Computing Science</a> (EWD896)</p> +<div><ol class="arabic simple"> +<li><p>The original Bertrand Meyer's one is about backward compatibility. You need to close the API of your module/library/service if it's meant for external use. Not implementation but exactly the API part of it. And only when it's used by external teams.</p></li> +<li><p>The Bob Martin's one is about avoiding ripple effects: you need to be able to extend the software behavior with modifying little or no original code. This is achieved by putting extension points to your code base."</p></li> +</ol> </div></blockquote> -<blockquote> -<div><p>📝 "Хороший специалист всегда осознает строго ограниченные размеры своего черепа, поэтому подходит к задачам с максимальной скромностью.</p> -<p>The competent programmer is fully aware of the strictly limited size of his own skull; -therefore, he approaches the programming task in full humility"</p> -<p class="attribution">—Edsger W. Dijkstra, 1972</p> +<p class="attribution">—"<a class="reference external" href="https://enterprisecraftsmanship.com/posts/ocp-vs-yagni/">OCP vs YAGNI</a>" by Vladimir Khorikov</p> </div></blockquote> </section> -<section id="steve-mcconnell"> -<h3><a class="toc-backref" href="#id10" role="doc-backlink">Steve McConnell</a></h3> +<section id="id3"> +<h3><a class="toc-backref" href="#id17" role="doc-backlink">SRP</a></h3> +<p>В качестве источника принципа SRP, Robert C. Martin в своей книге "Agile Software Development. Principles, Patterns, and Practices." указывает:</p> <blockquote> -<div><p>📝 "Главным Техническим Императивом Разработки ПО является управление сложностью. -Управлять сложностью будет гораздо легче, если при проектировании вы будете стремиться к простоте.</p> -<p>Есть два общих способа достижения простоты: -минимизация объема существенной сложности, с которой приходится иметь дело в любой конкретный момент времени, -и подавление необязательного роста несущественной сложности.</p> -<p>Software's Primary Technical Imperative is managing complexity. -This is greatly aided by a design focus on simplicity.</p> -<p>Simplicity is achieved in two general ways: -minimizing the amount of essential complexity that anyone's brain has to deal with at any one time, -and keeping accidental complexity from proliferating needlessly."</p> -<p class="attribution">—"Code Complete" 2nd edition by Steve McConnell, перевод: Издательско-торговый дом "Русская Редакция"</p> +<div><ol class="arabic simple"> +<li><p>DeMarco, Tom. Structured Analysis and System Specification. Yourdon Press Computing Series. Englewood Cliff, NJ: 1979.</p></li> +<li><p>Page-Jones, Meilir. The Practical Guide to Structured Systems Design, 2d ed. Englewood Cliff, NJ: Yourdon Press Computing Series, 1988.</p></li> +</ol> +<p class="attribution">—"Agile Software Development. Principles, Patterns, and Practices." by Robert C. Martin</p> </div></blockquote> -</section> -<section id="kent-beck"> -<h3><a class="toc-backref" href="#id11" role="doc-backlink">Kent Beck</a></h3> +<p>А здесь он дает более развернутую историю:</p> <blockquote> -<div><p>📝 "On the surface, being an XP programmer looks a lot like being a programmer within other software development disciplines. -You spend your time working with programs, making them bigger, simpler, faster. -Beneath the surface, however, the focus is quite different. -Your job isn't over when the computer understands what to do. -Your first value is communication with other people. -If the program runs, but there is some vital component of communication left to be done, you aren't done. -You write tests that demonstrate some vital aspect of the software. -You break the program into more smaller pieces, or merge pieces that are too small into larger, more coherent pieces. -You find a system of names that more accurately reflects your intent.</p> -<p>This may sound like a high-minded pursuit of perfection. -It is anything but. -You try to develop the most valuable software for the customer, but not to develop anything that isn't valuable. -If you can reduce the size of the problem enough, then you can afford to be careful with the work you do on what remains. -Then, you are careful by habit."</p> -<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> +<div><p>📝 "The 1970s and 1980s were a fertile time for principles of software architecture. +Structured Programming and Design were all the rage. +During that time the notions of Coupling and Cohesion were introduced by Larry Constantine, and amplified by Tom DeMarco, Meilir Page-Jones and many others."</p> +<p class="attribution">—"<a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html">The Single Responsibility Principle</a>" by Robert C. Martin</p> </div></blockquote> +<p>Т.е. он отсылает к <a class="reference external" href="http://wiki.c2.com/?CouplingAndCohesion">Constantine's Law</a>.</p> +<p>Этот принцип не имеет отношения к OOP, хотя и активно используется в OOP, в частности, в книгах:</p> +<ul class="simple"> +<li><p>"Code Complete" by Steve McConnell</p></li> +<li><p>"Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development" by Craig Larman, где этот принцип известен под аббревиатурой GRASP</p></li> +</ul> +<p>И этот принцип является одним из самых фундаментальных в разработке ПО. +Он применяется в структурном программировании, в OOP, в DDD при моделировании агрегатов, в микросервисах при поиске границ микросервисов и т.д.</p> +<p>А Kent Beck назвал его в одной из своих недавних статей</p> <blockquote> -<div><p>📝 "Of course, you can do a better job if you have more tools in your toolbox than if you have fewer, but it is much more important to have a handful of tools that you know when not to use, than to know everything about everything and risk using too much solution."</p> -<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> +<div><p>📝 "the basic forces acting on software design. +These were elucidated in the mid-70s by Yourdon &amp; Constantine in <a class="reference external" href="https://amzn.to/2GsuXvQ">Structured Design</a> and haven't changed."</p> +<p class="attribution">—"<a class="reference external" href="https://medium.com/@kentbeck_7670/monolith-services-theory-practice-617e4546a879">Monolith -&gt; Services: Theory &amp; Practice</a>" by Kent Beck</p> </div></blockquote> +<p>Каким бы образом это ни сделал Robert C. Martin, но он достиг поставленной цели - привлек массовое внимание к архитектурным принципам, имеющим действительно важное значение в Agile разработке.</p> +</section> +</section> +<section id="no-silver-bullet"> +<h2><a class="toc-backref" href="#id18" role="doc-backlink">No Silver Bullet</a></h2> +<p>Но правда и в том, что <a class="reference external" href="https://en.m.wikipedia.org/wiki/No_Silver_Bullet">серебряной пули нет</a>. +Нет магических пяти букв, которые волшебным образом сделают код экономически высокоэффективным, особенно, если про них узнали не из первоисточника, а из Википедии. +Зайдите на github, и вы увидите огромное многообразие взаимно-противоречивых демонстрационных приложений (reference applications), и каждое из них претендует на роль самой эталонной реализации Clean Architecture (это уже не совсем SOLID, но из этой же области). +Кто в лес, кто по дрова. +И только работы парней, обладающих <a class="reference external" href="http://www.kamilgrzybek.com/programming-and-design-resources/">широким архитектурным кругозором и литературным бэкграундом</a>, таких, как <a class="reference external" href="https://github.com/kgrzybek">Kamil Grzybek</a>, могут претендовать на роль эталонной реализации:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/kgrzybek/modular-monolith-with-ddd">Full Modular Monolith application with Domain-Driven Design approach</a> by Kamil Grzybek</p></li> +<li><p><a class="reference external" href="https://github.com/kgrzybek/sample-dotnet-core-cqrs-api">Sample .NET Core REST API CQRS implementation with raw SQL and DDD using Clean Architecture</a> by Kamil Grzybek</p></li> +</ul> +<p>В таком случае, SOLID уже не мешает создавать экономически высокоэффективные приложения (<a class="reference external" href="http://www.kamilgrzybek.com/design/clean-domain-model-attributes/">раз</a> и <a class="reference external" href="http://www.kamilgrzybek.com/design/grasp-explained/">два</a>).</p> +<p>Еще одно, наверное, самое популярное reference application - <a class="reference external" href="https://github.com/dotnet-architecture/eShopOnContainers">eShopOnContainers</a>, было разработано при значительном участии известного авторитета в области архитектуры Cesar De La Torre, который в своем <a class="reference external" href="https://devblogs.microsoft.com/cesardelatorre/free-ebookguide-on-net-microservices-architecture-for-containerized-net-applications/">блог-посте</a> пишет:</p> <blockquote> -<div><p>📝 Mastery - The spirit of xUnit is simplicity. -Martin Fowler said, "Never in the annals of software engineering was so much owed by so many to so few lines of code." -Some of the implementations have gotten a little complicated for my taste. -Rolling your own will give you a tool over which you have a feeling of mastery.</p> -<p class="attribution">—"Test-Driven Development By Example" by Kent Beck</p> +<div><p>"Using SOLID principles and Dependency Injection"</p> </div></blockquote> +<p>Речь идет об <a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/microservice-application-layer-web-api-design">этом месте гайда</a>.</p> +<p>В качестве итога можно привести слова самого Robert C. Martin:</p> <blockquote> -<div><p>📝 Travel light - You can't expect to carry a lot of baggage and move fast. -The artifacts we maintain should be:</p> +<div><p>📝 "<strong>Following the rules on the paint can won't teach you how to paint.</strong> +This is an important point. +Principles will not turn a bad programmer into a good programmer. +Principles have to be applied with judgement. +If they are applied by rote it is just as bad as if they are not applied at all. +Having said that, if you want to paint well, I suggest you learn the rules on the paint can. +You may not agree with them all. +You may not always apply the ones you do agree with. +But you'd better know them. +Knowledge of the principles and patterns gives you the justification to decide when and where to apply them. +If you don't know them, your decisions are much more arbitrary."</p> +<p class="attribution">—"<a class="reference external" href="https://sites.google.com/site/unclebobconsultingllc/getting-a-solid-start">Getting a SOLID start.</a>" by Robert C. Martin</p> +</div></blockquote> +<p>См. также:</p> <ul class="simple"> -<li><p>Few</p></li> -<li><p>Simple</p></li> -<li><p>Valuable</p></li> +<li><p>"<a class="reference external" href="https://sites.google.com/site/unclebobconsultingllc/getting-a-solid-start">Getting a SOLID start</a>"</p></li> +<li><p>"<a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html">The Single Responsibility Principle</a>"</p></li> +<li><p>"<a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html">The Open Closed Principle</a>"</p></li> +<li><p>"<a class="reference external" href="http://blog.cleancoder.com/uncle-bob/2020/10/18/Solid-Relevance.html">Solid Relevance</a>"</p></li> </ul> -<p>The XP team becomes intellectual nomads, always prepared to quickly pack up the tents and follow the herd. -The herd in this case might be a design that wants to go a different direction than anticipated, or a customer that wants to go a different direction than anticipated, or a team member who leaves, or a technology that suddenly gets hot, or a business climate that shifts.</p> -<p>Like the nomads, the XP team gets used to traveling light. -They don't carry much in the way of baggage except what they must have to keep producing value for the customer—tests and code.</p> -<p>&lt;...&gt;</p> -<p>Travel light - suggests that the manager doesn't impose a lot of overhead - long all-hands meetings, lengthy status reports. -Whatever the manager requires of the programmers shouldn't take much time to fulfill.</p> -<p>&lt;...&gt;</p> -<p>Travel light - The design strategy should produce no "extra" design. -There should be enough to suit our current purposes (the need to do quality work), but no more. -If we embrace change, we will be willing to start simple and continually refine.</p> -<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> +</section> +<section id="id4"> +<h2><a class="toc-backref" href="#id19" role="doc-backlink">Последние определения от 2022-07-06</a></h2> +<blockquote> +<div><p>💬 "The Single Responsibility Principle (SRP):</p> +<p>Gather together those things that change for the same reasons and at the same times. Separate those things that change for different reasons or at different times."</p> +<p class="attribution">—<a class="reference external" href="https://twitter.com/unclebobmartin/status/1544652844825038850?t=KWWq9TQ9XN3w9VksSRieSA&amp;s=19">Источник</a></p> </div></blockquote> <blockquote> -<div><p>📝 "It's hard to do simple things. -It seems crazy, but sometimes it is easier to do something more complicated than to do something simple. -This is particularly true when you have been successful doing the complicated thing in the past. -Learning to see the world in the simplest possible terms is a skill and a challenge. -The challenge is that you may have to change your value system. -Instead of being impressed when someone (like you, for instance) gets something complicated to work, you have to learn to be dissatisfied with complexity, not to rest until you can't imagine anything simpler working."</p> -<p class="attribution">—"Extreme Programming Explained" by Kent Beck</p> +<div><p>💬 "The Open-Closed Principle (OCP):</p> +<p>Separate modules that frequently change from modules that change less frequently with a layer of abstraction."</p> +<p class="attribution">—<a class="reference external" href="https://twitter.com/unclebobmartin/status/1544653655047118851?t=r4bY25YMWeHpAtEDtLsVdg&amp;s=19">Источник</a></p> </div></blockquote> <blockquote> -<div><p>📝 "I'm not a great programmer; I'm just a good programmer with great habits."</p> -<p class="attribution">—Kent Beck at "Refactoring: Improving the Design of Existing Code" 1st edition by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts</p> +<div><p>💬 "The Liskov Substitution Principle (LSP):</p> +<p>The implementation of an interface must never violate the contract between that interface and its users."</p> +<p class="attribution">—<a class="reference external" href="https://twitter.com/unclebobmartin/status/1544654145839316996?t=jsDVCEvXBlwM82JwXugdMw&amp;s=19">Источник</a></p> </div></blockquote> <blockquote> -<div><p>📝 "Solution Complexity</p> -<p>Sometimes systems grow big and complicated, out of proportion to the problem they solve. -The challenge is to stop making the problem worse. -It is difficult for a struggling team to keep going when every defect fixed creates three more. -XP can help.</p> -<p>One client began by getting the build process under control. -The team improved the build so instead of taking 24 hours on a dedicated machine with lots of manual intervention, the build took an hour and could run completely automatically on any machine. -Then, the team instituted stories and a story board so everyone knew who was working on what and how long they were taking. -After two years of steady improvement the team reduced costs 60%, going from seventy engineers to twenty; reduced the time to fix defects 66%; and reduced the time to release for major and minor point releases by 75%, from ten weeks to two weeks. -Once the team had stopped digging itself in deeper, it began to climb out by eliminating excess complexity while also fixing defects.</p> -<p>The XP strategy for dealing with excess complexity is always the same: chip away at the complexity while continuing to deliver. -Brighten the corner where you are. -If you are fixing a defect in an area, clean up while you are there. -One objection is that this "extra" cleanup takes too long. -The team is likely wasting time on interruptions to fix defects. -Cleaning up helps reduce the overhead of work. -Visible planning can make it easier for every one to see where the time is already going so it is easier to accept the estimates necessary to do the job right."</p> -<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck, "Chapter 15. Scaling XP :: Solution Complexity"</p> +<div><p>💬 "The Interface Segregation Principle (ISP):</p> +<p>Don't depend on things you don’t need."</p> +<p class="attribution">—<a class="reference external" href="https://twitter.com/unclebobmartin/status/1544654493677240324?t=uGpjX6exnonCpwh5VO6WXQ&amp;s=19">Источник</a></p> </div></blockquote> -</section> -<section id="martin-fowler"> -<h3><a class="toc-backref" href="#id12" role="doc-backlink">Martin Fowler</a></h3> <blockquote> -<div><p>📝 "A little time spent refactoring can make the code better communicate its purpose. Programming in this mode is all about saying exactly what you mean."</p> -<p class="attribution">—"Refactoring: Improving the Design of Existing Code", Martin Fowler</p> +<div><p>💬 "The Dependency Inversion Principle (DIP):</p> +<p>Lower level policies should depend on higher level policies."</p> +<p class="attribution">—<a class="reference external" href="https://twitter.com/unclebobmartin/status/1544655000525225985?t=gEoCa1rfs4i05snSJDZXqg&amp;s=19">Источник</a></p> </div></blockquote> +<div class="admonition seealso"> +<p class="admonition-title">См.также</p> +<ul class="simple"> +<li><p>"<a class="reference internal" href="../crash-course-in-software-development-economics.html"><span class="doc">Краткий курс по экономике разработки программного обеспечения</span></a>"</p></li> +<li><p>"<a class="reference internal" href="../software-construction/yagni.html#emacsway-yagni"><span class="std std-ref">YAGNI</span></a>"</p></li> +</ul> +</div> </section> -<section id="robert-c-martin"> -<h3><a class="toc-backref" href="#id13" role="doc-backlink">Robert C. Martin</a></h3> +Fri, 15 Jul 2022 00:00:00 Systems Development Life Cycle (SDLC) Referencehttps://dckms.github.io/system-architecture/emacsway/it/sdlc/sdlc-reference.html +<span id="emacsway-sdlc-literature"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<p>Grady Booch выделяет два ключевых критерия, которые определяют успех или неудачу проекта:</p> <blockquote> -<div><p>📝 "Professionals avoid getting so vested in an idea that they can't abandon it and turn around. -They keep an open mind about other ideas so that when they hit a dead end they still have other options."</p> -<p class="attribution">—"The Clean Coder: a code of conduct for professional programmers" by Robert C. Martin</p> +<div><p>📝 "Traits of Successful Projects</p> +<p>A successful software project is one in which the deliverables satisfy and possibly exceed the customer's expectations, the development occurred in a timely and economical fashion, and the result is resilient to change and adaptation. By this measure, we have observed several traits that are common to virtually all of the successful object-oriented systems we have encountered and noticeably absent from the ones that we count as failures:</p> +<ul class="simple"> +<li><p>Existence of a strong architectural vision</p></li> +<li><p>Application of a well-managed iterative and incremental development lifecycle"</p></li> +</ul> +<p class="attribution">—"Object-Oriented Analysis and Design with Applications" 3rd edition by Grady Booch, Robert A. Maksimchuk, Michael W. Engle, Bobbi J. Young Ph.D., Jim Conallen, Kelli A. Houston</p> </div></blockquote> +<p>Если с "architectural vision" все понятно, то с "well-managed development lifecycle" у многих могут возникать вопросы. Тем не менее, для успешности проекта процессы должны быть грамотно выбраны и качественно отлажены.</p> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://book4cio.ru/#page-14">Учебник 4CIO</a>" - глава 3.4. Управление разработкой ПО</p></li> +<li><p>"<a class="reference external" href="https://www.sebokwiki.org/wiki/Life_Cycle_Models">SEBoK: Life Cycle Models</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.sebokwiki.org/wiki/System_Life_Cycle_Process_Models:_Iterative">SEBoK: System Life Cycle Process Models: Iterative</a>"</p></li> +<li><p>"<a class="reference external" href="https://mellarius.ru/processes">Процессы</a>" at mellarius.ru - превосходный минималистичный и самодостаточный справочник.</p></li> +<li><p>Неплохой "<a class="reference external" href="https://www.tutorialspoint.com/sdlc/index.htm">SDLC Tutorial</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.tutorialspoint.com/sdlc/sdlc_quick_guide.htm">SDLC - Quick Guide</a>"</p></li> +<li><p>"<a class="reference external" href="https://itabok.iasaglobal.org/itabok3_0/architecture-methodologies-and-frameworks/">ITABoK: Architecture Methodologies and Frameworks</a>"</p></li> +<li><p>"<a class="reference external" href="https://itabok.iasaglobal.org/itabok3_0/digital-outcome-model/agility/">ITABoK: What is Agility</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.incose.org/products-and-publications/se-handbook">Systems engineering handbook. A guide for System Life Cycle Processes and activities</a>" by INCOSE</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/foundational/pmbok">The Project Management Body of Knowledge (PMBoK)</a>" by Project Management Institute (PMI)</p></li> +<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute (PMI), 2017</p></li> +<li><p>"<a class="reference external" href="https://www.iiba.org/career-resources/business-analysis-resources/iiba-bookstore/">Agile Extension to the BABOK® Guide</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/22-cpre-advanced-level-re-agile-handbook/handbook_cpre_al_re%40agile_en_v1.0.2.pdf">Handbook of RE@Agile According to the IREB Standard Education and Training for IREB Certified Professional for Requirements Engineering Advanced Level RE@Agile</a>" Version 1.0.2</p></li> +<li><p>"<a class="reference external" href="https://www.iso.org/standard/63712.html">ISO/IEC/IEEE 12207:2017 Systems and software engineering — Software life cycle processes</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.iso.org/standard/63711.html">ISO/IEC/IEEE 15288:2015 Systems and software engineering — System life cycle processes</a>"</p></li> +<li><p>"ISO/IEC/IEEE 29148:2018 Systems and software engineering — Life cycle processes — Requirements engineering"</p></li> +<li><p>"ISO/IEC/IEEE 15289:2019 Systems and software engineering — Content of life-cycle information items (documentation)"</p></li> +<li><p>"ISO/IEC/IEEE 24765:2017 Systems and software engineering — Vocabulary"</p></li> +<li><p>"ISO 9000:2005 Quality management systems — Fundamentals and vocabulary"</p></li> +<li><p>"ISO/IEC 33001:2015 Information technology — Process assessment — Concepts and terminology"</p></li> +<li><p>"ГОСТ Р ИСО/МЭК 12207-2010 Информационная технология. Системная и программная инженерия. Процессы жизненного цикла программных средств."</p></li> +<li><p>"ГОСТ Р 57193-2016 Системная и программная инженерия. Процессы жизненного цикла систем."</p></li> +<li><p>"Object-Oriented Analysis and Design with Applications" 3rd edition by Grady Booch, Robert A. Maksimchuk, Michael W. Engle, Bobbi J. Young Ph.D., Jim Conallen, Kelli A. Houston - "Chapter 6. Process"</p></li> +<li><p>"Software Architecture in Practice" 3d edition by Len Bass, Paul Clements, Rick Kazman - "Chapter 15. Architecture in agile projects"</p></li> +<li><p>"Software Architecture in Practice" 4th edition by Len Bass, Paul Clements, Rick Kazman</p></li> +<li><p>"<a class="reference external" href="https://www.amazon.com/Balancing-Agility-Discipline-Guide-Perplexed/dp/0321186125">Balancing Agility and Discipline: A Guide for the Perplexed</a>" by Barry Boehm, Richard Turner</p></li> +<li><p>"Extreme Programming Explained" 1st edition by Kent Beck (именно первое издание) - кто этой книги не читал, тот ничего в Agile не понимает.</p></li> +</ul> +<p>Три превосходные книги Dean Leffingwell:</p> +<ul class="simple"> +<li><p>"Scaling Software Agility: Best Practices for Large Enterprises" by Dean Leffingwell - о проблемах масштабирования команд.</p></li> +<li><p>"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell - о проблемах интегрирования аналитической и архитектурной работы в Agile.</p></li> +<li><p>"SAFe® 5.0: The World's Leading Framework for Business Agility" by Richard Knaster, Dean Leffingwell - наиболее удачная масштабируемая Agile-модель на сегодня.</p></li> +</ul> +<ul class="simple"> +<li><p>"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin - главы 3 и 8 просто необходимы для понимания области применения Scrum. +Очень хорошо в этой книге рассматриваются экономические аспекты разработки - выбор <a class="reference internal" href="uncertainty-management/balancing-prediction-adaptation.html#emacsway-balancing-prediction-adaptation"><span class="std std-ref">Pediction vs. Adaptation</span></a>, влияние <a class="reference internal" href="models/agile/agile.html#emacsway-agile-development-essence"><span class="std std-ref">характера роста стоимости изменения кода (Modifiability)</span></a> на экономическую целесообразность Agile.</p></li> +</ul> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.craiglarman.com/wiki/downloads/misc/history-of-iterative-larman-and-basili-ieee-computer.pdf">Краткая история итеративной разработки</a>" by Craig Larman</p></li> +<li><p>"<a class="reference external" href="https://less.works/less/framework/introduction">LeSS by Craig Larman</a>" - куча полезной информации, которую можно использовать автономно. (<a class="reference external" href="https://less.works/ru/less/framework/introduction">на русском</a>)</p></li> +</ul> +<ul class="simple"> +<li><p>"<a class="reference external" href="https://www.pmi.org/disciplined-agile">Disciplined Agile®</a>"</p></li> +<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/">SAFe - Scaled Agile Framework</a>"</p></li> +</ul> +<p>Нужно заметить, что Software является подмножеством System. +Раньше и Software, и System описывались одним стандартом ISO/IEC 12207:2008. +Потом их разделили на ISO/IEC/IEEE 12207:2017 и ISO/IEC/IEEE 15288:2015.</p> <blockquote> -<div><p>📝 "A good architecture comes from understanding it more as a journey than as a destination, more as an ongoing process of enquiry than as a frozen artifact."</p> -<p class="attribution">—"Clean Architecture: A Craftsman's Guide to Software Structure and Design" by Robert C. Martin</p> +<div><p>📝 "This document has a strong relationship with ISO/IEC/IEEE 15288:2015, Systems and Software Engineering System Life Cycle Processes, and is more applicable to software systems. +To account for situations in which both ISO/IEC/IEEE 15288:2015 and ISO/IEC/IEEE 12207:2017 are applied (e.g., a development of a system containing software, or the development of a software system containing hardware), their process structures are harmonized to be identical. +The processes of this document directly correspond to processes of ISO/IEC/IEEE 15288 with specialization for software products and services."</p> +<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> </div></blockquote> -</section> -<section id="bjarne-stroustrup"> -<h3><a class="toc-backref" href="#id14" role="doc-backlink">Bjarne Stroustrup</a></h3> +Wed, 13 Jul 2022 00:00:00 Code Reviewhttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/agile/practices/collaborative-development/code-review.html +<span id="emacsway-agile-practices-code-review"/> +<p><em>Автор раздела: Ivan Zakrevsky</em></p> +<nav class="contents" id="id1"> +<p class="topic-title">Содержание</p> +<ul class="simple"> +<li><p><a class="reference internal" href="#code-review" id="id4">Code Review</a></p> +<ul> +<li><p><a class="reference internal" href="#id2" id="id5">Возможные результаты Code Review</a></p></li> +<li><p><a class="reference internal" href="#apaptation-vs-prediction" id="id6">Apaptation vs Prediction</a></p></li> +<li><p><a class="reference internal" href="#continuous-review" id="id7">Continuous Review</a></p></li> +</ul> +</li> +</ul> +</nav> +<p>Является ли Code Review эффективной практикой?</p> +<section id="id2"> +<h2><a class="toc-backref" href="#id5" role="doc-backlink">Возможные результаты Code Review</a></h2> +<p>Давайте посмотрим, какие исходы обычно возникают в результате Code Review:</p> +<ol class="arabic"> +<li><p>Когда новый инкремент <a class="reference internal" href="../../../../../../soft-skills/knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">знаний</span></a> получен, тогда возникает:</p> +<ol class="arabic simple"> +<li><p>Конесенсус (обоюдное согласие на едином решении), который формируется, как правило, новым инкрементом знаний, полученным в процессе обсуждения Pull Request.</p></li> +<li><p><a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC">Психологическая защита</a>. Чувство ущербности на фоне грамотного спикера вынуждает специалиста защищать свою зону комфорта и социальное положение путем агрессивных попыток дискредитации носителя неудобных компетенций. Увы, подобные случаи происходили даже в практике достаточно известных авторов по архитектуре. Иными словами, мало знать, нужно уметь еще донести.</p></li> +</ol> +</li> +<li><p>Если знание по своему определению непротиворечиво и способно привести к обоюдному согласию (пусть и не всегда), то недостаток знаний (для качественной аргументации позиции) приводит к соперничеству <a class="reference internal" href="../../../../../../soft-skills/knowledge-vs-opinion.html#emacsway-knowledge-vs-opinion-in-psychology"><span class="std std-ref">мнений</span></a> за лидерство.</p> <blockquote> -<div><p>📝 "I like my code to be elegant and efficient. -The logic should be straightforward to make it hard for bugs to hide, -the dependencies minimal to ease maintenance, error handling complete according to an articulated strategy, -and performance close to optimal so as not to tempt people to make the code messy with unprincipled optimizations. -Clean code does one thing well."</p> -<p class="attribution">—Bjarne Stroustrup, inventor of C++ and author of The C++ Programming Language. -"Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin</p> +<div><p>📝 "Там, где заканчивается <strong>знание</strong>, начинается <strong>мнение</strong>".</p> +<p class="attribution">—"<a class="reference external" href="https://dic.academic.ru/dic.nsf/enc_philosophy/737/%D0%9C%D0%9D%D0%95%D0%9D%D0%98%D0%95">Философия: Энциклопедический словарь.</a>" — М.: Гардарики. Под редакцией А.А. Ивина. 2004.</p> </div></blockquote> +<p>Тогда возникает:</p> +<ol class="arabic simple"> +<li><p><a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%BD%D0%BE%D1%81%D1%82%D1%8C">Внешний конформизм</a>, когда одному из участников Code Review не удалось аргументированно пояснить свою позицию другому, и тот решил прекратить прения, оставшись внутри себя несогласным.</p></li> +<li><p><a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%98%D1%80%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%83%D1%81%D0%B8%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5">Эффект иррационального усиления</a> - когда психологически сложно расстаться с проделанным трудом.</p></li> +</ol> +</li> +</ol> +<p>Во всех перечисленных случаях, кроме первого, это приводит к демотивации и усиливает текучку кадров. Что, в свою очередь вызывает ущерб упущенной выгоды из-за сдвига графика выхода на рынок новых бизнес-фич в результате простаивания незаполненных вакансий, проблемы Брукса (отвлекания опытных специалистов на обучение новых, низкая эффективность новых специалистов из-за недостатка знаний и трат времени на освоение новых знаний), прямые потери (обучение, поиск соискателей) и т.п.</p> +<p>Поскольку ключевым условием достижения консенсуса ревьюера и автора Pull Request является новый инкремент знаний, резонно возникает вопрос: а нужно ли получение этого инкремента привязывать во времени к инспекции уже воплощенной реализации?</p> </section> -<section id="id4"> -<h3><a class="toc-backref" href="#id15" role="doc-backlink">Другие</a></h3> -<blockquote> -<div><p>📝 "Simplicity—the art of maximizing the amount of work not done—is essential."</p> -<p class="attribution">—"<a class="reference external" href="http://agilemanifesto.org/principles.html">Principles behind the Agile Manifesto</a>"</p> -</div></blockquote> -<blockquote> -<div><p>📝 "The design goal for Eventlet's API is simplicity and readability. -You should be able to read its code and understand what it's doing. -Fewer lines of code are preferred over excessively clever implementations."</p> -<p class="attribution">—"<a class="reference external" href="http://eventlet.net/doc/basic_usage.html">Eventlet's docs</a>"</p> -</div></blockquote> -<blockquote> -<div><p>📝 "Будьте скромны, не считайте себя супергением — это ваша первая ошибка. -Оставаясь скромным, вы в конечном итоге достигнете уровня супергения, и даже если нет, какая разница. -Ваш код должен быть прост настолько, что вам не нужно быть гением, чтобы работать с ним.</p> -<p>Be Humble, don't think of yourself as a super genius, this is your first mistake. -By being humble, you will eventually achieve super genius status =), and even if you don't, who cares! -your code is stupid simple, so you don't have to be a genius to work with it."</p> -<p class="attribution">—"<a class="reference external" href="https://people.apache.org/~fhanik/kiss.html">KISS principle</a>"</p> -</div></blockquote> -<blockquote> -<div><p>📝 "Когда кто-либо привязывается к одной какой-нибудь, хотя бы и верной, идее, то он, в сущности, попадает в то же положение, в каком находился бы человек, привязавший себя к столбу, для того чтобы не заблудиться. -То, что может быть желанной истиной на известной ступени духовного роста, может быть помехой к этому росту и заблуждением на другой, более высокой ступени."</p> -<p class="attribution">—Люси Малори</p> -</div></blockquote> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> -<ul class="simple"> -<li><p>"<a class="reference internal" href="../../../../../soft-skills/icebreaker-principle.html#emacsway-icebreaker-principle"><span class="std std-ref">Принцип ледокола</span></a>"</p></li> -<li><p>"<a class="reference internal" href="software-design.html#emacsway-agile-software-design"><span class="std std-ref">Role of Software Design in Agile</span></a>"</p></li> -<li><p>"<a class="reference internal" href="patterns.html#emacsway-agile-patterns"><span class="std std-ref">Role of Design Patterns in Agile</span></a>"</p></li> -</ul> -</div> +<section id="apaptation-vs-prediction"> +<h2><a class="toc-backref" href="#id6" role="doc-backlink">Apaptation vs Prediction</a></h2> +<p>Можно еще провести такую аналогию: Code Review - это форма инспекции и адаптации, т.е. эмпирический (опытный) способ обработки неопределенности. Это сродни хождению на ощуп. Куда-то добраться таким образом можно, но происпектировать таким образом можно только то, что можно потрогать, т.е. когда "уже пришли".</p> +<p>Процесс можно сделать эффективней, если расширить горизонт "видения", т.е. внести определенную долю Prediction-активности, и получение основного инкремента знаний перенести с Code Review на Design Review. +Как говорится, когда ты за рулем, то уже поздно читать инструкцию по вождению. +Очень хорошо эту мысль раскрывает "<a class="reference external" href="https://www.youtube.com/watch?v=Nf431Upix3M">Эксперимент с красными бусинками - Dr. Deming's Red Bead Experiment</a>".</p> +<p>Тут возникает вопрос о том, как достигнуть Design наименьшими трудозатратами, и именно эту проблему хорошо решает Event Storming, т.к. его можно осуществлять прямо в процессе обсуждения.</p> </section> +<section id="continuous-review"> +<h2><a class="toc-backref" href="#id7" role="doc-backlink">Continuous Review</a></h2> +<p>Можно еще обратиться к народной пословице о том, что лучше один раз увидеть, чем сто раз услышать. +Т.е. использовать Continuous Review (Pair Programming, Mobbing Programming).</p> +<p>Вопрос не в том, чтобы исключить Code Review, а в том, чтобы уменьшить его негативные последствия путем добавления других форм передачи инкремента знаний.</p> +<figure class="align-left" id="id3"> +<a class="reference internal image-reference" href="../../../../../../../_images/code-review-reason.png"><img alt="Диаграмма причин и способов проведения Code Review" src="../../../../../../../_images/code-review-reason.png" style="width: 90%;"/></a> +<figcaption> +<p><span class="caption-text">Когда-то делал на скорую руку диаграмму причин и форм проведения Code Review. Жалко выбрасывать, решил поделиться. <a class="reference download internal" download="" href="../../../../../../../_downloads/c86e4ec31cbc282fd144c5c7453f9cba/code-review-reason.archimate"><code class="xref download docutils literal notranslate"><span class="pre">Исходная</span> <span class="pre">модель</span></code></a>.</span></p> +</figcaption> +</figure> </section> -Fri, 01 Jul 2022 00:00:00 Несовпадение фаз спиралей обученияhttps://dckms.github.io/system-architecture/emacsway/soft-skills/learning-spiral-phase-mismatch.html<span class="target" id="index-0"/><section id="emacsway-learning-spiral-phase-mismatch"> +Tue, 12 Jul 2022 00:00:00 Несовпадение фаз спиралей обученияhttps://dckms.github.io/system-architecture/emacsway/soft-skills/learning-spiral-phase-mismatch.html<span class="target" id="index-0"/><section id="emacsway-learning-spiral-phase-mismatch"> <span id="id1"/> <p><em>Автор раздела: Ivan Zakrevsky</em></p> <nav class="contents" id="id2"> @@ -11909,153 +12155,7 @@ As Polya recommended in mathematical problem solving, understand the problem, de </div> </section> </section> -Thu, 27 Jan 2022 00:00:00 Agile Requirementshttps://dckms.github.io/system-architecture/emacsway/it/sdlc/models/agile/analysis/requirements/requirements.html -<span id="emacsway-agile-requirements"/> -<p><em>Автор раздела: Ivan Zakrevsky</em></p> -<nav class="contents" id="id1"> -<p class="topic-title">Содержание</p> -<ul class="simple"> -<li><p><a class="reference internal" href="#agile-requirements" id="id4">Agile Requirements</a></p> -<ul> -<li><p><a class="reference internal" href="#id2" id="id5">Что такое требование</a></p></li> -<li><p><a class="reference internal" href="#product-backlog-item-requirements" id="id6">Product Backlog Item и Requirements</a></p></li> -<li><p><a class="reference internal" href="#user-story-requirements" id="id7">Почему User Story, а не Requirements</a></p></li> -<li><p><a class="reference internal" href="#emacsway-agile-requirements-literature" id="id8">Литература про Agile-requirements</a></p></li> -</ul> -</li> -</ul> -</nav> -<section id="id2"> -<h2><a class="toc-backref" href="#id5" role="doc-backlink">Что такое требование</a></h2> -<p>Следует различать значения терминов <strong>needs</strong>, <strong>requirements</strong> и <strong>specification</strong>. -Вопросы возникают, как правило, там, где их не различают, и под требованиями зачастую понимают System Requirements Specification (SyRS), на который распространяется стандарт "ISO/IEC/IEEE 29148:2018 Systems and software engineering - Life cycle processes - Requirements engineering".</p> -<p>Однако, на сами требования распространяются стандарты SDLC:</p> -<ul class="simple"> -<li><p>"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p></li> -<li><p>"ISO/IEC/IEEE 15288:2015 Systems and software engineering - System life cycle processes"</p></li> -</ul> -<p>Итак, что такое требование:</p> -<blockquote> -<div><p>📝 "<strong>requirement</strong> - statement that translates or expresses a need and its associated constraints and conditions. -[SOURCE: ISO/IEC/IEEE 29148:2011, modified, NOTE has been removed.]"</p> -<p class="attribution">—"ISO/IEC/IEEE 12207:2017 Systems and software engineering - Software life cycle processes"</p> -</div></blockquote> -<p>Это все. Ни больше, ни меньше.</p> -</section> -<section id="product-backlog-item-requirements"> -<span id="emacsway-product-backlog-item"/><h2><a class="toc-backref" href="#id6" role="doc-backlink">Product Backlog Item и Requirements</a></h2> -<p>Какая связь между Product Backlog Item и Requirements?</p> -<blockquote> -<div><p>📝 "In the Scrum framework a <strong>product backlog</strong> lists all of the <strong>requirements</strong> for a solution, including both <strong>customer and technical requirements</strong>."</p> -<p class="attribution">—Agile Extension to the BABOK® Guide version 1 (obsolete, на момент написания статьи)</p> -</div></blockquote> -<blockquote> -<div><p>📝 "<strong>Backlog Item</strong> - An item on the backlog which represents one or more <strong>requirements</strong>.</p> -<p>&lt;...&gt;</p> -<p><strong>User Stories</strong> are used to convey a customer <strong>requirement</strong> for the delivery team."</p> -<p class="attribution">—Agile Extension to the BABOK® Guide version 2 (actual, на момент написания статьи)</p> -</div></blockquote> -<p>Актуальная версия Agile-расширения BABoK (на момент написания статьи) - вторая, хотя актуальная версия самого BABoK - третья.</p> -<blockquote> -<div><p>📝 "The <strong>Product Backlog</strong> is a list of <strong>functional and nonfunctional requirements</strong> that, when turned into functionality, will deliver this vision."</p> -<p class="attribution">—"Agile Project Management with Scrum" by Ken Schwaber</p> -</div></blockquote> -<blockquote> -<div><p>📝 "Agile projects generally maintain <strong>requirements</strong> in the form of user stories in a <strong>product backlog</strong>."</p> -<p class="attribution">—"Software Requirements (Developer Best Practices)" 3rd Edition by Karl Wiegers</p> -</div></blockquote> -<blockquote> -<div><p>📝 "Instead of compiling a large inventory of detailed <strong>requirements</strong> up front, we create placeholders for the <strong>requirements</strong>, called <strong>product backlog items (PBIs)</strong>"</p> -<p class="attribution">—"Essential Scrum: A Practical Guide to the Most Popular Agile Process" by Kenneth Rubin</p> -</div></blockquote> -<blockquote> -<div><p>📝 "XP- originated "<strong>user story</strong>" as the primary currency for expressing application <strong>requirements</strong>."</p> -<p>📝 "<strong>User stories</strong> are the agile replacement for most of what has been traditionally expressed as software <strong>requirements</strong> statements (or use cases in RUP and UML), and they are the workhorses of agile development."</p> -<p class="attribution">—"Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise" by Dean Leffingwell</p> -</div></blockquote> -<p>И есть у него еще такой <a class="reference external" href="https://scalingsoftwareagility.files.wordpress.com/2007/03/a-lean-and-scalable-requirements-information-model-for-agile-enterprises-pdf.pdf">документ</a>, который прекрасно раскрывает связь между требованиями и PBI.</p> -<blockquote> -<div><p>📝 "<strong>User Story</strong>: agile software development practice from Extreme Programming to express <strong>requirements</strong> from an end user perspective, emphasizing verbal communication. -In Scrum, it is often used to express functional items on the Product Backlog."</p> -<p class="attribution">—Официальный сайт Ken Schwaber, <a class="reference external" href="https://www.scrum.org/resources/professional-scrum-developer-glossary">glossary</a></p> -</div></blockquote> -<blockquote> -<div><p>📝 "The agile approach to <strong>requirements</strong> is based on <strong>user stories</strong>: units of functionality corresponding to interactions of users with the system."</p> -<p class="attribution">—"Agile! The Good, the Hype and the Ugly" by Bertrand Meyer</p> -</div></blockquote> -<p>У Mike Cohn есть прекрасная статья на тему, чем отличается User Story от других способов документирования требований, и начинается она со слов:</p> -<blockquote> -<div><p>📝 "Extreme programming (XP) introduced the practice of expressing <strong>requirements</strong> in the form of <strong>user stories</strong>"</p> -<p class="attribution">—"<a class="reference external" href="https://www.mountaingoatsoftware.com/articles/advantages-of-user-stories-for-requirements">Advantages of User Stories for Requirements</a>" by Mike Cohn</p> -</div></blockquote> -</section> -<section id="user-story-requirements"> -<span id="emacsway-user-story"/><h2><a class="toc-backref" href="#id7" role="doc-backlink">Почему User Story, а не Requirements</a></h2> -<p>Kent Beck разъясняет, почему он использовал термин Story вместо Requirements. -Ключевым аргументом здесь выступает семантическое различие - требования переменны, а не константны. -А так же то, что полнота требований недостижима.</p> -<blockquote> -<div><p>📝 "Software development has been steered wrong by the word "requirement", defined in the dictionary as "something mandatory or obligatory." -The word carries a connotation of absolutism and permanence, inhibitors to embracing change. -And the word "requirement" is just plain wrong. -Out of one thousand pages of "requirements", if you deploy a system with the right 20% or 10% or even 5%, you will likely realize all of the business benefit envisioned for the whole system. -So what were the other 80%? Not "requirements"; they weren't really mandatory or obligatory.</p> -<p><strong>Early estimation is a key difference between stories and other requirements practices.</strong> -Estimation gives the business and technical perspectives a chance to interact, which creates value early, when an idea has the most potential. -When the team knows the cost of features it can split, combine, or extend scope based on what it knows about the features' value."</p> -<p class="attribution">—"Extreme Programming Explained" 2nd edition by Kent Beck</p> -</div></blockquote> -<p>Bertrand Meyer о том, в чем отличия между User Story и Requirements. -Обратите внимание, Bertrand Meyer, как и Kent Beck, так же делает акцент на недостижимость полноты требований, и указывает на семантическое отличие термина Requirements по своему смыслу, хотя по стандарту итеративная разработка освобождается от полноты требований (и даже предназначается для её разрешения).</p> -<blockquote> -<div><p>📝 "Agile development accepts change. -In software projects, full requirements cannot be determined at the beginning; needs emerge as the project develops, and evolve as customers and others try intermediate releases. -Such change is considered a normal part of the development process.</p> -<p>&lt;...&gt;</p> -<p>The last principle gives us the second part of the replacement for requirements: use scenarios to define functionality. -A scenario is a description of a particular interaction of a user with the system, for example (if we are building mobile phone software) a phone conversation from the time the caller dials the number to the time the two parties get disconnected. -"Scenario" is not a common agile term, but covers variants such as use cases and user stories which differ by their level of granularity (a use case is a complete interaction, a user story an application of a smaller unit of functionality). -Scenarios are obtained from customers and indicate the fundamental properties of the system's functionality as seen from the user perspective. -Collecting scenarios, usually in the form of user stories, is the principal agile technique for requirements; it differs from traditional requirements elicitation in two fundamental ways:</p> -<ul class="simple"> -<li><p>A scenario is just one example; unlike requirements, it cannot lay claim to completeness. A set of scenarios, however large, cannot come even close to achieving this goal, in the same way that no number of tests of a program can replace a specification.</p></li> -<li><p>In agile development, requirements are not collected at the beginning of the project but throughout, as development progresses. Note, however, that this difference is not as absolute as the agile literature suggests when it blasts "waterfall approaches": while the traditional software engineering view presents requirements as a specific lifecycle step, coming early in the process, it does not rule out — except in the imagination of agile authors — a scheme in which the requirements are constantly updated in the rest of the lifecycle.</p></li> -</ul> -<p>&lt;...&gt;</p> -<p>The agile approach to requirements is based on user stories: units of functionality corresponding to interactions of users with the system.</p> -<p>&lt;...&gt;</p> -<p>We note once again the confusion inherent in such agile criticism as Beck's comment that "Requirements gathering isn't a phase that produces a static document", as if having a requirements phase implied that the resulting requirements document will be static. -The two matters are separate."</p> -<p class="attribution">—"Agile! The Good, the Hype and the Ugly" by Bertrand Meyer</p> -</div></blockquote> -<p>Подведем итог: требование в условиях недостаточной полноты требований, которое может быть изменено по мере снижения уровня неопределенности, традиционно называется User Story или PBI. -В таком случае требования уточняются по мере снижения уровня неопределенности, что является базовым принципом <a class="reference internal" href="../../../iterative.html#emacsway-iterative-development"><span class="std std-ref">итеративной модели</span></a> разработки.</p> -</section> -<section id="emacsway-agile-requirements-literature"> -<span id="id3"/><h2><a class="toc-backref" href="#id8" role="doc-backlink">Литература про Agile-requirements</a></h2> -<ul class="simple"> -<li><p>"<a class="reference external" href="https://www.ireb.org/content/downloads/22-cpre-advanced-level-re-agile-handbook/handbook_cpre_al_re%40agile_en_v1.0.2.pdf">Handbook of RE@Agile According to the IREB Standard Education and Training for IREB Certified Professional for Requirements Engineering Advanced Level RE@Agile</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.pmi.org/pmbok-guide-standards/practice-guides/agile">Agile Practice Guide</a>" by Project Management Institute, 2017</p></li> -<li><p>"Agile Extension to the BABOK® Guide" version 2 (actual, на момент написания статьи)</p></li> -<li><p>"<a class="reference external" href="https://www.amazon.com/Agile-Software-Requirements-Enterprise-Development/dp/0321635841">Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise</a>" by Dean Leffingwell.</p></li> -<li><p>"Software Requirements (Developer Best Practices)" 3rd Edition by Karl Wiegers</p></li> -<li><p>"<a class="reference external" href="https://scalingsoftwareagility.wordpress.com/2010/03/05/an-agile-architectural-epic-kanban-system-part-2-%E2%80%93-the-model/">An Agile Architectural Epic Kanban System: Part 2 – The Model</a>" by Dean Leffingwell</p></li> -<li><p>"<a class="reference external" href="https://scalingsoftwareagility.files.wordpress.com/2007/03/a-lean-and-scalable-requirements-information-model-for-agile-enterprises-pdf.pdf">A Lean and Scalable Requirements Information Model for the Agile Enterprise</a>" by Dean Leffingwell with Juha‐Markus Aalto</p></li> -</ul> -<p>См. также:</p> -<ul class="simple"> -<li><p>"<a class="reference external" href="http://agilemodeling.com/artifacts/#Requirements">Agile Modeling :: Requirements-Analysis Models</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.scaledagileframework.com/safe-requirements-model/">SAFe Requirements Model</a>"</p></li> -<li><p>"<a class="reference external" href="https://www.ireb.org/en/downloads/tag:handbook">Library of IREB artifacts</a>"</p></li> -</ul> -<div class="admonition seealso"> -<p class="admonition-title">См.также</p> -<ul class="simple"> -<li><p>"<a class="reference internal" href="../../../../uncertainty-management/adaptation/adaptation.html#emacsway-adaptation"><span class="std std-ref">Что такое Adaptation</span></a>"</p></li> -</ul> -</div> -</section> -Wed, 26 Jan 2022 00:00:00 Кристаллизация знаний. Как читать и не превратиться в коллекционера информации.https://dckms.github.io/system-architecture/emacsway/soft-skills/learning.html<span class="target" id="index-0"/><section id="emacsway-learning-in-psychology"> +Thu, 27 Jan 2022 00:00:00 Кристаллизация знаний. Как читать и не превратиться в коллекционера информации.https://dckms.github.io/system-architecture/emacsway/soft-skills/learning.html<span class="target" id="index-0"/><section id="emacsway-learning-in-psychology"> <span id="id1"/> <p><em>Автор раздела: Ivan Zakrevsky</em></p> <p>Иногда у меня спрашивают, как мне удается запоминать так много информации. diff --git a/searchindex.js b/searchindex.js index 7e4238d2..ef9ecaf7 100644 --- a/searchindex.js +++ b/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["README", "emacsway/index", "emacsway/it/concurrency/index", "emacsway/it/concurrency/saga", "emacsway/it/concurrency/transaction", "emacsway/it/ddd/ddd-in-practice/event-storming/archi", "emacsway/it/ddd/ddd-in-practice/event-storming/index", "emacsway/it/ddd/ddd-in-practice/index", "emacsway/it/ddd/grade/domain/aggregate-boundaries", "emacsway/it/ddd/grade/domain/aggregate-encapsulation", "emacsway/it/ddd/grade/domain/event-sourcing", "emacsway/it/ddd/grade/domain/file-structure", "emacsway/it/ddd/grade/domain/index", "emacsway/it/ddd/grade/domain/shotgun-surgery", "emacsway/it/ddd/grade/domain/specification", "emacsway/it/ddd/grade/domain/why-no-can-execute", "emacsway/it/ddd/grade/index", "emacsway/it/ddd/grade/infrastructure/index", "emacsway/it/ddd/grade/infrastructure/repository", "emacsway/it/ddd/index", "emacsway/it/ddd/strategic-design/index", "emacsway/it/ddd/tactical-design/cqrs/cqrs-command-and-result", "emacsway/it/ddd/tactical-design/cqrs/index", "emacsway/it/ddd/tactical-design/domain-model/domain-events/domain-events-in-ddd", "emacsway/it/ddd/tactical-design/domain-model/domain-events/index", "emacsway/it/ddd/tactical-design/domain-model/index", "emacsway/it/ddd/tactical-design/domain-model/value-objects/immutability", "emacsway/it/ddd/tactical-design/domain-model/value-objects/index", "emacsway/it/ddd/tactical-design/index", "emacsway/it/ddd/tactical-design/repository/anticorruption-layer", "emacsway/it/ddd/tactical-design/repository/causal-consistency", "emacsway/it/ddd/tactical-design/repository/index", "emacsway/it/index", "emacsway/it/integration/asynchronous/index", "emacsway/it/integration/asynchronous/message-ordering-in-competing-consumers", "emacsway/it/integration/index", "emacsway/it/sdlc/index", "emacsway/it/sdlc/models/agile/agile", "emacsway/it/sdlc/models/agile/analysis/concerns/balancing-business-technical-concerns", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/architecture-options", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/common-planning-errors", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/compound-interest", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/developer-motivation", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/index", "emacsway/it/sdlc/models/agile/analysis/concerns/index", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/index", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/when-to-refactor", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/when-to-write-unit-tests", "emacsway/it/sdlc/models/agile/analysis/index", "emacsway/it/sdlc/models/agile/analysis/requirements/documenting", "emacsway/it/sdlc/models/agile/analysis/requirements/index", "emacsway/it/sdlc/models/agile/analysis/requirements/nonfunctional-requirements", "emacsway/it/sdlc/models/agile/analysis/requirements/requirements", "emacsway/it/sdlc/models/agile/analysis/requirements/requirements-criteria", "emacsway/it/sdlc/models/agile/index", "emacsway/it/sdlc/models/agile/particular/index", "emacsway/it/sdlc/models/agile/practices/collaborative-development/code-review", "emacsway/it/sdlc/models/agile/practices/collaborative-development/index", "emacsway/it/sdlc/models/agile/practices/index", "emacsway/it/sdlc/models/evolutionary", "emacsway/it/sdlc/models/incremental", "emacsway/it/sdlc/models/index", "emacsway/it/sdlc/models/iterative", "emacsway/it/sdlc/models/spiral", "emacsway/it/sdlc/sdlc-reference", "emacsway/it/sdlc/uncertainty-management/adaptation/adaptation", "emacsway/it/sdlc/uncertainty-management/adaptation/crash-course-in-software-development-economics", "emacsway/it/sdlc/uncertainty-management/adaptation/index", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/borrowing-trouble", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/index", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/index", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/patterns", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/software-design", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/solid", "emacsway/it/sdlc/uncertainty-management/balancing-prediction-adaptation", "emacsway/it/sdlc/uncertainty-management/balancing-top-down-bottom-up-design-approaches", "emacsway/it/sdlc/uncertainty-management/index", "emacsway/it/sdlc/uncertainty-management/prediction/index", "emacsway/it/sdlc/uncertainty-management/prediction/prediction", "emacsway/it/self-education/index", "emacsway/it/self-education/self-education-for-software-engineer", "emacsway/it/self-education/success-roadmap", "emacsway/it/tdd/index", "emacsway/it/tdd/tdd", "emacsway/it/team-topologies/harlan-mills'-proposal", "emacsway/it/team-topologies/index", "emacsway/soft-skills/change-making", "emacsway/soft-skills/cognitive-biases", "emacsway/soft-skills/icebreaker-principle", "emacsway/soft-skills/index", "emacsway/soft-skills/knowledge-vs-opinion", "emacsway/soft-skills/learning", "emacsway/soft-skills/learning-spiral-phase-mismatch", "emacsway/soft-skills/planning-in-psychology", "index", "ivan.ivanov/index", "private/index", "stanislav.bolsun/index", "stanislav.bolsun/it/ddd/domain-model/domain-model-definition", "stanislav.bolsun/it/ddd/domain-model/index", "stanislav.bolsun/it/ddd/domain-model/language-context", "stanislav.bolsun/it/ddd/index", "stanislav.bolsun/it/index", "trunk/index", "trunk/it/concurrency/index", "trunk/it/ddd/ddd-in-practice/event-storming/index", "trunk/it/ddd/ddd-in-practice/index", "trunk/it/ddd/index", "trunk/it/ddd/strategic-design/index", "trunk/it/ddd/tactical-design/cqrs/index", "trunk/it/ddd/tactical-design/domain-model/domain-events/index", "trunk/it/ddd/tactical-design/domain-model/index", "trunk/it/ddd/tactical-design/domain-model/value-objects/index", "trunk/it/ddd/tactical-design/index", "trunk/it/ddd/tactical-design/repository/index", "trunk/it/index", "trunk/it/integration/asynchronous/index", "trunk/it/integration/index", "trunk/it/sdlc/index", "trunk/it/sdlc/models/agile/analysis/concerns/business-concerns/index", "trunk/it/sdlc/models/agile/analysis/concerns/index", "trunk/it/sdlc/models/agile/analysis/concerns/technical-concerns/index", "trunk/it/sdlc/models/agile/analysis/index", "trunk/it/sdlc/models/agile/analysis/requirements/index", "trunk/it/sdlc/models/agile/index", "trunk/it/sdlc/models/agile/practices/collaborative-development/index", "trunk/it/sdlc/models/agile/practices/index", "trunk/it/sdlc/models/index", "trunk/it/sdlc/uncertainty-management/adaptation/index", "trunk/it/sdlc/uncertainty-management/adaptation/software-construction/index", "trunk/it/sdlc/uncertainty-management/adaptation/software-design/index", "trunk/it/sdlc/uncertainty-management/index", "trunk/it/sdlc/uncertainty-management/prediction/index", "trunk/it/self-education/index", "trunk/it/tdd/index", "trunk/it/team-topologies/index", "trunk/soft-skills/index"], "filenames": ["README.rst", "emacsway/index.rst", "emacsway/it/concurrency/index.rst", "emacsway/it/concurrency/saga.rst", "emacsway/it/concurrency/transaction.rst", "emacsway/it/ddd/ddd-in-practice/event-storming/archi.rst", "emacsway/it/ddd/ddd-in-practice/event-storming/index.rst", "emacsway/it/ddd/ddd-in-practice/index.rst", "emacsway/it/ddd/grade/domain/aggregate-boundaries.rst", "emacsway/it/ddd/grade/domain/aggregate-encapsulation.rst", "emacsway/it/ddd/grade/domain/event-sourcing.rst", "emacsway/it/ddd/grade/domain/file-structure.rst", "emacsway/it/ddd/grade/domain/index.rst", "emacsway/it/ddd/grade/domain/shotgun-surgery.rst", "emacsway/it/ddd/grade/domain/specification.rst", "emacsway/it/ddd/grade/domain/why-no-can-execute.rst", "emacsway/it/ddd/grade/index.rst", "emacsway/it/ddd/grade/infrastructure/index.rst", "emacsway/it/ddd/grade/infrastructure/repository.rst", "emacsway/it/ddd/index.rst", "emacsway/it/ddd/strategic-design/index.rst", "emacsway/it/ddd/tactical-design/cqrs/cqrs-command-and-result.rst", "emacsway/it/ddd/tactical-design/cqrs/index.rst", "emacsway/it/ddd/tactical-design/domain-model/domain-events/domain-events-in-ddd.rst", "emacsway/it/ddd/tactical-design/domain-model/domain-events/index.rst", "emacsway/it/ddd/tactical-design/domain-model/index.rst", "emacsway/it/ddd/tactical-design/domain-model/value-objects/immutability.rst", "emacsway/it/ddd/tactical-design/domain-model/value-objects/index.rst", "emacsway/it/ddd/tactical-design/index.rst", "emacsway/it/ddd/tactical-design/repository/anticorruption-layer.rst", "emacsway/it/ddd/tactical-design/repository/causal-consistency.rst", "emacsway/it/ddd/tactical-design/repository/index.rst", "emacsway/it/index.rst", "emacsway/it/integration/asynchronous/index.rst", "emacsway/it/integration/asynchronous/message-ordering-in-competing-consumers.rst", "emacsway/it/integration/index.rst", "emacsway/it/sdlc/index.rst", "emacsway/it/sdlc/models/agile/agile.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/balancing-business-technical-concerns.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/architecture-options.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/common-planning-errors.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/compound-interest.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/developer-motivation.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/index.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/index.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/index.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/when-to-refactor.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/when-to-write-unit-tests.rst", "emacsway/it/sdlc/models/agile/analysis/index.rst", "emacsway/it/sdlc/models/agile/analysis/requirements/documenting.rst", "emacsway/it/sdlc/models/agile/analysis/requirements/index.rst", "emacsway/it/sdlc/models/agile/analysis/requirements/nonfunctional-requirements.rst", "emacsway/it/sdlc/models/agile/analysis/requirements/requirements.rst", "emacsway/it/sdlc/models/agile/analysis/requirements/requirements-criteria.rst", "emacsway/it/sdlc/models/agile/index.rst", "emacsway/it/sdlc/models/agile/particular/index.rst", "emacsway/it/sdlc/models/agile/practices/collaborative-development/code-review.rst", "emacsway/it/sdlc/models/agile/practices/collaborative-development/index.rst", "emacsway/it/sdlc/models/agile/practices/index.rst", "emacsway/it/sdlc/models/evolutionary.rst", "emacsway/it/sdlc/models/incremental.rst", "emacsway/it/sdlc/models/index.rst", "emacsway/it/sdlc/models/iterative.rst", "emacsway/it/sdlc/models/spiral.rst", "emacsway/it/sdlc/sdlc-reference.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/crash-course-in-software-development-economics.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/index.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/borrowing-trouble.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/index.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/index.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/patterns.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/software-design.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/solid.rst", "emacsway/it/sdlc/uncertainty-management/balancing-prediction-adaptation.rst", "emacsway/it/sdlc/uncertainty-management/balancing-top-down-bottom-up-design-approaches.rst", "emacsway/it/sdlc/uncertainty-management/index.rst", "emacsway/it/sdlc/uncertainty-management/prediction/index.rst", "emacsway/it/sdlc/uncertainty-management/prediction/prediction.rst", "emacsway/it/self-education/index.rst", "emacsway/it/self-education/self-education-for-software-engineer.rst", "emacsway/it/self-education/success-roadmap.rst", "emacsway/it/tdd/index.rst", "emacsway/it/tdd/tdd.rst", "emacsway/it/team-topologies/harlan-mills'-proposal.rst", "emacsway/it/team-topologies/index.rst", "emacsway/soft-skills/change-making.rst", "emacsway/soft-skills/cognitive-biases.rst", "emacsway/soft-skills/icebreaker-principle.rst", "emacsway/soft-skills/index.rst", "emacsway/soft-skills/knowledge-vs-opinion.rst", "emacsway/soft-skills/learning.rst", "emacsway/soft-skills/learning-spiral-phase-mismatch.rst", "emacsway/soft-skills/planning-in-psychology.rst", "index.rst", "ivan.ivanov/index.rst", "private/index.rst", "stanislav.bolsun/index.rst", "stanislav.bolsun/it/ddd/domain-model/domain-model-definition.rst", "stanislav.bolsun/it/ddd/domain-model/index.rst", "stanislav.bolsun/it/ddd/domain-model/language-context.rst", "stanislav.bolsun/it/ddd/index.rst", "stanislav.bolsun/it/index.rst", "trunk/index.rst", "trunk/it/concurrency/index.rst", "trunk/it/ddd/ddd-in-practice/event-storming/index.rst", "trunk/it/ddd/ddd-in-practice/index.rst", "trunk/it/ddd/index.rst", "trunk/it/ddd/strategic-design/index.rst", "trunk/it/ddd/tactical-design/cqrs/index.rst", "trunk/it/ddd/tactical-design/domain-model/domain-events/index.rst", "trunk/it/ddd/tactical-design/domain-model/index.rst", "trunk/it/ddd/tactical-design/domain-model/value-objects/index.rst", "trunk/it/ddd/tactical-design/index.rst", "trunk/it/ddd/tactical-design/repository/index.rst", "trunk/it/index.rst", "trunk/it/integration/asynchronous/index.rst", "trunk/it/integration/index.rst", "trunk/it/sdlc/index.rst", "trunk/it/sdlc/models/agile/analysis/concerns/business-concerns/index.rst", "trunk/it/sdlc/models/agile/analysis/concerns/index.rst", "trunk/it/sdlc/models/agile/analysis/concerns/technical-concerns/index.rst", "trunk/it/sdlc/models/agile/analysis/index.rst", "trunk/it/sdlc/models/agile/analysis/requirements/index.rst", "trunk/it/sdlc/models/agile/index.rst", "trunk/it/sdlc/models/agile/practices/collaborative-development/index.rst", "trunk/it/sdlc/models/agile/practices/index.rst", "trunk/it/sdlc/models/index.rst", "trunk/it/sdlc/uncertainty-management/adaptation/index.rst", "trunk/it/sdlc/uncertainty-management/adaptation/software-construction/index.rst", "trunk/it/sdlc/uncertainty-management/adaptation/software-design/index.rst", "trunk/it/sdlc/uncertainty-management/index.rst", "trunk/it/sdlc/uncertainty-management/prediction/index.rst", "trunk/it/self-education/index.rst", "trunk/it/tdd/index.rst", "trunk/it/team-topologies/index.rst", "trunk/soft-skills/index.rst"], "titles": ["\u041a\u0430\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f", "\u041f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e Emacsway", "Concurrency", "SAGA", "Transaction", "Event Storming with Archi", "Event Storming", "DDD in practice", "\u041f\u043e\u0438\u0441\u043a \u0433\u0440\u0430\u043d\u0438\u0446 \u0410\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0432", "\u041a\u0430\u043a \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0410\u0433\u0440\u0435\u0433\u0430\u0442 \u0432 \u0411\u0414 \u043d\u0435 \u0440\u0430\u0437\u0440\u0443\u0448\u0430\u044f \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u044f\u0446\u0438\u0438?", "Event Sourcing", "\u0424\u0430\u0439\u043b\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0414\u043e\u043c\u0435\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438", "Domain Layer", "Shotgun Surgery", "Specification in Golang", "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u0438 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 CanExecute pattern?", "Golang DDD (CQRS / Event Sourcing) Reference Application "Grade"", "Infrastructure", "Repository in Golang", "DDD", "Strategic design", "\u041c\u043e\u0436\u0435\u0442 \u043b\u0438 CQRS-\u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442?", "CQRS", "Domain Events in DDD", "Domain Events", "Domain Model", "Immutability", "Value Objects", "Tactical design", "Repository and Anticorruption Layer", "Repository and Causal Consistency", "Repository", "IT", "Asynchronous communication", "\u041e \u0433\u043e\u043d\u043a\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 \u043a\u043e\u043d\u043a\u0443\u0440\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u0432", "Integration", "SDLC", "\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Agile Development", "\u0411\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0411\u0438\u0437\u043d\u0435\u0441/\u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432", "Architecture: Selling Options", "\u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0447\u0430\u0441\u0442\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f", "Technical Debt \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u043d\u0442", "\u041c\u043e\u0442\u0438\u0432\u0430\u0446\u0438\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432", "\u0411\u0438\u0437\u043d\u0435\u0441-\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u044b", "\u0421oncerns in Agile", "\u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u044b", "\u041a\u043e\u0433\u0434\u0430 \u0434\u0435\u043b\u0430\u0442\u044c refactoring \u0432 legacy", "\u041a\u043e\u0433\u0434\u0430 \u043f\u0438\u0441\u0430\u0442\u044c Unit Tests \u0432 legacy", "Analysis in Agile", "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 Agile Requirements", "Requirements in Agile", "Agile nonfunctional Requirements", "Agile Requirements", "\u041a\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 Agile Requirements", "Agile", "Particular Agile Models", "Code Review", "Collaborative Development", "Agile Practices", "Evolutionary Development", "Incremental Development", "SDLC-Models", "Iterative Development", "Spiral Development", "Systems Development Life Cycle (SDLC) Reference", "\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Adaptation", "\u041a\u0440\u0430\u0442\u043a\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u043a\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f", "Adaptation", "Borrowing trouble", "Software Construction", "YAGNI", "Software Design", "Role of Design Patterns in Agile", "Role of Simplicity in Agile", "Role of Software Design in Agile", "Role of SOLID principles in Agile", "Balancing Prediction/Adaptation", "Balancing Top-Down/Bottom-Up Design Approaches", "\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e", "Prediction", "\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Prediction", "\u0421\u0430\u043c\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435", "\u0421\u043f\u0438\u0441\u043e\u043a \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u0441\u0430\u043c\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f", "\u041a\u0430\u043a \u0441\u0442\u0430\u0442\u044c \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c", "TDD", "TDD - \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435", "\u0420\u043e\u043b\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0432 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434, DDD \u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445", "Team Topologies", "\u041a\u0430\u043a \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432\u0435", "\u0421\u043f\u0438\u0441\u043e\u043a \u043f\u0441\u0438\u0445\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432", "\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u043b\u0435\u0434\u043e\u043a\u043e\u043b\u0430", "Soft Skills", "\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u043d\u0430 \u043f\u043e\u0447\u0432\u0435 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0430 \u0437\u043d\u0430\u043d\u0438\u0439", "\u041a\u0440\u0438\u0441\u0442\u0430\u043b\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0437\u043d\u0430\u043d\u0438\u0439. \u041a\u0430\u043a \u0447\u0438\u0442\u0430\u0442\u044c \u0438 \u043d\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u0432 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u043e\u043d\u0435\u0440\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438.", "\u041d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u0444\u0430\u0437 \u0441\u043f\u0438\u0440\u0430\u043b\u0435\u0439 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f", "\u041f\u0441\u0438\u0445\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f", "System Architecture", "\u041f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0418\u0432\u0430\u043d\u0430 \u0418\u0432\u0430\u043d\u043e\u0432\u0430", "\u041f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e", "\u041f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0421\u0442\u0430\u043d\u0438\u0441\u043b\u0430\u0432\u0430 \u0411\u043e\u043b\u0441\u0443\u043d\u0430", "Domain Model Definition", "Domain Model", "Language Context Definition", "DDD", "IT", "\u041e\u0431\u0449\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e", "Concurrency", "Event Storming", "DDD in practice", "DDD", "Strategic design", "CQRS", "Domain Events", "Domain Model", "Value Objects", "Tactical design", "Repository", "IT", "Asynchronous communication", "Integration", "SDLC", "\u0411\u0438\u0437\u043d\u0435\u0441-\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u044b", "\u0421oncerns in Agile", "\u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u044b", "Analysis in Agile", "Requirements in Agile", "Agile", "Collaborative Development", "Agile Practices", "SDLC Models", "Adaptation", "Software Construction", "Software Design", "\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e", "Prediction", "\u0421\u0430\u043c\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435", "TDD", "Team Topologies", "Soft Skills"], "terms": {"distributed": [0, 5, 23, 34, 75, 82, 100], "collaborative": [0, 21, 58, 86, 94, 128], "knowledge": [0, 38, 51, 59, 64, 65, 66, 68, 72, 75, 77, 85, 89, 100], "management": [0, 23, 34, 37, 38, 49, 51, 52, 64, 74, 76, 82, 88], "system": [0, 8, 9, 15, 21, 23, 34, 37, 38, 39, 46, 47, 49, 51, 52, 62, 64, 65, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90], "\u043e\u0431\u044a": [0, 38, 74, 82, 85, 86, 95], "\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446": [0, 5, 9, 10, 11, 15, 23, 37, 38, 64, 74, 75, 77, 83, 85, 88, 89, 90, 91, 92, 95, 138], "\u0432": [0, 5, 10, 12, 13, 16, 23, 26, 29, 30, 33, 37, 38, 41, 42, 45, 49, 51, 52, 53, 56, 60, 62, 64, 65, 66, 68, 72, 73, 74, 75, 77, 80, 82, 83, 85, 87, 89, 91, 94, 100, 102, 118, 123, 137, 138], "\u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d": [0, 34, 37, 40, 72, 74, 76, 85, 86, 90, 93], "\u043c\u0438\u0440": [0, 8, 21, 34, 37, 75, 83, 92, 100], "\u0441\u0442\u0430\u043b": [0, 5, 37, 38, 72, 73, 76, 82, 83, 85, 86, 88], "\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d": [0, 5, 8, 11, 23, 34, 37, 38, 56, 70, 82, 85, 86, 88, 90, 95, 100, 102], "\u0431\u043e\u043b\u044c\u0448": [0, 5, 8, 9, 23, 37, 38, 40, 46, 47, 52, 65, 68, 70, 72, 73, 74, 75, 76, 77, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100], "\u0438": [0, 5, 8, 9, 10, 13, 15, 26, 29, 30, 34, 37, 38, 39, 40, 42, 43, 46, 47, 49, 51, 56, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 76, 77, 80, 83, 87, 88, 89, 90, 91, 92, 94, 95, 102, 121, 137, 138], "\u0432\u043e\u0437\u043d\u0438\u043a\u043b": [0, 23, 34, 37], "\u043f\u043e\u0442\u0440\u0435\u0431\u043d": [0, 8, 21, 23, 38, 74, 76, 82, 86, 90], "\u044d\u0442": [0, 5, 8, 9, 11, 13, 15, 16, 26, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 51, 52, 56, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 86, 88, 89, 90, 93, 94, 95, 100, 102], "\u043e\u0431\u044a\u0435\u043c": [0, 21, 73, 74, 85, 86, 90, 95], "\u0442\u043e": [0, 5, 8, 9, 11, 13, 15, 21, 23, 26, 29, 30, 34, 37, 38, 41, 42, 46, 51, 52, 56, 60, 64, 65, 70, 72, 73, 74, 75, 76, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u0443\u043f\u0440\u0430\u0432\u043b\u044f": [0, 5, 21, 38, 72, 73, 74, 75, 77, 82, 83, 86, 88, 90, 94], "\u043e\u043f": [0, 74, 83, 85, 86, 92], "\u043f\u043e\u043a\u0430\u0437\u0430": [0, 13, 21, 23, 82, 86, 92], "\u0447\u0442\u043e": [0, 5, 8, 9, 11, 13, 15, 23, 30, 34, 38, 41, 42, 47, 51, 53, 54, 56, 60, 62, 64, 66, 67, 68, 70, 72, 73, 74, 75, 76, 77, 79, 82, 83, 86, 88, 89, 90, 92, 93, 94, 95, 102, 126, 130, 134], "\u0432\u044b\u0441\u043e\u043a": [0, 8, 11, 37, 70, 72, 73, 74, 77, 83, 85, 86, 90, 92, 100], "\u043e\u0431\u044a\u0435\u043c\u043d": [0, 38], "\u043c\u0430\u0442\u0435\u0440\u0438\u0430": [0, 82, 90], "\u043b\u0435\u0433\u0447": [0, 5, 21, 38, 70, 73, 74, 90, 92, 93], "\u0434\u043e\u0441\u0442\u0438\u0433\u0430": [0, 23, 40, 73, 83, 86, 88], "\u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432": [0, 38, 76, 83, 86, 90, 91, 92, 94, 138], "\u0430\u0432\u0442\u043e\u0440": [0, 3, 4, 5, 8, 9, 10, 11, 14, 15, 18, 21, 23, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 56, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 97, 100, 102], "\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440": [0, 5, 8, 9, 11, 21, 23, 30, 34, 38, 40, 51, 74, 75, 76, 77, 82, 83, 85, 86, 88, 92, 94, 100], "net": [0, 34, 38, 70, 75, 82, 86, 100], "microservices": [0, 5, 34, 85, 86], "architecture": [0, 5, 8, 9, 11, 13, 21, 23, 34, 37, 40, 41, 43, 46, 49, 51, 59, 64, 65, 66, 72, 73, 74, 75, 77, 80, 82, 85, 86, 90, 100, 121], "for": [0, 5, 8, 9, 11, 13, 15, 21, 23, 26, 29, 30, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 59, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 88, 89, 90, 92, 94, 95, 100], "containerized": [0, 23, 82], "applications": [0, 21, 23, 30, 34, 51, 64, 74, 75, 82], "\u0431\u043e\u043b": [0, 8, 9, 21, 23, 30, 37, 38, 41, 42, 47, 68, 70, 73, 74, 75, 76, 77, 82, 85, 86, 88, 90, 92, 93, 94, 100, 102], "4": [0, 5, 8, 9, 16, 21, 23, 34, 37, 38, 41, 42, 64, 65, 66, 74, 76, 77, 82, 85, 86, 92, 94], "5": [0, 5, 8, 9, 23, 34, 37, 38, 46, 49, 51, 52, 64, 65, 70, 76, 77, 82, 83, 85, 86, 89, 94, 95], "\u0442\u044b\u0441": 0, "\u0444\u043e\u0440\u043a": 0, "azure": [0, 23, 34, 82], "center": [0, 38], "1": [0, 5, 8, 15, 21, 23, 29, 34, 37, 38, 41, 46, 51, 52, 64, 66, 73, 74, 75, 76, 82, 85, 86, 88, 92, 94, 100, 102], "microsoft": [0, 21, 23, 34, 38, 41, 82], "\u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430": [0, 15], "\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d": [0, 21, 38, 46, 56, 70, 72, 73, 85, 92, 94, 100], "\u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [0, 15, 23, 34, 38, 75, 83, 90], "\u0441\u0438\u0441\u0442": [0, 34, 37, 38, 40, 64, 72, 73, 74, 75, 77, 85, 86, 88, 90, 92, 100], "\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d": [0, 5, 36, 37, 38, 40, 41, 60, 64, 72, 73, 74, 75, 76, 82, 86, 88, 90, 120], "\u0437\u043d\u0430\u043d": [0, 8, 9, 37, 56, 65, 72, 77, 82, 83, 85, 88, 89, 91, 94, 95, 100, 102, 138], "\u043e\u0442\u043a\u0440\u044b\u0442": [0, 5, 34, 38, 74, 75, 86, 90, 92], "\u043d\u0435\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d": 0, "\u0430\u0432\u0442\u043e\u0440\u0441\u043a": 0, "\u043a\u0440\u0443\u0433": [0, 9, 38, 40, 75, 92], "\u043c\u043e\u0436\u043d": [0, 5, 8, 9, 11, 21, 23, 30, 34, 37, 38, 40, 46, 47, 53, 56, 60, 64, 65, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u0437\u0430\u043c\u0435\u0442": [0, 21, 23, 34, 38, 51, 64, 65, 72, 76, 85, 95], "\u043d\u0435\u043a\u043e\u0442\u043e\u0440": [0, 9, 21, 34, 38, 40, 42, 46, 70, 72, 74, 77, 83, 85, 86, 100, 102], "\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b": [0, 8, 21, 34, 100], "\u0432\u0435\u0434\u0443\u0442": [0, 70, 74], "\u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d": [0, 34, 37, 64, 76, 83, 100], "\u0432\u0435\u0440\u0441": [0, 5, 9, 23, 34, 52, 82, 85], "\u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a": [0, 82], "\u0432\u043b\u0438\u0432": 0, "\u043d\u0438\u0445": [0, 5, 8, 9, 11, 37, 38, 46, 72, 74, 75, 77, 82, 83, 90, 93, 94, 102], "\u0433\u043b\u0430\u0432\u043d": [0, 40, 46, 73, 74, 76, 77, 80, 82, 83, 88, 89, 90, 93, 100], "\u0431\u0440\u0430\u043d\u0447": [0, 5], "\u0442": [0, 5, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 56, 62, 65, 70, 72, 73, 74, 75, 76, 80, 82, 83, 85, 86, 88, 90, 92, 94, 95, 100, 102], "\u0435": [0, 5, 8, 9, 15, 21, 23, 34, 37, 38, 40, 46, 52, 56, 65, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u0441\u0442\u0440\u0435\u043c": [0, 21, 23, 37, 38, 73, 74, 85, 86, 90], "\u0441\u043e\u0437\u0434\u0430\u0432\u0430": [0, 8, 9, 21, 46, 70, 73, 75, 76, 85, 86, 92, 100], "\u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d": [0, 15, 26, 34, 38, 40, 70, 75, 82, 83, 85, 86, 90, 92, 94, 95, 100, 102], "\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432": 0, "\u043a\u043e\u0442\u043e\u0440": [0, 5, 8, 9, 10, 11, 13, 15, 21, 23, 29, 34, 37, 38, 40, 41, 42, 46, 47, 52, 56, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100, 102], "\u043e\u0431\u043e\u0433\u0430\u0449\u0430": 0, "\u0438\u0437": [0, 5, 8, 9, 11, 15, 21, 23, 26, 30, 34, 37, 38, 40, 47, 51, 56, 60, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 90, 92, 93, 94, 95, 100, 102], "\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a": [0, 9, 21, 23, 29, 38, 73, 74, 75, 85, 86, 90, 92], "\u0434\u0438\u0441\u0442\u0438\u043b\u043b\u0438\u0440": [0, 93], "\u043e\u0442": [0, 8, 9, 11, 29, 34, 37, 38, 40, 41, 42, 46, 47, 51, 52, 65, 68, 72, 73, 74, 76, 80, 82, 83, 85, 86, 88, 92, 93, 94, 95, 100], "\u0432\u0441\u0435\u0433": [0, 5, 8, 11, 23, 34, 37, 38, 40, 42, 46, 47, 70, 74, 76, 82, 83, 85, 86, 88, 92, 95, 100, 102], "\u043b\u0438\u0448\u043d": [0, 70, 75, 82, 100], "\u043d\u0430\u0432\u043e\u0434": [0, 8, 86], "\u043c\u044b\u0441\u043b": [0, 8, 9, 23, 56, 73, 86, 90, 92, 100], "\u0430": [0, 5, 8, 9, 10, 11, 15, 30, 34, 37, 38, 40, 41, 46, 47, 51, 56, 62, 65, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 102], "\u0435\u0441\u043b": [0, 5, 8, 9, 11, 15, 23, 30, 34, 37, 38, 40, 41, 42, 47, 51, 56, 60, 64, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 88, 90, 92, 93, 94, 102], "\u0441\u043e\u0432\u043c\u0435\u0441\u0442": [0, 86], "\u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d": [0, 70, 72, 83, 92, 97, 98], "\u0432\u044b": [0, 21, 23, 37, 38, 42, 46, 47, 51, 60, 65, 68, 70, 72, 73, 74, 75, 77, 82, 83, 85, 86, 88, 90, 92, 94, 95, 97], "\u0441\u0430\u043c": [0, 5, 8, 9, 11, 13, 21, 23, 30, 34, 37, 38, 40, 41, 46, 47, 52, 62, 65, 70, 72, 73, 74, 75, 76, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100, 102], "\u0440\u0435\u0448\u0430": [0, 21, 30, 34, 38, 40, 56, 60, 73, 74, 76, 82, 85, 86, 88, 90, 92, 100], "\u0438\u043c\u0435\u043d": [0, 8, 9, 11, 21, 23, 26, 37, 38, 40, 41, 47, 51, 56, 62, 64, 65, 70, 72, 73, 74, 75, 82, 85, 86, 90, 92, 93, 94, 100], "\u0441\u0432\u043e": [0, 5, 8, 9, 11, 21, 26, 30, 37, 38, 40, 41, 42, 46, 51, 52, 56, 65, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100], "\u0437\u0430\u043c\u0435\u0442\u043a": [0, 15, 23, 30, 37], "\u0445\u043e\u0442": [0, 8, 9, 11, 21, 23, 30, 34, 38, 40, 47, 49, 52, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 92, 100, 102], "\u043f\u043e\u0434\u0435\u043b": [0, 23, 56, 82, 88, 94, 100], "\u0434\u043e\u0431\u0430\u0432": [0, 21, 34, 46, 47, 70, 74, 76, 85, 86, 94], "\u0431\u0430\u0437": [0, 9, 23, 38, 74, 76, 83, 85, 88], "\u0443": [0, 5, 8, 9, 11, 21, 23, 26, 30, 37, 38, 40, 41, 47, 52, 64, 70, 72, 74, 75, 76, 77, 82, 83, 85, 86, 88, 92, 93, 94, 95, 100], "\u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a": [0, 30, 82, 85], "\u043e\u0441\u043d\u043e\u0432": [0, 21, 23, 30, 37, 40, 72, 73, 76, 77, 80, 85, 86, 92, 100], "wiki": [0, 5, 51, 85], "\u0434\u0432\u0438\u0436\u043a": 0, "\u044f\u0432\u043b\u044f": [0, 5, 8, 9, 11, 15, 21, 23, 29, 30, 34, 37, 38, 41, 47, 49, 52, 56, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 92, 100, 102], "\u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d": [0, 11, 15, 21, 23, 30, 47, 75, 85, 86, 88, 93, 94, 95], "\u043d\u043e\u0441\u0438\u0442\u0435\u043b": [0, 56], "\u0438\u043d\u0444\u043e\u0440\u0430\u0446": 0, "\u043c\u043e\u0436\u0435\u0442": [0, 5, 8, 9, 11, 13, 15, 22, 26, 30, 34, 37, 38, 40, 41, 42, 46, 51, 52, 62, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 95, 97, 100, 102, 111], "\u0431\u044b\u0442": [0, 5, 8, 9, 11, 21, 23, 30, 34, 37, 38, 42, 52, 64, 70, 72, 73, 74, 75, 85, 86, 92, 93, 94, 97, 100, 102], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b": [0, 34], "\u0442\u043e\u043b\u044c\u043a": [0, 5, 8, 9, 10, 11, 21, 23, 30, 34, 37, 38, 40, 41, 42, 47, 56, 70, 73, 74, 75, 82, 83, 85, 86, 88, 92, 93, 94, 100], "\u0432\u0438\u0434": [0, 5, 8, 9, 16, 21, 23, 30, 37, 38, 40, 41, 65, 66, 70, 72, 73, 74, 85, 86, 88, 89, 92, 94, 95, 100], "\u0437\u043d\u0430\u0447": [0, 8, 9, 11, 23, 30, 38, 40, 70, 72, 73, 75, 77, 83, 85, 90, 92], "\u043e\u043d": [0, 5, 8, 9, 10, 11, 13, 15, 16, 21, 23, 26, 30, 34, 37, 38, 40, 41, 42, 47, 51, 52, 53, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u043d\u0435": [0, 5, 8, 10, 11, 12, 15, 16, 30, 34, 37, 38, 40, 41, 42, 47, 49, 51, 56, 60, 62, 64, 65, 68, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 91, 92, 94, 95, 100, 102, 138], "\u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f": [0, 38, 85], "\u0440\u0430\u0437\u043b\u0438\u0447\u043d": [0, 5, 11, 23, 38, 40, 65, 75, 76, 82, 83, 100, 102], "\u0440\u0430\u0437\u043d": [0, 5, 11, 23, 60, 65, 74, 76, 77, 82, 86, 88, 90, 92, 94, 100, 102], "\u0432\u043e\u0437\u043d\u0438\u043a\u0430": [0, 5, 8, 9, 11, 21, 23, 26, 30, 34, 37, 38, 40, 41, 47, 52, 56, 64, 65, 74, 75, 82, 83, 85, 86, 92, 100, 102], "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447": [0, 9, 23, 37, 38, 40, 65, 74, 75, 92, 100], "\u043c\u0435\u0436\u0434": [0, 8, 9, 11, 21, 23, 37, 38, 41, 42, 52, 65, 72, 73, 74, 75, 76, 77, 82, 83, 85, 88, 100, 102], "\u0432\u043e": [0, 11, 23, 37, 38, 46, 56, 65, 70, 72, 73, 74, 75, 76, 77, 83, 85, 86, 88, 92, 93, 94, 100, 102], "\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432": [0, 23, 85, 92, 100, 102], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d": [0, 5, 9, 10, 70, 73, 82, 102], "\u0432\u043e\u0437\u043c\u043e\u0436\u043d": [0, 5, 8, 9, 11, 21, 23, 34, 37, 38, 39, 40, 42, 46, 47, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 90, 92, 93, 100, 102], "\u0435\u0434\u0438\u043d\u0438\u0447\u043d": [0, 92], "\u0442\u0430\u043a": [0, 5, 8, 9, 11, 15, 16, 21, 23, 26, 30, 34, 38, 40, 41, 46, 54, 56, 62, 66, 67, 70, 72, 73, 74, 75, 76, 77, 79, 82, 83, 86, 88, 90, 92, 93, 94, 95, 100, 102, 126, 130, 134], "\u0436\u0435": [0, 5, 8, 9, 11, 15, 21, 23, 26, 30, 34, 37, 38, 40, 41, 42, 46, 52, 60, 65, 70, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 94, 100, 102], "\u0441\u0443\u0449\u0435\u0441\u0442\u0432": [0, 5, 8, 9, 15, 23, 30, 34, 38, 40, 46, 47, 53, 70, 72, 74, 75, 77, 82, 85, 86, 88, 90, 92, 100], "\u043f\u043e\u043b\u043d\u043e\u0442": [0, 37, 52, 65, 68, 76, 82, 88, 94, 102], "\u0434\u043b\u044f": [0, 8, 9, 15, 16, 23, 26, 30, 34, 37, 38, 40, 41, 46, 47, 51, 52, 56, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 81, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102, 135], "\u043e\u0434\u043d": [0, 5, 8, 9, 11, 13, 21, 23, 26, 30, 34, 37, 38, 40, 42, 51, 56, 60, 64, 68, 70, 72, 73, 74, 75, 77, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f": [0, 9, 38, 70, 75, 85, 86, 93, 94, 100, 102], "\u0446\u0435\u043d\u043d\u043e\u0441\u0442": [0, 8, 21, 38, 42, 70, 76, 85, 88, 93], "\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d": [0, 64, 82, 92], "\u043f\u043e\u043c\u0435\u0445": [0, 73], "\u0437\u0430\u0442\u0440\u0443\u0434\u043d\u044f": [0, 9, 11, 74, 75, 85, 86], "\u0435\u0433": [0, 5, 8, 9, 10, 21, 23, 26, 34, 37, 38, 40, 41, 42, 46, 56, 65, 68, 70, 72, 73, 74, 75, 76, 80, 83, 85, 86, 88, 90, 92, 93, 94, 100, 102], "\u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432": [0, 64, 74, 86, 92, 93], "\u043f\u043e\u043f\u044b\u0442\u043a": [0, 5, 8, 15, 82, 85, 86, 90, 92, 102], "\u0440\u0430\u0437\u0440\u0435\u0448": [0, 21, 37, 65], "\u043f\u043e\u0440\u043e\u0436\u0434\u0430": [0, 8, 11], "\u0440\u044f\u0434": [0, 5, 8, 21, 23, 37, 38, 41, 74, 80, 83, 85, 86, 88, 92, 102], "\u0432\u043e\u043f\u0440\u043e\u0441": [0, 8, 9, 11, 15, 21, 23, 30, 34, 37, 40, 41, 42, 46, 52, 56, 64, 65, 70, 72, 75, 76, 77, 83, 85, 86, 88, 92, 100], "\u043c\u043e\u0434\u0435\u0440\u0430\u0446": [0, 8], "\u0440\u0435\u0434\u0430\u043a\u0446\u0438\u043e\u043d": 0, "\u043f\u043e\u043b\u0438\u0442\u0438\u043a": [0, 90, 100], "\u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d": [0, 9, 21, 23, 38, 40, 56, 72, 73, 74, 75, 76, 83, 85, 86, 90, 100], "\u043a\u043e\u043d\u0441\u0435\u043d\u0441\u0443\u0441": [0, 38, 56], "\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d": [0, 38, 52, 65, 72, 75, 76, 80, 82, 88, 91, 94, 138], "\u0432\u044b\u0440\u0430\u0431\u043e\u0442\u043a": [0, 100], "\u043d\u043e\u0440\u043c": 0, "\u043f\u043e\u0432\u0435\u0434\u0435\u043d": [0, 9, 26, 38, 82, 85, 88, 100], "\u043f\u0440\u0430\u0432": [0, 8, 9, 38, 40, 46, 52, 56, 70, 72, 77, 80, 85, 86, 92, 94, 102], "\u0437\u0430\u0449": 0, "\u0434\u0438\u0432\u0435\u0440\u0441": 0, "\u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d": [0, 23], "\u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c": 0, "\u0438\u043b": [0, 5, 8, 9, 11, 15, 23, 26, 34, 37, 38, 40, 41, 42, 46, 51, 52, 64, 70, 72, 73, 74, 75, 77, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u043f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a": [0, 92], "\u0432\u0441\u0435": [0, 5, 8, 9, 11, 15, 21, 26, 30, 34, 37, 38, 40, 46, 47, 52, 60, 64, 68, 70, 72, 74, 75, 76, 77, 82, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u0440\u0435\u0437\u043a": [0, 100], "\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430": [0, 11, 23, 38, 85], "\u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d": [0, 8, 9, 21, 23, 38, 40, 46, 47, 62, 64, 70, 75, 82, 85], "\u0442\u0435\u0440\u044f": [0, 38, 75, 85, 88], "\u0442\u0430\u043a\u0436": [0, 5, 8, 9, 11, 15, 21, 23, 34, 37, 38, 40, 47, 51, 52, 62, 65, 74, 75, 76, 77, 82, 85, 86, 88, 90, 92, 93, 94, 102], "\u0437\u0430\u0442\u0440\u0443\u0434\u043d\u0438\u0442\u0435\u043b\u044c\u043d": [0, 38], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": [0, 5, 8, 9, 12, 21, 23, 26, 30, 34, 37, 38, 52, 56, 64, 74, 75, 85, 90, 94, 95], "offline": [0, 23, 30], "\u0440\u0435\u0436\u0438\u043c": [0, 38, 82, 85], "\u043e\u0441\u043e\u0431\u0435\u043d": [0, 21, 23, 40, 41, 73, 74, 75, 83, 85, 88, 92, 100], "\u0442\u0435\u043b\u0435\u0444\u043e\u043d": 0, "\u043e\u0442\u0434\u0435\u043b\u044c\u043d": [0, 5, 8, 9, 23, 34, 38, 60, 72, 74, 75, 82, 85, 86, 90, 94], "\u0440\u0435\u0448": [0, 8, 9, 11, 13, 38, 40, 56, 70, 72, 73, 85, 86, 88, 100], "\u043f\u0440\u043e\u0431\u043b\u0435\u043c": [0, 9, 11, 21, 26, 30, 34, 37, 38, 40, 41, 56, 64, 68, 70, 72, 73, 74, 76, 77, 80, 82, 83, 85, 86, 88, 90, 93, 94, 95, 100], "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f": [0, 5, 11, 37, 38, 46, 56, 72, 74, 85, 86, 90, 91, 100, 138], "\u0435\u0449": [0, 5, 8, 9, 11, 23, 34, 37, 38, 40, 41, 42, 52, 56, 65, 72, 74, 75, 76, 82, 83, 85, 86, 88, 90, 92, 93, 100, 102], "\u0432\u044b\u0433\u043b\u044f\u0434": [0, 8, 9, 30, 38, 46, 82, 94, 100], "\u043f\u0440\u043e\u0441\u0442": [0, 5, 8, 9, 11, 21, 23, 37, 38, 41, 46, 64, 70, 72, 74, 75, 77, 82, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100], "\u0442\u0435\u043a\u0441\u0442\u043e\u0432": [0, 5], "\u0444\u0430\u0439\u043b": [0, 5, 11, 13], "\u0447\u0430\u0449": [0, 5, 8, 38, 46, 47, 70, 83], "restructuredtext": 0, "\u043a\u043e\u043d\u0442\u0440\u043e\u043b": [0, 5, 26, 38, 47, 85], "\u043e\u0431\u044b\u0447\u043d": [0, 5, 9, 23, 30, 34, 38, 40, 47, 56, 70, 77, 82, 85, 86, 90, 92, 94, 95], "git": 0, "\u0441\u0440\u0435\u0434\u0441\u0442\u0432": [0, 8, 60, 64, 72, 82, 85, 90, 92, 100], "\u0443\u0441\u0442\u0440\u0430\u043d\u044f": [0, 38, 51, 86], "\u0437\u0430\u043a\u043b\u044e\u0447\u0430": [0, 11, 15, 23, 30, 37, 41, 65, 70, 74, 75, 80, 85, 88, 90, 92, 93, 94, 100], "\u0442\u043e\u043c": [0, 5, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 41, 42, 46, 47, 52, 56, 65, 68, 70, 72, 74, 75, 76, 77, 80, 82, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u043e\u0434\u0438\u043d": [0, 5, 8, 9, 11, 15, 21, 23, 26, 34, 40, 51, 56, 70, 72, 74, 75, 82, 83, 85, 86, 90, 93, 95, 100], "\u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440": [0, 8, 23, 26, 85], "\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430": [0, 75, 92], "\u043a\u0430\u0436\u0434": [0, 5, 8, 9, 23, 26, 30, 34, 42, 62, 65, 70, 72, 73, 74, 75, 82, 83, 85, 86, 90, 92, 93, 94, 95, 100], "\u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430": [0, 8], "\u0441\u0447\u0438\u0442\u0430": [0, 21, 23, 38, 46, 73, 74, 76, 82, 85, 90, 92, 102], "\u043d\u0443\u0436\u043d": [0, 5, 9, 11, 21, 23, 26, 34, 38, 40, 41, 51, 56, 64, 65, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100], "\u043e\u0431\u043e\u0433\u0430": 0, "\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432": [0, 9, 21, 23, 30, 38, 73], "\u0438\u0434": [0, 9, 11, 23, 37, 72, 73, 74, 75, 76, 85, 86, 92, 102], "\u043f\u043e\u0441\u0442\u0440\u043e": [0, 21, 73, 83], "\u0434\u0430\u043d": [0, 9, 13, 21, 23, 34, 38, 47, 53, 65, 70, 74, 85, 86, 88, 90, 92, 100, 102], "\u043e\u0441\u043d\u043e\u0432\u043d": [0, 8, 9, 21, 23, 37, 41, 49, 56, 65, 70, 74, 76, 80, 83, 86, 88, 89, 90, 92, 93, 100], "\u0441\u0443\u0442": [0, 8, 9, 21, 23, 41, 74, 82, 85, 86, 92, 95], "\u0441\u0443\u0431\u044a\u0435\u043a\u0442": [0, 92, 100], "\u043c\u043e\u0434\u0435\u043b": [0, 9, 12, 34, 37, 38, 40, 52, 56, 64, 65, 74, 75, 76, 80, 83, 86, 88, 89], "\u0432\u0440\u0435\u043c": [0, 8, 11, 13, 15, 21, 23, 26, 29, 34, 37, 38, 40, 41, 42, 65, 68, 70, 72, 74, 76, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 102], "\u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432": [0, 13, 23, 38, 68, 74, 95, 100], "\u0441\u043a\u043e\u0440": [0, 38, 40, 42, 46, 47, 56, 83, 85, 86, 94, 95, 100, 102], "\u043e\u0431\u044a\u0435\u043a\u0442": [0, 8, 9, 15, 21, 26, 74, 75, 77, 85, 90, 92, 100, 102], "\u043f\u043e\u0434\u0445\u043e\u0434": [0, 8, 9, 15, 21, 23, 34, 38, 42, 65, 70, 73, 77, 83, 85, 86, 88], "\u043a": [0, 5, 8, 9, 11, 15, 16, 21, 23, 30, 34, 37, 40, 41, 42, 46, 47, 53, 56, 62, 65, 68, 70, 72, 73, 74, 75, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100, 102], "\u0445\u0440\u0430\u043d\u0435\u043d": [0, 21, 23], "\u0438\u0437\u0431\u0430\u0432\u043b\u044f": [0, 70, 82], "\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d": [0, 11, 34, 56], "\u0432\u044b\u0448": [0, 37, 38, 68, 74, 75, 86, 88, 90, 100], "\u043f\u0440\u043e\u0431\u043b": [0, 8, 9, 13, 15, 21, 23, 34, 38, 41, 56, 68, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 93, 100], "\u0447\u0435\u043c": [0, 5, 8, 11, 23, 37, 38, 40, 42, 47, 51, 52, 56, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100], "\u043a\u043e\u0433": [0, 8, 40, 83], "\u0441\u0442\u0430\u0442": [0, 5, 8, 9, 15, 21, 23, 30, 34, 37, 38, 40, 46, 52, 70, 75, 76, 81, 85, 86, 88, 89, 90, 92, 93, 94, 95, 135], "\u0443\u0434\u0430\u043b\u044f": [0, 8, 21, 23, 34], "\u043d\u0435\u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d": [0, 11, 100], "\u0432\u0430\u0441": [0, 38, 41, 47, 72, 77, 82, 83, 85, 86, 94], "\u0441\u043e\u0445\u0440\u0430\u043d": [0, 5, 12, 23, 73, 75, 82, 88], "\u0441\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u043d": [0, 75], "\u0432\u043d\u0438\u043c\u0430\u043d": [0, 5, 8, 21, 23, 41, 47, 52, 65, 68, 72, 74, 75, 76, 82, 85, 86, 93, 100], "\u0434\u0435\u043b": [0, 8, 21, 23, 30, 34, 37, 38, 40, 41, 46, 70, 73, 74, 75, 76, 82, 83, 85, 86, 88, 92, 94, 95], "\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442": [0, 15, 21, 23, 37, 38, 40, 41, 51, 56, 73, 82, 83, 85, 86, 88, 92, 94, 95], "\u043f\u0443\u0431\u043b\u0438\u043a\u0443": 0, "\u0438\u0445": [0, 5, 8, 9, 11, 21, 23, 26, 29, 30, 37, 38, 40, 41, 42, 46, 52, 60, 64, 68, 70, 72, 74, 75, 76, 82, 83, 85, 86, 88, 90, 92, 93, 94, 100, 102], "\u043f\u0443\u0431\u043b\u0438\u0447\u043d": [0, 11, 21, 23, 30, 85, 86, 88, 97], "\u0437\u0430\u043a\u0440\u0435\u043f": [0, 83], "\u043f\u0440\u0438": [0, 5, 8, 9, 11, 21, 23, 26, 30, 34, 37, 38, 40, 41, 42, 53, 65, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 90, 92, 100, 102], "\u0430\u0432\u0442\u043e\u0440\u0441\u0442\u0432": [0, 75], "\u0432\u0430\u0448": [0, 21, 23, 38, 41, 42, 70, 72, 73, 74, 75, 82, 83, 85, 86, 88], "\u043e\u0431\u044f\u0437\u0430": [0, 9, 23, 38], "\u0441\u043b\u0435\u0434\u043e\u0432\u0430": [0, 11, 37, 38, 72, 85], "\u0447\u044c\u0438\u043c": 0, "\u0447\u0443\u0436": [0, 75, 89, 92], "\u0442\u043e\u0447\u043a": [0, 8, 37, 38, 51, 73, 77, 83, 85, 88, 89, 92, 94, 100], "\u0437\u0440\u0435\u043d": [0, 8, 23, 38, 51, 73, 74, 82, 83, 85, 88, 89, 92, 93, 94, 95, 100], "\u0440\u0435\u0430\u043b\u044c\u043d": [0, 8, 16, 83, 95, 100], "\u0436\u0438\u0437\u043d": [0, 8, 23, 70, 73, 83, 85, 88, 92, 100], "\u043d\u0435\u043c\u0430\u043b\u043e\u0432\u0430\u0436\u043d": [0, 23, 70, 82], "\u043f\u0441\u0438\u0445\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": [0, 37, 56, 82, 83, 85, 88, 90, 91, 92, 93, 94, 138], "\u0444\u0430\u043a\u0442\u043e\u0440": [0, 5, 42, 68, 70, 85, 100], "\u043a\u043e\u0433\u0434": [0, 9, 11, 21, 23, 26, 34, 38, 41, 45, 56, 65, 66, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 92, 95, 100, 123], "\u0447\u0435\u043b\u043e\u0432\u0435\u043a": [0, 11, 26, 38, 65, 68, 73, 74, 75, 82, 83, 85, 86, 88, 90, 92, 95, 100], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432": [0, 8, 30, 82, 85, 86], "\u0441\u0443\u0434": [0, 90, 100], "\u0431\u0443\u0434\u0435\u0442": [0, 5, 8, 9, 21, 23, 26, 30, 34, 37, 38, 40, 42, 47, 70, 73, 74, 75, 76, 77, 82, 83, 85, 86, 90, 92, 93, 94, 95, 100], "\u043e\u0446\u0435\u043d\u0438\u0432\u0430": [0, 38, 74, 95], "\u043f\u043e\u0437\u0438\u0446": [0, 38, 40, 56, 83, 86, 88, 92, 93], "\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442": [0, 38, 42, 52, 64, 65, 74, 76, 92], "\u043f\u043e\u0437\u0432\u043e\u043b\u044f": [0, 5, 11, 21, 23, 34, 37, 38, 40, 70, 73, 74, 75, 77, 85, 86, 100, 102], "\u0441\u043d\u044f\u0442": [0, 21, 72, 95, 100], "\u0431\u0430\u0440\u044c\u0435\u0440": [0, 82], "\u0443\u0441\u043a\u043e\u0440\u044f": [0, 74, 76], "\u043e\u0431\u043c": [0, 23, 86], "\u043f\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u043e\u0432\u0430": 0, "\u043f\u043e\u044f\u0432\u043b\u0435\u043d": [0, 51, 65, 68, 75, 89], "\u0441\u0435\u0433\u043e\u0434\u043d": [0, 15, 37, 38, 41, 64, 70, 74, 76, 82, 86, 92], "\u0436\u0438\u0432\u0435\u0442": 0, "\u0443\u0441\u043b\u043e\u0432": [0, 8, 9, 21, 23, 30, 33, 37, 52, 56, 65, 68, 70, 76, 85, 86, 88, 90, 92, 118], "\u0441\u0442\u0435\u0441\u043d\u0435\u043d": 0, "\u043d\u0430\u0441": [0, 5, 8, 23, 30, 37, 41, 68, 85, 88, 94, 100], "\u0435\u0441\u0442": [0, 5, 9, 11, 13, 23, 26, 34, 37, 38, 40, 42, 52, 65, 73, 74, 75, 82, 83, 85, 86, 88, 90, 92, 95, 100], "\u043e\u0431\u043e\u0433\u0430\u0442": 0, "\u043d\u043e": [0, 5, 8, 9, 11, 15, 16, 23, 30, 34, 37, 38, 40, 42, 46, 56, 65, 70, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 100, 102], "\u043f\u0440\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": 0, "\u0442\u0435\u043c": [0, 5, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 47, 52, 64, 65, 68, 72, 74, 76, 80, 82, 83, 85, 89, 90, 92, 93, 94, 95, 100], "\u043f\u043e\u044d\u0442": [0, 8, 15, 21, 23, 38, 40, 41, 46, 62, 68, 70, 72, 73, 74, 75, 77, 82, 83, 85, 86, 88, 90, 92, 94, 100, 102], "\u043a\u043e\u0440\u043e\u0442\u043a": [0, 21, 34, 37, 85, 88], "\u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d": [0, 37, 75, 76, 82, 85, 86, 95], "\u043a\u043e\u043d\u0435\u0447\u043d": [0, 8, 23, 37, 38, 40, 46, 65, 70, 73, 74, 77, 82, 85, 88, 92, 100], "\u0438\u0442\u043e\u0433": [0, 52, 72, 73, 74, 75, 77, 88], "\u043b\u044e\u0434": [0, 38, 42, 68, 70, 73, 75, 83, 85, 86, 88, 92, 94], "\u0442\u0440\u0430\u0442": [0, 47, 56, 83, 85, 92], "\u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440": 0, "\u043d\u0430\u043c\u043d": [0, 5, 21, 74, 82, 86, 88], "\u0442\u0440\u0435\u0431": [0, 8, 9, 11, 13, 21, 23, 34, 38, 40, 46, 47, 65, 70, 74, 83, 85, 86, 89, 92, 95, 100, 102], "\u043d\u0430\u043f\u0438\u0441\u0430\u043d": [0, 37, 47, 52, 53, 74, 77, 82, 85, 90], "\u0434\u0435\u043b\u0430": [0, 5, 9, 11, 23, 37, 38, 42, 45, 47, 52, 56, 65, 66, 68, 70, 72, 73, 74, 75, 83, 85, 88, 92, 93, 100, 102, 123], "\u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b": 0, "\u0445\u043e\u0440\u043e\u0448": [0, 8, 9, 21, 23, 34, 38, 40, 42, 53, 56, 64, 66, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 90, 93, 94, 95], "\u0440\u043e\u0436\u0434\u0430": 0, "\u043a\u0440\u0438\u0441\u0442\u0430\u043b\u0438\u0437\u0438\u0440": 0, "\u0437\u0430": [0, 8, 9, 11, 15, 21, 23, 26, 30, 34, 37, 42, 56, 70, 72, 74, 75, 76, 82, 83, 85, 86, 88, 90, 92, 93, 95, 100], "\u0447\u0435\u0433": [0, 21, 37, 42, 74, 75, 100], "\u0447\u0430\u0441\u0442": [0, 5, 9, 21, 23, 30, 34, 37, 42, 43, 46, 47, 65, 66, 70, 74, 75, 76, 83, 85, 86, 88, 92, 94, 100, 102, 121], "\u0442\u043e\u043d\u0443\u0442": 0, "\u0431\u0435\u0437\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430": 0, "\u0441\u0432\u0430\u043b\u043a": [0, 5], "\u0441\u0440\u0435\u0434": [0, 23, 38, 41, 74, 75, 83, 85, 86, 88, 93], "\u043e\u043a\u0435\u0430": 0, "\u043d\u0435\u0441\u043c\u043e\u0442\u0440": [0, 9, 65, 85, 88], "\u0444\u0430\u043a\u0442": [0, 9, 11, 15, 21, 30, 72, 76, 85, 92, 93, 95, 100], "\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d": [0, 9, 21, 40, 75, 92, 100, 102], "\u0431\u044b\u0441\u0442\u0440": [0, 5, 38, 40, 41, 42, 46, 74, 86], "\u0441\u0442\u0430\u043d\u043e\u0432": [0, 8, 21, 23, 37, 38, 47, 65, 68, 70, 72, 74, 76, 85, 86, 90], "\u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d": 0, "\u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432": [0, 5, 8, 9, 21, 23, 30, 34, 37, 38, 40, 83, 86, 90], "\u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430": 0, "\u0444\u043e\u0440\u043c": [0, 5, 9, 23, 38, 56, 82, 85, 86, 92, 94, 95, 100, 102], "\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d": [0, 21, 34, 82, 86], "\u0447\u0442\u043e\u0431": [0, 5, 8, 9, 11, 21, 23, 26, 34, 37, 38, 40, 41, 42, 46, 56, 60, 68, 70, 72, 73, 74, 75, 82, 83, 85, 86, 88, 90, 92, 93, 95, 100], "\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430": [0, 34, 38, 42, 62, 65, 74, 82, 86, 90, 95, 100], "\u0431\u044b": [0, 8, 9, 11, 23, 34, 38, 40, 70, 73, 75, 76, 77, 82, 83, 86, 88, 92, 94, 100], "\u043f\u0440\u0438\u0432\u0430\u0442\u043d": 0, "\u0441\u043f\u043e\u0441\u043e\u0431": [0, 5, 8, 9, 11, 13, 21, 23, 26, 34, 38, 47, 49, 52, 56, 65, 70, 73, 74, 75, 76, 77, 80, 86, 88, 90, 92, 94], "\u043d\u0430\u0432\u0435\u0440\u043d": [0, 21, 34, 41, 47, 65, 75, 83, 85, 86, 92], "\u0437\u0430\u043c\u0435\u0447\u0430": [0, 94], "\u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [0, 83, 89, 90, 92, 94, 100], "\u0447\u0430\u0442": [0, 34], "\u043c\u043e\u043b\u043e\u0434": [0, 83, 100], "\u0440\u0435\u0431\u044f\u0442": [0, 38], "\u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d": [0, 5, 82, 88, 92, 93], "\u0437\u0430\u0434\u0430": [0, 5, 23, 70, 74, 90, 94], "\u0442\u043e\u0442": [0, 8, 15, 21, 23, 26, 34, 56, 64, 75, 76, 77, 83, 85, 88, 90, 93, 100], "\u043f\u0435\u0440\u0432": [0, 8, 9, 11, 21, 23, 34, 37, 41, 42, 46, 56, 64, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 92, 94, 100, 102], "\u043a\u0442\u043e": [0, 5, 8, 9, 21, 34, 40, 51, 64, 73, 75, 83, 85, 86, 88, 90, 92, 93, 94, 100], "\u044d\u043a\u0441\u043f\u0435\u0440\u0442": [0, 8, 82], "\u043e\u0442\u0432\u0435\u0442": [0, 8, 9, 21, 23, 34, 70, 82, 88], "\u0441\u043b\u0435\u0434": [0, 5, 8, 11, 21, 23, 34, 37, 38, 46, 47, 52, 65, 70, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 92, 94, 100], "\u043f\u043e\u043f\u0443\u0433\u0430\u0439\u043d\u0438\u0447\u0430": 0, "\u0443\u0436": [0, 5, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 51, 56, 65, 74, 75, 76, 80, 82, 83, 85, 86, 88, 90, 92, 94, 95, 100, 102], "\u043d\u0438\u043a\u0442": [0, 21, 38, 40, 60, 74, 82, 88, 90, 92], "\u0445\u043e\u0447\u0435\u0442": [0, 9, 40, 46, 92], "\u0442\u043e\u0433\u0434": [0, 8, 9, 11, 15, 21, 23, 26, 34, 38, 56, 73, 75, 76, 77, 83, 85, 86, 88, 93, 95, 100], "\u043f\u044b\u0442\u0430": [0, 9, 21, 38, 65, 70, 73, 74, 85, 88, 90, 92, 94], "\u043e\u0442\u0432\u0435\u0447\u0430": [0, 8, 21, 38, 75, 76, 82, 86], "\u043c\u0430\u043b\u043e\u043e\u043f\u044b\u0442\u043d": [0, 38, 74], "\u0437\u0430\u0447\u0430\u0441\u0442": [0, 23, 38, 40, 41, 52, 68, 74, 76, 92], "\u0432\u0440\u0435\u0434": [0, 72], "\u043f\u043e\u043b\u044c\u0437": [0, 8, 9, 21, 23, 38, 40, 72], "\u0447\u0435\u0440\u0435\u0437": [0, 5, 8, 9, 11, 21, 23, 40, 70, 75, 82, 83, 84, 86, 88, 92, 136], "\u043e\u0442\u044b\u0441\u043a\u0430": [0, 23], "\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d": [0, 23, 26, 37, 38, 40, 65, 68, 70, 75, 82, 83, 85, 88, 94, 95, 100], "\u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a": [0, 5, 8, 21, 23, 65, 75, 82, 86, 92, 100], "\u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d": [0, 8, 11, 15, 23, 37, 38, 65, 70, 74, 86, 94, 100, 102], "\u0441\u043b\u043e\u0436\u043d": [0, 11, 15, 21, 30, 37, 38, 39, 43, 47, 56, 60, 66, 68, 70, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 90, 92, 121], "\u0432\u044b\u044f\u0432": [0, 92], "\u043d\u0430\u043f\u043b\u043e\u0434": 0, "\u0434\u0435\u0437\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446": 0, "\u0442\u0430\u043c": [0, 5, 9, 15, 23, 34, 37, 52, 56, 65, 70, 85, 86, 90, 92, 94], "\u0433\u0434\u0435": [0, 9, 11, 15, 21, 30, 34, 38, 40, 41, 47, 52, 56, 65, 74, 75, 83, 85, 86, 90, 92, 94, 95, 100, 102], "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430": 0, "\u043f\u0438\u0448\u0443\u0442": [0, 21, 62, 74, 90], "\u043d\u0435\u043b\u044c\u0437": [0, 9, 21, 23, 75, 76, 86, 102], "\u043b\u0438": [0, 8, 9, 11, 12, 22, 34, 38, 42, 47, 56, 70, 72, 82, 86, 90, 100, 102, 111], "\u0446\u0435\u043b": [0, 9, 11, 15, 21, 23, 29, 30, 37, 38, 40, 46, 51, 65, 70, 72, 73, 74, 75, 76, 83, 85, 86, 90, 92, 100, 102], "\u043f\u0443\u0442": [0, 5, 8, 21, 26, 34, 38, 40, 46, 56, 65, 72, 73, 76, 80, 82, 83, 85, 86, 88, 92, 93, 100], "\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d": [0, 9, 15, 21, 23, 30, 34, 37, 38, 40, 46, 67, 68, 70, 74, 75, 76, 81, 83, 85, 86, 90, 92, 93, 95, 130, 135], "\u0441\u043e\u043e\u0431\u0449\u0435\u043d": [0, 8, 21, 23, 30, 33, 118], "\u0437\u0430\u043c\u0435\u0442\u043e\u043a": 0, "\u043f\u043e\u0432\u044b\u0441": [0, 8, 37, 38, 72, 83, 85, 86, 88, 100], "\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c": 0, "\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d": [0, 37, 56, 64, 74, 75, 83, 86, 92], "\u0440\u043e\u0434": [0, 21, 42, 82, 86, 92, 93], "\u0441\u043a\u0435\u043b\u0435\u0442": [0, 86], "\u043d\u0430\u043b\u0438\u043f\u0430": 0, "\u0431\u0435\u0437": [0, 5, 8, 15, 21, 37, 38, 47, 70, 73, 74, 75, 82, 83, 85, 86, 92, 94, 95, 100, 102], "\u0431\u0435\u0441\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d": 0, "\u043e\u043a\u0435\u0430\u043d": 0, "\u0441\u043b\u044b\u0448\u0430": [0, 75, 85, 88], "\u0430\u043d\u0442\u0438\u043f\u0430\u0442\u0442\u0435\u0440\u043d": 0, "\u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u043e\u043d\u0435\u0440": [0, 37, 83, 91, 95, 138], "\u043d\u0430\u043a\u0430\u043f\u043b\u0438\u0432\u0430": [0, 38], "\u043c\u043d\u043e\u0433": [0, 9, 11, 13, 23, 37, 38, 40, 42, 46, 64, 68, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 93, 100, 102], "\u043d\u0430\u0439\u0442": [0, 8, 21, 23, 73, 74, 82, 85], "\u043d\u0438\u0431\u0443\u0434": [0, 23, 70, 73, 74], "\u043c\u0435\u0441\u0441\u0438\u0432": 0, "\u043d\u0435\u0440\u0435\u0430\u043b\u044c\u043d": 0, "\u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441": [0, 83], "\u043f\u043e\u043b\u043d\u043e\u0442\u0435\u043a\u0441\u0442\u043e\u0432": 0, "\u043f\u043e\u0438\u0441\u043a": [0, 5, 12, 41, 56, 72, 75, 76, 93, 96, 100], "\u043c\u043e\u0440\u0444\u043e\u043b\u043e\u0433": 0, "\u0434\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d": 0, "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0437\u0430\u0446": [0, 92], "\u043a\u043e\u043d\u0442\u0435\u043d\u0442": 0, "\u043f\u0440\u0438\u0447": [0, 9, 13, 23, 34, 37, 38, 74, 86, 92], "\u0434\u0435\u0440\u0435\u0432": [0, 75], "\u043c\u043e\u0433\u0443\u0442": [0, 8, 9, 11, 21, 23, 26, 38, 40, 41, 46, 47, 64, 65, 70, 72, 74, 75, 77, 82, 83, 85, 86, 92, 93, 94, 100, 102], "\u043f\u0435\u0440\u0435\u0441\u0435\u043a\u0430": [0, 9, 82, 85], "\u0441\u043e\u0431": [0, 9, 11, 23, 37, 38, 74, 75, 83, 85, 86, 102], "\u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434": [0, 8, 74], "\u0444\u0430\u0439\u043b\u043e\u0432": [0, 5, 12, 85], "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440": [0, 5, 8, 9, 12, 21, 46, 75, 77, 85], "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442": [0, 37, 52, 82], "\u0430\u043b\u0444\u0430\u0432\u0438\u0442\u043d": [0, 96], "\u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b": [0, 23, 26, 96], "\u0442\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d": 0, "\u0438\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d": 0, "\u043f\u0435\u0440\u0435\u043a\u0440\u0435\u0441\u0442\u043d": 0, "\u0434\u0430\u0436": [0, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 41, 46, 47, 52, 56, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 90, 92, 94, 102], "\u043a\u0440\u043e\u0441\u0441": 0, "\u043f\u0440\u043e\u0435\u043a\u0442\u043d": [0, 72, 73, 76, 86], "\u0441\u0441\u044b\u043b\u043a": [0, 8, 9, 11, 16, 21, 23, 75], "\u0441\u0442\u0440\u0430\u043d\u0438\u0446": [0, 38, 82, 86, 93, 95], "\u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440": [0, 70, 72, 73, 75, 76, 85, 86, 92, 93, 100, 102], "\u043a\u0430\u043d\u0430\u043b": [0, 23, 30, 34, 89], "\u043d\u043e\u0432": [0, 5, 8, 9, 23, 30, 34, 37, 38, 46, 47, 56, 62, 70, 72, 73, 74, 75, 76, 82, 83, 85, 88, 92, 93, 94, 95, 100], "\u043b\u0435\u0433\u043a": [0, 5, 9, 21, 23, 30, 37, 38, 51, 70, 73, 74, 75, 82, 85, 88, 94], "\u043e\u0442\u0440\u0430\u0436\u0430": [0, 5, 23, 34, 38, 92], "channel": [0, 23, 34], "\u0431\u043e\u0442": 0, "\u043f\u043b\u0430\u0433\u0438\u043d": [0, 5], "\u043e\u0431\u0440\u0430\u0437": [0, 5, 8, 9, 13, 15, 21, 23, 26, 30, 34, 37, 38, 41, 56, 65, 70, 72, 74, 75, 76, 80, 85, 86, 90, 92, 93, 95, 100, 102], "\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d": [0, 21, 23], "\u0441\u043e\u0445\u0440\u0430\u043d\u044f": [0, 5, 23, 82, 85, 102], "\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d": [0, 64, 76, 82], "\u043d\u0430\u0431\u043e\u0440": [0, 38, 76, 85], "\u043f\u0440\u0438\u043d\u0446\u0438\u043f": [0, 5, 8, 9, 21, 26, 37, 38, 40, 46, 52, 66, 70, 72, 73, 74, 75, 76, 85, 88, 91, 92, 93, 94, 95, 138], "\u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d": 0, "\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430": [0, 8, 9, 34, 37, 38, 65, 70, 72, 76, 80, 85], "open": [0, 5, 9, 23, 46, 51, 73, 75, 82, 86, 88], "source": [0, 5, 21, 23, 34, 37, 38, 51, 52, 60, 62, 65, 74, 75, 76, 77, 82, 85, 86, 100], "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [0, 50, 52, 125], "sphinx": 0, "doc": 0, "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0449": 0, "\u0444\u043e\u0440\u043c\u0430\u0442": [0, 9, 21], "\u0440\u0430\u0437\u043c\u0435\u0442\u043e\u043a": 0, "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f": [0, 21, 23, 38, 70, 77], "\u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432": [0, 85], "index": [0, 21, 66], "table": [0, 23, 51, 85], "of": [0, 5, 8, 9, 11, 13, 14, 15, 21, 26, 29, 30, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 53, 59, 60, 62, 63, 64, 65, 66, 68, 70, 71, 76, 77, 80, 83, 85, 88, 90, 92, 93, 94, 95, 100, 132], "content": [0, 34, 38, 49, 64, 82, 85], "toc": 0, "toctree": 0, "\u0438\u0435\u0440\u0430\u0440\u0445": [0, 46], "\u0441\u0432\u044f\u0437": [0, 5, 21, 23, 37, 38, 40, 52, 70, 72, 75, 85, 86, 88, 93, 100, 102], "\u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a": [0, 21], "js": 0, "\u0431\u0440\u0430\u0443\u0437\u0435\u0440": 0, "todo": 0, "\u043b\u0438\u0441\u0442": [0, 8, 74], "\u0441\u0442\u043e\u0440\u043e\u043d": [0, 9, 11, 21, 23, 37, 40, 68, 70, 74, 75, 80, 82, 83, 86, 88, 92, 93, 94, 100, 102], "\u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a": 0, "\u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441": [0, 5, 15, 82], "\u044f\u0437\u044b\u043a": [0, 15, 21, 23, 26, 34, 37, 38, 72, 74, 75, 82, 85, 86, 93, 102], "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d": [0, 21, 26, 38, 70, 72, 75, 85, 86, 88, 89, 93, 94], "\u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c": 0, "\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432": [0, 8, 11, 23, 30, 40, 65, 70, 73, 74, 82, 85, 86, 93, 100], "\u0433\u043e\u0442\u043e\u0432": [0, 21, 23, 46, 70], "\u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a": [0, 23, 34, 38, 75, 76, 82, 92, 93], "\u0432\u0430\u0436\u043d": [0, 9, 21, 34, 37, 38, 46, 51, 62, 65, 72, 73, 74, 75, 76, 82, 83, 85, 88, 90, 92, 94, 95, 102], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443": [0, 5, 8, 13, 21, 23, 30, 34, 38, 39, 86, 90], "\u0432\u043e\u0442": [0, 5, 8, 21, 23, 30, 38, 72, 75, 82, 83, 85, 88, 89, 90, 92, 95], "\u043f\u0438\u0448\u0435\u0442": [0, 21, 38, 40, 41, 47, 51, 74, 75, 82, 85, 90], "\u0435\u0432\u0433\u0435\u043d": [0, 76], "\u043f\u0435\u0448\u043a": 0, "\u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b": [0, 38, 85], "\u0440\u043e\u0441\u0441\u0438\u0439\u0441\u043a": 0, "ddd": [0, 8, 9, 11, 14, 15, 24, 29, 30, 32, 34, 37, 75, 76, 87, 88, 100, 104, 112, 117, 137], "\u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432": [0, 13, 85, 92], "\u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0438\u0442\u0435\u043b": [0, 30, 46, 82], "\u0446\u0438\u0430": 0, "\u043b\u0435\u0442": [0, 21, 38, 73, 74, 76, 83, 86, 88, 94, 100], "2020": [0, 37, 38, 40, 86], "\u044f": [0, 9, 11, 15, 21, 23, 34, 37, 38, 40, 46, 47, 70, 72, 74, 75, 82, 83, 85, 86, 88, 92, 93, 94, 95, 102], "\u043f\u0440\u043e\u0445\u043e\u0434": [0, 76, 83, 94], "\u043a\u0443\u0440\u0441": [0, 37, 38, 40, 46, 67, 68, 70, 74, 75, 82, 88, 130], "\u0441\u0438\u0441\u0442\u0435\u043c\u043d": [0, 23, 41, 64, 65, 72, 76, 80, 82, 83, 86, 100], "\u043c\u044b\u0448\u043b\u0435\u043d": [0, 23, 41, 82, 83, 89, 92], "\u043b\u0435\u0432\u0435\u043d\u0447\u0443\u043a": 0, "\u0430\u043d\u0430\u0442\u043e\u043b": 0, "\u0437\u0430\u043d\u044f\u0442": [0, 42, 85, 86], "\u0432\u0441\u044f\u0447\u0435\u0441\u043a": 0, "\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434": [0, 8, 15, 23, 72, 82, 85], "\u043f\u0438\u0441\u044c\u043c": [0, 34], "\u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430": [0, 23, 75, 80, 82, 85, 100, 102], "\u0441\u043e\u0437\u0434\u0430\u043d": [0, 8, 9, 21, 23, 38, 46, 74, 77, 85, 86, 90, 102], "\u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442": [0, 23, 82], "\u043a\u043d\u0438\u0433": [0, 8, 9, 11, 13, 21, 23, 30, 34, 37, 38, 40, 46, 51, 64, 72, 75, 76, 82, 83, 85, 86, 93, 94, 95], "\u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d": 0, "\u0441\u043b\u043e\u0432": [0, 8, 10, 11, 23, 34, 37, 38, 40, 46, 52, 56, 72, 73, 74, 75, 77, 85, 86, 89, 92, 93, 94, 100], "\u043f\u043e\u043d\u0438\u043c\u0430\u043d": [0, 21, 23, 38, 64, 72, 75, 82, 83, 86, 88, 93, 94, 100, 102], "\u043f\u0440\u043e\u0439\u0434\u0435\u043d": 0, "\u043b\u0443\u0447\u0448": [0, 5, 8, 21, 23, 30, 37, 38, 40, 42, 56, 60, 68, 70, 72, 73, 74, 75, 77, 82, 83, 85, 86, 90, 92, 93, 94, 95], "\u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430": [0, 93], "\u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434": [0, 23, 30, 37, 38, 56, 70, 74, 85, 86, 88, 90, 93, 102], "\u0442\u043e\u0433": [0, 8, 9, 11, 21, 23, 30, 34, 37, 38, 40, 42, 47, 68, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 89, 90, 92, 93, 95, 100, 102], "\u043c\u044b": [0, 5, 8, 9, 11, 13, 21, 23, 30, 34, 37, 38, 40, 65, 68, 70, 72, 74, 75, 76, 83, 85, 86, 90, 93, 94, 100, 102], "\u043f\u0440\u043e\u0433\u043e\u043d\u044f": 0, "\u0441\u0435\u0431": [0, 15, 23, 37, 38, 40, 47, 56, 62, 73, 75, 82, 83, 85, 86, 88, 92, 93], "\u0432\u043d\u0443\u0442\u0440\u0435\u043d": [0, 9, 11, 23, 37, 38, 40, 73, 74, 75, 82, 85, 100], "\u0434\u0438\u0430\u043b\u043e\u0433": [0, 102], "\u043c\u0435\u0445\u0430\u043d\u0438\u0447\u0435\u0441\u043a": [0, 11, 74], "\u043f\u0430\u043c\u044f": [0, 9, 82, 85, 89, 102], "\u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d": [0, 5], "\u043f\u043e\u043d\u0438\u043c\u0430": [0, 23, 37, 38, 52, 64, 72, 75, 83, 85, 86, 93, 94, 100], "\u043d\u0430\u0448": [0, 21, 37, 38, 40, 41, 46, 68, 70, 74, 88, 94, 100], "\u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d": [0, 21, 23, 52, 68, 75, 76, 88, 92], "\u0441\u0442\u0440\u043e\u0433": [0, 8, 21, 34, 73, 92, 100], "\u0441\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430": [0, 86, 100], "\u043e\u0431\u0440\u044b\u0432\u0430": 0, "\u0441\u043e\u0441\u0442\u043e\u044f": [0, 8, 75, 85], "\u043f\u043e\u043b\u0443\u043e\u0431\u0440\u0430\u0437": 0, "\u043d\u0435\u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430": 0, "\u043b\u043e\u0436\u043d": [0, 41, 89, 100, 102], "\u043e\u0449\u0443\u0449\u0435\u043d": [0, 11, 42, 47, 83, 85], "\u043f\u043e\u043d\u044f\u0442\u043d": [0, 23, 34, 64, 70, 74, 90, 100], "\u043f\u0438\u0448": [0, 72, 85], "\u0447\u0435\u0442\u043a": [0, 23, 73, 94, 100], "\u0442\u0435\u0437\u0438\u0441": 0, "\u0441\u043b\u043e\u0436": [0, 85], "\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [0, 8, 11, 13, 21, 23, 34, 38, 56, 70, 72, 74, 77, 85, 86, 90, 92, 100], "\u043f\u043e\u0440\u044f\u0434\u043a": [0, 8, 21, 23, 34, 38, 40, 82], "\u0432\u0435\u0440\u043d\u0443\u0442": [0, 9, 23, 47], "\u0434\u043e\u043e\u0441\u043c\u044b\u0441\u043b": 0, "\u043e\u0441\u0442\u0430": [0, 9, 11, 30, 34, 38, 40, 49, 56, 65, 70, 75, 83, 85, 88, 90, 93, 95], "\u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442": [0, 86], "\u043f\u0440\u0438\u0433\u043e\u0434\u043d": 0, "\u0434\u0430\u043b\u044c\u043d": [0, 42, 72, 73, 74, 85, 88, 100], "\u043f\u0440\u043e\u0440\u0430\u0431\u043e\u0442\u043a": [0, 5, 92], "\u043e\u0442\u0447\u0443\u0436\u0434\u0430": 0, "\u043c\u043e\u0436": [0, 8, 37, 40, 70, 74, 94, 100], "\u0437\u0430\u043f\u043e\u0441\u0442": [0, 95], "\u0442\u0435\u043b\u0435\u0433\u0440": 0, "\u043e\u0442\u043f\u0440\u0430\u0432": [0, 23, 30], "\u0432\u0437\u044f\u0442": [0, 9, 38, 46, 86, 90], "\u043d\u0430\u0447\u0430": [0, 47, 70, 72, 74, 76, 83, 85, 86], "\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430": [0, 38, 74], "\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446": [0, 8, 85], "\u0431\u044b\u043b": [0, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 41, 51, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 100], "\u0443\u043a\u0430\u0437\u0430": [0, 38, 60, 90, 102], "how": [0, 9, 11, 15, 21, 23, 34, 37, 38, 39, 46, 49, 51, 60, 62, 65, 66, 70, 72, 73, 74, 75, 76, 80, 82, 85, 86, 88, 89, 90, 94, 100], "to": [0, 5, 8, 9, 11, 13, 15, 21, 23, 26, 29, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 59, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 76, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100], "take": [0, 21, 23, 34, 37, 38, 41, 46, 51, 68, 73, 74, 80, 85, 93], "smart": [0, 53, 68, 70], "notes": [0, 34, 37, 76, 82], "\u043a\u043b\u0430\u0441\u0441\u043d": [0, 30, 38], "\u043f\u043e\u0438\u043d\u0442": [0, 8], "\u043f\u0440\u0438\u0432\u044b\u043a\u0430": [0, 5], "\u043d\u0430\u043c": [0, 8, 9, 21, 23, 37, 42, 70, 74, 85, 90, 92, 100], "\u043f\u0440\u043e\u0449": [0, 70, 72, 74, 85, 88, 90], "\u043f\u0438\u0441\u0430": [0, 9, 13, 21, 38, 45, 46, 65, 66, 70, 72, 74, 75, 76, 85, 88, 92, 123], "\u0442\u0443\u0442": [0, 5, 8, 21, 23, 34, 38, 51, 56, 73, 82, 85, 88, 94, 95], "\u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": [0, 85], "\u043f\u0440\u0438\u0432\u044b\u0447\u043a": [0, 68, 82, 95], "\u043a\u0440\u043e\u043c": [0, 9, 23, 30, 34, 37, 38, 40, 56, 70, 74, 85, 86, 102], "\u0443\u043a\u0430\u0437\u044b\u0432\u0430": [0, 21, 42, 52, 75, 83, 102], "\u0440\u0430\u043d": [0, 21, 23, 34, 37, 38, 40, 46, 72, 77, 85, 86], "\u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": 0, "https": [0, 5, 8, 16, 21, 34, 37, 38, 76, 82, 89, 92, 100], "t": [0, 5, 8, 9, 11, 21, 23, 29, 30, 34, 37, 38, 39, 42, 46, 47, 49, 51, 52, 53, 60, 62, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 94, 100], "me": [0, 13, 23, 37, 38, 41, 46, 72, 74, 85, 86, 92, 100], "dddevotion": [0, 100], "176": 0, "\u043c\u0435\u043d": [0, 9, 15, 21, 23, 38, 40, 64, 70, 72, 74, 82, 83, 85, 90, 92, 93], "\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u043b": [0, 93], "\u0441\u0438\u043b\u044c\u043d": [0, 8, 9, 40, 41, 65, 68, 74, 77, 83, 85, 88, 90, 95], "\u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d": [0, 74, 93, 94], "\u043d\u0435\u0431\u043e\u043b\u044c\u0448": [0, 5, 8, 9, 23, 38, 74, 82, 85, 86, 92], "\u043a\u043d\u0438\u0436\u0435\u0447\u043a": 0, "\u0447\u0438\u0442\u0430": [0, 21, 37, 56, 64, 76, 82, 83, 85, 91, 95, 138], "\u043f\u043e\u0432\u0430\u0440\u043d\u0438\u043d": [0, 82, 93], "\u0441\u0435\u0440\u0433": [0, 5, 66, 70, 75, 82, 94, 95], "\u043f\u0440\u043e\u0447\u0435\u0441\u0442": 0, "\u0434\u0435\u043d": [0, 21, 70, 76, 82, 85, 95], "\u0441\u043a\u0430\u0447\u0430": [0, 82], "\u0437\u0434\u0435": [0, 5, 9, 11, 21, 23, 30, 34, 37, 38, 40, 52, 53, 65, 75, 76, 80, 82, 83, 85, 86, 89, 90, 92], "\u043f\u0435\u0440\u0435\u043e\u0446\u0435\u043d": 0, "\u0432\u0435\u0441": [0, 8, 38, 73, 90, 93, 94, 100], "\u0437\u043e\u043b\u043e\u0442": [0, 93], "\u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442": [0, 34, 51, 82], "\u043f\u0440\u043e": [0, 21, 23, 38, 60, 62, 68, 75, 76, 90, 92, 100], "\u043e\u0441\u043e\u0431": [0, 8, 73, 85, 86], "\u0437\u043d\u0430\u0447\u0435\u043d": [0, 8, 9, 23, 26, 30, 34, 38, 52, 70, 75, 76, 82, 83, 85, 90, 91, 92, 93, 138], "\u043f\u0440\u0438\u043c\u0435\u043d\u044f": [0, 9, 13, 21, 23, 34, 65, 75, 83, 94], "\u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d": 0, "\u043d\u0443": [0, 21, 23, 38, 82, 85, 86, 90], "\u0440\u0430\u0437": [0, 8, 21, 23, 34, 37, 38, 46, 56, 70, 73, 74, 75, 77, 82, 85, 86, 88, 100], "\u0437\u0430\u0442\u0440\u043e\u043d\u0443\u0442": 0, "a": [0, 5, 8, 9, 11, 13, 15, 21, 23, 26, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 59, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100], "mind": [0, 23, 37, 47, 49, 51, 53, 70, 73, 75, 82, 85], "numbers": [0, 23, 34, 74, 75, 82, 86], "excel": [0, 5, 8, 82], "at": [0, 5, 9, 11, 21, 23, 29, 34, 37, 38, 39, 42, 46, 47, 49, 51, 52, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 95, 100], "math": [0, 75, 82], "and": [0, 5, 9, 11, 13, 15, 21, 31, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 76, 77, 80, 83, 85, 88, 89, 90, 92, 93, 94, 95, 100, 116], "science": [0, 23, 62, 65, 68, 73, 82, 85, 86], "by": [0, 5, 8, 9, 11, 13, 14, 15, 21, 23, 26, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 75, 77, 80, 82, 83, 85, 88, 89, 90, 92, 93, 94, 95, 100], "barbara": [0, 82], "ann": [0, 82], "oakley": [0, 82], "\u043f\u0435\u0440\u0435\u0432\u043e\u0434": [0, 8, 9, 11, 21, 26, 34, 37, 38, 42, 46, 47, 60, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 88, 90, 100], "\u0434\u0443\u043c\u0430": [0, 38, 40, 46, 72, 73, 74, 83, 85, 90, 102], "\u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a": [0, 37, 40, 62, 85, 90, 100, 102], "\u043b\u044e\u0431": [0, 5, 11, 23, 26, 37, 38, 47, 70, 72, 73, 74, 75, 82, 85, 86, 88, 90, 92, 100, 102], "\u0431\u0430\u0440\u0431\u0430\u0440": 0, "\u043e\u0430\u043a\u043b": 0, "\u043f\u0438\u0441\u044c\u043c\u0435\u043d": 0, "\u043d\u0435\u0440\u0435\u0434\u043a": [0, 37, 38, 40, 75, 76, 82, 83, 92], "\u0438\u0441\u043f\u044b\u0442\u044b\u0432\u0430": 0, "\u0437\u0430\u0442\u0440\u0443\u0434\u043d\u0435\u043d": 0, "\u0440\u0430\u0431\u043e\u0442": [0, 5, 9, 23, 37, 38, 40, 42, 46, 51, 60, 62, 64, 70, 72, 73, 74, 75, 77, 82, 85, 86, 88, 89, 90, 92, 93, 95], "\u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442": [0, 38, 60, 70, 72, 73, 74, 75, 76, 77, 90], "\u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0435\u043d": 0, "\u043f\u0430\u043c\u044f\u0442": [0, 38, 73, 74, 75, 82, 90, 92, 93, 94], "\u0438\u0441\u0445\u043e\u0434\u043d": [0, 16, 56, 85, 86, 92], "\u0441\u043d\u0438\u0436\u0430": [0, 42, 65, 74, 85, 94, 95], "\u0440\u0435\u0448\u0435\u043d": [0, 5, 8, 9, 11, 21, 34, 37, 39, 40, 41, 56, 60, 68, 72, 73, 74, 76, 77, 82, 83, 85, 86, 88, 90, 93, 94, 100], "\u0432\u044b\u0440\u0430\u0431\u043e\u0442\u0430": [0, 82, 92], "\u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d": [0, 82], "\u043f\u0440\u0435\u0436\u0434": [0, 70, 76, 85, 86, 102], "\u043e\u0442\u0440\u0430\u0437": 0, "\u043b\u0438\u0431": [0, 5, 8, 9, 11, 21, 23, 30, 34, 38, 73, 74, 75, 85, 88, 92, 94, 95, 100, 102], "\u0435\u0434\u0438\u043d": [0, 5, 11, 21, 23, 34, 37, 56, 75, 88], "\u0438\u0441\u0442\u0438\u043d": [0, 21, 73, 74, 83, 85, 86, 90, 93, 100, 102], "\u0432\u0441\u0435\u0433\u0434": [0, 9, 21, 23, 37, 38, 46, 56, 70, 75, 82, 85, 92, 93, 95, 100, 102], "\u043f\u043e\u0434": [0, 5, 21, 23, 26, 37, 38, 46, 52, 53, 56, 73, 74, 75, 76, 82, 83, 86, 92, 93, 94, 100], "\u0440\u0443\u043a": [0, 40, 56, 65, 82, 86], "\u0432\u043d\u0430\u0447\u0430\u043b": [0, 11, 46, 47, 85], "\u0443\u0441\u0438\u043b": [0, 38, 74, 83, 86, 92, 93, 95], "\u0432\u043e\u043b": [0, 38, 88], "\u0441\u0430\u043c\u043e\u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d": 0, "\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442": [0, 8, 9, 15, 22, 37, 38, 62, 65, 73, 74, 82, 83, 85, 86, 92, 93, 100, 111], "\u043f\u0440\u043e\u044f\u0432\u043b\u044f": [0, 34, 85, 94], "\u043e\u0447\u0435\u043d": [0, 5, 11, 15, 21, 23, 37, 38, 41, 56, 64, 68, 70, 73, 74, 75, 76, 82, 85, 86, 88, 89, 94, 100], "\u0432\u0435\u0434": [0, 11, 23, 37, 65, 70, 72, 85], "\u043e\u0431\u0440\u0430\u0449\u0430": [0, 5, 46, 47, 68, 85, 89], "\u0437\u0430\u043f\u0438\u0441\u0430": 0, "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432": [0, 82, 85], "\u0434\u043e\u0441\u0442\u0443\u043f": [0, 5, 8, 9, 11, 16, 21, 23, 82], "\u043a\u043e\u043c\u0430\u043d\u0434": [0, 22, 37, 38, 41, 42, 46, 49, 51, 64, 65, 70, 74, 76, 85, 87, 111, 137], "\u043a\u0440\u0430\u0442\u043d": [0, 40, 94], "\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d": [0, 5], "\u0441\u043e\u0437\u0434\u0430": [0, 5, 8, 11, 23, 30, 38, 70, 72, 73, 74, 76, 77, 85, 86, 88, 90, 93, 100], "\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u0430\u0440": 0, "\u043f\u0435\u0440\u0435\u0439\u0434": [0, 72], "private": [0, 8, 9, 11, 23, 85], "\u0438\u043c": [0, 21, 23, 26, 38, 46, 72, 74, 75, 76, 77, 85, 86, 88, 92, 102], "_html_extra": 0, "ivan": [0, 3, 4, 5, 8, 9, 10, 11, 14, 15, 18, 21, 23, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 56, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 86, 88, 89, 90, 92, 93, 94, 95, 100], "ivanov": 0, "\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440": [0, 5, 82], "\u0441\u0440\u0430\u0437": [0, 9, 21, 38, 46, 74, 86, 90, 100], "\u0432\u043d\u0435\u0441": 0, "gitignore": 0, "\u043e\u0431\u043b\u0435\u0433\u0447": [0, 9, 88, 92], "\u0447\u0438\u0442\u0430\u0442\u0435\u043b": [0, 82], "\u043e\u0447\u0435\u0432\u0438\u0434\u043d": [0, 8, 23, 38, 74, 85, 102], "sectionauthor": 0, "\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c": [0, 5, 11, 15, 37, 38, 46, 47, 51, 64, 70, 72, 74, 75, 82, 83, 85, 86, 92, 100], "\u043f\u043e\u0442": [0, 9, 11, 23, 34, 37, 38, 40, 41, 46, 53, 64, 70, 73, 74, 75, 76, 82, 83, 85, 86, 88, 92], "\u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430": [0, 37], "\u0432\u0441\u0435\u0445": [0, 5, 8, 11, 21, 34, 38, 40, 56, 70, 74, 85, 86, 90], "\u0432\u0438\u0434\u0435\u043d": [0, 56, 76, 82], "\u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u043a\u0430\u0446": [0, 8, 16], "\u0433\u0438\u0431\u043a\u043e\u0441\u0442": [0, 8, 23, 70], "\u0432\u043a\u043b\u044e\u0447\u0430": [0, 21, 23, 38, 40, 85, 92, 100, 102], "\u043f\u043e\u0434\u0434\u0435\u0440\u0435\u0432": 0, "\u0442\u0435\u0433\u0438\u0440": 0, "\u043f\u043e\u043c\u043e\u0449": [0, 5, 8, 21, 23, 34, 38, 46, 70, 74, 85, 88, 100, 102], "include": [0, 51, 77, 86], "\u0432\u0441\u0442\u0430\u0432\u043b\u044f": 0, "\u043f\u043e\u043b\u043d\u043e\u0441\u0442": [0, 8, 23, 38, 65, 72, 77, 82, 85, 86, 88, 90, 94, 100, 102], "\u0447\u0430\u0441\u0442\u0438\u0447\u043d": [0, 15, 21, 37, 40, 76], "\u0441\u043c": [0, 5, 9, 11, 23, 38, 40, 41, 51, 52, 62, 65, 70, 73, 74, 75, 76, 82, 83, 85, 86, 90, 92, 94, 100, 102], "options": [0, 38, 41, 43, 66, 70, 73, 74, 76, 121], "start": [0, 21, 23, 47, 73, 74, 75, 76, 77, 82, 85, 86], "line": [0, 34, 38, 40, 66, 70, 74, 75, 76, 90], "after": [0, 15, 21, 23, 34, 37, 38, 51, 72, 73, 76, 85, 86], "end": [0, 23, 34, 37, 38, 49, 52, 60, 73, 74, 76, 85, 86, 90], "before": [0, 21, 23, 29, 34, 37, 46, 47, 49, 51, 65, 70, 72, 74, 75, 76, 85, 86, 94], "dry": [0, 9], "\u043c\u0438\u043d\u0438\u043c\u0437\u0438\u0440\u0443": 0, "\u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d": [0, 38, 40, 65, 74], "\u043e\u0440\u0433\u0438\u043d\u0438\u0430\u043b\u044c\u043d": 0, "\u0442\u0435\u043a\u0441\u0442": [0, 23, 38, 92, 102], "\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430": 0, "\u043d\u0435\u043d\u0443\u0436\u043d": [0, 23, 82, 100], "\u0432\u0430\u043c": [0, 21, 23, 37, 38, 41, 46, 68, 70, 72, 73, 74, 76, 77, 82, 85, 86], "\u0443\u0434\u0430\u043b": [0, 5, 23, 30], "\u0446\u0435\u043b\u0438\u043a": [0, 5, 23, 72, 85], "\u0432\u044b\u0431\u043e\u0440\u043e\u0447\u043d": 0, "cherry": 0, "pick": [0, 38, 76, 86], "uuid4": 0, "\u0441\u0432\u044f\u0437\u0430": [0, 5, 11, 37, 38, 42, 46, 74, 75, 85, 102], "\u0441\u043b\u0435\u0434\u0443": 0, "\u043f\u0440\u0430\u043a\u0442\u0438\u043a": [0, 5, 13, 15, 23, 34, 37, 38, 40, 56, 65, 70, 72, 75, 76, 82, 85, 86, 88, 94, 100], "\u0432\u043c\u0435\u0441\u0442": [0, 5, 8, 9, 21, 37, 38, 40, 42, 52, 60, 70, 73, 74, 83, 85, 88, 90, 97], "uuid": [0, 21, 23], "\u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d": 0, "label": [0, 51], "names": [0, 23, 37, 73, 82], "\u043f\u0440\u0435\u0444\u0438\u043a\u0441": 0, "\u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a": [0, 11, 23, 30, 37, 38, 40, 51, 56, 65, 70, 74, 75, 76, 82, 83, 85, 86, 90, 92, 94, 102], "\u043f\u0435\u0440\u0435\u043c\u0435\u0449": [0, 8], "\u043f\u0440\u043e\u0441\u0442\u0430\u043d\u0441\u0442\u0432": 0, "ext": 0, "autosectionlabel": 0, "allow": [0, 11, 23, 37, 76, 86], "reference": [0, 8, 9, 19, 23, 34, 36, 75, 82, 86, 109, 120], "sections": 0, "using": [0, 5, 9, 11, 23, 29, 34, 72, 73, 74, 75, 76, 80, 82, 85, 86, 100], "its": [0, 9, 15, 21, 23, 26, 34, 37, 38, 47, 49, 51, 52, 62, 70, 73, 74, 75, 76, 85, 86], "title": [0, 82], "\u043e\u0431\u043b\u0435\u0433\u0447\u0430": [0, 5, 21, 75, 82], "\u0438\u0437\u043c\u0435\u043d\u0435\u043d": [0, 5, 9, 11, 15, 23, 26, 30, 37, 40, 41, 47, 64, 70, 74, 75, 76, 83, 85, 86, 90, 91, 102, 138], "\u043b\u043e\u043a\u0430\u0446": 0, "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430": 0, "seealso": 0, "intersphinx": 0, "pull": [0, 23, 38, 56, 75, 77], "request": [0, 21, 23, 56], "trunk": 0, "branch": 0, "\u044d\u0442\u043e\u0442": [0, 5, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 41, 46, 65, 70, 72, 73, 74, 75, 77, 82, 83, 85, 86, 88, 90, 92], "\u0441\u0440\u0430\u0432\u043d": [0, 23, 38, 70, 85, 86], "\u0448\u0438\u043d": [0, 23, 30], "\u0441\u043e\u0431\u044b\u0442": [0, 8, 10, 21, 38, 75, 80, 88, 94], "event": [0, 7, 8, 9, 12, 19, 21, 30, 34, 38, 56, 76, 86, 108, 109], "sourcing": [0, 12, 19, 21, 23, 34, 109], "\u043e\u043a\u0430\u0437\u0430": [0, 5, 9, 11, 70, 72, 73, 83, 88, 92, 102], "\u0434\u043e\u0441\u0442\u0443\u043f\u043d": [0, 8, 11, 21, 23, 34, 82, 85, 88, 89], "\u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442": [0, 82], "\u0434\u043e\u043c\u0435\u043d": [0, 8, 10, 12, 30, 89], "\u043f\u043e\u0438\u0441\u043a\u043e\u0432": [0, 82], "\u0442\u0440\u0430\u0444\u0444\u0438\u043a": 0, "\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d": [0, 23, 37, 70, 73, 75, 82, 92], "\u0430\u0434\u0440\u0435\u0441": 0, "\u0438\u0441\u043f\u043e\u043b\u044c\u0437": [0, 5, 9, 11, 13, 15, 21, 23, 30, 34, 37, 38, 46, 47, 53, 70, 75, 77, 82, 85, 86, 88, 100, 102], "custom": [0, 9, 85], "page": [0, 21, 23, 70, 74, 75, 85, 96], "metadata": [0, 13, 23, 34], "canonical": [0, 96, 100], "url": [0, 21], "my": [0, 21, 23, 38, 41, 46, 62, 68, 72, 73, 74, 76, 83, 85, 86, 88, 90, 92], "domain": [0, 5, 8, 9, 11, 14, 16, 21, 26, 28, 29, 30, 34, 49, 65, 72, 73, 74, 75, 76, 86, 90, 103, 115], "ru": [0, 41, 64, 82, 89, 92], "path": [0, 23, 74, 82, 85], "base": [0, 21, 23, 37, 51, 62, 65, 74, 75, 77, 80], "\u0437\u0430\u043a\u0440\u044b\u0432\u0430": 0, "\u0441\u043b\u044d\u0448": 0, "html_baseurl": 0, "html_theme_options": 0, "canonical_url": 0, "\u0441\u0442\u0440\u043e\u0439\u0442": 0, "github": [0, 5, 8, 9, 16, 34, 75, 82, 89], "\u043f\u043b\u0430\u043d\u0438\u0440": 0, "\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a": [0, 8, 30, 86, 88, 100], "web": [0, 23, 37, 51, 76, 82, 86], "\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441": [0, 5, 9, 11, 21, 23, 30, 86], "desktop": 0, "client": [0, 15, 21, 23, 29, 73, 74], "gitlab": [0, 5], "\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b": [0, 9], "python": [0, 23, 34, 82], "\u0443\u0441\u0442\u0430\u043d\u043e\u0432": [0, 8, 9, 38], "\u0437\u0430\u0432\u0438\u0441\u0438\u043c": [0, 5, 9, 11, 15, 21, 34, 38, 40, 65, 74, 80, 85, 86, 94, 95, 100], "\u043a\u043e\u0440\u043d\u0435\u0432": [0, 8, 11], "\u0432\u044b\u043f\u043e\u043b\u043d": [0, 8, 40, 46, 77, 85, 86, 92], "pip": 0, "install": [0, 38], "r": [0, 38, 74, 82, 88], "requirements": [0, 23, 37, 38, 48, 59, 60, 62, 64, 65, 74, 75, 76, 77, 80, 82, 85, 124], "freeze": 0, "txt": 0, "\u043e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440": [0, 47], "conf": 0, "py": 0, "\u043f\u043e\u0434\u0440\u043e\u0431\u043d": [0, 8, 21, 23, 30, 38, 46, 86], "\u0441\u043c\u043e\u0442\u0440": [0, 23, 38, 40, 41, 74, 82, 85, 88], "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446": [0, 9, 23], "\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434": [0, 92], "\u0441\u0431\u043e\u0440\u043a": 0, "make": [0, 11, 21, 23, 29, 37, 38, 39, 41, 46, 47, 51, 53, 65, 68, 70, 73, 74, 75, 76, 77, 80, 85, 86, 90, 94, 100], "build": [0, 9, 23, 38, 46, 51, 66, 70, 73, 74, 82, 86, 92], "d": [0, 23, 38, 46, 64, 68, 70, 75, 76, 82, 85, 100], "language": [0, 5, 21, 23, 29, 51, 73, 74, 76, 82, 85, 100, 101], "b": [0, 5, 9, 21, 23, 30, 34, 37, 38, 40, 46, 75, 77, 82, 88], "_build": 0, "docker": [0, 5], "sphinx_image": 0, "run": [0, 21, 23, 37, 38, 60, 73, 74, 76, 85, 90], "v": [0, 8, 9, 53, 66, 82], "pwd": 0, "sphinxtechnicalwriting": 0, "\u043b\u043e\u043a\u0430\u043b\u044c\u043d": [0, 11, 21, 29], "\u0437\u0430\u043f\u0443\u0441\u043a": 0, "m": [0, 5, 23, 30, 34, 37, 38, 46, 73, 74, 75, 76, 82, 85, 88, 94, 95], "http": [0, 21, 23, 34, 76, 82, 85, 89], "server": [0, 21, 23, 34, 38, 74], "pdf": [0, 21, 23, 30, 34, 38, 82, 85], "epub": 0, "the": [0, 5, 8, 9, 11, 13, 14, 15, 21, 23, 26, 29, 30, 34, 37, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 77, 80, 82, 83, 85, 88, 90, 92, 93, 94, 95, 100], "introduction": [0, 34, 38, 75, 82], "method": [0, 9, 21, 23, 37, 38, 51, 60, 66, 72, 74, 85, 90], "\u0433\u043e\u0434": [0, 8, 37, 38, 46, 70, 73, 74, 75, 76, 83, 86, 92, 95], "\u0441\u0442\u0430\u0440\u0442\u043e\u0432": 0, "\u0442\u0440\u044e\u043a": [0, 9], "\u043d\u0435\u043c\u0435\u0446\u043a": [0, 83], "\u0443\u0447\u0435\u043d": [0, 68, 73, 85], "\u043d\u0435\u0432\u0435\u0440\u043e\u044f\u0442\u043d": [0, 37], "\u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0438\u0432\u043d": [0, 68, 86], "niklas": 0, "luhmann": 0, "\u0441\u0434\u0435\u043b\u0430": [0, 5, 8, 9, 11, 21, 23, 26, 30, 34, 37, 38, 46, 47, 56, 60, 70, 73, 74, 75, 82, 83, 85, 86, 88, 89, 90, 92, 95, 100], "\u0431\u0443\u043c\u0430\u0436\u043d": [0, 86], "\u043a\u0430\u0440\u0442\u043e\u0447\u043a": [0, 46], "\u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0430\u0446": [0, 38, 72, 73, 74, 90], "\u0440\u0438\u0441\u043a": [0, 15, 30, 38, 40, 47, 70, 86, 88, 89, 90], "\u0432\u043d\u0435\u0448\u043d": [0, 5, 9, 11, 23, 38, 56, 74, 85, 88, 92], "\u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d": [0, 8, 9, 21, 23, 34, 38, 40, 41, 70, 72, 73, 74, 75, 76, 77, 85, 88, 90, 93, 100], "\u0442\u0438\u043f": [0, 9, 38, 82, 86, 100, 102], "\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440": [0, 74, 85], "\u0432\u0435\u043d\u0434\u043e\u0440": 0, "\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0437\u043c": 0, "\u043f\u043e\u043b\u043d": [0, 8, 21, 26, 37, 38, 72, 85, 86, 102], "\u043d\u0430\u0434": [0, 5, 21, 34, 38, 46, 47, 60, 68, 70, 72, 74, 77, 82, 83, 85, 86, 88, 90, 92, 93, 95], "\u0441\u0432\u043e\u0431\u043e\u0434\u043d": [0, 38, 82], "\u043e\u0431\u043e\u0433\u0430\u0449\u0435\u043d": 0, "\u0434\u0438\u0441\u0442\u0438\u043b\u043b\u044f\u0446": 0, "in": [0, 5, 8, 9, 11, 12, 13, 15, 17, 19, 21, 24, 26, 29, 30, 34, 37, 39, 41, 42, 46, 47, 49, 51, 52, 53, 54, 59, 60, 62, 63, 64, 65, 66, 68, 70, 71, 76, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100, 109, 112, 126, 132], "our": [0, 21, 23, 34, 37, 38, 41, 46, 49, 51, 62, 65, 68, 70, 73, 74, 75, 76, 85, 86, 90, 100], "age": [0, 9], "when": [0, 9, 21, 23, 26, 29, 34, 37, 38, 40, 42, 46, 47, 49, 51, 52, 53, 65, 68, 72, 73, 74, 75, 76, 82, 85, 86, 88, 100], "cloud": [0, 34, 82], "services": [0, 23, 64, 74, 75, 82, 86, 93], "can": [0, 5, 8, 9, 11, 13, 15, 21, 23, 29, 34, 37, 38, 39, 41, 42, 46, 49, 51, 52, 59, 62, 65, 66, 68, 70, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 95, 100], "shut": 0, "down": [0, 21, 23, 37, 38, 41, 51, 74, 76, 78, 80, 82, 85, 133], "get": [0, 8, 9, 21, 23, 34, 37, 38, 51, 52, 60, 62, 68, 74, 76, 77, 80, 85, 86, 100], "bought": 0, "or": [0, 5, 8, 9, 11, 15, 21, 23, 26, 34, 37, 38, 39, 40, 42, 46, 49, 51, 52, 53, 60, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 86, 90, 100], "change": [0, 9, 11, 21, 23, 26, 37, 38, 39, 46, 47, 49, 52, 64, 65, 66, 70, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88], "privacy": [0, 11], "policy": [0, 23], "any": [0, 9, 11, 21, 23, 37, 38, 39, 41, 42, 49, 51, 65, 70, 72, 73, 74, 76, 85, 86, 90, 100], "day": [0, 23, 34, 37, 38, 46, 47, 70, 74, 76, 82, 85, 95], "last": [0, 23, 34, 37, 52, 65, 68, 85], "thing": [0, 9, 21, 23, 29, 34, 37, 38, 46, 51, 70, 72, 73, 74, 85, 88, 90], "you": [0, 8, 9, 13, 15, 21, 23, 29, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 60, 62, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 93, 94, 95, 100], "want": [0, 9, 21, 23, 37, 38, 46, 51, 60, 62, 65, 72, 74, 75, 76, 77, 80, 85, 90, 100], "is": [0, 5, 8, 9, 11, 13, 15, 21, 26, 29, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 59, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 76, 77, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 100], "proprietary": 0, "formats": 0, "data": [0, 9, 21, 23, 29, 34, 38, 74, 75, 82, 85, 86, 90, 93, 100], "lock": [0, 23, 30, 82], "with": [0, 6, 8, 9, 11, 15, 21, 23, 26, 29, 30, 34, 37, 38, 39, 41, 47, 49, 51, 52, 59, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88, 90, 93, 94, 95, 100, 107], "your": [0, 9, 21, 23, 34, 37, 38, 41, 42, 46, 62, 65, 70, 73, 74, 75, 77, 82, 85, 86, 90, 100], "sits": 0, "local": [0, 21, 23, 86], "folder": 0, "never": [0, 23, 29, 34, 37, 38, 41, 47, 70, 73, 75, 76, 77, 82, 100], "leave": [0, 23, 37, 86], "life": [0, 23, 34, 36, 37, 38, 49, 51, 52, 59, 60, 62, 63, 65, 70, 74, 76, 77, 82, 85, 86, 100, 120], "s": [0, 8, 9, 13, 21, 23, 26, 29, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 56, 60, 64, 65, 66, 68, 70, 73, 74, 76, 77, 80, 82, 85, 86, 88, 89, 90, 92, 93, 100], "work": [0, 9, 15, 21, 23, 34, 37, 38, 39, 41, 42, 51, 62, 65, 66, 70, 73, 74, 75, 76, 77, 80, 82, 85, 86, 92, 93, 94, 95], "held": [0, 37], "hostage": 0, "again": [0, 21, 23, 29, 37, 52, 74, 76, 77, 85], "plain": [0, 9, 23, 34, 52, 75, 82], "text": 0, "also": [0, 9, 15, 21, 23, 26, 34, 37, 38, 51, 68, 73, 74, 76, 82, 85, 86, 100], "gives": [0, 5, 11, 23, 38, 52, 62, 75, 76, 85, 86, 100], "unparalleled": 0, "interoperability": [0, 38], "use": [0, 9, 11, 15, 21, 23, 29, 34, 37, 38, 49, 51, 52, 65, 73, 75, 76, 82, 85, 86, 94, 100], "kind": [0, 9, 23, 47, 74, 85], "sync": 0, "encryption": 0, "processing": [0, 21, 23, 34, 74, 90], "that": [0, 9, 11, 15, 21, 23, 26, 29, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 59, 60, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 93, 94, 100], "works": [0, 23, 42, 46, 51, 68, 75, 77, 85, 93], "files": [0, 5, 23, 75], "md": [0, 86], "template": [0, 51, 82], "based": [0, 11, 21, 23, 34, 37, 38, 49, 52, 63, 72, 74, 76, 80, 82, 85, 86, 88, 100], "on": [0, 5, 9, 11, 13, 15, 21, 23, 30, 34, 37, 38, 41, 46, 47, 49, 51, 52, 62, 63, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88, 90, 92, 95, 100], "was": [0, 15, 21, 23, 34, 37, 38, 39, 41, 51, 62, 65, 70, 72, 73, 74, 75, 76, 80, 85, 86, 93], "designed": [0, 9, 23, 29, 37, 74, 86], "these": [0, 9, 21, 23, 29, 37, 38, 46, 51, 65, 70, 72, 74, 75, 76, 85, 86, 100], "criteria": [0, 5, 38, 51, 53, 86], "future": [0, 21, 23, 34, 37, 38, 39, 65, 68, 74, 75, 76, 85], "proof": 0, "store": [0, 21, 23, 34, 51, 82], "locally1": 0, "as": [0, 9, 11, 13, 15, 21, 23, 26, 29, 34, 37, 38, 39, 41, 46, 47, 49, 51, 52, 60, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 94, 100], "not": [0, 5, 8, 9, 11, 15, 21, 23, 26, 29, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 59, 62, 65, 70, 73, 74, 76, 80, 82, 85, 86, 90, 92, 93, 94, 95, 100], "tied2": 0, "single": [0, 11, 21, 23, 34, 38, 62, 74, 75, 76, 85, 86, 94, 100], "editor": [0, 23], "statically": 0, "generated": [0, 13, 21, 23, 74, 82], "site": [0, 82], "browsing": 0, "publishing": [0, 23, 34, 88], "remain": [0, 34], "simple": [0, 9, 23, 29, 34, 37, 38, 70, 73, 74, 75, 77, 82, 85, 86, 90], "possible": [0, 21, 23, 34, 37, 38, 49, 51, 68, 73, 74, 75, 76, 85, 86], "whilst": 0, "being": [0, 11, 21, 23, 34, 37, 38, 39, 42, 46, 49, 51, 70, 73, 74, 75, 76, 82, 85, 100], "feature": [0, 21, 23, 34, 38, 51, 62, 70, 74, 86], "rich": [0, 82], "via": [0, 23, 85, 86], "plugins": [0, 5], "zettel": 0, "philosophy": [0, 38], "\u0438\u043d\u0442\u0435\u0440\u0435\u0441": [0, 21, 37, 40, 41, 42, 44, 46, 66, 70, 72, 76, 82, 86, 100, 122], "\u0442\u0435\u0445": [0, 21, 37, 38, 46, 83, 85, 88, 90], "\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430": [0, 13], "tutorial": [0, 34, 64, 74, 82], "srid": 0, "io": [0, 34], "readme": [0, 23], "com": [0, 5, 8, 9, 16, 21, 23, 34, 37, 75, 80, 82, 85, 89], "\u0441\u0440\u0430\u0432\u043d\u0435\u043d": [0, 46, 65, 92, 100], "multi": [0, 21, 85, 86, 88], "repository": [0, 9, 17, 23, 28, 37, 51, 76, 82, 115], "documentation": [0, 23, 37, 49, 51, 64, 76, 82, 86], "generator": 0, "tech": [0, 37, 38], "writers": [0, 75], "who": [0, 23, 37, 38, 39, 46, 49, 51, 62, 73, 74, 75, 76, 85, 86, 90, 94], "writing": [0, 23, 37, 42, 46, 47, 53, 72, 74, 76, 77, 82, 85, 90], "asciidoc": 0, "compatible": 0, "favorite": [0, 76, 85, 88, 92], "apps": [0, 21, 23, 82], "aims": 0, "be": [0, 8, 9, 11, 21, 23, 26, 29, 34, 37, 38, 39, 41, 46, 47, 49, 51, 52, 53, 59, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88, 90, 94, 100], "extremely": [0, 37, 42, 76, 80, 100], "configurable": 0, "idea": [0, 23, 34, 38, 49, 52, 73, 75, 85, 86, 94, 100], "another": [0, 9, 11, 21, 23, 26, 29, 34, 49, 51, 70, 72, 74, 82, 85, 86, 93, 100], "silo": 0, "instead": [0, 5, 21, 23, 37, 39, 42, 47, 49, 52, 70, 73, 75, 85, 86, 93, 100], "integrate": [0, 23, 29, 86], "into": [0, 9, 11, 15, 21, 23, 29, 34, 37, 38, 41, 49, 51, 52, 60, 62, 65, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 100], "existing": [0, 9, 21, 23, 37, 38, 46, 47, 66, 70, 73, 74, 82, 85, 95], "workflow": [0, 8, 82], "no": [0, 8, 21, 23, 26, 34, 37, 38, 42, 46, 49, 51, 52, 60, 62, 65, 70, 72, 73, 74, 76, 77, 82, 85, 86, 90, 100], "two": [0, 11, 15, 21, 26, 29, 34, 37, 38, 52, 70, 73, 74, 75, 76, 82, 85, 86, 90, 95], "people": [0, 11, 23, 37, 38, 40, 41, 46, 49, 65, 68, 70, 73, 74, 75, 76, 85, 86, 88, 100], "are": [0, 5, 9, 11, 15, 21, 23, 29, 34, 37, 38, 40, 41, 42, 46, 47, 49, 51, 52, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 94, 100], "same": [0, 9, 21, 23, 26, 34, 37, 38, 39, 41, 52, 73, 74, 75, 76, 77, 85, 86, 90, 93], "multiple": [0, 23, 34, 74, 75, 77, 85, 86, 90, 100], "editors": [0, 74], "all": [0, 9, 11, 21, 23, 29, 34, 37, 38, 41, 42, 46, 47, 49, 51, 52, 60, 62, 64, 70, 72, 73, 74, 75, 76, 82, 85, 86, 90, 100], "stored": [0, 9, 21], "however": [0, 23, 34, 38, 46, 47, 51, 52, 70, 72, 73, 76, 85, 86, 100], "edit": [0, 74, 85], "many": [0, 9, 11, 15, 21, 23, 34, 37, 38, 46, 51, 62, 65, 68, 73, 74, 75, 76, 82, 85, 86, 92, 93, 95, 100], "different": [0, 21, 23, 29, 34, 38, 46, 51, 60, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 100], "ways": [0, 15, 21, 23, 29, 34, 37, 38, 52, 73, 74, 75, 82, 85, 86, 90], "depending": [0, 74, 85, 100], "task": [0, 9, 21, 23, 38, 73, 82, 86, 92], "100": [0, 41, 51, 62, 70, 73, 75, 85], "will": [0, 9, 21, 23, 26, 29, 34, 37, 38, 42, 46, 47, 49, 51, 52, 65, 68, 72, 73, 74, 75, 76, 77, 82, 85, 86, 92, 100], "always": [0, 9, 14, 21, 23, 34, 38, 46, 70, 73, 74, 75, 76, 85, 86, 100], "completely": [0, 9, 23, 34, 37, 46, 65, 73, 85], "join": 0, "community": [0, 34, 37, 38, 76, 82, 85, 86], "help": [0, 23, 29, 37, 38, 41, 51, 62, 65, 73, 77, 82, 83, 85, 86, 100], "us": [0, 9, 21, 23, 34, 37, 38, 41, 46, 51, 52, 62, 65, 68, 70, 72, 74, 75, 76, 85, 86, 100], "ideal": [0, 34, 38], "note": [0, 15, 21, 23, 34, 38, 46, 52, 74, 85], "taking": [0, 23, 38, 62, 73, 82, 85], "app": [0, 21, 23], "why": [0, 21, 23, 29, 34, 37, 38, 51, 65, 70, 74, 75, 82, 86, 100], "create": [0, 11, 21, 23, 34, 38, 49, 51, 52, 74, 82, 85, 86, 100], "there": [0, 8, 9, 11, 15, 21, 23, 34, 37, 38, 39, 41, 42, 46, 49, 51, 65, 70, 72, 73, 74, 75, 76, 77, 80, 85, 86, 100], "but": [0, 5, 9, 11, 15, 21, 23, 29, 34, 37, 38, 39, 41, 42, 46, 49, 51, 52, 59, 60, 62, 70, 72, 73, 74, 75, 76, 77, 80, 85, 86, 93, 94, 100], "mobile": [0, 52], "space": [0, 23, 38, 75, 76, 80, 82, 83, 86, 100], "lacking": 0, "good": [0, 9, 23, 29, 37, 38, 42, 52, 53, 70, 72, 73, 74, 75, 76, 82, 85, 86, 95, 100], "which": [0, 9, 11, 13, 15, 21, 23, 34, 37, 38, 39, 41, 51, 52, 60, 64, 65, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 93], "give": [0, 11, 37, 38, 46, 73, 74, 85, 86], "control": [0, 11, 23, 26, 34, 37, 38, 47, 72, 73, 76, 85, 86], "over": [0, 9, 23, 29, 34, 37, 38, 39, 41, 51, 62, 73, 74, 76, 82, 85, 86, 94], "operate": [0, 86], "protocols": 0, "support": [0, 21, 23, 34, 38, 46, 49, 51, 74, 82, 85, 86, 92, 94], "\u043a\u043b\u0430\u0441\u0441": [0, 8, 9, 15, 23, 30, 46, 74, 75, 77, 85, 90, 102], "\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442": [0, 13, 38, 82, 85, 92, 94, 100], "\u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d": [0, 93, 100], "\u0433\u0435\u043d\u0435\u0440\u0430\u0446": 0, "\u0431\u043b\u043e\u0433": [0, 23, 75], "\u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b": [0, 34, 82, 92], "\u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d": [0, 23, 38, 100], "\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430": [0, 5, 9, 15, 21, 23, 30, 34, 37, 38, 74, 82, 85, 90], "\u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d": [0, 5, 38, 46, 72, 85, 86, 100], "\u0440\u0430\u0437\u043c\u0435\u0442\u043a": 0, "shortcodes": 0, "\u0443\u043f\u0440\u043e\u0449\u0430": [0, 8, 37, 73, 74, 75], "\u0432\u0441\u0442\u0430\u0432\u043a": [0, 23], "\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c": [0, 5, 56, 82], "\u0444\u043e\u0440\u043c\u0443\u043b": [0, 89], "\u0441\u043d\u043e\u0441\u043e\u043a": 0, "\u0441\u0441\u044b\u043b\u043e\u043a": 0, "\u0442\u0432\u0438\u0442": 0, "\u0432\u0438\u0434\u0435": [0, 21, 66, 73, 82, 95], "\u044d\u043b\u0435\u043c\u0435\u043d\u0442": [0, 5, 11, 21, 37, 38, 42, 62, 73, 74, 75, 77, 85, 88, 90, 92, 94, 100], "\u043d\u0430\u0438\u0431\u043e\u043b": [0, 8, 9, 21, 23, 38, 42, 43, 47, 64, 66, 73, 75, 83, 85, 86, 95, 121], "\u0438\u0437\u0432\u0435\u0441\u0442\u043d": [0, 5, 9, 13, 21, 23, 38, 40, 53, 56, 65, 73, 75, 76, 83, 85, 86, 88, 92, 100], "c\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 0, "hugo": 0, "\u043d\u0430\u043f\u0438\u0441\u0430": [0, 21, 47, 72, 74, 77, 83, 85], "go": [0, 9, 11, 21, 23, 34, 37, 38, 42, 47, 65, 68, 70, 73, 74, 76, 77, 82, 85, 86], "\u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f": [0, 21, 23, 52], "\u0431\u0438\u043d\u0430\u0440\u043d": 0, "\u0438\u0441\u043f\u043e\u043b\u043d\u044f": [0, 23], "jekyll": 0, "\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a": [0, 102], "ruby": [0, 72, 75, 82, 85], "p\u0430ges": 0, "\u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": [0, 21, 23, 85], "\u0433\u0440\u0443\u043f\u043f": [0, 30, 34, 38, 40, 73, 86, 90, 92, 100], "javascript": 0, "\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a": [0, 9, 72, 86], "gastby": 0, "next": [0, 34, 37, 38, 49, 62, 65, 74, 80, 85, 86], "nuxt": 0, "vuepress": 0, "\u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d": [0, 8, 23, 75, 86], "hexo": 0, "eleventy": 0, "mkdocs": 0, "pelican": 0, "middleman": 0, "\u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d": [0, 53], "\u043a\u0440\u0430\u0441\u0438\u0432": [0, 34, 73, 85, 90, 100], "\u0434\u0438\u0437\u0430\u0439\u043d": [0, 37, 70, 72, 74, 75, 83, 85], "material": [0, 82], "doks": 0, "docsy": 0, "just": [0, 11, 21, 23, 29, 34, 37, 38, 39, 42, 46, 47, 49, 51, 52, 60, 70, 72, 73, 74, 76, 77, 82, 85, 86, 88, 90, 92, 95, 100], "docs": [0, 34, 73, 82], "theme": 0, "\u043d\u0430\u0446\u0435\u043b": [0, 86], "\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d": 0, "\u043a\u043d\u0438\u0436\u043d": 0, "c": [0, 5, 9, 14, 15, 21, 23, 30, 34, 37, 38, 40, 41, 46, 66, 68, 70, 74, 75, 76, 80, 82, 85, 93], "\u043e\u0433\u043b\u0430\u0432\u043b\u0435\u043d": 0, "\u0441\u043b\u0435\u0432": 0, "mdbook": 0, "\u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d": [0, 9, 23, 37, 73, 82], "\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d": [0, 23, 75], "rust": 0, "\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f": 0, "jupyterbook": 0, "bookdown": 0, "\u0441\u043f\u0438\u0441\u043e\u043a": [0, 5, 34, 38, 81, 83, 85, 86, 88, 91, 92, 93, 94, 95, 135, 138], "\u043f\u043e\u043b\u0443\u044f\u0440\u043d": 0, "\u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442": [0, 8, 9, 11, 23, 34, 37, 53, 74], "imdone": 0, "core": [0, 23, 34, 37, 75, 76, 82, 85, 86, 100], "kanban": [0, 51, 52, 82, 86, 95], "processor": [0, 23], "coddx": 0, "alpha": 0, "board": [0, 37, 73, 86], "manages": [0, 86], "tasks": [0, 9, 23, 38, 51, 74, 86, 90], "save": [0, 5, 9, 21, 23, 42, 51, 76], "them": [0, 11, 21, 23, 29, 34, 37, 38, 46, 51, 53, 62, 72, 73, 74, 75, 76, 77, 80, 85, 86, 89, 94], "file": [0, 5, 37, 75, 76], "orgzly": 0, "outliner": 0, "notebooks": 0, "code": [0, 5, 9, 11, 13, 15, 21, 23, 29, 34, 37, 38, 46, 47, 51, 57, 60, 66, 68, 70, 72, 73, 74, 75, 76, 77, 86, 89, 90, 93, 95, 100, 127], "joplin": 0, "an": [0, 5, 9, 11, 15, 21, 23, 26, 29, 34, 37, 38, 39, 41, 49, 51, 52, 62, 65, 68, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 94, 100], "do": [0, 9, 11, 15, 21, 23, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 59, 62, 65, 66, 72, 73, 74, 76, 82, 85, 86, 90, 100], "application": [0, 8, 9, 13, 19, 21, 23, 34, 38, 41, 51, 52, 64, 72, 75, 76, 82, 85, 86, 100, 109], "synchronization": 0, "capabilities": [0, 23, 34, 59, 65, 86], "windows": 0, "macos": 0, "linux": [0, 82], "ios": 0, "taskjuggler": 0, "modern": [0, 65, 74, 82, 90], "powerful": [0, 9, 38, 60, 85, 86, 90], "free": [0, 15, 21, 39], "software": [0, 5, 8, 9, 11, 15, 21, 23, 26, 29, 34, 37, 38, 40, 41, 42, 46, 49, 51, 52, 53, 59, 60, 62, 63, 64, 65, 66, 67, 68, 70, 72, 73, 75, 76, 77, 80, 82, 90, 92, 100, 130], "project": [0, 23, 37, 38, 42, 46, 49, 51, 52, 64, 65, 68, 72, 74, 76, 77, 80, 82, 85, 86, 100], "tool": [0, 23, 51, 60, 73, 90], "new": [0, 5, 8, 9, 15, 21, 23, 34, 37, 38, 46, 47, 51, 60, 62, 65, 70, 72, 74, 75, 76, 77, 82, 85, 86, 88, 90], "approach": [0, 5, 9, 15, 21, 23, 34, 37, 38, 51, 52, 60, 62, 65, 66, 70, 74, 75, 76, 82, 85, 86], "planning": [0, 37, 38, 51, 59, 60, 62, 65, 73, 74, 76, 80, 82, 83, 86, 95], "tracking": [0, 38], "more": [0, 9, 11, 13, 15, 21, 23, 29, 34, 37, 38, 39, 40, 46, 47, 49, 51, 52, 62, 64, 65, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88, 90, 100], "flexible": [0, 70, 85], "superior": [0, 5, 23, 37], "commonly": [0, 37], "used": [0, 5, 9, 21, 23, 29, 34, 37, 38, 47, 52, 62, 70, 73, 74, 75, 76, 82, 85, 86, 94], "gantt": [0, 65], "chart": [0, 34, 65], "editing": 0, "tools": [0, 23, 38, 65, 73, 76, 82, 85, 86], "\u0438\u043c\u043f\u043e\u0440\u0442\u0435\u0440": 0, "jira": 0, "org": [0, 34, 62, 82, 86, 92, 95], "download": [0, 5, 34, 82], "workshop": [0, 38, 82], "tj3": 0, "manual": [0, 38, 51, 73], "\u043f\u0440\u0438\u043c\u0435\u0440": [0, 8, 9, 21, 23, 30, 34, 38, 39, 70, 72, 73, 74, 82, 85, 86, 90, 92, 93, 97, 98, 100, 102], "\u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043c": [0, 15], "\u043d\u0430\u0447\u0430\u043b": [0, 23, 37, 40, 72, 76, 83, 85], "\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d": [0, 5, 9, 21, 23, 37, 38, 39, 64, 72, 73, 75, 76, 86, 88, 92], "\u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432": [0, 5, 21, 23, 38, 73, 82, 86, 88], "myst": 0, "parser": 0, "\u0440\u043e\u043b": [0, 23, 38, 40, 73, 75, 83, 85, 87, 88, 95, 100, 102, 137], "\u043c\u043e\u0441\u0442": 0, "docutils": 0, "it": [0, 1, 8, 9, 11, 13, 15, 21, 26, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 59, 60, 62, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 89, 90, 92, 93, 94, 96, 99, 100, 105], "commonmark": 0, "\u0432\u0430\u0440\u0438\u0430\u043d\u0442": [0, 5, 8, 9, 11, 13, 21, 23, 34, 37, 38, 70, 72, 73, 77, 82, 83, 85, 88, 90, 92, 93], "\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446": 0, "m2r": 0, "converter": 0, "mdtorst": 0, "library": [0, 23, 52, 75, 82], "convert": 0, "restructed": 0, "rst": [0, 51], "markor": 0, "f": [0, 21, 23, 37, 38, 46, 82, 85, 86], "droid": 0, "google": [0, 34, 82], "play": [0, 23, 74], "termux": 0, "unix": [0, 82], "like": [0, 9, 11, 21, 23, 29, 34, 38, 41, 46, 47, 51, 73, 74, 75, 76, 80, 85, 86, 100], "environment": [0, 21, 23, 37, 38, 51, 65, 76, 85, 86], "python3": 0, "first": [0, 15, 21, 23, 34, 37, 38, 42, 46, 47, 72, 73, 74, 76, 77, 82, 85, 86, 88, 89, 94, 95, 100], "integrated": [0, 49, 86], "mgit": 0, "working": [0, 23, 37, 49, 51, 62, 65, 66, 70, 72, 73, 74, 76, 77, 82, 85, 86, 90, 95, 100], "copy": [0, 21, 23, 26, 34, 85], "1writer": 0, "beautiful": [0, 21, 88], "ia": 0, "writer": 0, "award": 0, "winning": [0, 39, 66, 74], "design": [0, 5, 8, 9, 11, 19, 21, 23, 26, 34, 37, 38, 40, 41, 46, 49, 56, 59, 60, 64, 66, 67, 68, 70, 73, 75, 76, 78, 80, 86, 90, 92, 94, 95, 100, 109, 130, 133], "delivers": [0, 86], "essential": [0, 37, 38, 51, 52, 62, 64, 65, 66, 73, 74, 76, 82, 86, 90, 100], "experience": [0, 21, 23, 29, 37, 38, 46, 68, 74, 77, 82, 85, 86, 88], "editorial": 0, "great": [0, 21, 23, 37, 38, 73, 74, 75, 82, 85, 86, 95], "automation": [0, 82], "scripts": [0, 86], "unofficial": [0, 82], "itexteditors": 0, "roundup": 0, "\u0441\u0435\u0440\u0432\u0438\u0441": [0, 5, 23, 86], "\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d": [0, 21, 23, 34, 46, 75, 85, 89], "\u043f\u0440\u0435\u0434\u0435\u043b": [0, 8, 23, 37, 40, 65, 73, 74, 75, 76, 80, 83, 86, 90, 92, 100], "\u0438\u0434\u0435": [0, 23, 37, 38, 76, 85, 86, 88], "markown": 0, "gui": [0, 5], "\u043a\u043b\u0438\u0435\u043d\u0442": [0, 9, 11, 15, 21, 23, 100], "\u043d\u0435\u0434\u0430\u0432\u043d": [0, 38, 75, 85, 89, 94], "\u043f\u043e\u044f\u0432": [0, 8, 13, 21, 34, 37, 38, 40, 47, 72, 75, 76, 85, 86], "\u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a": [0, 75, 82, 92], "\u043e\u0437\u043d\u0430\u0447\u0430": [0, 21, 23, 30, 37, 40, 41, 72, 73, 74, 75, 76, 83, 85], "\u0448\u0430\u0440": [0, 74, 90, 100], "\u0434\u0432\u0443\u043c": [0, 8, 26, 38, 86, 94, 100, 102], "\u043f\u0440\u043e\u0431\u043e\u0432\u0430": [0, 9, 38], "\u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u0442": 0, "\u0440\u0430\u0441\u0441\u043a\u0430\u0436": [0, 38], "\u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442": 0, "\u043f\u043e\u043b\u0443\u0447": [0, 9, 21, 23, 30, 34, 56, 70, 73, 75, 82, 83, 85, 88, 92, 100, 102], "\u0437\u0430\u0442": [0, 5, 9, 21, 23, 34, 70, 74, 75, 77, 82, 85, 94, 95], "\u0434\u0430\u0435\u0442": [0, 5, 8, 11, 23, 46, 51, 70, 74, 75, 82, 85, 86, 93], "\u0434\u0435\u043b\u044c\u043d": 0, "\u0441\u043e\u0432\u0435\u0442": [0, 23, 38, 40, 46, 82, 92], "\u043f\u043e\u043c\u0438\u043c": [0, 23, 38, 86], "publish": [0, 5, 9, 23, 34], "\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430": 0, "\u043c\u0430\u0441\u0441\u043e\u0432": [0, 37, 72, 75, 76], "\u0438\u043c\u043f\u043e\u0440\u0442": [0, 11], "\u0432\u0441\u0442\u0440\u0435\u0447\u0430": [0, 38, 65, 75, 82, 100], "so": [0, 9, 13, 21, 23, 34, 37, 38, 39, 42, 46, 49, 51, 52, 62, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 95, 100], "importer": [0, 9], "\u044d\u043a\u0441\u043f\u043e\u0440\u0442": [0, 5, 9], "evernote2md": 0, "enex": 0, "ever2simple": 0, "migrate": 0, "from": [0, 8, 9, 11, 21, 23, 29, 34, 37, 38, 39, 42, 51, 52, 64, 65, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 93, 95], "simplenote": 0, "formatting": 0, "ever2text": 0, "exports": 0, "\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a": [0, 8, 9, 21, 23, 30, 34, 41, 46, 47, 72, 74, 75, 77, 85, 86, 88, 90, 92, 94, 100], "\u043a\u043e\u0440\u043e\u0431\u043e\u0447\u043d": 0, "feed": [0, 96], "contrib": 0, "yasfb": 0, "lsaffre": 0, "sphinxfeed": 0, "prometheusresearch": 0, "sphinxcontrib": 0, "newsfeed": 0, "issues": [0, 23, 26, 38, 65, 72, 77, 85, 86], "2": [0, 8, 11, 21, 23, 29, 34, 37, 38, 46, 49, 51, 52, 64, 65, 66, 70, 73, 74, 75, 76, 77, 82, 85, 86, 90, 100, 102], "integrations": [0, 23], "rssfeed": 0, "plugin": [0, 5, 75], "wbernest": 0, "bokker": 0, "bot": 0, "thefeedreaderbot": 0, "www": [0, 5, 34, 76, 85, 89, 92], "integromat": 0, "en": [0, 9, 82], "bots": 0, "faq": 0, "jdillard": 0, "needs": [0, 21, 23, 34, 37, 38, 49, 52, 59, 62, 65, 74, 75, 76, 77, 80, 86, 100], "allows": [0, 9, 23, 34, 37, 62, 65, 74, 76, 85], "definition": [0, 21, 23, 34, 37, 38, 51, 59, 60, 74, 75, 76, 77, 80, 101], "linking": 0, "filtering": 0, "need": [0, 15, 21, 23, 26, 34, 37, 38, 46, 47, 49, 51, 52, 65, 70, 72, 73, 74, 75, 76, 77, 80, 85, 86, 100], "objects": [0, 9, 11, 21, 23, 25, 26, 29, 41, 51, 72, 73, 74, 75, 77, 82, 85, 90, 100, 113], "default": [0, 9, 23, 34, 85], "specifications": [0, 29, 37, 49, 51, 65, 76], "implementations": [0, 23, 38, 73], "test": [0, 47, 49, 51, 72, 73, 74, 82, 86, 93], "cases": [0, 15, 21, 23, 34, 38, 41, 46, 49, 51, 52, 75, 86], "traceability": [0, 49], "extension": [0, 9, 21, 49, 52, 64, 74, 75, 82], "defining": [0, 23, 51], "items": [0, 34, 38, 49, 51, 52, 64, 65, 74, 82, 86, 90], "relations": [0, 5, 75, 82], "between": [0, 9, 11, 21, 23, 26, 29, 37, 38, 42, 46, 47, 51, 52, 62, 72, 74, 75, 76, 77, 82, 85, 86, 100], "those": [0, 9, 21, 23, 37, 38, 41, 42, 46, 60, 65, 70, 74, 75, 76, 77, 85, 86, 90, 100], "e": [0, 8, 9, 21, 23, 37, 38, 39, 46, 49, 53, 62, 64, 65, 73, 76, 77, 82, 85, 86, 88], "g": [0, 8, 23, 30, 34, 38, 46, 49, 60, 64, 74, 77, 82, 86, 88, 90], "iso26262": 0, "projects": [0, 23, 37, 38, 49, 51, 52, 64, 65, 72, 74, 76, 77, 82, 85, 86], "kroki": 0, "embed": 0, "plantuml": [0, 5, 82], "dot": 0, "etc": [0, 21, 23, 34, 37, 38, 40, 65, 76, 82, 86, 100], "diagrams": [0, 82], "\u0441\u043e\u0441\u0442\u043e\u044f\u043d": [0, 5, 9, 11, 15, 21, 23, 38, 47, 72, 82, 85, 86, 100, 102], "\u0440\u0430\u0437\u0432\u0438\u0442": [0, 13, 15, 38, 70, 73, 85, 86, 92, 94], "\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d": [0, 77, 82], "\u043f\u043e\u043a": [0, 5, 8, 9, 11, 21, 26, 34, 38, 77, 82, 85, 88, 90, 92], "\u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440": [0, 34], "\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a": [0, 5, 8, 9, 11, 23, 37, 41, 44, 46, 51, 66, 70, 72, 73, 74, 75, 82, 90, 122], "\u043e\u0442\u0434\u0430\u043b\u0435\u043d": 0, "\u043f\u0435\u0440\u0441\u043f\u0435\u043a\u0442\u0438\u0432": [0, 40, 75], "\u043f\u0440\u0438\u0441\u043f\u043e\u0441\u043e\u0431": 0, "\u043c\u043e\u043c\u0435\u043d\u0442": [0, 5, 8, 9, 11, 21, 23, 34, 37, 38, 47, 52, 68, 72, 73, 74, 76, 77, 83, 85, 86, 88, 90, 95, 100], "\u0441\u0442\u043e": [0, 9, 23, 56, 82, 83, 85, 86], "\u0432\u044b\u0431\u0438\u0440\u0430": [0, 38, 76], "\u043f\u043e\u0434\u043f\u0438\u0441\u043e\u043a": 0, "\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430": [0, 5], "\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440": [0, 5, 8], "\u043f\u0440\u0438\u043d\u044f\u0442": [0, 21, 23, 37, 38, 70, 76, 77, 88, 92, 94], "\u043a\u043e\u043c\u043c\u0438\u0442": [0, 5, 23], "\u043a\u043e\u043c\u043c": 0, "\u0441\u043e\u0434\u0435\u0440\u0436": [0, 9, 23, 74, 77, 82, 85, 90], "\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d": [0, 21, 23], "\u043f\u0440\u0438\u043d\u0438\u043c\u0430": [0, 8, 9, 15, 23, 37, 38, 40, 68, 70, 75, 82, 86], "\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a": [0, 5, 51, 72, 85], "p": [0, 38, 41, 65, 73, 75, 82, 86, 88, 93], "\u043b\u0438\u0447\u043d": [0, 13, 38, 75, 82, 85], "\u0437\u0430\u043f\u0438\u0441\u043d": 0, "\u043a\u043d\u0438\u0436\u043a": 0, "\u0443\u0447\u0435\u0431\u043d": [0, 82, 88], "\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a": [0, 92], "soft": [1, 23, 37, 82, 89, 96, 105], "skills": [1, 49, 82, 86, 89, 96, 105], "saga": [2, 8, 21, 82, 106], "transaction": [2, 21, 23, 106], "\u0440\u0430\u0437\u0434\u0435\u043b": [3, 4, 5, 8, 9, 10, 11, 14, 15, 16, 18, 21, 23, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 56, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 86, 88, 89, 90, 92, 93, 94, 95, 100, 102], "zakrevsky": [3, 4, 5, 8, 9, 10, 11, 14, 15, 18, 21, 23, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 56, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 86, 88, 89, 90, 92, 93, 94, 95], "\u0438\u0441\u0447\u0435\u0440\u043f\u0430": [5, 8], "\u043d\u0435\u0447\u0438\u0442\u0430": [5, 75], "\u043d\u0435\u0443\u043f\u0440\u0430\u0432\u043b\u044f": 5, "\u0432\u044b\u0440\u043e\u0432\u043d\u044f": [5, 37], "\u0431\u0435\u0437\u0443\u0441\u043f\u0435\u0448\u043d": [5, 90], "\u043d\u0430": [5, 8, 9, 10, 11, 13, 15, 21, 23, 26, 34, 37, 39, 40, 41, 42, 47, 49, 52, 53, 56, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 80, 83, 86, 88, 89, 91, 93, 94, 100, 102, 138], "\u0441\u0435\u0440\u0432\u0435\u0440": [5, 21, 23, 38], "\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430": [5, 100], "\u043f\u043e": [5, 8, 9, 11, 13, 15, 16, 21, 23, 34, 37, 38, 41, 46, 47, 51, 52, 53, 56, 60, 62, 64, 65, 67, 68, 70, 72, 73, 74, 75, 76, 77, 83, 85, 89, 90, 92, 93, 94, 102, 130], "miro": [5, 82], "\u0432\u044b\u043d\u0443\u0436\u0434\u0430": [5, 37, 38, 56, 76, 92], "\u0437\u043d\u0430\u0447\u0438\u043c": [5, 83], "\u043f\u043e\u043a\u0438\u0434\u0430": [5, 23], "\u043f\u0435\u0440\u0438\u043c\u0435\u0442\u0440": 5, "\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d": [5, 21, 26, 47, 73, 74, 90], "\u043b\u0438\u0446\u0435\u043d\u0437\u0438\u043e\u043d": 5, "\u043d\u0430\u0445\u043e\u0434": [5, 23, 26, 34, 38, 40, 41, 47, 65, 70, 73, 74, 75, 85, 86, 88, 90, 92, 94, 102], "\u0434\u0430\u0432\u043b\u0435\u043d": [5, 38, 88], "\u0433\u0435\u043e\u043f\u043e\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a": 5, "\u043a\u0430\u043a": [5, 8, 11, 12, 13, 15, 16, 21, 23, 26, 29, 30, 34, 37, 38, 41, 42, 46, 47, 51, 52, 56, 60, 65, 68, 72, 73, 74, 75, 76, 77, 80, 81, 82, 85, 86, 89, 90, 91, 92, 94, 95, 96, 100, 102, 135, 138], "\u0432\u0432\u0438\u0434": [5, 23], "\u043d\u0435\u043c": [5, 8, 21, 30, 74, 76, 83, 85, 86, 102], "\u043d\u0435\u043f\u043b\u043e\u0445": [5, 37, 64, 74, 82, 86, 89], "\u043d\u0430\u0434\u0435\u0436\u0434": [5, 70], "\u043f\u043e\u0434\u0430": 5, "domorobo": 5, "\u0441\u044b\u0440\u043e\u0432\u0430\u0442": 5, "\u043f\u0440\u043e\u0446\u0435\u0441\u0441": [5, 8, 15, 21, 23, 37, 38, 40, 46, 47, 51, 56, 64, 65, 70, 74, 75, 76, 77, 82, 85, 86, 88, 89, 90, 93, 94, 100], "\u043f\u0440\u0438\u0432\u043b\u0435\u043a\u043b": 5, "figure": [5, 23, 37, 51, 65, 70, 74, 76, 77, 82, 85, 86, 94], "13": [5, 8, 21, 23, 29, 38, 74, 82, 83, 100], "agile": [5, 8, 23, 29, 40, 41, 46, 61, 62, 64, 65, 66, 68, 70, 71, 77, 83, 85, 88, 92, 94, 100, 129, 132], "modeling": [5, 8, 21, 23, 30, 34, 37, 52, 76, 100], "archimate": [5, 76, 82], "jean": [5, 82], "baptiste": [5, 82], "sarrodie": [5, 82], "presentation": [5, 21, 82], "enterprise": [5, 13, 23, 34, 38, 51, 52, 64, 65, 72, 82, 100], "modelling": 5, "scale": [5, 23, 34, 37, 38, 46, 49, 74, 82, 86], "programme": [5, 82], "\u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430": [5, 9, 11, 38], "\u043e\u0431\u043d\u0430\u0440\u0443\u0436": [5, 9, 11, 46, 47, 75, 83, 92, 102], "\u0441": [5, 8, 9, 11, 15, 23, 30, 34, 37, 38, 40, 41, 42, 46, 47, 51, 56, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 100, 102], "\u043b\u0435\u0433\u043a\u043e\u0441\u0442": [5, 73, 75, 86, 93], "\u0440\u0430\u0437\u0432": [5, 74, 75], "\u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446": [5, 21], "\u0434\u0440\u0443\u0433": [5, 8, 9, 11, 15, 21, 23, 26, 29, 30, 34, 37, 38, 39, 40, 42, 46, 47, 51, 52, 56, 70, 72, 74, 75, 77, 80, 83, 85, 88, 90, 92, 93, 94, 100, 102], "\u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a": [5, 8, 37, 56, 83, 86, 90, 92, 102], "\u043a\u043b\u0438\u043a": 5, "\u043c\u044b\u0448\u043a": 5, "\u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d": 5, "jarchi": 5, "\u043f\u043e\u0434\u0442\u044f\u0433\u0438\u0432\u0430": 5, "\u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430": [5, 88], "\u0444\u043e\u043d\u043e\u0432": [5, 82, 102], "\u043d\u043e\u0442\u0430\u0446": [5, 82], "\u0446\u0432\u0435\u0442": 5, "\u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d": [5, 75, 85], "10": [5, 8, 21, 23, 34, 37, 38, 52, 70, 74, 76, 80, 82, 85, 86, 95], "business": [5, 21, 23, 34, 37, 38, 39, 40, 46, 49, 51, 52, 62, 64, 65, 66, 73, 76, 80, 82, 86, 88, 100], "process": [5, 21, 30, 34, 37, 38, 46, 51, 52, 62, 64, 65, 66, 70, 73, 74, 75, 76, 77, 82, 85, 86, 100], "cooperation": 5, "viewpoint": [5, 21], "premise": [5, 37], "\u0437\u0430\u043a\u0440\u044b\u0442": [5, 85], "under": [5, 37, 38, 49, 51, 73, 74, 76, 85, 86, 100], "mit": [5, 82], "license": [5, 51], "\u043d\u0430\u043b\u0438\u0447": [5, 21, 74, 102], "\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f": [5, 11, 30, 37, 38, 64, 65, 73, 75, 77, 82, 100, 102], "\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d": [5, 8, 9, 11, 21, 23, 38, 65, 73, 74, 82, 86, 90, 92], "\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442": [5, 11, 21, 23, 34, 41, 65, 73, 75, 76, 77, 86, 92, 93, 94], "\u0441\u043b\u0435\u0434\u0441\u0442\u0432": [5, 11, 37, 38, 88, 93], "\u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430": [5, 13], "\u0432\u044b\u0434\u0435\u043b\u044f": [5, 11, 64, 92, 95], "\u0441oupling": 5, "\u0441ohesion": 5, "\u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a": [5, 30, 38, 60, 75, 82, 85, 90, 100], "\u0442\u043e\u0447\u043d\u043e\u0441\u0442": [5, 37, 65, 80, 83, 86, 100], "\u043d\u0430\u0438\u043b\u0443\u0447\u0448": [5, 38, 41, 65, 86], "\u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430": [5, 8, 9, 11, 21, 23, 34, 38, 64, 70, 73, 74, 75, 77, 85, 86, 90, 92, 93], "\u043c\u0433\u043d\u043e\u0432\u0435\u043d": [5, 72, 85], "\u043f\u0435\u0440\u0435\u0439\u0442": [5, 8, 94], "context": [5, 23, 29, 34, 37, 38, 49, 75, 76, 86, 92, 100, 101], "map": [5, 82, 86], "\u0432\u043a\u043b\u0430\u0434\u043a": 5, "properties": [5, 21, 23, 30, 34, 38, 52], "\u0432\u044b\u0431\u0440\u0430": [5, 23, 37, 38, 64, 73, 75, 88, 90], "\u0441\u0435\u043a\u0446": 5, "analisis": 5, "\u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430": [5, 85], "\u0442\u0440\u0430\u0441\u0441\u0438\u0440\u043e\u0432\u043a": 5, "\u0434\u043e": [5, 8, 21, 23, 30, 37, 41, 47, 65, 70, 73, 74, 75, 76, 82, 83, 86, 88, 90, 92], "\u043f\u043e\u0441\u043b": [5, 8, 15, 21, 23, 30, 34, 37, 38, 46, 72, 74, 75, 76, 85, 86, 90, 102], "\u043d\u0435\u0433": [5, 8, 23, 47, 52, 85, 86, 88, 92, 94], "\u043e\u043a\u043d": [5, 74], "window": [5, 38, 74], "navigator": 5, "\u0434\u0432\u0435": [5, 11, 21, 23, 34, 40, 75, 76, 85, 86, 88, 100, 102], "\u043a\u043d\u043e\u043f\u043a": 5, "show": [5, 74, 82], "target": [5, 15, 21, 23, 51], "\u0440\u0430\u0437\u0431\u0438\u0435\u043d": [5, 37, 74, 86, 90], "\u043d\u0435\u043a": [5, 8, 9, 88], "\u043f\u0440\u0438\u0437\u043d\u0430\u043a": [5, 9, 29, 75, 82, 86, 92], "\u0431\u0430\u0437\u043e\u0432": [5, 52, 77, 82, 88, 100], "\u0441\u0446\u0435\u043d\u0430\u0440": [5, 8, 23, 51, 83, 85, 92], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d": [5, 8, 9, 11, 15, 21, 23, 26, 37, 38, 40, 65, 66, 70, 72, 75, 85, 86, 90, 94, 102], "\u0446\u0435\u043b\u0435\u0432": 5, "\u043e\u0442\u0440\u0430\u0436": [5, 102], "\u043e\u0441\u0442\u0430\u043b\u044c\u043d": [5, 8, 21, 23, 38, 40, 70, 82, 83, 85, 86, 90], "\u0443\u0434\u0435\u0448\u0435\u0432\u043b\u044f": 5, "\u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d": [5, 9, 70, 74], "\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d": [5, 9, 13, 23, 46, 56, 70, 72, 74, 76, 85, 86], "\u043d\u0438\u043c": [5, 15, 23, 38, 70, 73, 75, 80, 83, 88, 95], "\u0434\u043e\u0431\u0430\u0432\u043b\u044f": [5, 37, 46, 70, 74, 85], "\u043e\u0442\u043a\u0440\u044b\u0432\u0430": [5, 9, 21, 37, 74, 88], "\u0438\u0441\u0442\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 5, "\u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d": [5, 30, 95], "\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449": [5, 23, 34, 40, 62, 74, 82, 85, 86, 94], "\u0436\u0443\u0440\u043d\u0430\u043b\u0438\u0440\u043e\u0432\u0430\u043d": 5, "\u0432\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d": [5, 23], "\u043e\u0442\u0432\u0435\u0442\u0432\u043b\u0435\u043d": 5, "\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d": [5, 21, 37, 82], "\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a": [5, 23, 37, 38, 41, 42, 46, 47, 51, 52, 62, 64, 65, 67, 68, 70, 72, 73, 74, 75, 76, 80, 82, 83, 84, 86, 89, 90, 92, 93, 130, 136], "\u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432\u043d": [5, 83, 92], "\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446": [5, 86], "motivation": [5, 21, 38, 75], "elements": [5, 9, 21, 37, 51, 62, 72, 73, 74, 75, 77, 82, 86], "stakeholder": [5, 37, 38, 75], "driver": [5, 9, 86], "assessment": [5, 64, 82], "goal": [5, 9, 21, 23, 37, 38, 51, 52, 73, 74, 76, 77, 86, 90, 100], "outcome": [5, 38], "principle": [5, 15, 21, 23, 49, 52, 73, 74, 85, 86, 93], "requirement": [5, 38, 51, 52, 70], "constraint": 5, "\u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446": [5, 95], "\u0432\u043b\u0438\u044f\u043d": [5, 38, 41, 64, 72, 75, 80, 86, 88], "\u0444\u0438\u043a\u0441\u0430\u0446": [5, 92], "\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d": [5, 16, 21, 23, 34, 37, 38, 40, 47, 49, 51, 53, 65, 70, 74, 75, 76, 80, 82, 83, 86], "\u0432\u043e\u043f\u043b\u043e\u0449\u0435\u043d": [5, 56, 73], "twin": [5, 77], "peak": [5, 23], "\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442": 5, "\u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430": [5, 23, 38], "\u0434\u0440\u0430\u0439\u0432\u0435\u0440": 5, "\u0432\u043b\u0438\u044f": [5, 38, 40, 46, 70, 74, 76, 83, 102], "\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a": [5, 37, 64, 86], "\u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430": [5, 11, 41, 74, 76, 92, 94], "pbi": [5, 49, 52, 80, 86], "\u0431\u043e\u0433\u0430\u0442": 5, "\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d": [5, 11, 23, 34], "api": [5, 21, 23, 73, 75, 85], "\u0441\u0432\u0435\u0440\u043a": 5, "\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446": [5, 9, 11, 21, 23, 30, 34, 37, 38, 40, 41, 51, 56, 65, 72, 74, 75, 76, 80, 82, 83, 85, 86, 90, 94, 100], "\u043a\u043e\u0434": [5, 9, 11, 15, 16, 23, 34, 37, 38, 41, 42, 47, 64, 66, 70, 72, 75, 76, 82, 85, 86, 90, 94], "\u0440\u0435\u0437\u043e\u043b\u044c\u0432": 5, "\u0432\u043e\u0437\u043c\u043e\u0436": [5, 8, 83], "\u0432\u044b\u0431\u043e\u0440": [5, 23, 37, 38, 64, 65, 70, 76, 80, 88, 89], "\u0434\u0432\u0443\u0445": [5, 23, 37, 70, 72, 82, 85, 86, 88, 92, 102], "\u0441\u043b\u0438\u0432\u0430": 5, "\u0440\u0430\u0437\u043b\u0438\u0447": [5, 52, 77], "\u043d\u0438\u043a\u0430\u043a": [5, 26, 34, 38, 70, 77, 83, 100], "\u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430": 5, "temp": 5, "\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437": 5, "\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440": 5, "\u0443\u0447\u0438\u0442\u044b\u0432\u0430": [5, 34, 38, 65, 75, 83, 85], "\u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442": [5, 9, 11, 21, 23, 75, 83, 92, 93, 100], "\u043c\u043d\u0435": [5, 23, 34, 40, 46, 72, 74, 75, 83, 85, 86, 88, 92, 93, 100], "\u0434\u0432\u0430": [5, 13, 21, 23, 26, 34, 38, 64, 72, 73, 74, 75, 85, 86, 90, 92, 100], "\u0441\u043b\u0438\u0442": 5, "\u0441\u043b\u0443\u0447\u0430": [5, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 41, 46, 47, 52, 56, 65, 75, 77, 82, 83, 85, 86, 88, 93, 94, 100, 102], "\u0443\u0442\u0440\u0430\u0442": [5, 23, 40], "\u043e\u0431\u043e": [5, 21, 65, 85], "\u0443\u0440\u043e\u0432\u043d": [5, 8, 11, 15, 21, 23, 30, 34, 37, 52, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 94, 100], "\u043e\u043f\u0438\u0441\u0430\u043d": [5, 8, 23, 51, 82, 93, 100, 102], "grafico": 5, "format": [5, 9, 23], "\u0434\u0435\u0439\u0441\u0442\u0432\u0435\u043d": [5, 88], "\u0432\u043f\u0440\u043e\u0447": [5, 11, 21, 23, 75, 83], "views": [5, 11, 49, 74, 75, 77, 82], "\u0443\u0441\u043b\u043e\u0436\u043d\u044f": [5, 73, 75, 94], "\u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432": [5, 23, 70, 75, 86, 102], "\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440": [5, 10, 23, 30, 34], "\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e": 5, "\u0441\u043e\u043e\u0431\u0449\u0430": [5, 74], "\u043e": [5, 8, 9, 11, 13, 15, 23, 30, 33, 38, 40, 41, 42, 46, 47, 51, 52, 56, 60, 64, 65, 66, 68, 72, 74, 75, 76, 80, 82, 83, 86, 89, 90, 93, 94, 95, 100, 102, 118], "\u043e\u043f\u0440\u0435\u0434\u0435\u043b": [5, 38, 46, 85, 86, 92, 100, 102], "\u0441\u043c\u044b\u0441\u043b": [5, 8, 9, 23, 41, 52, 74, 75, 82, 85, 92, 94, 100, 102], "\u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d": [5, 9, 23, 74], "\u0437\u0430\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430": 5, "csv": 5, "\u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d": [5, 8, 23, 65, 72, 76, 85, 94, 100], "\u043a\u043e\u043f": [5, 26, 82, 100], "\u043f\u0435\u0440\u0435\u0434": [5, 8, 9, 15, 23, 38, 40, 46, 47, 75, 85, 92], "\u0433\u0440\u0435\u043f\u0430": 5, "\u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443": 5, "\u043c\u0435\u043d\u044c\u0448": [5, 38, 40, 52, 70, 73, 74, 85, 86, 88, 90, 93, 94, 100], "\u0443\u043c\u0435\u043d\u044c\u0448\u0430": [5, 75, 102], "\u0432\u0435\u0440\u043e\u044f\u0442\u043d": [5, 9, 15, 23, 37, 38, 70, 73, 74, 82, 83, 85, 88, 90, 92], "\u0434\u043e\u043f\u0443\u0449\u0435\u043d": [5, 65, 92], "\u043e\u0448\u0438\u0431\u043a": [5, 15, 38, 43, 46, 47, 65, 66, 73, 74, 75, 82, 83, 86, 89, 90, 92, 94, 121], "\u043d\u0435\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d": 5, "\u0438\u0437\u0431\u0435\u0433\u0430": [5, 15, 21, 47, 83], "\u0434\u043e\u0441\u043a": [5, 95], "\u0432\u0440\u0435\u043c\u0435\u043d": [5, 8, 11, 23, 34, 37, 38, 42, 46, 47, 56, 72, 73, 74, 75, 76, 82, 83, 85, 86, 90, 92, 94, 95], "\u043f\u0435\u0440\u0435\u0434\u0430": [5, 9, 21, 26, 102], "\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a": [5, 8, 23, 30], "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u043e\u043d": [5, 86], "\u043c\u0435\u0440": [5, 8, 23, 38, 40, 46, 47, 52, 65, 70, 72, 83, 85, 86, 94], "\u0441\u043d\u0438\u0437": [5, 13, 37, 46, 72, 74, 77, 85, 86, 88, 90], "\u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d": [5, 30, 73, 85, 92], "\u0434\u0438\u0441\u0442\u0440\u0438\u0431\u0443\u0442": 5, "coarchi": 5, "\u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d": [5, 21, 37, 38, 52, 82], "rsa": 5, "\u043a\u043b\u044e\u0447": [5, 8, 9, 21, 23, 30, 38], "\u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d": [5, 41, 46, 70, 74, 75, 85, 90], "\u0434\u043e\u043f\u0443\u0441\u043a\u0430": [5, 8, 23, 34, 40, 73, 92, 102], "\u0430\u0433\u0440\u0435\u0433\u0430\u0442": [5, 10, 12, 23, 30, 34, 75], "\u0431\u043e\u043b\u0442\u043b\u0438\u0432": 5, "\u043f\u0440\u043e\u0431\u0443": [5, 77], "\u043e\u0431\u044a\u0435\u0434\u0438\u043d": 5, "\u043e\u0431\u0449": [5, 11, 21, 34, 73, 74, 75, 77, 82, 85, 86, 88, 90, 92, 100], "\u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430": [5, 21, 85, 86], "\u0438\u0437\u043c\u0435\u043d": [5, 23, 26, 34, 37, 38, 46, 52, 74, 76, 83, 85, 88, 90], "\u0441\u043e\u0432\u043e\u043a\u0443\u043f\u043d": [5, 41, 65, 75, 83, 85, 92, 102], "coupling": [5, 9, 11, 13, 23, 37, 72, 73, 74, 75, 82, 85, 86, 100], "\u043e\u0432": 5, "cohesion": [5, 9, 11, 73, 74, 82, 86, 100], "\u0432\u043d\u0443\u0442\u0440": [5, 9, 11, 23, 30, 56, 86, 100], "\u0443\u043f\u0430": [5, 8], "\u0435\u0434\u0438\u043d\u0438\u0446": [5, 23, 74, 75, 85, 86, 95, 102], "\u0432\u043e\u0437\u0440\u043e\u0441": 5, "\u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d": [5, 8, 16, 30, 77, 92, 100], "\u043e\u043f\u0440\u0430\u0432\u0434\u0430": [5, 38, 70, 72, 85, 86], "_coupling": 5, "_cohesion": 5, "\u043b\u043e\u0433\u0438\u043a": [5, 34, 74, 75, 82, 92], "\u0432\u044b\u043d\u0435\u0441": [5, 83], "\u0442\u0435\u043a\u0443\u0449": [5, 8, 23, 38, 70, 82, 85, 86, 95, 100], "\u043f\u043e\u043d\u0430\u0434\u043e\u0431": [5, 70, 82, 86, 100], "readmodels": 5, "measuring": [5, 86], "information": [5, 9, 21, 23, 34, 38, 39, 49, 51, 52, 64, 65, 68, 74, 76, 82, 85, 86, 90], "theory": [5, 70, 74, 75, 76, 82, 85, 86, 92, 93], "edward": [5, 13, 23, 72, 82], "allen": [5, 9, 82], "taghi": 5, "khoshgoftaar": 5, "florida": 5, "atlantic": 5, "university": [5, 23, 30, 34, 60, 77, 82, 90], "boca": 5, "raton": 5, "usa": 5, "analysis": [5, 23, 37, 38, 49, 52, 54, 59, 60, 64, 65, 66, 72, 74, 75, 76, 77, 80, 82, 85, 86, 100, 126], "identifying": [5, 38, 77, 82], "microservice": [5, 23, 82, 86, 100], "boundaries": [5, 9, 11, 23, 29, 82, 85, 86], "bounded": [5, 23, 29, 34, 37, 86, 92, 100], "contexts": [5, 11, 23, 34, 74, 82, 86, 92, 100], "vladik": [5, 37, 73, 82], "khononov": [5, 37, 73, 82], "tackling": [5, 11, 23, 26, 34, 73, 74, 75, 82, 90, 100], "complexity": [5, 11, 23, 26, 34, 38, 60, 70, 73, 74, 76, 77, 82, 85, 90, 100], "learning": [5, 37, 41, 65, 73, 75, 76, 82, 85, 88], "driven": [5, 9, 11, 21, 23, 26, 34, 37, 38, 46, 72, 73, 74, 75, 76, 82, 85, 86, 90, 93, 100], "aligning": [5, 82], "strategy": [5, 23, 38, 46, 66, 68, 70, 72, 73, 76, 77, 82, 85, 86, 94], "1st": [5, 8, 23, 37, 38, 42, 46, 47, 64, 66, 68, 70, 73, 74, 82, 83, 94, 95], "edition": [5, 8, 15, 21, 23, 34, 37, 38, 42, 46, 47, 49, 51, 52, 53, 60, 62, 64, 65, 66, 68, 70, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 94, 95], "vlad": [5, 82], "balancing": [5, 34, 37, 38, 64, 68, 70, 74, 78, 82, 133], "successful": [5, 23, 37, 38, 46, 62, 64, 70, 72, 73, 74, 76, 82, 85, 100], "general": [5, 21, 23, 29, 34, 70, 73, 74, 76, 77, 82, 85, 90, 93], "systems": [5, 21, 23, 34, 36, 37, 38, 40, 41, 49, 52, 59, 60, 62, 63, 65, 66, 73, 75, 76, 77, 82, 85, 86, 100, 120], "vladislav": [5, 82], "\u043a\u043e\u0440\u043e\u0431\u043a": [5, 23], "exarchi": 5, "contribs": 5, "script": [5, 23, 85], "database": [5, 9, 21, 23, 29, 34, 76, 82, 85, 86], "\u0432\u044b\u0433\u0440\u0443\u0436\u0430": 5, "rdbms": [5, 23, 82], "\u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d": 5, "sql": [5, 9, 13, 21, 23, 30, 75, 82], "\u043f\u043e\u0434\u043e\u0431\u043d": [5, 37, 38, 47, 56, 72, 74, 75, 83, 85, 86, 88], "\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430": 5, "acceptance": [5, 49, 51, 82], "bdd": 5, "specification": [5, 9, 12, 21, 38, 51, 52, 65, 74, 75, 82], "\u0442\u0435\u0441\u0442\u043e\u0432": [5, 9, 85], "\u043a\u0435\u0439\u0441": [5, 9, 21, 82], "stands": [5, 65], "friendly": 5, "collection": [5, 29, 38, 75], "way": [5, 8, 9, 21, 23, 26, 34, 38, 39, 41, 46, 47, 49, 51, 52, 70, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 95, 100], "persist": [5, 51], "bunch": [5, 37, 38, 74], "xml": 5, "one": [5, 9, 11, 15, 21, 26, 29, 34, 37, 38, 39, 42, 49, 51, 52, 60, 62, 64, 65, 70, 73, 74, 76, 77, 82, 86, 90, 93, 94, 95, 100], "per": [5, 23, 38, 46, 74, 82], "element": [5, 9, 21, 49, 62, 74, 100], "view": [5, 9, 21, 38, 46, 52, 74, 77, 85, 86, 90, 100], "explained": [5, 21, 37, 38, 42, 46, 47, 52, 64, 66, 68, 70, 73, 74, 76, 82, 83, 86, 94], "\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443": 5, "ci": [5, 86], "\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d": 5, "maxim": [5, 66, 82], "levchenko": 5, "container": [5, 23, 82], "gh": 5, "action": [5, 21, 23, 34, 38, 82], "pages": [5, 37, 52, 76, 82, 95], "htmlreport": 5, "example": [5, 8, 9, 15, 21, 23, 34, 37, 38, 46, 51, 52, 65, 70, 72, 73, 76, 82, 85, 86, 93, 100], "others": [5, 9, 23, 34, 37, 38, 49, 51, 52, 72, 74, 75, 82, 85, 86, 88, 90], "\u0441\u043e": [5, 23, 26, 37, 38, 46, 47, 51, 52, 72, 74, 76, 77, 80, 83, 85, 86, 88, 90, 92, 94, 95, 100], "sketch": 5, "\u0441\u0442\u0440": 5, "110": 5, "\u043f\u0440\u043e\u0432\u043e\u0434": 5, "\u0441\u0435\u0430\u043d\u0441": [5, 74], "mapping": [5, 13, 21, 29, 76, 82, 86], "\u0433\u0430\u0440\u043c\u043e\u043d\u0438\u0447\u043d": 5, "\u0441\u043e\u0447\u0435\u0442\u0430": [5, 21, 70, 75], "\u0433\u043e\u0432\u043e\u0440": [5, 8, 9, 11, 21, 23, 30, 34, 37, 38, 40, 46, 51, 56, 68, 70, 72, 75, 76, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u0431\u0430\u0440\u0430\u043d": [5, 82], "\u0434\u043e\u043a\u043b\u0430\u0434": [5, 76, 100], "\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d": [5, 21, 23, 34, 38, 65, 82, 85, 86, 89, 90, 95], "simon": [5, 76], "brown": [5, 38, 76, 82], "\u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0440\u0443\u0447\u043d": [5, 21], "\u0441\u0441\u044b\u043b\u0430": [5, 34, 86], "guide": [5, 9, 21, 37, 40, 41, 49, 51, 52, 62, 64, 65, 66, 73, 74, 75, 76, 80, 82, 85], "\u0441\u0430\u0439\u0442": [5, 34, 52, 53, 82, 85], "omg": 5, "\u0432\u044b\u043b\u043e\u0436": 5, "\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d": [5, 9, 23, 75], "\u043e\u0448\u0438\u0431\u043e\u043a": [5, 15, 74, 77, 82, 83, 90], "\u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d": 5, "\u043d\u0435\u0437\u0430\u043a\u043e\u043c\u043c\u0438\u0447\u0435\u043d": 5, "\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d": [5, 8, 9, 10, 34, 100], "7": [5, 8, 21, 23, 38, 42, 66, 70, 74, 82, 85, 86, 88, 90, 100], "if": [5, 8, 9, 11, 15, 21, 23, 29, 34, 37, 38, 39, 41, 42, 46, 49, 51, 52, 60, 62, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 94, 95, 100], "import": [5, 8, 9, 11], "refresh": [5, 21], "error": [5, 8, 9, 15, 21, 34, 73, 74, 77, 90], "archi": [6, 82, 107], "storming": [7, 56, 76, 86, 108], "\u043e\u043f\u0438\u0441\u0430": [8, 15, 16, 23, 34, 38, 46, 65, 76, 85, 88, 100], "6": [8, 9, 16, 21, 23, 34, 37, 38, 46, 51, 64, 65, 75, 76, 82, 85, 86, 88], "\u0441\u0438\u0441\u0442\u0435\u043c": [8, 9, 16, 21, 23, 34, 37, 38, 40, 46, 47, 65, 68, 70, 72, 73, 74, 75, 77, 85, 86, 89, 90, 92, 100], "\u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d": [8, 16, 86], "\u0447\u043b\u0435\u043d": [8, 16, 42, 74, 85, 90], "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446": [8, 16, 23, 30, 38, 76, 82, 83, 86, 88], "\u0443\u0441\u0442\u0430\u0432": [8, 16], "\u0440\u0435\u0433\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [8, 16], "\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d": [8, 16], "\u0438\u0442": [8, 16, 37, 82, 100], "\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440": [8, 16, 38, 51, 70, 73, 74, 86, 89, 94, 100], "\u0432\u044b\u0434\u0435\u043b": [8, 38, 86, 94], "\u043e\u0442\u0434\u0430": 8, "20": [8, 23, 38, 52, 66, 70, 76, 77, 85, 86], "\u043f\u0440\u0438\u0437\u043d\u0430\u043d": [8, 88], "\u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u043c": 8, "\u0440\u0430\u0432\u043d\u043e\u0446\u0435\u043d": 8, "\u0438\u0437\u043b\u0438\u0448\u043a": 8, "\u043f\u0435\u0440\u0435\u043d\u043e\u0441": [8, 9, 21], "\u043d\u0438\u0437\u043a": [8, 11, 21, 38, 56, 70, 74, 75, 88], "\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c": 8, "\u0442\u0440\u0435\u0431\u0443\u0435\u043c": [8, 21, 75, 94, 95], "40": [8, 73, 83, 93], "\u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442": 8, "\u0433\u043e": [8, 83], "14": [8, 23, 38, 51, 66, 76, 100], "3": [8, 21, 23, 34, 37, 38, 40, 51, 64, 65, 66, 70, 74, 75, 76, 77, 82, 85, 86, 100], "\u0443\u043c\u043e\u043b\u0447\u0430\u043d": [8, 85], "\u043d\u0430\u0441\u0442\u043e\u044f": [8, 38, 70, 82, 85, 86, 92, 102], "\u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d": [8, 11, 23, 42, 73, 86, 100, 102], "\u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d": [8, 100], "\u0440\u0430\u0441c\u043c\u043e\u0442\u0440": 8, "relationships": [8, 11, 23, 34, 74, 75, 85, 100], "vladimir": [8, 9, 14, 15, 21, 23, 75, 82], "khorikov": [8, 9, 14, 15, 21, 23, 75, 82], "\u0431\u0443\u0434": [8, 21, 23, 34, 46, 70, 74, 85], "\u043f\u0440\u0438\u0432\u0435\u0434": [8, 23, 38, 82, 100], "\u0437\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d": 8, "\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442": [8, 11, 37, 38, 73, 74, 75, 77, 83, 85, 90, 100, 102], "stackoverflow": [8, 9], "public": [8, 9, 11, 23, 82, 85, 89], "class": [8, 9, 21, 23, 38, 74, 75, 85, 86, 90], "student": 8, "entity": [8, 9, 11, 21, 23, 65], "string": [8, 9], "name": [8, 9, 23, 26, 49, 75], "email": [8, 23, 82], "readonly": 8, "ilist": 8, "studentinstructor": 8, "_studentinstructors": 8, "ireadonlylist": 8, "instructor": 8, "instructors": 8, "select": [8, 38, 82], "x": [8, 21, 34, 37, 85, 86], "orderby": 8, "dateadded": 8, "tolist": 8, "internal": [8, 9, 21, 34, 37, 38, 74, 76, 85, 86], "void": [8, 9, 21, 23, 70], "addinstructor": 8, "add": [8, 23, 38, 46, 47, 51, 70, 74, 76, 77, 85, 86], "students": 8, "addstudent": 8, "var": 8, "this": [8, 9, 11, 15, 21, 23, 26, 29, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 62, 63, 64, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 93, 94, 100], "datetime": 8, "now": [8, 21, 23, 29, 34, 38, 46, 65, 70, 74, 75, 76, 85, 86], "\u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430": [8, 70, 75, 85, 102], "\u043f\u0440\u0435\u0434\u043f\u0440\u0438\u043d\u044f\u0442": 8, "\u043a\u043e\u043d\u0442\u0443\u0440": [8, 89], "\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d": [8, 15, 21, 23, 30, 37, 38, 42, 47, 70, 72, 73, 74, 80, 85, 88, 90, 92, 100, 102], "\u043f\u0435\u0440\u0435\u0440\u0430\u0431\u043e\u0442\u043a": [8, 46, 47], "\u043c\u043e\u0433\u043b": [8, 9, 21, 38, 74, 83, 88, 90], "\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430": 8, "\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u043e\u043d": 8, "online": [8, 23, 92], "\u0442\u0430\u0431\u043b\u0438\u0446": [8, 9, 30, 85], "\u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b": 8, "\u043f\u0440\u0438\u043c\u0435\u0440\u043d": [8, 40, 76, 83], "package": [8, 9, 11, 23, 85], "grade_1": [8, 9], "errors": [8, 15, 21, 74, 90], "time": [8, 9, 21, 23, 34, 37, 38, 39, 41, 46, 47, 49, 51, 52, 53, 62, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 95], "type": [8, 9, 21, 23, 34, 37, 38, 46, 74, 76], "memberid": [8, 9], "uint64": [8, 9], "grade": [8, 9, 19, 109], "uint": [8, 9], "availableendorsementcount": [8, 9], "receivedendorsementcount": 8, "endorsementid": 8, "artifactdescription": 8, "weight": [8, 38, 85, 86], "uint8": [8, 9], "const": 8, "peerweight": 8, "higherweight": 8, "expert": [8, 72, 74, 92, 100], "candidate": [8, 51, 77], "grade1": 8, "grade2": 8, "grade3": 8, "withoutgrade": 8, "0": [8, 9, 49, 51, 64, 74, 82, 86], "specialist": 8, "struct": [8, 9], "id": [8, 9, 21, 23, 34, 82], "assignments": 8, "assignment": [8, 21], "version": [8, 9, 23, 34, 49, 52, 64, 74, 75, 82], "createdat": [8, 9], "func": [8, 9], "getid": [8, 9], "return": [8, 9, 15, 21, 23, 26, 38, 51, 70, 86], "getgrade": 8, "getversion": 8, "increasereceivedendorsementcount": 8, "w": [8, 38, 64, 74, 75, 82, 92], "setgrade": [8, 9], "else": [8, 23, 74, 76, 86], "append": 8, "increaseversion": 8, "specialistid": 8, "specialistversion": 8, "assignedgrade": 8, "endorser": [8, 9], "endorse": 8, "adesc": 8, "allowed": [8, 11, 23, 34, 38], "only": [8, 9, 11, 21, 23, 34, 37, 38, 41, 47, 49, 62, 65, 72, 74, 75, 76, 77, 80, 82, 85, 86, 100], "members": [8, 9, 11, 23, 38, 42, 51, 74, 86, 90], "equal": [8, 38], "lower": [8, 38, 39, 75, 77, 85], "have": [8, 9, 11, 21, 23, 29, 34, 37, 38, 39, 46, 47, 49, 51, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 92, 95, 100], "reached": [8, 23], "limit": [8, 11, 38, 74, 86], "available": [8, 9, 38, 51, 82], "recommendations": 8, "year": [8, 23, 46, 62, 70, 76, 86], "himself": [8, 37, 76, 82, 95], "nil": [8, 9], "decreaseavailableendorsementcount": 8, "endorserid": [8, 9], "endorsergrade": [8, 9], "endorserversion": 8, "specialistgrade": 8, "\u043c\u0435\u0442\u043e\u0434": [8, 9, 11, 15, 21, 23, 34, 65, 72, 74, 75, 76, 77, 85, 90, 92, 93], "\u0444\u0430\u0431\u0440\u0438\u0447\u043d": 8, "\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449": [8, 23, 82], "\u0438\u0437\u0432\u043b\u0435\u043a\u0430": [8, 100], "\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f": [8, 34], "\u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a": [8, 23, 30, 33, 118], "\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c": [8, 21, 23, 30, 37, 85, 86], "\u0434\u043e\u0441\u0442\u0430\u0432\u043a": [8, 23, 30, 34, 86], "\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430": [8, 30, 34], "\u0441\u0438\u043d\u0445\u0440\u043e\u043d": [8, 23, 34], "\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446": [8, 23, 30], "mediator": [8, 23, 72, 73], "observer": [8, 23], "\u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d": [8, 21, 23], "message": [8, 21, 23, 34], "broker": 8, "endorsementcreated": 8, "\u043f\u043e\u0434\u043f\u0438\u0441\u0430": 8, "\u0432\u044b\u0437\u044b\u0432\u0430": [8, 9, 23, 38, 56, 65, 74, 95], "\u0432\u044b\u0447\u0438\u0442\u0430\u043d": 8, "\u0441\u0447\u0435\u0442\u0447\u0438\u043a": 8, "\u0443\u043a\u0430\u0437\u0430\u043d": [8, 30, 100, 102], "\u0437\u0430\u0432\u0438\u0441\u044f": 8, "\u043e\u0442\u043d\u043e\u0448\u0435\u043d": [8, 23, 38, 42, 65, 75, 85, 88, 94, 100, 102], "\u043e\u0431\u0440\u0430\u0442": [8, 21, 23, 37, 38, 52, 56, 65, 72, 76, 82, 85, 86, 92, 93, 100], "\u0438\u043c\u0435\u0435\u0442": [8, 9, 21, 23, 29, 34, 37, 38, 40, 65, 70, 72, 74, 75, 76, 82, 83, 85, 86, 94, 100, 102], "\u0443\u0441\u0435\u0447": 8, "\u0441\u043d\u044d\u043f\u0448\u043e\u0442": 8, "sourced": [8, 23, 30, 34, 82], "log": [8, 23], "\u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430": [8, 38], "\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d": [8, 42, 85, 86], "\u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d": [8, 37, 38, 65, 73, 75, 76, 92, 93, 94, 100], "\u043f\u0435\u0440\u0438\u043e\u0434": [8, 95], "\u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u043d": 8, "\u043a\u043b\u0430\u0441\u0441\u043d\u043e\u0441\u0442": 8, "\u043f\u043e\u043b\u0433\u043e\u0434": 8, "\u0442\u0440\u0435\u0431\u043e\u0432\u0430": [8, 11, 23, 65, 72, 73, 85], "\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d": [8, 21, 88, 89, 94], "\u0442\u0435\u0447\u0435\u043d": [8, 70, 74, 85], "\u0438\u043d": [8, 10, 21, 23, 34, 37, 38, 40, 41, 46, 56, 70, 72, 75, 85, 88, 89, 92, 94, 102], "\u043c\u043e\u0433": [8, 21, 38, 70, 74, 82, 83, 85, 86], "readmodel": 8, "\u043e\u0447\u0435\u0440\u0435\u0434": [8, 23, 34, 37, 38, 56, 70, 74, 85, 86, 90, 93, 100], "\u0441\u043c\u043e\u0433": [8, 74, 75, 85, 88], "\u043f\u043e\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430": 8, "artifact": [8, 73, 74, 76, 100], "\u0434\u0432\u0430\u0436\u0434": [8, 40], "\u043f\u0440\u043e\u0439\u0434": 8, "\u0440\u0435\u0430\u043b\u0438\u0437": [8, 29, 34, 75, 82, 86], "\u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442": [8, 9, 11, 15, 23, 26, 100], "\u043f\u0440\u0435\u0432\u044b\u0448\u0430": [8, 73, 74, 86], "\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d": [8, 15, 102], "\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a": [8, 10, 23, 30], "\u0432\u044b\u0437\u043e\u0432": [8, 9, 23, 62, 86], "\u043e\u0431\u0441\u0443\u0434": [8, 15, 23], "\u043f\u0440\u043e\u0441\u043b\u0435\u0436\u0438\u0432\u0430": [8, 85], "\u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440": [8, 23, 30, 72, 100], "\u0434\u0430\u0432\u0430": [8, 21, 30, 38, 56, 73, 75, 86], "endorsera": 8, "specialista": 8, "\u043f\u0440\u0438\u0441\u0432\u043e\u0435\u043d": 8, "\u0445\u0432\u0430\u0442\u0430": [8, 38], "\u043f\u0440\u043e\u0432\u0435\u0440\u043a": [8, 92], "\u0434\u0435\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 8, "endorserb": 8, "\u0443\u0441\u043f\u0435\u0442": [8, 74], "\u0434\u0430\u0442": [8, 62, 82, 85, 88], "\u0437\u0430\u0447\u0442": 8, "\u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a": [8, 70, 85, 86, 92], "\u043d\u0430\u0440\u0443\u0448\u0430": [8, 9, 21], "\u0437\u0430\u043f\u0440\u0435\u0442": [8, 21, 40, 75], "\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d": 8, "\u0441\u0438\u0442\u0443\u0430\u0446": [8, 21, 37, 38, 47, 82, 85, 88, 92, 93, 100, 102], "\u043d\u0430\u043b\u043e\u0436": [8, 37, 38], "\u043f\u043e\u043a\u0440\u044b\u0432\u0430": [8, 86], "\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0442\u043d": [8, 9, 15], "\u0438\u043d\u0434\u0435\u043a\u0441": 8, "\u043f\u043e\u043b": [8, 9, 13, 60, 85, 90], "\u043e\u0441\u0442\u0430\u0432\u0430": [8, 37], "\u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b": [8, 37, 38, 72, 85, 86, 94], "\u0437\u0430\u0434\u0435\u0440\u0436\u043a": [8, 21], "\u043f\u0440\u0438\u0447\u0438\u043d": [8, 11, 15, 21, 30, 37, 38, 41, 56, 65, 70, 75, 76, 82, 83, 85, 86, 88, 89, 92, 93, 94, 100], "\u0432\u0441\u0442\u0430\u043b": 8, "\u0437\u0430\u0442\u0443\u043f": 8, "\u0447\u0435\u043a": 8, "\u0431\u0434": [8, 12, 21, 23], "\u0437\u0430\u043f\u0443\u0441\u0442": [8, 34, 73], "\u0441\u0435\u0442": [8, 34], "\u0440\u0430\u0437\u0434\u0430": 8, "\u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430": [8, 92], "\u0443\u043f\u0440\u0435\u0436\u0434\u0430": [8, 37], "\u0432\u044b\u0434\u0432\u0438\u0433\u0430": [8, 23, 65], "\u043f\u0430\u0440\u0442\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430": 8, "\u043e\u0431": [8, 9, 11, 15, 21, 34, 37, 38, 40, 65, 70, 75, 76, 77, 82, 83, 85, 86, 92, 100, 102], "\u0437\u0430\u043d\u0438\u043c\u0430": [8, 9, 34, 38, 41, 46, 51, 70, 72, 74, 75, 76, 82, 83, 85, 86, 92, 93, 100], "\u043f\u0430\u0440\u0442\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d": [8, 23, 30, 34], "\u0437\u043d\u0430\u0435\u0442": [8, 21, 38, 47, 82, 83, 85, 86, 90, 92, 102], "\u043f\u0430\u0440\u0442\u0438\u0446": [8, 30], "\u0430\u0432\u0442\u043e\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [8, 30], "\u043f\u0435\u0440\u0432\u0438\u0447\u043d": [8, 9, 10, 23, 30, 37, 65, 92], "\u0433\u043b\u0430\u0441": [8, 38], "\u0434\u0443\u0431\u043b\u0438\u043a\u0430\u0442": 8, "\u043d\u0435\u0447\u0435\u0442\u043a": 8, "\u0432\u0432\u043e\u0434": [8, 21, 23, 34, 65, 70, 74, 75, 85, 100], "\u043f\u0440\u0435": 8, "\u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": [8, 30], "\u0434\u043b\u0438\u0442": 8, "\u0447\u0430\u0441": [8, 30, 74, 85, 86, 95], "\u0434\u043d\u044f\u043c": 8, "\u0432\u0440\u044f\u0434": [8, 9, 21, 82], "\u0431\u0443\u0434\u0443\u0442": [8, 21, 23, 26, 34, 38, 46, 47, 82, 83, 85, 86, 88, 95], "\u0432\u043e\u0441\u0442\u043e\u0440\u0433": 8, "\u043a\u0430\u0436\u0435\u0442": [8, 21, 38, 47, 83, 85], "\u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442": [8, 11, 75, 88], "\u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d": 8, "\u043e\u0434\u043e\u0431\u0440\u0435\u043d": 8, "\u043d\u0435\u043e\u0434\u043e\u0431\u0440\u0435\u043d": 8, "\u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430": 8, "\u0441\u043c\u043e\u0436\u0435\u0442": [8, 42, 46, 70, 75, 82, 85, 86, 92], "\u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430": 8, "\u043e\u0431\u043b\u0430\u0441\u0442": [8, 11, 21, 23, 34, 37, 38, 40, 60, 64, 65, 68, 72, 74, 75, 80, 82, 88, 90, 92, 102], "\u044d\u043a\u0441\u043f\u0435\u0440\u0442\u043d": 8, "\u0432\u043d\u043e\u0441": [8, 23, 38, 65, 74], "\u043f\u0440\u0430\u0432\u043a": [8, 13], "artifactid": 8, "status": [8, 15, 21, 23, 51, 73, 85], "artifactstatus": 8, "description": [8, 23, 38, 52, 74, 82, 83], "competenceids": 8, "competenceid": 8, "competence": 8, "competencename": 8, "\u0437\u0430\u0434\u0430\u0447": [8, 23, 34, 37, 41, 46, 51, 60, 73, 74, 75, 76, 83, 85, 86, 88, 90, 94, 95, 100], "\u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440": 8, "\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430": [8, 75, 82], "\u0441\u0442\u0440\u0430\u0442\u0435\u0433": [8, 34, 37, 38, 46, 68, 70, 72, 77, 85, 86], "\u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440": 8, "\u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430": [8, 9, 11, 26], "\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442": [8, 9, 15, 26, 34, 38, 40, 52, 65], "\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d": [8, 37, 38, 88, 100], "\u0432\u044b\u0434\u0435\u043b\u0435\u043d": [8, 9, 38, 41, 70, 86], "\u043d\u0443\u0436": [8, 10, 94], "\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430": [8, 9, 38, 41, 70], "trilemma": [8, 14], "\u0443\u0447\u0438\u0442\u044b\u0432": [8, 86], "\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d": [8, 89], "model": [8, 9, 11, 14, 21, 23, 28, 29, 30, 34, 37, 38, 51, 52, 59, 60, 62, 65, 74, 75, 76, 77, 82, 86, 88, 103, 115], "purity": [8, 82], "completeness": [8, 52, 82], "\u0440\u0430\u0437\u043c\u0435\u0441\u0442": [8, 11], "\u043f\u043e\u0434\u0441\u043a\u0430\u0436\u0435\u0442": 8, "\u0441\u0435\u0439\u0447\u0430\u0441": [8, 38, 70, 95], "\u043f\u0440\u0438\u0432\u043e\u0434": [8, 21, 23, 34, 40, 41, 56, 65, 68, 77, 82, 83, 85, 86, 90, 95], "\u0445\u0440\u0430\u043d": [8, 11, 23], "\u043d\u0430\u0433\u0440\u0430\u0434\u043d": 8, "\u043f\u043e\u0447\u0435\u0442\u043d": 8, "\u0433\u0440\u0430\u043c\u043e\u0442": 8, "\u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442": 8, "\u0434": [8, 75, 76, 82, 86, 88, 90, 92, 95, 100, 102], "\u043d\u0430\u0433\u0440\u0430\u0436\u0434\u0430": 8, "\u0434\u043e\u043b\u0436\u043d": [8, 9, 10, 11, 23, 30, 34, 37, 38, 40, 41, 42, 46, 47, 51, 64, 68, 70, 72, 74, 75, 82, 85, 86, 88, 90, 92, 93, 94, 100], "\u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0430": [8, 85, 100], "\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0430": 8, "\u0434\u043e\u043b\u0436": [8, 9, 23, 34, 38, 51, 73, 74, 75, 83, 85, 86, 88], "\u0443\u0434\u0430\u043b\u0435\u043d": [8, 9, 29, 34, 37], "\u0432\u0440\u043e\u0434": [8, 75], "\u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430": [8, 23, 38, 72, 83, 85, 92, 94], "\u0438\u043c\u0435\u0442": [8, 11, 23, 40, 73, 74, 75, 83, 90], "\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d": [8, 9, 92], "\u0441\u0432\u0435\u0440\u0442\u043a": 8, "left": [8, 37, 72, 73, 85], "fold": [8, 75], "\u043f\u0440\u043e\u0435\u043a\u0446": [8, 100], "\u0442\u0435\u043f\u0435\u0440": [8, 21, 23, 30, 38, 40, 70, 74, 82, 83, 85, 86, 88, 92], "\u0435\u043c": [8, 9, 15, 23, 38, 83, 86, 88, 100], "\u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d": [8, 38], "\u0443\u0441\u043f\u0435\u0435\u0442": 8, "\u0433\u043b\u0430\u0432": [8, 11, 13, 21, 23, 30, 34, 38, 51, 64, 70, 74, 76, 85, 86, 100], "9": [8, 23, 38, 74, 76, 85], "coding": [8, 37, 74, 76, 90], "up": [8, 21, 23, 34, 37, 38, 51, 52, 62, 65, 70, 72, 73, 74, 75, 76, 78, 80, 82, 85, 86, 95, 100, 133], "lean": [8, 23, 38, 46, 51, 52, 64, 65, 76, 77, 82, 88], "development": [8, 23, 36, 38, 46, 47, 49, 51, 52, 54, 58, 61, 65, 66, 70, 72, 73, 74, 75, 76, 82, 85, 86, 88, 90, 92, 93, 94, 95, 100, 120, 126, 128, 129], "james": [8, 38, 75, 76, 82, 95], "o": [8, 15, 21, 82], "coplien": [8, 76, 82], "gertrud": [8, 76, 82], "bj\u00f8rnvig": [8, 76, 82], "\u0434\u0435\u043d\u0435\u0436\u043d": 8, "\u0441\u0447\u0435\u0442": [8, 42, 70, 77, 83, 85, 90, 100], "\u043f\u043e\u0445\u043e\u0436": [8, 9, 23, 38, 75], "\u0432\u0442\u043e\u0440": [8, 9, 11, 13, 21, 23, 34, 37, 40, 46, 52, 72, 74, 76, 77, 83, 85, 86, 88, 89, 92, 94, 100], "\u043e\u043f\u0438\u0441\u044b\u0432\u0430": [8, 11, 38, 64, 72, 74, 85, 86, 92, 94, 102], "vaughn": [8, 9, 21, 23, 29, 30, 34, 82, 100], "vernon": [8, 9, 21, 23, 29, 30, 34, 82, 100], "\u0438\u043d\u0442\u0435\u0440\u0432": [8, 21, 30, 73], "uncertainty": [8, 30, 34, 38, 65, 76], "reactive": [8, 23, 30, 34, 82], "reviewed": [8, 30, 34, 37, 76], "thomas": [8, 30, 34, 37, 76, 82, 90, 94], "betts": [8, 23, 30, 34, 82], "\u0441\u044e\u0434": [8, 21, 23, 38, 82], "\u043e\u0442\u043d\u0435\u0441\u0442": [8, 30, 94], "engines": [8, 82], "\u043f\u0435\u0441\u0441\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": 8, "\u044d\u0442\u0430\u043f": [8, 9, 13, 73, 77, 82, 85, 86], "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u0435\u043d": [8, 38, 75, 83, 100], "\u043d\u0435\u0443\u0434\u0430\u0447": [8, 64, 83], "\u043e\u0442\u043f\u0443\u0441\u043a\u0430": 8, "\u0443\u0441\u043f\u0435\u0445": [8, 38, 64, 73, 83, 85, 89, 95], "receiveendorsement": 8, "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432": [8, 60, 70, 83, 86, 90], "\u043e\u0442\u043f\u0443\u0441\u0442": 8, "\u043f\u043e\u0437\u0432\u043e\u043b": [8, 37, 72, 76, 85, 86, 88, 100], "\u0437\u0430\u0432\u0435\u0440\u0448": [8, 23, 74, 83], "\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c": [8, 23, 30, 34, 100], "\u0437\u0430\u043c\u0435\u043d": [8, 23, 38, 82, 92, 102], "pendingendorsementcount": [8, 9], "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [8, 30], "\u043e\u0441\u0442\u0430\u043d\u043e\u0432": [8, 9, 83, 86, 100], "\u0438\u0441\u043a\u043b\u044e\u0447": [8, 30, 34, 56, 73, 76], "\u0431\u0443\u0434\u0443\u0449": [8, 21, 23, 38, 47, 68, 70, 76, 85, 86], "\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d": [8, 11], "grade_2": [8, 9], "endorsementcount": [8, 9], "lowerweight": 8, "proposed": [8, 65, 86], "accepted": [8, 23, 34, 38, 51, 53], "receivedendorsements": 8, "aid": [8, 46], "receive": [8, 23, 34, 37], "endorsements": 8, "higher": [8, 23, 38, 39, 70, 74, 75, 77, 86, 90], "cancompleteendorsement": 8, "able": [8, 37, 38, 39, 46, 62, 65, 73, 74, 75, 76, 85, 86], "complete": [8, 23, 34, 38, 51, 52, 60, 62, 65, 73, 74, 75, 77, 82, 86, 90, 95], "_": [8, 9, 73], "range": [8, 38, 51, 85], "isendorsedby": 8, "has": [8, 9, 15, 21, 23, 29, 34, 37, 38, 39, 49, 52, 64, 65, 72, 73, 74, 75, 76, 85, 86, 90, 100], "already": [8, 15, 21, 23, 34, 73, 74, 85, 86], "been": [8, 9, 21, 23, 34, 38, 41, 49, 51, 52, 65, 70, 72, 73, 74, 75, 76, 86, 90], "endorsed": 8, "recogniser": 8, "actualizegrade": 8, "getreceivedendorsementcount": 8, "counter": [8, 74], "getspecialistgrade": 8, "getweight": 8, "rid": [8, 37, 76], "bool": [8, 9, 23], "canreserveendorsement": 8, "reserveendorsement": 8, "reserved": 8, "releaseendorsementreservation": 8, "completeendorsement": 8, "reservation": 8, "emacsway": [8, 16, 96], "tree": [8, 85, 86], "main": [8, 9, 23, 77, 86], "\u043f\u0440\u043e\u0435\u043a\u0442": [8, 12, 13, 23, 37, 38, 40, 41, 42, 46, 64, 65, 68, 70, 72, 74, 75, 76, 77, 80, 82, 85, 86, 92], "\u043f\u0440\u0435\u0434\u0443\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430": [8, 70], "multitenancy": 8, "\u0441\u0432\u0435\u0442": [8, 21, 38, 47, 75, 86, 88, 92], "\u0433\u0438\u0431\u043a": [8, 23, 37, 51, 70, 75, 76, 85], "\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 8, "tenant": 8, "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440": [8, 9, 23, 73], "\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d": [8, 92, 100, 102], "\u043f\u0435\u0440\u0435\u0435\u0445\u0430": 8, "\u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430": 8, "\u0440\u043e\u0441\u0442": [8, 21, 37, 40, 41, 64, 65, 70, 73, 74, 75, 76, 80, 83, 85, 86, 90, 94, 100], "\u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442": [8, 74, 77, 85, 100], "rules": [8, 23, 34, 72, 75, 82, 85, 86, 94], "engine": 8, "aka": [8, 9, 34, 82], "production": [8, 9, 23, 37, 70, 76, 82, 85, 86], "rule": [8, 9, 21, 23, 34, 46, 52, 62, 72, 85], "grule": 8, "implementation": [8, 14, 21, 23, 34, 38, 51, 60, 68, 72, 74, 75, 76, 77, 82, 85, 86, 90, 100], "golang": [8, 9, 11, 12, 13, 15, 17, 19, 21, 23, 34, 82, 109], "\u043b\u0438\u0448": [9, 21, 23, 38, 40, 70, 74, 83, 85, 86, 102], "\u0434\u044b\u0440\u044f\u0432": 9, "\u0440\u0435\u0448\u0435\u0442": 9, "\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d": [9, 72, 85, 86], "\u0437\u0430\u043f\u0440\u043e\u0441": [9, 21, 23, 30, 34], "\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d": [9, 15, 23, 38, 40, 41, 46, 73, 74, 85, 86, 90, 92], "\u0431\u043b\u0438\u0437\u043a": [9, 41], "\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d": [9, 21, 72, 82, 90, 94, 100], "\u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430": [9, 21, 23, 30, 52, 56, 82, 85], "\u043d\u0438\u043a": [9, 21, 88, 94], "\u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b": [9, 100], "preserving": 9, "encapsulation": 9, "avoids": [9, 23], "exposing": [9, 23], "originator": 9, "should": [9, 11, 21, 23, 29, 37, 38, 46, 49, 51, 53, 62, 65, 70, 72, 73, 74, 75, 76, 80, 85, 86, 90, 100], "manage": [9, 23, 51, 74, 86], "must": [9, 21, 23, 26, 29, 34, 37, 38, 51, 73, 74, 75, 76, 85, 86, 88], "nevertheless": [9, 34], "outside": [9, 21, 23, 38, 76, 86], "shields": 9, "other": [9, 21, 23, 26, 29, 34, 37, 38, 39, 41, 42, 49, 51, 52, 65, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 94, 95, 100], "potentially": [9, 23, 38, 51], "complex": [9, 21, 23, 38, 60, 62, 70, 74, 75, 76, 77, 85, 86, 90, 100], "internals": [9, 11, 23, 34, 82], "thereby": [9, 86], "patterns": [9, 11, 13, 23, 30, 34, 37, 66, 71, 73, 74, 75, 76, 82, 86, 92, 94, 132], "reusable": [9, 72, 73, 82], "object": [9, 15, 21, 23, 26, 29, 37, 38, 64, 72, 73, 74, 75, 76, 77, 82, 85, 90, 100], "oriented": [9, 15, 21, 23, 37, 64, 72, 73, 74, 75, 76, 77, 82, 86, 90], "erich": [9, 72, 73, 82], "gamma": [9, 23, 72, 73, 82], "richard": [9, 49, 51, 64, 72, 73, 82, 86, 88], "helm": [9, 72, 73, 82], "ralph": [9, 72, 73, 76, 80, 82, 85], "johnson": [9, 72, 73, 76, 82, 85], "john": [9, 23, 34, 38, 46, 66, 70, 72, 73, 82, 85, 88, 95], "vlissides": [9, 72, 73, 82], "\u0430\u0432\u0442\u043e\u0440\u0438\u0442\u0435\u0442\u043d": [9, 15, 40, 41, 75, 82, 85, 92], "some": [9, 21, 23, 26, 34, 37, 38, 42, 46, 49, 51, 60, 63, 65, 70, 72, 73, 74, 75, 76, 82, 85, 86, 90, 95, 100], "form": [9, 21, 23, 38, 49, 51, 52, 74, 75, 85, 86], "serialization": 9, "rest": [9, 21, 23, 52, 70, 73, 74, 75, 82, 85], "discussion": [9, 21, 23], "mechanism": [9, 23, 34], "assumed": 9, "built": [9, 38, 65, 77, 85, 86, 100], "although": [9, 21, 23, 34, 70, 77, 85], "highly": [9, 21, 23, 37, 76, 82, 86], "advantageous": [9, 100], "their": [9, 21, 23, 26, 34, 37, 38, 39, 46, 49, 51, 52, 64, 65, 72, 73, 74, 75, 76, 82, 85, 86, 92], "platform": [9, 65, 74], "results": [9, 34, 37, 38, 51, 74, 82, 85], "though": [9, 23, 34, 37, 38, 74, 75, 76, 77], "quite": [9, 21, 23, 34, 37, 47, 51, 73, 76, 85], "useful": [9, 21, 23, 29, 34, 37, 53, 82, 86], "dealing": [9, 23, 34, 65, 73, 82], "snapshots": 9, "better": [9, 15, 21, 23, 34, 37, 38, 42, 51, 65, 70, 72, 73, 74, 75, 77, 82, 85], "insulates": 9, "serializer": 9, "versioning": [9, 23, 34, 82], "problems": [9, 15, 21, 37, 38, 63, 65, 68, 72, 74, 77, 82, 85, 86, 100], "released": [9, 38, 49, 86], "either": [9, 15, 21, 23, 26, 34, 37, 38, 51, 75, 76, 85], "deleted": 9, "recreated": 9, "updated": [9, 21, 23, 52, 62], "match": [9, 49, 76, 82], "schema": [9, 23], "separated": 9, "snapshot": 9, "itself": [9, 21, 23, 34, 38, 62, 65, 72, 73, 74, 76, 85, 86], "cqrs": [9, 11, 19, 28, 34, 75, 109, 115], "documents": [9, 21, 37, 38, 82], "greg": [9, 21, 23, 34, 82], "young": [9, 21, 23, 34, 64, 82], "\u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446": [9, 21, 46, 70, 73], "\u043f\u0430\u0442\u0442\u0435\u0440\u043d": [9, 21, 23, 34, 75, 82, 85, 88, 94], "visitor": 9, "\u0447\u0438\u0441\u043b": [9, 11, 23, 34, 38, 41, 74, 85, 86, 90, 93, 100], "\u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a": [9, 23, 30, 56, 72, 77, 82, 85, 88, 91, 94, 138], "\u043e\u0442\u043d\u043e\u0441": [9, 23, 38, 74, 80, 83, 86, 92, 100], "breaking": [9, 23, 85, 86], "assumes": [9, 65], "concreteelement": 9, "enough": [9, 21, 23, 37, 38, 49, 51, 60, 62, 70, 73, 74, 76, 82, 86, 90, 100], "let": [9, 23, 34, 37, 38, 72, 74, 76, 85, 86], "visitors": 9, "job": [9, 15, 21, 37, 38, 42, 46, 72, 73, 74, 76, 85, 86], "result": [9, 13, 15, 21, 23, 37, 38, 51, 64, 74, 76, 85, 86], "often": [9, 21, 23, 34, 37, 38, 46, 49, 51, 52, 68, 72, 74, 76, 77, 85, 86, 92, 94, 100], "forces": [9, 38, 65, 75, 85, 86], "provide": [9, 23, 34, 38, 42, 49, 74, 77, 86, 90, 100], "operations": [9, 21, 23, 29, 34, 85, 86, 90], "access": [9, 11, 21, 23, 51], "state": [9, 11, 21, 23, 34, 37, 72, 74, 89], "may": [9, 21, 23, 34, 37, 38, 46, 51, 65, 73, 74, 75, 76, 77, 85, 86], "compromise": 9, "\u043e\u0431\u0445\u043e\u0434": [9, 23, 37, 83], "\u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0447\u0435\u0441\u043a": 9, "\u0432\u043b\u043e\u0436\u0435\u043d": [9, 11, 23, 30, 41], "\u0441\u0443\u0449\u043d\u043e\u0441\u0442": [9, 13, 23, 30, 73, 100], "\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440": [9, 70], "\u0432\u044b\u0440\u0430\u0436\u0435\u043d": [9, 21, 23, 37, 85, 102], "\u043b\u0438\u0448\u0430": [9, 23, 40, 83], "\u0432\u043e\u0437\u0432\u0440\u0430\u0442": [9, 15, 21], "\u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430": 9, "walkable": 9, "accept": [9, 21, 23, 34, 37, 38, 73], "setfield": 9, "walkwalkable": 9, "walkuint8": 9, "walkuint64": 9, "walkuint": 9, "walktime": 9, "endorsement": 9, "interfaces": [9, 51, 72, 74, 82, 86], "value": [9, 11, 21, 23, 25, 26, 37, 38, 39, 41, 42, 49, 52, 62, 66, 70, 73, 74, 76, 82, 85, 86, 93, 100, 113], "\u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d": [9, 65, 74, 90], "\u043f\u0440\u043e\u0441\u0442\u0430\u0432": 9, "\u043e\u0441\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d": [9, 73, 92], "\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d": [9, 11, 30, 86, 92, 93], "\u0440\u0430\u0437\u043c\u0430\u0437\u044b\u0432\u0430": 9, "walkers": 9, "repositories": [9, 23], "\u0440\u0430\u0437\u043b\u0435\u0442": [9, 13], "\u0434\u0440\u043e\u0431": [9, 13], "smell": [9, 13, 76], "\u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d": [9, 86, 100], "\u0434\u0438\u0430\u043b\u0435\u043a\u0442": 9, "\u0432\u043d\u0435\u0434\u0440\u0435\u043d": [9, 73, 86, 88], "querybuilder": 9, "\u043d\u0430\u0447\u0438\u043d\u0430": [9, 21, 23, 38, 40, 46, 47, 52, 56, 70, 74, 77, 82, 83, 85, 86, 88, 92, 94, 95, 100], "\u0441\u043b\u0438\u0448\u043a": [9, 11, 23, 38, 46, 74, 76, 82, 85, 86, 88, 94], "\u0434\u0435\u0442\u0430\u043b": [9, 74, 90, 100], "\u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d": [9, 21, 23, 37, 40, 64, 65, 75, 76, 80, 86], "\u0432\u043e\u0437\u043b\u043e\u0436": 9, "\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 9, "\u043e\u0441\u0432\u043e\u0431\u043e\u0434": 9, "\u0440\u0430\u0437\u0440\u044b\u0432\u0430": 9, "\u043e\u0431\u044f\u0437\u0430\u043d": [9, 38, 73, 75, 83, 85], "\u043f\u043e\u0434\u0440\u044b\u0432\u0430": [9, 88], "\u0434\u0432\u0435\u0440": 9, "\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c": [9, 21, 76], "valueobject": 9, "\u0431\u0440\u0435\u0448": 9, "\u0441\u043f\u0440\u0430\u0432\u0435\u0434\u043b\u0438\u0432": [9, 23, 42], "\u0440\u0430\u0434": [9, 38, 75], "\u043e\u0442\u043c\u0435\u0442": 9, "\u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d": [9, 30, 40], "\u043c\u0443\u0442\u0438\u0440\u0443\u0435\u043c": 9, "\u043f\u0440\u043e\u0432\u0435\u0440": [9, 37, 74], "scan": 9, "src": 9, "\u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432": [9, 21, 23, 83, 85, 88], "special": [9, 23, 34, 51, 85], "case": [9, 21, 23, 29, 34, 37, 38, 51, 52, 70, 73, 74, 76, 82, 85, 86, 100], "null": [9, 70], "\u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430": [9, 46], "\u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f": [9, 11, 26], "\u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a": [9, 75, 76, 88], "\u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430": [9, 15, 23, 86], "validating": 9, "historical": [9, 37, 76], "valid": [9, 14, 23], "orms": [9, 21], "within": [9, 11, 23, 34, 37, 38, 51, 65, 73, 74, 75, 76, 77, 85, 86], "boundary": [9, 11, 23, 86], "\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430": [9, 15, 22, 26, 74, 76, 111], "\u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d": 9, "\u043f\u0440\u0438\u0433\u043e\u0434": 9, "handled": [9, 23, 76, 86], "namedvaluechecker": 9, "instance": [9, 21, 23, 26, 73, 85, 93], "types": [9, 21, 23, 38, 51, 65, 74, 75], "int64": 9, "float64": 9, "byte": [9, 23], "\u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043d": [9, 102], "\u0437\u0430\u0449\u0438\u0449\u0435\u043d": [9, 11], "\u0430\u0442\u0440\u0438\u0431\u0443\u0442": [9, 11, 26, 51, 75], "\u0440\u0435\u0444\u043b\u0435\u043a\u0446": 9, "\u0440\u0435\u0444\u043b\u0435\u043a\u0441": [9, 100], "\u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430": [9, 70], "\u0447": [9, 38], "\u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d": [9, 34, 77], "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d": [9, 34], "\u043f\u0440\u043e\u0431": [9, 77], "marshal": 9, "protected": 9, "inner": 9, "hidden": [9, 23], "fmt": 9, "reflect": [9, 23, 34, 41, 77, 100], "bitly": 9, "simplejson": 9, "json": [9, 23, 82, 89], "j": [9, 23, 30, 34, 38, 51, 64, 74, 82, 86, 88, 90], "va": 9, "valueof": 9, "vt": 9, "elem": 9, "typeof": 9, "i": [9, 11, 13, 21, 23, 34, 37, 38, 39, 41, 46, 51, 53, 60, 62, 65, 70, 72, 73, 74, 75, 76, 82, 85, 86, 92, 94, 95], "numfield": 9, "set": [9, 15, 21, 23, 37, 38, 46, 49, 52, 53, 62, 65, 72, 74, 75, 76, 85, 100], "field": [9, 21, 23, 38, 74, 76], "tag": 9, "sprintf": 9, "indirect": 9, "marshaljson": 9, "jessonchan": 9, "abc": 9, "println": 9, "implementing": [9, 11, 21, 23, 29, 34, 38, 46, 51, 70, 75, 76, 82, 100], "aggregate": [9, 11, 23, 30, 34], "around": [9, 11, 23, 37, 38, 62, 70, 73, 75, 76, 82, 86, 95], "problem": [9, 21, 23, 26, 37, 38, 49, 60, 65, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 90, 100], "tight": [9, 86], "clients": [9, 21, 23, 65], "choose": [9, 11, 23, 37, 38, 76, 77, 85, 86], "et": [9, 23, 74, 86], "al": [9, 23, 74, 86], "double": [9, 86], "dispatch": [9, 23], "callback": [9, 21], "publishes": [9, 21, 23], "would": [9, 11, 21, 23, 26, 34, 37, 38, 41, 46, 51, 65, 70, 72, 75, 76, 85, 86, 100], "implement": [9, 11, 23, 37, 49, 70, 72, 76, 80, 82, 85], "passing": [9, 23, 26, 37], "implementer": 9, "argument": [9, 21, 23, 26, 37, 74, 76, 77, 82, 85, 86, 94], "then": [9, 11, 21, 23, 26, 29, 34, 37, 38, 41, 46, 51, 60, 62, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90], "requested": 9, "without": [9, 11, 21, 23, 34, 37, 38, 51, 65, 70, 74, 76, 85, 86], "revealing": 9, "shape": [9, 86, 100], "trick": [9, 23], "wed": 9, "sort": [9, 37, 72, 85], "keep": [9, 23, 37, 38, 51, 53, 73, 74, 85, 86, 90], "focused": [9, 23, 38, 82, 85, 86, 100], "rendering": 9, "states": [9, 23, 75], "interest": [9, 21, 23, 37, 38, 41, 42, 70, 76, 77, 100], "backlogitem": [9, 23], "providebacklogiteminterest": 9, "backlogiteminterest": 9, "aninterest": 9, "informtenantid": 9, "tenantid": 9, "informproductid": 9, "productid": 9, "informbacklogitemid": 9, "backlogitemid": 9, "informstory": 9, "story": [9, 23, 37, 38, 49, 51, 53, 65, 73, 76, 82], "informsummary": 9, "summary": [9, 86], "informtype": 9, "tostring": 9, "providetasksinterest": 9, "tasksinterest": 9, "alltasks": 9, "informtaskcount": 9, "size": [9, 73, 74, 76, 86, 92], "various": [9, 23, 37, 38, 51, 76], "providers": 9, "implemented": [9, 21, 23, 37, 38, 82, 100], "classes": [9, 23, 74, 75, 77, 85, 90], "much": [9, 21, 23, 37, 38, 42, 46, 47, 68, 70, 72, 73, 74, 75, 77, 82, 85, 86, 88, 100], "entities": [9, 11, 23, 75, 82], "describe": [9, 37, 86], "validation": [9, 15, 23, 38, 59, 60, 82], "delegated": 9, "separate": [9, 23, 38, 51, 52, 74, 75, 82, 85, 86, 90, 95], "validator": 9, "aware": [9, 23, 38, 51, 73, 85, 92], "consider": [9, 21, 23, 34, 37, 38, 51, 70, 74, 77, 86, 90], "responsibility": [9, 21, 23, 34, 37, 38, 75, 86], "natural": [9, 23, 86], "well": [9, 23, 37, 38, 39, 46, 51, 60, 62, 64, 66, 70, 73, 74, 75, 76, 77, 85, 86, 90, 93, 100], "such": [9, 15, 21, 23, 34, 37, 38, 46, 49, 51, 52, 65, 72, 74, 75, 76, 77, 85, 86, 90, 94, 100], "trade": [9, 23, 37, 38, 74, 76, 77, 82, 85, 86], "offs": [9, 38, 77, 85, 86], "discussed": [9, 23, 34, 37, 86], "technical": [9, 11, 21, 23, 37, 38, 39, 43, 46, 49, 52, 65, 66, 70, 72, 73, 76, 82, 85, 86, 90, 100, 121], "team": [9, 23, 32, 38, 42, 46, 49, 51, 52, 73, 74, 76, 80, 86, 100, 117], "getters": 9, "setters": 9, "holub": 9, "load": [9, 23, 51, 74, 86, 90], "java": [9, 21, 23, 34, 75, 82, 85], "util": 9, "locale": 9, "employee": [9, 23], "employeeid": 9, "money": [9, 38, 41, 74, 82], "salary": 9, "addname": 9, "addid": 9, "addsalary": 9, "providename": 9, "provideid": 9, "providesalary": 9, "close": [9, 15, 21, 49, 52, 68, 73, 75], "builder": 9, "export": 9, "setstate": 9, "exportable": [9, 11], "exportto": 9, "exportableuint": 9, "ex": 9, "endorserexportersetter": 9, "setid": 9, "setavailableendorsementcount": 9, "setpendingendorsementcount": 9, "setversion": 9, "setcreatedat": 9, "uintexporter": 9, "endorserexporter": 9, "val": 9, "personimporter": 9, "int": 9, "getage": 9, "personexporter": 9, "setdetails": 9, "person": [9, 11, 26, 39, 74, 76, 82, 85, 86, 90, 95], "\u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d": 9, "\u0438\u043d\u0442\u0435\u0440\u0435\u0444\u0435\u0439\u0441": 9, "\u043f\u043e\u043b\u0443\u0447\u0430": [9, 21, 23, 37, 38, 41, 47, 62, 77, 85, 86, 88], "\u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0432\u043d": 9, "\u0434\u0435\u043a\u043b\u0430\u0440\u0438\u0440\u043e\u0432\u0430": 9, "\u0441\u0435\u0442\u0442\u0435\u0440": 9, "\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440": [9, 21, 23, 34, 37, 38, 40, 41, 56, 65, 72, 73, 74, 75, 76, 87, 88, 90, 92, 93, 100, 137], "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d": [9, 21, 23, 37, 38, 40, 46, 64, 67, 68, 70, 73, 74, 75, 76, 81, 83, 85, 86, 92, 93, 95, 130, 135], "\u0443\u043c\u0435\u043d\u044c\u0448": [9, 37, 56, 72, 75, 85, 86, 88], "\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a": [9, 40, 42, 74, 75, 85, 90, 92], "\u0442\u0440\u0443\u0434\u043e\u0437\u0430\u0442\u0440\u0430\u0442": [9, 56, 70, 74], "minimize": [9, 38, 74, 90], "human": [9, 37, 38, 42, 74, 90], "resources": [9, 23, 38, 49, 65, 74, 82, 86], "required": [9, 23, 38, 46, 49, 62, 72, 74, 75, 85, 86], "maintain": [9, 23, 34, 38, 51, 52, 70, 73, 74, 85], "clean": [9, 21, 23, 37, 38, 40, 41, 66, 68, 73, 74, 75, 76, 82], "craftsman": [9, 21, 40, 41, 66, 73, 74, 75, 76, 82, 85], "robert": [9, 13, 21, 23, 34, 37, 38, 40, 41, 64, 66, 68, 72, 75, 76, 77, 80, 82, 85, 92, 93], "martin": [9, 13, 14, 21, 23, 34, 37, 38, 40, 41, 46, 62, 65, 66, 68, 70, 72, 75, 76, 80, 82, 85, 86, 93, 95], "\u043e\u043e": [9, 21, 37, 38, 42, 46, 47, 68, 70, 74, 86], "\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432": [9, 21, 37, 38, 42, 46, 47, 68, 70, 74, 86, 88], "\u043f\u0438\u0442\u0435\u0440": [9, 21, 37, 38, 42, 46, 47, 68, 70, 74, 82, 86, 88], "\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d": [9, 23, 37, 47, 75, 102], "\u043f\u0430\u043a\u0435\u0442\u0438\u0440\u043e\u0432\u0430": [9, 23, 34], "\u0443\u0441\u0442\u0443\u043f\u0430": [9, 38, 88], "\u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d": [9, 23], "\u043e\u0431\u043e\u0439\u0442": [9, 15, 21, 23, 37, 70, 94, 102], "\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0435\u0440": [9, 11], "\u0443\u0434\u043e\u0431\u043d": [9, 11, 15, 23, 74], "\u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d": [9, 75], "\u0441\u043f\u0438\u0441\u043a": [9, 11, 21, 23, 30, 34, 38, 75], "\u043f\u0440\u0438\u0434\u0435\u0442": [9, 34, 46, 85, 92, 94, 100], "\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430": 9, "\u043a\u043e\u043d\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d": 9, "\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d": [9, 23], "\u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434\u0441\u0442\u0432": [9, 75, 76, 85, 88, 90, 95], "\u043e\u0431\u043b\u0430\u0434\u0430": [9, 11, 38, 60, 65, 68, 74, 75, 85, 86, 90, 92, 93, 95, 100], "\u0445\u0440\u0443\u043f\u043a\u043e\u0441\u0442": 9, "\u043d\u0435\u043c\u043d": [9, 21, 38, 40, 65, 72, 75, 82, 83, 86], "\u0441\u043c\u0443\u0449\u0430": [9, 15], "\u0441\u043c\u0435\u0448\u0438\u0432\u0430\u043d": 9, "\u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c": [9, 21, 82], "fp": [9, 21], "oop": [9, 21, 37, 75, 76], "\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [9, 21, 23, 34, 38, 40, 46, 47, 51, 74, 85, 93], "\u0447\u0438\u0441\u0442": [9, 11, 21, 70, 74, 85], "\u043c\u0443\u0442\u0438\u0440": [9, 11], "\u0441\u043c\u0443\u0449\u0435\u043d": 9, "\u043f\u043e\u0447": [9, 21, 30, 37, 38, 40, 41, 70, 73, 74, 75, 86, 88, 89, 90, 94, 100], "generics": 9, "exporterfactory": 9, "function": [9, 15, 21, 23, 38, 46, 49, 62, 65, 74, 75, 85], "attr1": 9, "attr2": 9, "attr3": 9, "\u043e\u0434\u043d\u0430\u043a": [9, 11, 21, 23, 30, 34, 37, 38, 42, 46, 47, 52, 70, 72, 74, 76, 85, 86, 88, 92, 93, 100], "\u043f\u0440\u043e\u0434\u043e\u043b\u0436": [9, 38, 100], "\u0440\u0430\u0437\u0432\u0438\u0432\u0430": [9, 74, 82, 83, 85, 86], "\u0432\u044b\u0437\u0432\u0430": [9, 15, 21, 38, 72, 86, 94], "michael": [9, 23, 30, 34, 38, 64, 66, 70, 74, 82], "feathers": [9, 66, 70, 82], "oo": [9, 82], "makes": [9, 11, 13, 21, 23, 34, 37, 38, 51, 62, 65, 66, 68, 70, 74, 75, 76, 85, 86, 93, 100], "understandable": 9, "encapsulating": [9, 23], "moving": [9, 42, 60, 76], "parts": [9, 11, 23, 34, 37, 46, 47, 72, 75, 76, 82, 85, 86], "minimizing": [9, 37, 73, 74, 76, 86, 90], "\u0441\u043a\u0430\u0437\u0430": [9, 21, 23, 46, 60, 70, 73, 74, 82, 85, 86, 90, 94, 100], "\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430": [9, 47, 85], "\u0447\u0435\u0440\u043d": [9, 85], "\u044f\u0449\u0438\u043a": [9, 85], "\u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d": [9, 21, 37, 46, 73, 82], "\u0432\u0435\u0440\u043d": [9, 21, 23, 37, 38, 40, 41, 73, 77, 86, 88], "\u0432\u0432\u0435\u0434\u0435\u043d": [9, 23, 34, 70, 82, 100], "\u0434\u0430\u0432\u043d": [9, 88], "\u043f\u0440\u043e\u0441\u0442\u043e\u0442": [9, 21, 23, 30, 38, 73, 74, 75, 90], "\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [9, 42, 46, 47, 74, 84, 136], "\u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d": [9, 73, 100, 102], "\u0448\u0430\u0431\u043b\u043e\u043d": [9, 23, 37, 76], "\u0441\u043a\u0440\u043e\u043c\u043d": [9, 73, 83], "\u0442\u044f\u0436\u0435\u043b": [9, 68, 74, 85, 100], "\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c": 9, "\u0441\u043e\u0432\u043f\u0430\u0434\u0430": [9, 82, 100], "\u0433\u0440\u0430\u043d\u0438\u0446": [9, 11, 12, 23, 29, 34, 75, 86, 92, 93, 100], "\u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0442\u043e\u0440": 9, "long": [9, 23, 37, 38, 41, 62, 73, 74, 76, 82, 85, 86, 95], "known": [9, 21, 23, 37, 38, 39, 41, 65, 74, 85, 90], "testability": 9, "attribute": [9, 15, 21, 23, 29, 38, 86], "architectures": [9, 23, 37, 38, 66, 75, 76, 82, 86], "humble": [9, 73, 82], "because": [9, 11, 21, 23, 34, 37, 38, 46, 51, 62, 65, 70, 73, 74, 75, 76, 77, 80, 85, 86, 100], "separation": [9, 21, 23, 37, 75, 76, 85, 86], "behaviors": 9, "testable": [9, 49, 53, 85], "non": [9, 21, 23, 38, 51, 62, 76, 77, 86], "defines": [9, 23, 51, 86], "architectural": [9, 37, 38, 46, 51, 52, 60, 64, 74, 76, 77, 82, 86], "presenter": 9, "\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 9, "\u043f\u0440\u0438\u0434\u0430": [9, 38, 94], "\u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440": [9, 11], "endorserstate": 9, "dto": 9, "\u043e\u0442\u043b\u0438\u0447": [9, 34, 38, 52, 85, 88, 92, 95], "\u0441\u0435\u0442\u0435\u0432": [9, 21, 34, 86], "\u0447\u0443\u0442": [9, 82, 83], "\u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d": [9, 88], "\u043a\u043e\u043d\u0442\u0440\u0430\u0441\u0442\u0438\u0440": 9, "\u0440\u0430\u0437\u043d\u043e\u0432\u0438\u0434\u043d": [9, 85], "\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [9, 37, 46, 60, 65, 68, 70, 72, 73, 74, 75, 76, 77, 85, 86, 90, 93, 94], "\u043f\u043e\u043c\u043e\u0433\u0430": [9, 23, 38, 70, 74, 82, 85, 90, 92, 93, 100], "\u0432\u044b\u044f\u0432\u043b\u044f": [9, 93], "\u0437\u0430\u0449\u0438\u0449\u0430": [9, 56, 92], "presenters": 9, "helps": [9, 23, 38, 53, 73, 74, 85, 86, 90, 100], "identify": [9, 46, 85], "protect": [9, 26], "\u0436\u0435\u043b\u0430\u043d": [9, 38, 70, 85, 86, 100], "\u043f\u0435\u0440\u0435\u0434\u0430\u0447": [9, 23, 34, 56, 86], "transfer": [9, 34, 82], "\u0444\u0443\u043d\u043a\u0446": [9, 23, 38, 41, 46, 62, 70, 74, 85, 86], "\u0443\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430": 9, "\u0430\u0441\u0441\u043e\u0446\u0438\u0430\u0442\u0438\u0432\u043d": 9, "\u043c\u0430\u0441\u0441\u0438\u0432": 9, "\u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430": [9, 73, 74, 75, 83, 85, 90], "\u0445\u0438\u0442\u0440": 9, "\u0437\u0430\u043f\u0438\u0441": [9, 21, 23], "\u043d\u0430\u0437\u0432\u0430": [9, 75, 76, 100], "\u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f": [9, 74, 90], "\u0437\u043d\u0430\u0442": [9, 21, 56, 82, 83, 93, 95], "\u0438\u0442\u0430\u043a": [9, 21, 23, 40, 52, 75, 83], "typically": [9, 23, 29, 37, 38, 49, 51, 74, 77, 85, 86], "crosses": 9, "consists": [9, 62, 86, 100], "structures": [9, 37, 38, 64, 75, 76, 82, 86], "basic": [9, 38, 42, 72, 75, 86], "structs": 9, "simply": [9, 21, 23, 38, 41, 51, 74, 75, 76, 86, 90], "arguments": [9, 21, 85], "calls": [9, 21, 23, 74, 85, 86], "pack": [9, 73], "hashmap": 9, "construct": [9, 29], "important": [9, 15, 21, 23, 34, 37, 38, 39, 41, 49, 51, 65, 73, 74, 75, 76, 85, 86, 90], "isolated": [9, 82, 86], "passed": [9, 11, 23, 26, 34, 37], "across": [9, 23, 29, 34, 38, 46, 75, 76, 85, 86], "we": [9, 21, 23, 34, 37, 38, 41, 46, 51, 52, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 82, 85, 86, 90, 92, 94, 95, 100], "don": [9, 21, 23, 30, 34, 37, 38, 42, 46, 47, 49, 51, 60, 62, 66, 68, 70, 73, 74, 75, 76, 77, 82, 85, 86, 95], "cheat": [9, 82, 89], "pass": [9, 34, 85], "rows": [9, 23], "dependency": [9, 34, 75], "violates": 9, "frameworks": [9, 64, 76, 85], "convenient": [9, 23], "response": [9, 21, 23, 37, 77], "query": [9, 15, 23, 29, 75, 82], "might": [9, 21, 23, 26, 29, 34, 37, 38, 42, 49, 51, 62, 70, 73, 74, 75, 76, 77, 85, 86, 90, 100], "call": [9, 21, 23, 38, 51, 75, 76, 85, 86], "row": [9, 23], "inward": 9, "doing": [9, 15, 21, 23, 37, 38, 39, 41, 42, 72, 73, 76, 80, 82, 85, 86], "violate": [9, 38, 75], "force": [9, 21, 23, 38, 65, 75, 85, 86], "circle": 9, "know": [9, 23, 37, 38, 41, 47, 51, 60, 62, 73, 74, 75, 76, 82, 85, 100], "something": [9, 21, 23, 37, 38, 41, 42, 46, 49, 51, 52, 65, 70, 72, 73, 74, 76, 85], "about": [9, 11, 21, 23, 34, 37, 38, 41, 42, 51, 52, 62, 65, 70, 72, 73, 74, 77, 80, 82, 85, 86, 90, 100], "outer": [9, 38], "thus": [9, 23, 34, 62, 70, 75], "most": [9, 23, 29, 37, 38, 42, 47, 51, 52, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 82, 85, 86, 90], "dataaccessinterface": 9, "\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d": [9, 23, 70], "usecaseinteractor": 9, "\u0437\u0430\u0431\u0438\u0440\u0430": [9, 23], "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440": 9, "outputdata": 9, "outputboundary": 9, "uses": [9, 21, 23, 75, 85, 86], "bring": [9, 23, 38, 47, 77, 86, 100], "memory": [9, 21, 23, 29], "upon": [9, 21, 23, 38, 76, 85, 86], "completion": [9, 23], "gathers": 9, "constructs": [9, 21], "old": [9, 37, 46, 47, 74, 76, 77, 85], "through": [9, 11, 21, 23, 34, 37, 38, 49, 51, 72, 74, 76, 77, 82, 85, 88, 94], "\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440": [9, 23, 38, 40, 82, 85, 93], "es": [9, 82], "\u043a\u043e\u043d\u0442\u0440\u0438\u0431\u044c\u044e\u0442\u043e\u0440": 9, "eventstore": [9, 34, 82], "nick": [9, 82, 86, 88], "tune": [9, 82, 86, 88], "\u0443\u0441\u043f\u0435\u043b": [9, 23], "\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430": [9, 23, 38], "\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c": 9, "\u043e\u0431\u043e\u0431\u0449\u0435\u043d": [9, 72, 85, 93], "\u043f\u043b\u043e\u0434": [9, 100], "\u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d": [9, 34], "\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430": 9, "\u043f\u043e\u0434\u0442\u0430\u043b\u043a\u0438\u0432\u0430": [9, 23], "\u043d\u0435\u0441\u043b\u043e\u0436\u043d": [9, 70, 74, 90], "\u0438\u0437\u0431\u0435\u0436\u0430": [9, 23, 26, 34, 38, 77, 86, 93, 102], "\u0442\u0438\u043f\u0438\u0437\u0430\u0446": 9, "\u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d": [9, 34], "\u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u043e\u0432\u0430": [9, 38], "\u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u043d": 9, "\u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d": [9, 23, 85], "\u0433\u043e\u0440\u0430\u0437\u0434": [9, 21, 38, 70, 73, 74, 90, 92], "\u043c\u0430\u0441\u0441": [9, 38, 76, 86, 92], "\u0441\u0440\u0435\u0437": 9, "\u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a": [9, 100], "\u0442\u0435\u0440\u043c\u0438\u043d": [10, 21, 23, 34, 38, 41, 52, 65, 74, 75, 83, 85, 86, 90, 100, 102], "streamid": [10, 34], "streamname": 10, "streamtype": 10, "streamposition": 10, "\u043d\u0435\u0441\u0443\u0442": 10, "\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0432\u043d": 10, "\u043f\u043e\u044f\u0432\u043b\u044f": [10, 68, 70, 72, 76, 85], "\u0441\u0442\u0430\u0434": [10, 40, 46, 72, 85, 94], "\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430": 10, "\u0441\u0442\u0440\u043e\u043a": [10, 30, 47, 72, 93], "\u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430": 11, "commands": [11, 21, 23], "events": [11, 25, 30, 34, 86, 113], "integration": [11, 30, 32, 34, 76, 82, 86, 117], "\u043f\u043e\u0434\u0447\u0435\u0440\u043a\u043d\u0443\u0442": [11, 76, 100], "high": [11, 23, 29, 38, 65, 66, 70, 73, 74, 75, 76, 77, 80, 82, 85, 86, 100], "chapter": [11, 15, 21, 23, 29, 34, 37, 38, 42, 46, 51, 64, 65, 66, 68, 70, 73, 74, 75, 76, 77, 82, 85, 86, 100], "five": [11, 51, 74], "expressed": [11, 21, 37, 52, 86, 100], "modules": [11, 15, 21, 74, 75], "heart": [11, 23, 26, 34, 38, 70, 73, 74, 75, 76, 82, 90, 100], "eric": [11, 23, 26, 34, 38, 46, 74, 75, 76, 82, 90, 100], "evans": [11, 23, 26, 34, 74, 75, 76, 82, 90, 100], "\u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u044f\u0446": [11, 12], "\u043e\u0433\u0440\u0430\u043d\u0438\u0447": [11, 23, 38, 90, 100, 102], "\u0438\u0437\u0432\u043d": [11, 38], "\u043c\u043e\u0434\u0443\u043b": [11, 74], "\u0434\u0430\u044e\u0442": [11, 74, 75, 82, 85], "\u0438\u0437\u0443\u0447": [11, 38, 74, 77], "\u043f\u043e\u0434\u0440\u043e\u0431": [11, 74], "\u043d\u043e\u0441\u0442": [11, 74], "\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432": [11, 34, 72, 74, 75, 82], "\u0432\u043d\u0438\u043a": [11, 74, 82], "\u0432\u0437\u0430\u0438\u043c\u043e\u043e\u0442\u043d\u043e\u0448\u0435\u043d": [11, 38, 74, 85], "\u0432\u0434\u0430\u0432": [11, 74], "\u0434\u0435\u0442\u0430": [11, 60, 74, 77, 90, 100], "\u0434\u0435\u043b\u0435\u043d": [11, 74], "\u0441\u043e\u0431\u043b\u044e\u0434\u0430": [11, 23, 74], "low": [11, 23, 30, 34, 38, 70, 73, 74, 75, 77, 90], "\u0441\u0432\u044f\u0437\u043d\u043e\u0441\u0442": [11, 74], "\u0433\u0440\u0435\u0448\u0430\u0442": [11, 74], "\u0443\u043a\u043b\u043e\u043d": [11, 74], "\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442": [11, 74], "\u0432\u0435\u043d": [11, 74], "\u043a\u0440\u0438\u0442\u0435\u0440": [11, 30, 37, 40, 50, 64, 74, 125], "\u044f\u043a\u043e\u0431": [11, 23, 74, 75], "\u0438\u0437\u043c\u0435\u0440": [11, 74], "\u043f\u043e\u0434\u0441\u0447\u0438\u0442\u0430": [11, 74], "\u0430\u0441\u0441": [11, 74], "\u0446\u0438\u0430\u0446": [11, 74], "\u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432": [11, 21, 42, 74], "\u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a": [11, 73, 74, 100, 102], "\u043f\u043e\u0434\u0440\u0430\u0437\u0434": [11, 74], "\u043b\u0435\u043d": [11, 74], "\u0438\u0434\u0435\u0439\u043d": [11, 74], "\u043a\u043e\u043d\u0446\u0435\u043f\u0446": [11, 23, 74, 85, 86], "\u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d": [11, 15, 21, 23, 38, 40, 74, 86, 88, 100], "\u0443\u0434\u0435\u0440": [11, 74], "\u0436\u0438\u0432\u0430": [11, 74], "\u0443\u043c": [11, 37, 60, 74, 75, 76, 90], "\u043f\u0440\u0435\u0434\u043c\u0435\u0442": [11, 74, 100, 102], "\u043e\u0442\u0441\u044e\u0434": [11, 21, 74, 75, 90], "\u043f\u043b\u043e\u0445": [11, 21, 46, 73, 74, 76, 85], "\u0442\u0440\u0443\u0434\u043d": [11, 70, 74, 75, 82], "\u043f\u043e\u043d\u044f": [11, 21, 23, 38, 41, 46, 60, 73, 74, 77, 82, 83, 90, 102], "\u043d\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430": [11, 74], "\u043a\u0430\u0448": [11, 74], "they": [11, 21, 23, 29, 34, 37, 38, 42, 46, 47, 49, 51, 52, 62, 65, 68, 72, 73, 74, 75, 76, 77, 85, 86, 90, 92, 100], "look": [11, 21, 34, 41, 60, 70, 74, 77, 82, 85, 86, 90], "detail": [11, 34, 49, 72, 74, 77, 82, 86, 100], "module": [11, 74, 75, 86], "overwhelmed": [11, 74], "whole": [11, 15, 21, 23, 37, 38, 39, 52, 74, 75, 76, 77, 82, 86, 90, 100], "exclude": [11, 74], "interior": [11, 74], "truism": [11, 74], "explanations": [11, 74], "tend": [11, 23, 38, 74, 85, 86, 100], "sound": [11, 23, 37, 73, 74, 76, 77], "metrics": [11, 23, 74, 82], "judged": [11, 74], "mechanically": [11, 74], "distributions": [11, 74], "associations": [11, 23, 74], "interactions": [11, 42, 52, 74, 76], "yet": [11, 23, 34, 74, 76, 82, 85, 86, 88], "isn": [11, 23, 29, 37, 38, 49, 51, 52, 68, 73, 74, 76, 85], "divided": [11, 21, 72, 74, 86], "concepts": [11, 21, 23, 64, 72, 74, 82, 100], "things": [11, 15, 21, 23, 34, 37, 38, 41, 46, 47, 65, 70, 73, 74, 75, 77, 82, 85, 86, 88, 94], "think": [11, 13, 23, 29, 37, 38, 41, 46, 49, 70, 72, 73, 74, 76, 85, 86, 90, 100], "once": [11, 21, 23, 38, 46, 51, 52, 65, 70, 73, 74, 76, 85, 90], "hence": [11, 21, 23, 51, 74, 76, 86], "incoherent": [11, 74], "fragments": [11, 74], "ideas": [11, 23, 34, 37, 38, 72, 73, 74, 75, 82, 85, 88, 92], "hard": [11, 23, 37, 38, 66, 68, 70, 73, 74, 76, 82, 85, 86, 88], "understand": [11, 21, 23, 37, 38, 46, 60, 70, 72, 73, 74, 75, 80, 82, 85, 86, 90], "undifferentiated": [11, 74], "soup": [11, 74], "\u043b": [11, 26, 74, 75, 82, 88, 92, 100], "\u0431\u0440\u043e\u0434\u043e\u0432": [11, 26, 74, 75, 100], "\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": [11, 15, 65, 80, 89, 92, 93], "\u0432\u0438\u043d\u0435\u0433\u0440\u0435\u0442": 11, "\u043f\u043e\u0432\u044b\u0448\u0430": [11, 37, 72, 73, 74, 77, 85, 86], "\u043a\u043e\u0433\u043d\u0438\u0442\u0438\u0432\u043d": [11, 37, 38, 40, 85, 86, 88, 89, 100], "\u043d\u0430\u0433\u0440\u0443\u0437\u043a": [11, 37, 46, 74, 85, 86, 90, 92, 100], "\u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [11, 65], "\u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d": [11, 23], "\u043a\u043e\u043d\u0442\u0440\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442": 11, "\u043a\u0440\u0430\u0442\u043a\u043e\u0432\u0440\u0435\u043c\u0435\u043d": [11, 85], "\u043e\u0442\u0434\u0430\u0432\u0430": [11, 23], "\u043d\u0430\u0440\u0443\u0436": [11, 21, 47], "\u0433\u0440\u0443\u043f\u043f\u0438\u0440": 11, "\u0432\u044b\u0431\u0435\u0440": 11, "\u0434\u0438\u043d": 11, "\u043e\u0431\u0440\u0430\u0449\u0435\u043d": [11, 86, 92], "\u0440\u0430\u0437\u0440\u0435\u0448\u0430": [11, 37, 38, 40, 65], "\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d": 11, "\u043e\u043f\u0435\u0440\u0430\u0446": [11, 23, 74, 85, 93], "\u043a\u043e\u043d": [11, 83], "\u0442\u0440\u043e\u043b\u0438\u0440": 11, "\u043d\u0435\u043e\u0436\u0438\u0434\u0430": 11, "\u0441\u0445\u0435\u043c": [11, 23, 38], "\u0440\u0430\u0437\u0443\u043c\u043d": [11, 72], "\u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u0435\u043d": [11, 38, 75], "cluster": [11, 23], "aggregates": [11, 23, 82], "define": [11, 23, 37, 49, 51, 52, 76, 77, 86, 100], "each": [11, 21, 23, 26, 34, 37, 38, 42, 51, 60, 62, 72, 73, 74, 75, 76, 82, 85, 86, 90, 94, 95, 100], "root": [11, 23, 38], "inside": [11, 23, 51, 76, 82, 86], "external": [11, 37, 38, 74, 75, 76, 85, 86], "hold": [11, 21, 23, 51], "references": [11, 21, 23, 82], "transient": 11, "out": [11, 21, 26, 29, 30, 34, 37, 38, 39, 41, 52, 60, 70, 72, 73, 74, 76, 85, 86, 90], "operation": [11, 15, 21, 23, 34, 49], "controls": [11, 23, 86], "cannot": [11, 21, 23, 26, 34, 37, 38, 52, 74, 76, 86, 90], "blindsided": [11, 23], "changes": [11, 21, 23, 34, 37, 38, 47, 62, 65, 70, 74, 75, 76, 77, 85, 86], "arrangement": [11, 38], "practical": [11, 21, 23, 34, 37, 38, 51, 52, 64, 65, 66, 75, 76, 82, 85, 86, 95, 100], "enforce": [11, 82, 86], "invariants": [11, 21, 23, 26], "\u043f\u0430\u043a\u0435\u0442": [11, 34, 74, 85, 90], "\u043d\u0435\u0436\u0435\u043b": [11, 40, 73, 76, 95], "\u043f\u043e\u0441\u0442\u043e\u0440\u043e\u043d": [11, 86], "\u043f\u043e\u043b\u0443\u0447\u0430\u0442": [11, 21], "law": [11, 38, 74, 76, 86], "demeter": 11, "\u043f\u0440\u044f\u043c": [11, 37, 56, 70, 74, 75, 85, 95], "\u043f\u043b\u043e\u0441\u043a": 11, "\u043e\u0431\u0435\u0441\u043f\u0435\u0447": [11, 73, 75, 85, 86, 88, 90, 95, 100], "\u0430\u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a": 11, "\u0433\u0440\u0430\u0444": 11, "\u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d": [11, 21, 70, 72, 83, 85, 92, 100], "\u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a": 11, "\u0438\u043c\u0435\u043b": [11, 37, 38, 73, 75], "\u043e\u0441\u0432\u0435\u0434\u043e\u043c\u043b": 11, "\u0438\u043d\u0430\u0447": [11, 26, 30, 38, 73, 83, 85, 94, 95, 100, 102], "\u043f\u0440\u0438\u0448\u043b": [11, 38, 56, 73, 83, 88], "\u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d": [11, 38, 85], "c\u0443\u0449\u043d\u043e\u0441\u0442": 11, "\u0440\u0430\u0437\u043c\u0435\u0442": 11, "\u043d\u0430\u0432\u0438\u0433\u0430\u0446": [11, 90, 100], "\u043f\u043e\u0437\u0436": [11, 23, 37, 38, 68, 72, 76, 83, 85], "\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u0432\u0430": 11, "\u043a\u0440\u0430\u0439\u043d": [11, 23, 38, 83, 88, 100], "shared": [11, 23, 26, 38, 72, 74, 76, 85, 86], "common": [11, 15, 21, 23, 34, 37, 38, 52, 64, 74, 76, 80, 85, 86], "aggregate_name": 11, "\u0432\u043e\u0441\u0442\u0440\u0435\u0431\u043e\u0432\u0430": [11, 34, 41, 65, 70, 90], "\u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436": 11, "\u043f\u043e\u0434\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440": 11, "\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d": [11, 23, 26, 51, 85, 86], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c": [11, 86, 100, 102], "\u043d\u0430\u0437\u0432\u0430\u043d": [11, 21, 23, 75, 90], "\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d": 11, "part": [11, 21, 23, 34, 37, 38, 42, 46, 51, 52, 65, 74, 75, 76, 77, 82, 85, 86, 90], "customer": [11, 23, 29, 37, 38, 46, 51, 52, 64, 68, 70, 73, 74, 75, 76, 77, 86], "live": [11, 23, 38, 86], "subpackage": 11, "named": [11, 37], "circular": 11, "dependencies": [11, 23, 30, 34, 65, 73], "put": [11, 21, 23, 38, 41, 46, 70, 75, 77, 85], "functions": [11, 15, 21, 23, 49, 62, 74, 75, 82, 85, 100], "having": [11, 21, 34, 37, 52, 65, 75, 85, 86, 93], "additionally": [11, 38], "even": [11, 21, 23, 34, 37, 38, 46, 51, 52, 62, 65, 70, 73, 74, 76, 82, 85, 86, 95, 100], "modify": [11, 21, 23, 34, 37, 38, 70, 72, 74], "proper": [11, 15, 21, 23, 34, 38, 41, 74], "methods": [11, 21, 23, 37, 38, 49, 65, 74, 76, 85], "hexagonal": [11, 72], "anton": [11, 82], "st\u00f6ckl": [11, 82], "tactical": [11, 19, 23, 34, 37, 74, 82, 109], "layer": [11, 16, 23, 31, 75, 80, 116], "\u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0435\u043d": 11, "\u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d": 11, "\u043f\u0440\u043e\u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430": 11, "\u043f\u0440\u0438\u0432\u0435\u043b": [11, 37, 41, 86], "\u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d": [11, 34], "\u0442\u0430\u0449": 11, "\u043a\u0443\u0447": [11, 64], "\u043e\u0431\u044a\u044f\u0432\u043b": [11, 85], "\u0438\u0437\u0431\u044b\u0442\u043e\u043a": [11, 93], "\u043f\u0435\u0440\u0435\u0443\u0441\u043b\u043e\u0436\u043d\u0435\u043d": [11, 70], "\u0431\u043b\u0438\u0436": 11, "\u0432\u044b\u0440\u0430\u0436\u0430": [11, 37, 75, 80, 88, 92, 102], "\u0442\u043e\u0447\u043d": [11, 21, 23, 70, 100, 102], "\u0432\u044b\u043d\u0435\u0441\u0442": [11, 23], "\u0441\u043e\u0434\u0435\u0440\u0436\u0430": [11, 21, 23, 26, 74, 85, 90, 100, 102], "\u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d": [11, 75], "\u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u043e\u043d\u0438\u0440": 11, "\u043b\u043e\u0433\u0438\u0447\u043d": [11, 23, 30], "\u0441\u043b\u0443\u0436\u0430\u0442": [11, 38, 100], "\u043c\u043e\u0434\u0435\u043b\u0438\u0440": 11, "\u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d": [11, 21, 23, 34, 37, 74, 75, 80, 85], "\u0432\u043e\u0437\u0440\u0430\u0441\u0442": 11, "\u0444\u0438\u043a\u0441\u0438\u0440": 11, "values": [11, 21, 23, 38, 42, 76, 86], "\u0438\u043c\u0435\u044e\u0442": [11, 23, 40, 65, 75, 77, 85, 86, 92], "\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d": [11, 23], "\u043a\u043e\u043b\u043b\u0438\u0437": 11, "\u0440\u0430\u0437\u0440\u0443\u0448": 12, "shotgun": 12, "surgery": [12, 85], "canexecute": 12, "pattern": [12, 14, 21, 23, 29, 34, 37, 38, 72, 73, 76, 82, 85, 86, 93], "raw": [13, 75, 82], "\u043e\u0431\u0440\u0435\u0442\u0430": [13, 37, 41, 72, 75, 76, 83], "\u0438\u0431": [13, 23, 38, 88, 92], "fowler": [13, 14, 21, 23, 37, 38, 40, 41, 46, 62, 65, 66, 70, 72, 75, 76, 80, 82, 85, 86, 94, 95], "reflective": 13, "program": [13, 23, 41, 51, 52, 60, 73, 74, 76, 77, 82, 85, 88, 90, 100], "generation": [13, 23, 82, 89, 95], "explicit": [13, 23, 38, 46, 100], "see": [13, 21, 23, 34, 37, 38, 39, 51, 60, 70, 73, 74, 75, 76, 82, 85, 86, 90, 100], "what": [13, 21, 23, 34, 37, 38, 41, 42, 47, 49, 51, 52, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 82, 85, 86, 90, 100], "going": [13, 21, 23, 29, 37, 38, 70, 73, 74, 85, 100], "debugger": 13, "usually": [13, 21, 23, 29, 37, 38, 41, 52, 72, 74, 76, 77, 85, 100], "prefer": [13, 34, 65, 85], "reflection": [13, 68], "easier": [13, 21, 23, 37, 70, 73, 74, 85, 90], "less": [13, 23, 38, 49, 51, 64, 68, 70, 72, 74, 75, 76, 82, 85], "sophisticated": 13, "developers": [13, 23, 37, 38, 46, 49, 51, 72, 74, 75, 76, 77, 82, 85, 86, 90], "guess": [13, 68, 70], "unsophisticated": 13, "david": [13, 23, 30, 34, 37, 72, 82, 88, 94], "rice": [13, 23, 72, 82], "matthew": [13, 23, 72, 82, 86], "foemmel": [13, 23, 72, 82], "hieatt": [13, 23, 72, 82], "mee": [13, 23, 72, 82], "randy": [13, 23, 38, 72, 82], "stafford": [13, 23, 72, 82], "\u043f\u043e\u0434\u0430\u0432\u043b\u044f": [13, 38], "orm": [13, 21], "\u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d": [13, 52, 80, 86], "\u0448\u0438\u0440\u043e\u043a": [13, 21, 37, 38, 65, 75, 76, 85, 88, 90, 92, 102], "\u043a\u043e\u0434\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446": 13, "sqlc": 13, "vs": [14, 21, 41, 64, 65, 74, 75, 76, 82, 83, 86, 94], "\u0441\u043c\u0435\u043b": [15, 73], "\u043f\u0435\u0440\u0432\u043e\u043f\u0440\u043e\u0445\u043e\u0434\u0446": 15, "\u043f\u043e\u0432\u043b\u0438\u044f": [15, 37], "\u0438\u043d\u0434\u0443\u0441\u0442\u0440": [15, 21, 37, 75, 76, 83, 85, 92, 95], "\u043c\u043e": [15, 21, 23, 34, 38, 46, 68, 70, 72, 74, 75, 82, 83, 85, 88, 90, 92, 93, 94, 100], "\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d": 15, "\u043f\u0440\u0438\u0437\u043d\u0430\u0442\u0435\u043b": 15, "\u0432\u043b\u0430\u0434\u0438\u043c\u0438\u0440": 15, "\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d": [15, 21, 34, 38, 40, 42, 68, 70, 74, 75, 82, 85, 86, 90, 93, 100, 102], "\u043e\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d": [15, 40, 70, 92], "\u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440": 15, "\u0432\u0430\u043b\u0438\u0434\u043d": 15, "\u0430\u0442\u043e\u043c\u0430\u0440\u043d": [15, 30, 34], "\u0432\u0430\u043b\u0438\u0434\u0430\u0446": [15, 21], "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u043c": [15, 86, 102], "\u0443\u0431\u0435\u0434": [15, 37, 38, 85], "\u043a\u043b\u044e\u0447\u0435\u0432": [15, 21, 23, 38, 40, 52, 56, 62, 64, 73, 75, 83, 85, 90, 94, 102], "\u0441\u0432\u043e\u0434": [15, 21, 23, 30, 74, 75, 102], "cqs": [15, 23], "\u0441\u043e\u0433\u043b\u0430\u0441": [15, 38, 40, 46, 56, 88], "\u0441\u043e\u0432\u0441": [15, 16, 23, 37, 75, 83, 85, 88, 94], "\u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d": [15, 21, 23, 100, 102], "\u0434\u0435\u0439\u0441\u0442\u0432": [15, 23, 34, 38, 42, 46, 72, 85, 86, 90, 100], "\u0438\u0441\u0445\u043e\u0434": [15, 23, 38, 40, 56, 70, 72, 75, 83, 85], "\u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0435\u043d": [15, 37, 40, 68, 70, 85], "command": [15, 23, 75], "\u0441\u043b\u0443\u0436\u0435\u0431\u043d": 15, "\u0443\u0441\u043f\u0435\u0448\u043d": [15, 38, 64, 75, 76, 81, 86, 92, 100, 135], "\u043f\u043e\u0432\u0442\u043e\u0440": [15, 37, 46, 65, 85], "here": [15, 21, 23, 34, 37, 38, 46, 51, 62, 65, 75, 82, 85, 86, 93], "deal": [15, 21, 23, 38, 59, 62, 65, 70, 73, 74, 76, 86, 90], "objections": [15, 21, 23], "side": [15, 23, 76, 82, 85], "effect": [15, 23, 42, 46, 72, 74, 76, 85, 86], "style": [15, 21, 23, 37, 38, 39, 62, 65, 72, 76, 80, 85], "handling": [15, 21, 23, 29, 34, 38, 51, 73], "sometimes": [15, 21, 23, 34, 38, 49, 60, 68, 72, 73, 77, 85], "effects": [15, 21, 23, 38, 75, 77, 85, 86, 88], "really": [15, 21, 23, 34, 37, 38, 52, 65, 68, 70, 74, 75, 76, 77, 80, 82, 85, 86, 90, 100], "procedure": [15, 21, 23], "addition": [15, 21, 23, 39, 65, 86], "returns": [15, 21, 23], "indicating": [15, 21], "went": [15, 21, 38, 76, 85, 100], "roughly": [15, 21, 38, 74, 82, 85, 95], "speaking": [15, 21, 23], "technique": [15, 21, 34, 52, 85, 86], "enable": [15, 21, 37, 74, 77, 85, 86], "perform": [15, 21, 23, 38, 46, 62, 85, 86], "represented": [15, 21], "some_operation": [15, 21], "how_did_it_go": [15, 21], "returning": [15, 21, 23, 38, 46, 85], "lame": [15, 21], "anyway": [15, 21, 23, 46, 76], "transforms": [15, 21], "adding": [15, 21, 23, 38, 41, 70, 74, 85, 86], "does": [15, 21, 23, 34, 37, 38, 41, 46, 49, 51, 52, 62, 65, 73, 74, 76, 80, 85, 86, 88, 100], "routine": [15, 21], "own": [15, 21, 23, 26, 37, 38, 49, 73, 74, 76, 85, 86, 92], "problematic": [15, 21, 38], "than": [15, 21, 23, 29, 34, 37, 38, 39, 46, 47, 49, 51, 62, 65, 70, 72, 73, 74, 75, 76, 77, 85, 86, 90, 94, 100], "indicator": [15, 21], "structure": [15, 21, 23, 37, 38, 40, 41, 66, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88], "equivalent": [15, 21, 23], "several": [15, 21, 23, 64, 70, 74, 75, 85, 86, 90], "components": [15, 21, 23, 34, 51, 72, 74, 75, 82, 85, 86], "getting": [15, 21, 34, 38, 42, 51, 73, 75, 82, 85, 88], "above": [15, 21, 23, 51, 70, 85, 86], "scheme": [15, 21, 23, 38, 52], "global": [15, 21, 23, 82], "variables": [15, 21, 38, 42, 74, 85, 93], "raises": [15, 21, 38], "especially": [15, 21, 38, 74, 85, 88], "large": [15, 21, 23, 34, 46, 52, 64, 75, 76, 82, 85, 86, 100], "where": [15, 21, 23, 29, 34, 37, 38, 41, 47, 49, 62, 65, 73, 74, 75, 76, 82, 85, 86, 100], "trigger": [15, 21, 23], "construction": [15, 21, 23, 37, 59, 67, 75, 76, 77, 82, 86, 130], "2nd": [15, 21, 23, 34, 37, 38, 46, 52, 60, 62, 65, 66, 70, 73, 74, 76, 77, 82, 85, 86, 90], "bertrand": [15, 21, 23, 38, 52, 75, 82], "meyer": [15, 21, 23, 38, 52, 75, 82], "23": [15, 21, 23, 38, 66, 76, 85, 94], "\u043d\u0435\u0442": [15, 21, 23, 34, 38, 40, 41, 46, 73, 75, 77, 83, 86, 88, 90, 94, 95, 100], "\u0440\u0430\u0437\u0434\u0435\u043b\u044f": [15, 23, 60, 74, 75, 88, 90], "\u043f\u0440\u043e\u0432\u0435\u0440\u044f": [15, 85], "infrastructure": [16, 21, 23, 34, 38, 86], "\u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447": 16, "\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446": 16, "\u0432\u044b\u043f\u043e\u043b\u043d\u044f": [16, 23, 40, 41, 46, 73, 85, 86, 95], "\u0431\u0438\u0437\u043d\u0435\u0441": [16, 34, 37, 39, 40, 41, 44, 51, 56, 65, 66, 70, 72, 75, 80, 86, 100, 122], "practice": [19, 21, 23, 34, 37, 38, 42, 49, 51, 52, 64, 65, 66, 72, 74, 75, 76, 77, 82, 85, 90, 92, 93, 100, 109], "strategic": [19, 75, 82, 86, 100, 109], "tbd": [20, 55, 65, 110], "\u043f\u043e\u0441\u0432\u044f\u0449": [21, 23, 34, 37, 38, 75, 76, 82, 86], "\u0434\u043e\u0432\u043e\u043b\u044c\u043d": [21, 38, 73, 86], "\u0434\u0438\u0441\u043a\u0443\u0441\u0441\u0438\u043e\u043d": 21, "\u043f\u043e\u0441\u043b\u0435\u0434\u043d": [21, 37, 73, 74, 85, 88, 92], "\u043d\u0430\u043c\u0435\u0442": 21, "\u043f\u043e\u043b\u044f\u0440\u0438\u0437\u0430\u0446": 21, "\u0441\u0442\u0440\u0435\u043c\u0438\u0442\u0435\u043b\u044c\u043d": [21, 76, 86], "\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d": [21, 23, 64, 65, 87, 100, 137], "\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a": [21, 23, 30, 37, 56, 65, 76, 80], "\u043f\u0440\u043e\u0431\u0443\u0434": 21, "\u0433\u043e\u043d\u043a": [21, 23, 30, 33, 118], "race": 21, "condition": [21, 76, 85], "\u0432\u0437\u0430\u0438\u043c\u043e\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a": 21, "deadlocks": 21, "\u043e\u0431\u0443\u0441\u043b\u043e\u0432\u043b": [21, 94], "\u043f\u0435\u0440\u0435\u043c\u0435\u043d": [21, 34, 38, 40, 41, 52, 65, 74, 85], "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c": [21, 37, 38, 40, 42, 46, 60, 70, 73, 74, 75, 77, 85, 90, 94], "\u0438\u0437\u043c\u0435\u043d\u044f": [21, 23, 65, 74, 82, 85, 86], "\u043d\u0438\u043a\u043e\u0433\u0434": [21, 23, 38, 47, 75, 83, 88, 92], "\u043e\u043a\u0430\u0436\u0435\u0442": [21, 37, 38, 70, 90], "\u0441\u0442\u043e\u043b\u043a\u043d\u0435\u0442": 21, "\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a": 21, "\u043f\u043e\u043f\u0430\u0441\u0442": [21, 83], "conditions": [21, 51, 52, 76], "deadlock": 21, "concurrent": [21, 23, 51, 82], "update": [21, 23, 34, 37, 62, 65], "due": [21, 23, 38, 65, 70, 76, 77, 86], "mutable": [21, 82], "variable": [21, 38, 74, 76, 85], "ever": [21, 23, 37, 38, 74, 76, 86], "locks": [21, 23], "\u043e\u0442\u043a\u0430\u0437\u0430": [21, 23, 34, 37, 70, 76, 94], "\u0438\u043c\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d": 21, "\u043f\u043e\u0434\u0432\u0438\u0434": 21, "\u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432": [21, 23, 30, 77, 85, 92], "\u043c\u0443\u043b\u044c\u0442\u0438\u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u0435\u043d": 21, "scala": [21, 23, 30, 34, 82], "elixir": 21, "\u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0430": [21, 30, 51, 74], "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f": [21, 85, 102], "\u0434\u043e\u043f\u043e\u043b\u043d\u044f": [21, 65, 77], "\u0431\u0435\u0440\u0442\u0440\u0430\u043d": 21, "\u043c\u0435\u0439\u0435\u0440": [21, 73], "\u0442\u0435\u043d\u0434\u0435\u043d\u0446": [21, 40, 47, 65, 93, 94], "\u043f\u043e\u043f\u0443\u043b\u044f\u0440\u0438\u0437\u0430\u0446": 21, "\u0441\u043a\u0430\u0436": [21, 23], "\u043e\u0431\u044a\u0435\u043a\u0442\u043d": [21, 37, 77], "\u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433": [21, 38, 64, 73, 86], "\u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442": 21, "\u0432\u0437\u0433\u043b\u044f\u0434": [21, 72, 82, 85], "\u0440\u0435\u0447": [21, 23, 65, 75, 83, 86, 102], "\u0438\u0434\u0435\u0442": [21, 23, 38, 65, 74, 75, 85, 86, 100], "\u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432": [21, 37, 77], "\u043d\u0438\u0447": [21, 46, 64, 70, 82, 83, 85, 95], "\u0432\u0438\u0436": [21, 70], "\u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d": [21, 23, 73], "\u043f\u043e\u043b\u0435\u0437\u043d": [21, 64, 70, 82, 86], "\u0434\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432": [21, 92], "\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d": [21, 23, 83, 85], "\u043d\u0430\u0437\u0430\u0434": [21, 30, 47, 60, 74, 90], "\u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430": [21, 23, 75, 86], "\u0444\u043f": 21, "\u043f\u043e\u0441\u0442\u0430\u0440\u0430": 21, "\u0434\u0430": [21, 38, 46, 75, 76, 92, 94], "\u0432\u043e\u0448\u043b": 21, "\u043a\u0430\u0447\u0435\u0441\u0442\u0432": [21, 23, 26, 30, 37, 38, 42, 46, 50, 51, 70, 73, 75, 76, 83, 85, 86, 88, 93, 94, 100, 125], "\u0432\u043f\u0435\u0447\u0430\u0442\u043b": 21, "\u0441\u043c\u0435": 21, "\u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a": [21, 37, 38, 70, 74], "\u043f\u043e\u043c\u043d": [21, 38, 83, 90, 92, 94], "\u0441\u0430\u0439\u043c\u043e\u043d": 21, "\u043f\u0435\u0439\u0442\u043e\u043d": 21, "\u0434\u0436\u043e\u043d\u0441": 21, "\u0441\u0442\u0430\u0440\u0430": [21, 70, 83, 85, 88, 100], "\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d": [21, 86], "\u043f\u0440\u0438\u043c\u0435\u0447\u0430\u043d": 21, "\u0431\u0435\u0440\u0442\u0440\u0430": 21, "functional": [21, 37, 38, 51, 52, 75, 82, 86], "\u0438\u0434\u0435\u0430\u043b\u044c\u043d": [21, 38, 73, 75, 94, 102], "\u0432\u0435\u0434\u0443\u0449": [21, 37, 76, 88], "\u043a\u0440\u0430\u0441\u043e\u0442": 21, "composing": 21, "contracts": [21, 86], "adventure": 21, "financial": [21, 38, 39, 41], "engineering": [21, 23, 34, 37, 38, 49, 51, 52, 59, 60, 62, 63, 64, 65, 66, 73, 74, 75, 76, 77, 80, 82, 85, 86], "\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432": [21, 42, 70, 74, 85, 86, 90], "eiffel": 21, "\u0441\u0431\u043b\u0438\u0436\u0435\u043d": 21, "\u044f\u0441\u043d": [21, 23, 70, 73, 86], "\u0440\u0430\u0437\u043b\u0438\u0447\u0430": [21, 52], "\u0440\u0430\u0437\u043d\u0438\u0446": [21, 23, 30, 40, 73, 74, 82, 88], "\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d": 21, "\u0437\u043d\u0430": [21, 74, 92, 93, 100], "\u043f\u043e\u0439\u0442": [21, 34], "\u0434\u0430\u043b\u044c\u0448": [21, 23, 85], "\u0440\u0430\u0431\u043e\u0442\u0430": [21, 23, 26, 37, 38, 40, 42, 46, 47, 68, 70, 73, 74, 82, 83, 85, 86, 88, 90, 93, 94, 100], "\u043f\u043e\u0431\u043e\u0447\u043d": [21, 34], "\u044d\u0444\u0444\u0435\u043a\u0442": [21, 34, 38, 40, 46, 56, 65, 74, 76, 83, 85, 86, 88, 91, 92, 94, 95, 138], "\u0441\u0435\u0440\u0433\u0435": [21, 82, 94], "\u0442\u0435\u043f\u043b\u044f\u043a\u043e\u0432": [21, 82, 94], "both": [21, 23, 29, 34, 37, 38, 49, 52, 64, 74, 76, 77, 85, 86, 100], "theoretical": 21, "reasons": [21, 23, 37, 38, 65, 75, 77, 82, 85, 86], "detailed": [21, 37, 52, 74, 76, 77], "elsewhere": 21, "methodological": [21, 38], "serious": [21, 38, 74], "developed": [21, 23, 37, 38, 51, 76, 85, 86, 100], "observes": 21, "scrupulously": 21, "advantage": [21, 23, 37, 85], "schools": [21, 85], "programming": [21, 23, 37, 42, 46, 47, 52, 56, 64, 66, 68, 70, 72, 73, 74, 75, 76, 82, 83, 85, 92, 94, 95], "regrettable": 21, "apply": [21, 23, 34, 49, 51, 72, 75, 77, 82, 85, 86], "continuing": [21, 73, 85, 86, 100], "calling": 21, "rather": [21, 23, 29, 37, 38, 46, 49, 74, 75, 76, 85, 86, 90, 94], "procedures": [21, 38, 49, 86], "achieve": [21, 23, 34, 38, 73, 74, 86], "key": [21, 23, 37, 38, 46, 51, 52, 62, 74, 76, 77, 85, 86], "seems": [21, 38, 73], "viable": 21, "obtain": [21, 23], "since": [21, 23, 34, 38, 74, 76, 77, 85, 86], "expressions": [21, 85], "involve": [21, 23], "queries": [21, 23, 34, 51], "understood": [21, 34, 38, 41, 72, 74, 75], "traditional": [21, 23, 49, 52, 74, 82], "mathematics": [21, 62, 65, 82, 85], "while": [21, 23, 26, 34, 37, 38, 39, 49, 52, 62, 73, 74, 76, 85, 86, 90, 100], "acknowledging": 21, "notion": [21, 74, 76, 85, 95], "fundamental": [21, 37, 49, 52, 74, 76, 80, 82], "role": [21, 37, 38, 51, 66, 70, 71, 76, 82, 85, 86, 92, 132], "concept": [21, 23, 34, 38, 72, 86], "computations": [21, 23, 34], "rober": 21, "blog": [21, 82], "cleancoder": 21, "uncle": [21, 37, 74], "bob": [21, 37, 74, 75], "2014": [21, 34, 82, 88], "11": [21, 23, 38, 85, 86], "24": [21, 23, 66, 68, 70, 73], "fpvsoo": 21, "html": [21, 34], "2018": [21, 38, 52, 64, 65, 77, 82], "04": 21, "\u043f\u043e\u043a\u043b\u043e\u043d\u043d\u0438\u043a": 21, "emacs": [21, 23, 74], "lisp": 21, "clojure": [21, 82], "2019": [21, 38, 46, 64, 82], "08": 21, "22": [21, 23, 37, 38], "whyclojure": 21, "\u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d": [21, 23, 86], "\u0432\u0432\u0435\u043b": [21, 23, 38, 74], "starting": [21, 23, 37, 74, 76, 85], "creation": [21, 23, 38, 77], "previously": [21, 23], "occurs": [21, 23, 38, 76], "whether": [21, 23, 34, 38, 51, 74, 76, 85, 90, 100], "mutates": [21, 23], "entirety": 21, "nothing": [21, 23, 38, 42, 74, 76, 85, 88, 92], "uis": [21, 23, 82], "agh": [21, 23, 82], "segregation": [21, 23, 75], "originally": [21, 38, 51], "considered": [21, 23, 37, 51, 52, 63, 75, 86], "originated": [21, 52], "maintains": 21, "pure": [21, 86], "difference": [21, 23, 51, 52, 74, 76, 77, 82, 85, 100], "split": [21, 38, 52, 82, 85, 86], "containing": [21, 23, 64, 82, 86], "\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440": [21, 23, 38], "\u0432\u043d\u0438\u0437": [21, 65, 74, 77], "\u043f\u0440\u043e\u0440\u0435\u0446\u0435\u043d\u0437\u0438\u0440\u043e\u0432\u0430": 21, "eshoponcontainers": [21, 23, 75, 82], "\u043a\u0440\u0430\u0441\u043d": [21, 56, 85], "devised": [21, 23], "asserts": [21, 23, 38, 85], "following": [21, 23, 37, 38, 39, 49, 62, 74, 75, 76, 85], "every": [21, 23, 29, 34, 37, 38, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 95, 100], "performs": [21, 23, 62], "caller": [21, 23, 52], "words": [21, 23, 29, 37, 41, 75, 85, 86], "asking": [21, 23, 41], "question": [21, 23, 74, 85, 88, 94], "answer": [21, 23, 38, 70, 85], "formally": [21, 23], "referentially": [21, 23], "transparent": [21, 23], "possess": [21, 23, 51], "wikipedia": [21, 23, 39, 85], "level": [21, 23, 37, 38, 51, 52, 64, 74, 75, 76, 77, 82, 86, 88, 90, 100], "means": [21, 23, 34, 37, 38, 39, 42, 49, 62, 65, 74, 75, 76, 77, 85, 90], "modifies": [21, 23], "declared": [21, 23, 85], "directly": [21, 23, 38, 46, 64], "indirectly": [21, 23], "cause": [21, 23, 34, 38, 75], "modification": [21, 23, 75], "alter": [21, 23, 37, 74, 85], "journey": [21, 23, 34, 73, 82], "introducing": [21, 23, 76, 82, 85], "\u043d\u0430\u0443\u043a": [21, 41, 68, 73, 82, 92, 93, 102], "\u043a\u043e\u043d\u0441\u0443\u043b\u044c\u0442\u0430\u043d\u0442": 21, "cesar": [21, 75, 82], "de": [21, 34, 38, 75, 82], "la": [21, 75, 82], "torre": [21, 75, 82], "nilsson": 21, "udi": [21, 75, 82], "dahan": [21, 75, 82], "\u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441": [21, 38], "\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446": [21, 88], "\u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d": 21, "\u043f\u043e\u043f\u044b\u0442\u0430": [21, 74, 85, 88, 90, 92], "\u043d\u0430\u0447\u043d": [21, 38, 72, 100], "produce": [21, 23, 37, 38, 49, 62, 73], "produces": [21, 52, 85, 86], "body": [21, 38, 64, 66, 75], "contains": [21, 23, 37, 51, 74, 76, 77, 82, 86, 90], "attempt": [21, 76, 85, 86, 100], "instruction": [21, 23], "whose": [21, 38, 39, 85, 86], "accompanied": 21, "full": [21, 23, 26, 34, 52, 70, 73, 75, 76, 82, 85, 92, 94], "fledged": [21, 23], "underlying": [21, 37], "usable": 21, "difficult": [21, 23, 37, 38, 40, 46, 70, 73, 74, 75, 85, 100], "defined": [21, 23, 29, 52, 65, 74, 75, 82, 86, 90], "interface": [21, 23, 29, 74, 75, 85, 86], "offered": [21, 85], "short": [21, 37, 38, 62, 74, 76, 77, 82, 90], "affect": [21, 34, 85], "accessible": 21, "secret": [21, 88], "refers": [21, 49], "exported": 21, "reason": [21, 23, 29, 34, 37, 38, 46, 51, 74, 75, 85, 86], "generally": [21, 23, 38, 49, 51, 52], "fully": [21, 23, 51, 73, 74, 82, 86, 92], "permit": [21, 23], "selectively": 21, "soon": [21, 23, 38, 42, 46, 47, 68, 74, 76, 82, 95], "none": [21, 74], "changing": [21, 23, 37, 74, 76, 80, 82, 85], "visible": [21, 37, 38, 73, 76], "least": [21, 23, 29, 37, 38, 75, 76, 85], "brings": [21, 38], "back": [21, 23, 34, 37, 38, 41, 47, 60, 74, 75, 76, 77, 82, 85, 86, 90, 100], "expression": [21, 75, 85], "exchange": 21, "subexpression": 21, "\u043f\u043e\u0434\u0432\u0435\u0434": [21, 52, 77], "\u0440\u0435\u0437\u044e\u043c": [21, 38], "\u0432\u0441\u0435\u043c": [21, 30, 38, 42, 73, 74, 85, 86, 88, 90, 100], "\u0437\u0430\u043f\u0440\u0435\u0449\u0430": 21, "\u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d": [21, 38], "\u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d": [21, 23, 37], "\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": [21, 83, 93, 95, 96], "\u0437\u0430\u043f\u0440\u0435\u0449": 21, "\u043f\u043e\u043b\u0443\u0447\u0435\u043d": [21, 23, 38, 56, 65, 77, 83], "\u0443\u0447\u0442": [21, 88], "railway": [21, 82], "\u043f\u043e\u044f\u0441\u043d\u0435\u043d": 21, "\u0438\u0437\u0431\u0435\u0433\u0430\u043d": 21, "\u043e\u0442\u043b\u0438\u0447\u043d": [21, 37, 74, 86, 100], "\u0432\u044b\u044f\u0441\u043d": [21, 37, 74], "\u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436": 21, "few": [21, 23, 37, 38, 65, 73, 76, 77, 86, 100], "reminders": 21, "terminology": [21, 64, 82], "features": [21, 37, 38, 41, 47, 51, 52, 62, 65, 70, 74, 76, 82, 85, 86], "characterize": 21, "serves": [21, 38, 49], "say": [21, 23, 34, 38, 41, 46, 72, 74, 75, 85, 86], "reserving": 21, "corresponding": [21, 23, 51, 52], "algorithm": [21, 23], "computes": 21, "needed": [21, 23, 37, 38, 49, 70, 76, 77, 85, 86, 100], "associated": [21, 23, 34, 37, 52, 74, 75, 76], "together": [21, 23, 38, 74, 75, 76, 85], "called": [21, 23, 34, 37, 38, 41, 52, 68, 72, 74, 75, 85, 94], "routines": [21, 34, 74, 86, 90], "specify": [21, 37, 49, 51, 65], "course": [21, 34, 37, 38, 41, 46, 70, 73, 74, 76, 82, 85], "producing": [21, 38, 42, 49, 73], "obviously": [21, 74, 85], "yes": [21, 23, 37, 76], "among": [21, 23, 34, 37, 38, 85, 86], "sense": [21, 23, 37, 38, 51, 62, 70, 74, 75, 85, 86], "accessing": [21, 29], "anything": [21, 23, 26, 38, 42, 62, 65, 73, 85, 86], "performed": [21, 23, 86], "indicate": [21, 23, 34, 38, 52], "ancillary": 21, "official": 21, "purpose": [21, 23, 34, 49, 73, 74, 86, 100], "answering": 21, "\u043b\u0435\u0436": [21, 23, 41, 42, 74, 76, 90], "\u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442": [21, 88, 90, 100], "glossary": [21, 52, 53, 62, 82], "\u0432\u044b\u0440\u0430\u0437": [21, 23, 75, 100], "\u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c": [21, 93, 94, 100, 102], "\u0432\u0430\u0436": [21, 76], "\u0434\u0430\u043b": [21, 23, 72, 82, 83, 88, 92, 100], "\u0434\u043d\u0438": 21, "\u043d\u0430\u043f\u043e\u043c\u043d": [21, 70, 74, 75, 88], "\u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d": [21, 34, 38, 56], "\u043d\u0435\u0437\u0430\u0441\u043b\u0443\u0436\u0435\u043d": 21, "\u043e\u043f\u0443\u0441\u043a\u0430": [21, 85], "\u043a\u0440\u043e\u0435\u0442": [21, 23, 85], "\u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430": [21, 85], "\u0437\u0430\u0432\u0438\u0441": [21, 23, 34, 38, 40, 41, 65, 70, 82, 83, 85, 86, 88, 93], "point": [21, 23, 34, 37, 38, 39, 46, 49, 51, 72, 73, 74, 75, 76, 77, 85, 86, 94], "clarified": [21, 23, 75, 82], "examine": [21, 74], "further": [21, 34, 38, 65, 70, 74, 76, 82, 92], "consequences": [21, 23, 38], "treat": [21, 23], "seen": [21, 23, 34, 51, 52, 74, 85, 92], "endanger": 21, "assume": [21, 23, 34, 75, 85, 86], "allocate": 21, "mathematical": [21, 23, 60, 82, 85, 90], "perspective": [21, 23, 38, 52, 77, 86], "pretend": [21, 23], "times": [21, 23, 34, 37, 38, 46, 74, 75, 76, 77, 82, 85, 86, 100], "past": [21, 23, 73], "present": [21, 23, 34, 38, 49, 70], "inscribed": [21, 23], "book": [21, 23, 38, 82, 85, 95], "legitimate": [21, 23], "initialize": [21, 23], "observations": [21, 23], "second": [21, 23, 34, 37, 38, 46, 52, 72, 75, 76, 80, 82, 85, 86, 100], "created": [21, 23, 34, 51, 86, 100], "\u0437\u0430\u043c\u0435\u0447\u0430\u043d": 21, "rfc": [21, 23], "7231": [21, 23], "post": [21, 23, 74, 94], "origin": [21, 23, 34], "send": [21, 23, 34], "201": [21, 23], "location": [21, 23], "header": [21, 23], "provides": [21, 23, 29, 34, 38, 42, 51, 59, 60, 63, 76, 82, 85], "identifier": [21, 23, 34], "primary": [21, 23, 37, 38, 52, 73, 76, 90], "resource": [21, 23, 82, 92], "section": [21, 23, 74, 75], "representation": [21, 23, 85], "describes": [21, 23, 65], "referring": [21, 23, 72, 73, 75], "\u043f\u043e\u044f\u0441\u043d\u044f": [21, 37], "\u043f\u0440\u043e\u0447\u0442\u0435\u043d": [21, 82], "\u0442\u043e\u0436": [21, 23, 30, 38, 72, 76, 83, 85, 86, 88, 92, 100], "unfortunately": [21, 68, 75, 76], "unacceptably": 21, "restrictive": 21, "explaining": [21, 74], "prohibits": 21, "harmless": [21, 23], "necessary": [21, 23, 38, 49, 51, 65, 73, 76, 77, 85, 86], "kinds": [21, 23, 75], "acceptable": [21, 23, 38, 51, 65], "category": [21, 82], "affecting": 21, "depth": [21, 86], "sure": [21, 23, 29, 34, 38, 47, 82, 85, 86], "familiar": [21, 37, 76, 85], "abstraction": [21, 23, 51, 74, 75, 76, 77, 85, 86, 90, 100], "contract": [21, 23, 75, 85, 86], "particular": [21, 23, 38, 52, 54, 75, 100], "accompanying": 21, "figures": [21, 74], "saw": [21, 23, 85], "represent": [21, 23, 51, 86, 100], "stack": [21, 23], "representations": [21, 82], "made": [21, 23, 26, 37, 38, 39, 42, 62, 68, 74, 75, 76, 80, 82, 86, 100], "array": [21, 23], "top": [21, 38, 74, 76, 78, 82, 86, 92, 133], "marker": [21, 23], "count": [21, 23, 64, 82, 85, 95], "differ": [21, 52], "sizes": 21, "indices": 21, "terms": [21, 23, 37, 38, 46, 62, 73, 74, 85, 90, 100], "belongs": 21, "c1": 21, "c2": [21, 37, 80, 85], "still": [21, 23, 37, 38, 39, 70, 73, 76, 85, 86], "represents": [21, 23, 49, 52, 76, 100], "yields": [21, 23], "stacks": [21, 23], "some_value": [21, 23], "guarantee": [21, 23, 34], "capacity": [21, 23, 38, 74, 90], "significant": [21, 23, 34, 38, 46, 77, 85, 86], "ill": [21, 23, 86], "appear": [21, 34, 62, 68], "shortly": 21, "machine": [21, 73], "metaphor": [21, 41], "correspond": [21, 64], "buttons": 21, "absolutely": [21, 23, 38, 88], "answers": [21, 38, 85, 92], "given": [21, 34, 37, 38, 42, 49, 74, 75, 76, 86], "button": 21, "energy": [21, 70, 72, 85], "automatically": [21, 73, 74], "switching": [21, 34], "off": [21, 23, 37, 38, 70, 72, 74, 76, 82, 85, 94], "circuits": 21, "nobody": [21, 34, 38], "presses": 21, "turning": 21, "whenever": [21, 23, 85], "someone": [21, 38, 73, 86], "included": [21, 23, 74], "unnoticeable": 21, "\u0443\u0432\u0438\u0434": [21, 23, 75], "\u043d\u0438\u0436": [21, 23, 68, 75], "\u043e\u0431\u0448\u0438\u0440\u043d": [21, 34], "\u0442\u043e\u043d\u043a": 21, "\u043e\u0441\u0432\u043e": [21, 82, 86, 93], "\u043f\u043e\u0433\u0440\u0443\u0436\u0435\u043d": 21, "clone": 21, "creates": [21, 23, 38, 46, 52, 73, 77], "carbon": 21, "exists": 21, "overwrite": 21, "fields": 21, "achieves": 21, "y": [21, 34, 37, 73, 88], "8": [21, 23, 37, 38, 64, 66, 82, 86], "copying": [21, 85], "\u043e\u0441\u043d\u043e\u0432\u0430": [21, 38, 40, 72, 85, 92], "notification": [21, 23, 34], "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430": [21, 23, 74, 75, 86, 90], "\u0430\u0434\u0440\u0435\u0441\u0430\u0446": 21, "pop": 21, "\u0431\u0443\u0444\u0444\u0435\u0440": 21, "buffer": [21, 23, 34], "queue": [21, 23, 34], "next_element": [21, 23], "item": [21, 23, 51], "remove": [21, 23, 38, 85], "notation": [21, 23], "easy": [21, 23, 37, 38, 41, 62, 70, 72, 74, 75, 76, 85], "exclusive": [21, 23], "sacrificing": [21, 23, 38, 70, 74], "enclose": [21, 23], "instructions": [21, 23], "replaced": [21, 23], "formal": [21, 23], "30": [21, 23, 37, 38, 80, 85], "12": [21, 23, 38, 46, 66, 74, 76, 85], "\u0434\u043e\u0433\u0430\u0434\u0430": [21, 37, 38], "\u043f\u043e\u0434\u0432\u043e\u0436": 21, "asynchronous": [21, 23, 34, 35, 119], "reply": [21, 23], "202": [21, 23], "\u0432\u0435\u0440\u043d\u0443\u043b": [21, 30], "\u0432\u043e\u043e\u0431\u0449": [21, 34, 40, 46, 51, 75, 83, 92, 94, 100, 102], "\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432": [21, 70, 88], "submitted": [21, 23], "poll": [21, 23], "easily": [21, 23, 37, 70, 74, 85, 86], "solved": [21, 23], "guids": [21, 23], "ids": [21, 23, 34], "comment": [21, 23, 34, 52], "68": [21, 23], "\u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430": 21, "ulid": 21, "hi": [21, 23], "lo": [21, 23], "\u043f": [21, 23, 37, 56, 70, 72, 82, 83, 85, 88, 90, 92, 94, 100], "requests": [21, 23], "enclosed": [21, 23], "payload": [21, 23], "current": [21, 23, 34, 38, 39, 47, 51, 65, 73, 82, 85, 86], "successfully": [21, 23, 86], "inform": [21, 23, 38], "user": [21, 23, 38, 49, 51, 53, 59, 65, 74, 75, 77, 82, 86], "agent": [21, 23], "sending": [21, 23], "\u0432\u044b\u0433\u043e\u0434": [21, 37, 56, 65, 70, 80, 86], "\u0432\u044b\u0437": [21, 62, 76, 88], "\u043c\u043d\u043e\u0433\u043e\u043a\u0440\u0430\u0442\u043d": [21, 72, 85], "\u043f\u043e\u0432\u0442\u043e\u0440\u044f": [21, 72, 85], "\u0443\u0449\u0435\u0440\u0431": [21, 38, 40, 56, 66, 86], "\u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430": [21, 23, 30, 37, 86, 88], "truth": [21, 37, 80, 86], "redux": [21, 75, 82], "steps": [21, 23, 34, 38, 77], "flux": 21, "attempts": 21, "mutations": 21, "predictable": [21, 38, 62], "imposing": [21, 76], "certain": [21, 38, 49, 75, 86, 100], "restrictions": 21, "updates": [21, 23], "happen": [21, 23, 26, 34, 74, 86, 100], "reflected": [21, 23, 34, 76], "three": [21, 37, 38, 46, 73, 76, 85, 86], "principles": [21, 23, 34, 37, 38, 49, 65, 66, 70, 71, 72, 73, 74, 76, 82, 85, 86, 100, 132], "described": [21, 23, 51, 74, 75], "read": [21, 23, 34, 38, 49, 72, 73, 74, 82, 86, 95], "emit": 21, "describing": 21, "happened": [21, 23, 72, 74, 85], "flow": [21, 23, 38, 72, 82, 86], "fundamentals": [21, 64, 82], "handle": [21, 23, 34, 38], "bi": 21, "directional": 21, "uni": 21, "particularly": [21, 23, 46, 65, 73, 75, 86], "aren": [21, 39, 70, 73, 75, 76, 77, 82, 85, 86], "too": [21, 23, 37, 38, 51, 65, 68, 73, 74, 75, 80, 85, 86, 100], "comfortable": [21, 23], "hate": 21, "ui": [21, 80, 83, 86], "\u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446": 21, "\u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d": 21, "\u0443\u0441\u0442\u0440\u0430\u043d": [21, 30, 34, 88], "\u043c\u043e\u043d\u0443\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [21, 82], "\u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d": [21, 38, 82], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442": [21, 23, 70, 85, 86], "\u043a\u043e\u0440\u0437\u0438\u043d": 21, "\u0442\u043e\u0432\u0430\u0440": 21, "\u0441\u043e\u0432\u043c\u0435\u0449\u0435\u043d": 21, "\u0441\u043e\u043e\u0431\u0449": [21, 23, 92], "\u043f\u0440\u043e\u0434\u0430\u0436": 21, "\u043e\u0431\u043d\u043e\u0432": 21, "\u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430": 21, "\u0437\u0430\u043a\u0430\u0437\u0430": 21, "\u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d": 21, "\u043d\u0430\u043c\u0435\u0440\u0435\u043d": [21, 42, 72, 85, 92], "\u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u0438\u0437\u0438\u0440": 21, "logic": [21, 34, 73, 74, 82], "overbooking": 21, "nosql": [21, 23, 82], "distilled": [21, 23, 34, 82, 86], "\u0434\u0432\u0443\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d": 21, "\u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f": 21, "\u0447\u0442\u0435\u043d": [21, 74, 82, 83, 85, 92], "\u0441\u043e\u0432\u043c\u0435\u0449": 21, "\u0437\u0430\u043a\u0430\u0437": 21, "\u0440\u0435\u043f\u043b\u0438\u043a": 21, "staleness": 21, "fact": [21, 23, 26, 34, 37, 38, 47, 65, 68, 70, 74, 76, 85, 86, 100], "shown": [21, 23, 38, 51], "changed": [21, 23, 26, 38, 74, 75, 76, 85], "actor": [21, 23, 30, 34, 75, 82], "stale": [21, 82], "almost": [21, 38, 74, 85, 86, 100], "cache": 21, "serving": 21, "performance": [21, 34, 38, 51, 73, 82, 86], "entirely": [21, 38], "trust": 21, "users": [21, 23, 34, 38, 51, 52, 75, 76], "decisions": [21, 29, 37, 38, 62, 65, 68, 74, 75, 76, 77, 80, 85, 86], "could": [21, 23, 26, 29, 34, 38, 51, 70, 73, 74, 76, 77, 80, 85, 86], "date": [21, 23, 37, 65, 82, 85], "\u043e\u0442\u0434\u0435\u043b\u0435\u043d": [21, 86], "\u0437\u0430\u043a\u043e\u043d\u0447": [21, 46, 74, 85], "image": [21, 23, 37, 60, 62, 65, 74, 76, 77, 86], "autonomous": [21, 86], "component": [21, 23, 73, 75, 86], "decided": [21, 23, 72, 76, 85], "modifying": [21, 23, 41, 72, 75], "persistent": [21, 23, 51], "notifying": 21, "world": [21, 23, 37, 38, 39, 49, 51, 62, 64, 73, 76, 82, 83, 85, 86, 94, 100], "coming": [21, 23, 52, 62, 85], "appropriate": [21, 23, 29, 38, 76, 77, 85, 86], "explicitly": [21, 23, 72, 73, 85], "takes": [21, 23, 38, 51, 73, 74, 76, 86], "account": [21, 23, 34, 64, 86], "factors": [21, 38, 65, 70, 85], "volatility": 21, "exploits": 21, "characteristics": [21, 23, 51, 65, 76], "creating": [21, 23, 38, 49, 74, 80, 85, 86, 100], "simpler": [21, 23, 37, 70, 73, 76, 85], "scalable": [21, 23, 34, 51, 52, 82, 86], "\u043f\u043e\u043d\u0438\u043c": [21, 23, 83, 100], "\u0432\u0430\u0436\u043d\u043e\u0441\u0442": [21, 38, 75, 88, 90], "evironment": 21, "sandbox": 21, "\u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a": 21, "\u043d\u0430\u0440\u0443\u0448": [21, 23, 34], "\u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430": [21, 74], "\u043a\u043e\u043b\u043b\u0435\u043a\u0446": [21, 23], "\u0440\u0430\u0437\u0443\u043c\u0435\u0435\u0442": [21, 23, 37, 86], "\u0438\u043d\u0438\u0446\u0438\u0430\u0442\u043e\u0440": 21, "\u0432\u043a\u043b\u044e\u0447": [21, 75, 82, 100], "\u043a\u0430\u043d\u0430": [21, 34, 100], "\u043f\u043e\u0440": [21, 73, 75, 82, 88, 90], "\u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436": 21, "\u043d\u0438": [21, 34, 37, 38, 52, 70, 72, 74, 75, 82, 83, 85, 86, 90, 100], "\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432": [21, 56, 74, 86], "\u0443\u0432\u0435\u0434\u043e\u043c\u043b": 21, "\u0435\u0434\u0438\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d": [21, 74], "\u043f\u043e\u0432\u043e\u0434": [21, 23, 72, 74, 83, 86, 88, 93], "seem": [21, 23, 85], "strange": [21, 23, 74], "parameters": [21, 23], "registry": [21, 23], "static": [21, 23, 29, 52], "re": [21, 23, 37, 38, 47, 52, 64, 65, 68, 70, 74, 75, 77, 82, 85, 86, 92, 100], "querying": [21, 23], "collecting": [21, 23, 52], "parameter": [21, 23, 39], "redirect": [21, 23], "screen": [21, 23], "showing": [21, 23, 38], "very": [21, 23, 29, 38, 62, 70, 74, 76, 85, 86, 94, 100], "accomplished": [21, 23, 37, 38, 86], "bit": [21, 23, 37, 46, 51, 74, 75, 76, 90], "controversial": [21, 23, 46], "frankly": [21, 23, 37, 76], "care": [21, 23, 34, 37, 42, 85], "simplest": [21, 23, 51, 70, 73, 75, 85], "possibly": [21, 23, 37, 51, 64, 70, 85], "steal": [21, 23], "unit": [21, 23, 38, 45, 46, 52, 66, 70, 74, 82, 85, 86, 123], "controllers": [21, 23], "diet": [21, 23], "posts": [21, 23, 82], "\u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d": [21, 37], "myth": [21, 23, 86], "requires": [21, 23, 34, 38, 46, 73, 74, 86, 90], "eventual": [21, 30, 34], "consistent": [21, 23, 34, 82], "immediately": [21, 23, 34, 38, 76, 86], "succeeds": [21, 23], "legacy": [21, 23, 38, 45, 66, 70, 76, 82, 83, 123], "transitioning": [21, 23, 46], "eventually": [21, 23, 34, 37, 38, 41, 73, 74, 82, 86], "stores": [21, 23], "bogus": [21, 23], "hoops": [21, 23], "mimicking": [21, 23], "synchronous": [21, 23], "bang": [21, 23], "door": [21, 23, 41], "pitchforks": [21, 23], "torches": [21, 23], "try": [21, 23, 38, 47, 51, 52, 68, 73, 74, 77, 85, 90, 100], "transition": [21, 23, 38, 49], "immediate": [21, 23, 38, 76, 85], "consistency": [21, 31, 34, 82, 116], "unless": [21, 23, 34, 86], "expects": [21, 23], "confirmation": [21, 23], "making": [21, 23, 26, 34, 37, 38, 47, 65, 66, 70, 73, 74, 76, 82, 85, 88, 89, 100], "series": [21, 23, 51, 59, 60, 74, 75, 77, 82, 86], "confirmations": [21, 23], "received": [21, 23, 34], "annoy": [21, 23], "snot": [21, 23], "bus": [21, 23, 34], "queues": [21, 23, 82], "messaging": [21, 23, 30, 34, 82], "says": [21, 23, 37, 62, 75, 76], "thou": [21, 23], "shalt": [21, 23], "nservicebus": [21, 23], "merely": [21, 23, 37, 76], "separating": [21, 23, 38, 90, 100], "varied": [21, 23], "until": [21, 23, 26, 34, 38, 39, 51, 65, 68, 73, 77, 85, 86], "prove": [21, 23, 74], "models": [21, 23, 29, 34, 36, 37, 38, 49, 51, 52, 54, 62, 64, 65, 76, 82, 100, 120], "decision": [21, 23, 38, 39, 46, 65, 68, 70, 76, 82, 86, 88, 89], "impacts": [21, 23, 86], "slip": [21, 23], "emulate": [21, 23], "attempting": [21, 23, 49, 76], "wrong": [21, 23, 37, 38, 52, 65, 72, 75, 76, 85, 86], "busting": [21, 23, 82], "myths": [21, 23, 38, 82], "\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430": [21, 23], "scaling": [21, 23, 34, 64, 73, 82, 86], "orthogonal": [21, 23], "contextual": [21, 23], "certainly": [21, 23, 29, 37, 70, 74, 85], "doesn": [21, 23, 29, 34, 37, 38, 42, 51, 68, 72, 73, 74, 77, 85, 86, 94, 100], "require": [21, 23, 34, 37, 51, 73, 74, 75, 76, 86], "async": [21, 23], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442": [21, 23], "\u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440": [21, 23], "\u043d\u0438\u0447\u0442": [21, 23, 40, 42, 82], "\u0432\u043d\u043e\u0432": [21, 23], "\u0443\u043f\u0440\u043e\u0441\u0442": [21, 23, 37, 74, 76], "\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d": 21, "\u0441\u043b\u0443\u0447": [21, 26, 70, 74], "\u0441\u043c\u043e\u0433\u0443\u0442": [21, 38, 72, 85], "\u0442\u0443": [21, 88], "\u0440\u0430\u0437\u0431\u0438\u0440\u0430": [21, 40, 70, 83], "\u0437\u0430\u0431\u043b\u0443\u0436\u0434\u0435\u043d": [21, 65, 73, 85, 86, 92], "\u043c\u0430\u043a\u0441": 21, "\u0430\u0440\u0448\u0438\u043d": 21, "oskar": [21, 86], "dudycz": [21, 86], "facts": [21, 23], "versus": [21, 23, 37, 38, 41, 65, 74, 76, 85, 86], "mark": [21, 38, 82, 88], "seemann": 21, "handlers": [21, 23, 34], "steven": [21, 82, 88], "van": [21, 34, 82], "deursen": 21, "\u0441\u043f\u043e\u0440\u043d": [23, 46], "\u0442\u043e\u0447\u0435\u043a": [23, 74, 82, 93, 94], "\u0432\u0435\u0449": [23, 37, 38, 74, 75, 82, 85, 100], "\u043f\u0435\u0440\u0432\u043e\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a": [23, 53, 85, 94], "\u043c\u043e\u0442\u0438\u0432": 23, "\u0442\u0435": [23, 38, 46, 70, 74, 75, 76, 85, 92, 100, 102], "zealots": 23, "extreme": [23, 37, 42, 46, 47, 52, 64, 66, 68, 70, 73, 74, 76, 82, 83, 94, 95], "creators": 23, "royalist": 23, "king": [23, 76, 92], "captures": [23, 76, 77], "phenomenon": [23, 77], "find": [23, 34, 37, 38, 46, 47, 51, 65, 72, 73, 74, 77, 82, 85, 95], "foundational": 23, "texts": 23, "beck": [23, 37, 38, 41, 42, 46, 47, 52, 64, 66, 68, 70, 72, 75, 76, 82, 83, 85, 86, 88, 92, 93, 94, 95], "larman": [23, 37, 38, 40, 41, 64, 75, 82, 83, 88, 94], "cockburn": [23, 37, 76], "occupy": [23, 100], "plane": 23, "discourse": 23, "avoid": [23, 34, 38, 49, 73, 74, 76, 85, 86, 89], "below": [23, 42], "belt": 23, "hits": 23, "approaches": [23, 37, 38, 42, 49, 51, 52, 65, 73, 76, 78, 85, 86, 92, 133], "hype": [23, 52, 82], "ugly": [23, 47, 52, 82], "\u0434\u0440": [23, 41, 88, 92, 102], "\u043e\u0431\u0437\u043e\u0440": [23, 37], "\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b": 23, "\u043a\u043e\u043b\u043b\u0435\u043a\u0442": [23, 88, 92], "\u0441\u0447\u0430\u0441\u0442": [23, 68, 82, 90], "\u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d": 23, "experts": [23, 51, 82, 95], "activity": [23, 38, 46, 62, 74, 77, 100], "discrete": [23, 74, 90], "distinct": [23, 85, 100], "related": [23, 34, 38, 49, 75, 82], "arises": [23, 38, 46, 74], "kept": [23, 74], "internally": [23, 38, 86], "asynchronously": 23, "propagate": [23, 74], "nodes": [23, 34], "network": [23, 34, 86], "resolve": [23, 34, 38, 77, 86], "arriving": 23, "order": [23, 26, 34, 37, 38, 51, 74, 76, 82, 86], "sources": 23, "supposed": [23, 37, 49], "conceptually": [23, 75, 86], "constituent": 23, "cautious": 23, "locking": 23, "schemes": [23, 38], "interfere": 23, "pointlessly": 23, "unusable": 23, "similar": [23, 29, 39, 46, 74], "arise": [23, 26, 76, 86], "distributing": [23, 77], "servers": 23, "designing": [23, 34, 38, 74, 76, 82, 86], "transactions": [23, 34, 82], "govern": 23, "distribution": 23, "synchronously": 23, "\u043a\u0440\u0430\u0435\u0443\u0433\u043e\u043b\u044c\u043d": 23, "\u0441\u0438\u043b": [23, 38, 40, 73, 83, 86, 88, 90, 92, 95], "cap": [23, 34, 82], "\u0442\u0435\u043e\u0440\u0435\u043c": 23, "\u0440\u0443\u0441\u0441\u043a": [23, 34, 38, 40, 41, 60, 64, 66, 73, 74, 77, 82, 88, 90], "\u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442": [23, 38, 56, 65, 76, 83, 86, 88, 92, 94], "availability": [23, 34, 38], "partition": 23, "tolerance": 23, "\u0442\u0430": [23, 26, 38, 65, 76, 82, 86, 88, 100], "\u0443\u0437\u043b": [23, 34, 86], "\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430": [23, 100], "\u043c\u0438\u043d\u0443\u0442\u043a": 23, "\u0430\u0432\u0442\u043e\u043c\u043e\u0431\u0438\u043b": 23, "\u043f\u0440\u0438\u0439\u0442": [23, 70, 100], "\u0442\u0438\u043f\u043e\u0440\u0430\u0437\u043c\u0435\u0440": 23, "\u0432\u0435\u0440\u043d\u043e\u043d": [23, 100], "\u043f\u0440\u0438\u0431\u0435\u0433\u0430": 23, "commit": 23, "\u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d": [23, 34, 76, 86, 92], "\u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441": [23, 34, 75, 87, 92, 93, 100, 137], "\u043f\u0440\u0430\u0432\u0434": [23, 34, 73, 75, 88, 92, 95, 100], "\u0443\u0445\u0443\u0434\u0448": 23, "\u0443\u0440\u043e\u0432\u0435\u043d": [23, 72, 73, 75, 77, 83, 85, 86, 88, 94, 95], "\u043d\u0430\u0438\u043c\u0435\u043d": [23, 38], "\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446": [23, 72], "\u043c\u043e\u043d\u043e\u043b\u0438\u0442": 23, "\u0441\u0442\u0440\u0435\u043c\u043b\u0435\u043d": [23, 37, 38, 73, 74, 85, 86, 90], "eliminate": [23, 38, 70, 74, 86], "commits": 23, "modified": [23, 34, 52, 86], "dependent": [23, 34, 38, 85], "occur": [23, 34, 38, 70, 75], "instances": [23, 26, 34], "synchronized": 23, "remote": [23, 82], "latency": [23, 30, 34], "decoupling": [23, 73, 74], "performing": [23, 38, 74, 90], "cooperating": 23, "loose": [23, 72, 73], "\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d": [23, 34, 37, 86], "\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432": [23, 90], "\u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d": [23, 37, 75, 86], "\u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430": 23, "relational": 23, "fine": [23, 75, 76, 82, 86], "grained": [23, 82, 86], "rationale": 23, "embracing": [23, 52, 76], "spanning": 23, "number": [23, 34, 37, 38, 51, 52, 65, 74, 75, 76, 80, 85, 86, 90], "substantial": 23, "scalability": 23, "instant": 23, "accepting": [23, 38, 51], "atomic": 23, "larger": [23, 38, 73, 86], "correctly": [23, 65, 85], "bill": [23, 37, 38, 82], "wagner": [23, 82], "mike": [23, 52, 76, 82, 83, 88, 92], "rousos": [23, 82], "\u0443\u0445\u0443\u0434\u0448\u0435\u043d": [23, 38, 74], "\u043a\u0440\u0443\u043f\u043d": [23, 74, 76, 83, 86, 90], "\u0432\u0438\u0434\u043d": [23, 46, 75, 83, 92], "\u0441\u0442\u043e\u043b\u044c\u043a": [23, 41, 75, 85], "\u0441\u043a\u043e\u043b\u044c\u043a": [23, 38, 41, 75, 83, 86, 92, 100], "\u0440\u0430\u0437\u043c\u0435\u0440": [23, 73, 76, 86, 92, 93, 100], "smaller": [23, 34, 38, 52, 72, 73, 74, 75, 85, 86, 90], "biased": 23, "toward": [23, 38, 76, 77, 82, 95], "success": [23, 37, 38, 46, 51, 62, 76, 85, 86], "meaning": [23, 38, 74, 75, 100], "conflicts": [23, 38, 82], "preventing": [23, 74, 85], "rare": 23, "small": [23, 38, 53, 72, 73, 74, 75, 76, 86], "\u043f\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0447\u0438\u043d": 23, "\u0432\u043e\u0432\u0441": [23, 38, 76, 85, 93, 102], "maintained": [23, 37, 51, 76], "spans": 23, "expected": [23, 37, 38, 65, 76, 85, 86], "batch": 23, "mechanisms": [23, 82, 86], "resolved": [23, 38, 65, 72], "specified": [23, 49, 65], "applied": [23, 37, 38, 64, 75, 76, 82, 88], "enforced": [23, 34, 49], "six": [23, 37, 74, 76, 86], "cycle": [23, 36, 37, 38, 49, 51, 52, 59, 60, 62, 63, 65, 74, 76, 77, 82, 86, 88, 120], "insert": 23, "delete": 23, "ordinarily": 23, "tempting": [23, 47, 74], "saving": [23, 34], "presumably": 23, "initiate": 23, "units": [23, 34, 52, 75, 85], "keeps": [23, 72, 82, 85, 95], "hands": [23, 34, 73, 77, 82, 86, 100], "\u043a\u043e\u0440\u043d": [23, 38, 73], "ownership": [23, 86, 94], "rigorous": 23, "includes": [23, 51, 60, 72, 74, 82, 85, 86, 94, 100], "owners": [23, 38, 86], "identity": [23, 26], "traffic": [23, 34], "involved": [23, 37, 38, 39, 40, 80, 86], "\u043a\u0441\u0442\u0430\u0442": [23, 34, 65, 74, 75, 83, 85, 94, 95], "siegel": 23, "1990s": [23, 76], "published": [23, 38, 46, 76, 82], "specific": [23, 34, 38, 49, 51, 52, 53, 72, 82, 85, 86, 100], "contained": 23, "member": [23, 38, 73, 86], "distinguishable": 23, "\u0441\u043e\u0436\u0430\u043b\u0435\u043d": [23, 38, 68, 70, 75, 82], "\u0443\u0434\u0430": [23, 37, 56, 74, 76, 85, 88, 93, 102], "\u0443\u043f\u043e\u043c\u0438\u043d\u0430": [23, 38, 40, 53, 86, 89], "poeaa": [23, 72], "\u0437\u0432\u0443\u0447": [23, 38, 40], "coarse": 23, "alternative": [23, 34, 38, 49, 70, 76], "16": [23, 51, 72, 74, 76, 83, 88, 93], "contention": [23, 34], "concurrency": [23, 32, 117], "\u043d\u0430\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d": 23, "\u043e\u0431\u044a\u044f\u0441\u043d\u044f": [23, 30, 37, 74, 75, 85, 92, 94, 100], "\u0432\u044b\u0441\u043e\u043a\u043e\u043d\u0430\u0433\u0440\u0443\u0436\u0435\u043d": 23, "\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c": [23, 64, 76, 86], "\u0431\u044b\u0432\u0430": [23, 34, 83, 86, 88, 92, 100], "executing": [23, 37, 76], "additional": [23, 37, 38, 76, 86], "execute": [23, 38, 76], "invariant": [23, 34, 82], "discussing": 23, "logically": 23, "everything": [23, 34, 38, 46, 70, 72, 73, 76, 82, 85, 86], "adheres": 23, "matter": [23, 38, 51, 66, 74, 86, 100], "irrelevant": 23, "synonymous": 23, "employing": 23, "typical": [23, 86], "persistence": [23, 82], "properly": [23, 38, 74, 82, 85], "applying": [23, 62, 65, 72, 75, 82, 85], "limiting": [23, 37, 76, 86], "overly": [23, 38, 76], "strict": 23, "thumb": [23, 62], "addresses": [23, 75], "true": [23, 37, 38, 73, 74, 85, 86, 100], "remember": [23, 37, 38, 51, 53, 74, 85, 90, 94], "drivers": [23, 77, 85, 86], "determining": [23, 86], "\u0447\u0435\u0442\u044b\u0440": [23, 38, 40, 42, 82], "\u0446\u0438\u0442\u0438\u0440\u043e\u0432\u0430": 23, "\u043a\u043e\u043c": [23, 85], "\u0432\u043f\u043b\u043e\u0442": [23, 30, 37, 88], "gaining": 23, "insight": [23, 77, 100], "discovery": [23, 86], "\u043e\u0442\u0440\u044b\u0432\u043e\u043a": 23, "scenarios": [23, 52, 86], "challenging": 23, "determine": [23, 85], "classic": [23, 74, 76, 85], "correct": [23, 26, 100], "neither": [23, 38], "tendencies": 23, "preference": [23, 76], "break": [23, 73, 74, 82, 86, 88, 90], "tie": 23, "revealed": 23, "guideline": [23, 38, 46, 85], "examining": 23, "transactionally": 23, "adhering": 23, "wisdom": [23, 74], "breaker": 23, "gain": [23, 37, 47, 70], "deeper": [23, 42, 73], "understanding": [23, 37, 38, 41, 49, 51, 65, 72, 73, 74, 77, 82, 86, 100], "exposes": [23, 85], "real": [23, 62, 65, 75, 76, 82, 85, 86, 100], "ones": [23, 34, 64, 70, 75, 82, 95], "valuable": [23, 29, 37, 38, 53, 62, 65, 70, 73, 77, 85], "defaulting": 23, "leaning": 23, "\u0446\u0438\u0442\u0430\u0442": [23, 37, 38], "\u0432\u043e\u043d": 23, "\u044d\u0440\u0438\u043a": [23, 100], "\u044d\u0432\u0430\u043d\u0441": [23, 100], "\u0441\u043f\u0435\u0448": [23, 88], "\u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430": [23, 38, 70, 86, 88], "architects": [23, 38, 46, 86], "okay": 23, "original": [23, 37, 74, 75, 76, 82, 86], "\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430": [23, 46], "\u0443\u0433\u043b": 23, "\u043e\u043f\u044f": [23, 82, 85, 86, 92, 94], "ll": [23, 34, 37, 41, 74, 75, 76, 77, 80, 82, 85, 86, 90, 95], "theorem": [23, 34, 82], "optimally": 23, "incredibly": 23, "concerned": 23, "according": [23, 38, 52, 64, 73, 82, 100], "committing": [23, 65], "modifications": [23, 37, 38, 76], "succeed": [23, 37, 38, 65, 76, 100], "techniques": [23, 38, 74, 82, 86, 90], "big": [23, 34, 37, 38, 46, 51, 60, 70, 73, 74, 76, 77, 80, 82, 86, 90], "initial": [23, 59, 60, 62, 76, 80, 86], "step": [23, 52, 65, 77, 82, 85, 86], "meant": [23, 75, 85], "failures": [23, 38, 64], "\u0437\u0430\u0431\u0435\u0433": 23, "\u043d\u0430\u043f\u0435\u0440\u0435\u0434": 23, "\u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d": [23, 41, 74, 85, 92], "confuse": 23, "loading": [23, 82], "perfectly": [23, 72, 74, 76, 85, 86], "equally": 23, "permissible": 23, "practices": [23, 34, 37, 38, 49, 51, 52, 53, 54, 64, 65, 74, 75, 76, 77, 82, 85, 88, 94, 126], "19": [23, 38, 82], "\u043e\u0431\u0440\u0430\u0449": [23, 65], "highload": [23, 34], "throughput": 23, "persists": 23, "batches": 23, "timescaledb": 23, "batched": 23, "inserts": 23, "databases": [23, 37, 82], "employed": 23, "environments": [23, 75, 76], "ingesting": 23, "kafka": [23, 34, 82], "timescale": 23, "ingest": 23, "130k": 23, "3m": 23, "approximately": [23, 86], "15x": 23, "vanilla": 23, "postgresql": [23, 82], "couple": 23, "100m": 23, "freedman": [23, 30, 34], "cto": [23, 34, 86], "co": [23, 76, 86], "founder": [23, 86], "professor": [23, 37], "computer": [23, 38, 62, 65, 68, 73, 74, 82, 85, 90], "princeton": [23, 30, 34, 60, 82, 90], "rates": [23, 34, 70], "bulk": 23, "parallel": [23, 34, 77, 86], "hundreds": [23, 37, 74, 76], "thousands": [23, 37], "spend": [23, 38, 47, 49, 72, 73, 74, 86], "connection": 23, "overhead": [23, 46, 73, 74, 86], "parsing": 23, "tips": 23, "improve": [23, 74, 85, 86], "postgres": [23, 82], "extra": [23, 38, 46, 73, 74], "coordination": [23, 82, 86], "completed": [23, 37, 74, 76, 86], "write": [23, 47, 49, 51, 72, 73, 74, 77, 85, 86, 90], "wrap": [23, 85], "nice": [23, 76, 85, 86, 94], "gains": [23, 38, 42], "begin": [23, 34, 38, 51, 85, 86, 88], "took": [23, 73, 74], "15": [23, 37, 38, 64, 66, 70, 73, 80, 82, 85, 86], "minutes": [23, 38, 46, 74], "seconds": [23, 51], "ve": [23, 37, 38, 51, 62, 65, 70, 74, 75, 82, 85, 86], "suddenly": [23, 73], "boosted": 23, "3x": 23, "3k": 23, "batching": 23, "performant": 23, "manner": [23, 38, 76], "running": [23, 37, 38, 85, 93, 94, 100], "completes": [23, 38], "82": [23, 34, 38, 75, 82], "10k": 23, "writes": [23, 76], "fairly": [23, 85], "modest": [23, 85], "hardware": [23, 64], "faster": [23, 37, 38, 42, 73, 74, 86], "craig": [23, 34, 37, 38, 40, 41, 64, 75, 82, 83, 88, 94], "kerstiens": 23, "citusdata": 23, "turn": [23, 37, 38, 72, 73, 75, 76, 85, 86], "autocommit": 23, "issuing": 23, "libraries": 23, "behind": [23, 29, 34, 37, 38, 73, 74, 82, 85], "done": [23, 34, 37, 38, 41, 42, 46, 51, 62, 65, 70, 72, 73, 74, 76, 86, 88], "insertion": 23, "committed": 23, "separately": [23, 86, 100], "lot": [23, 29, 37, 38, 70, 73, 76, 86], "added": [23, 29, 34, 38, 51, 74, 86], "populating": 23, "disable": 23, "\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d": [23, 77, 100], "\u0440\u0435\u0446\u0435\u043f\u0442": 23, "\u0430\u043a\u0442\u0443\u0430\u043b": 23, "\u0441\u0435\u0440\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430": 23, "\u0441\u0432\u043e\u0431\u043e\u0434": [23, 38], "\u0432\u0441\u044f": [23, 37, 41, 70, 86, 95], "postgrespro": [23, 82], "\u043f\u0430\u043a\u0435\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [23, 30], "\u0432\u0441\u043f\u043e\u043c\u043d": [23, 60, 72, 85, 86, 90, 94], "\u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448": [23, 34, 77], "\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d": [23, 34], "blue": 23, "green": [23, 85], "deployment": [23, 75, 82, 86], "\u044f\u0432\u043d": [23, 29, 38, 102], "preferred": [23, 73], "triggered": 23, "\u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c": [23, 30, 74, 85], "\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440": 23, "come": [23, 37, 38, 52, 74, 85, 86, 92], "span": [23, 39], "ef": [23, 82], "cosmosdb": 23, "deferred": [23, 76], "raise": 23, "actually": [23, 37, 38, 49, 70, 74, 76, 100], "right": [23, 34, 37, 38, 39, 42, 52, 68, 70, 73, 74, 75, 76, 80, 82, 85, 86, 88], "depends": [23, 29, 74], "tell": [23, 37, 38, 46, 74, 76, 86], "service": [23, 34, 41, 75, 82, 86], "granular": 23, "impact": [23, 34, 38, 49, 76], "regard": [23, 76, 85], "investment": [23, 37, 38, 46, 72], "willing": [23, 73, 85], "detect": [23, 34], "inconsistencies": 23, "compensatory": 23, "actions": [23, 34, 38, 51], "afterwards": 23, "dispatched": [23, 34, 86], "issue": [23, 34, 37, 38], "tables": 23, "detects": [23, 34], "runs": [23, 37, 38, 73, 76, 82], "comparing": [23, 38, 41, 66, 86], "list": [23, 38, 52, 82, 86], "topic": [23, 34, 38, 74, 76, 90], "deep": [23, 34, 38, 82], "raising": [23, 38], "ordering": [23, 34, 38, 63], "guidelines": [23, 37, 76, 82], "exist": 23, "place": [23, 37, 38, 51, 74, 75, 76], "ignoring": [23, 85], "cost": [23, 34, 37, 38, 39, 41, 52, 60, 63, 65, 66, 70, 74, 76, 77, 80, 86, 89], "exceptional": 23, "circumstances": [23, 76, 85], "tells": [23, 37, 38, 76, 86], "unsatisfactory": 23, "shouldn": [23, 37, 68, 73, 74, 82, 90, 100], "wants": [23, 42, 46, 73, 75, 86], "elaborate": [23, 38, 49, 76, 86], "costs": [23, 37, 70, 73, 74, 86], "informed": [23, 37, 38, 65, 68, 77], "later": [23, 29, 34, 38, 51, 60, 62, 65, 68, 72, 76, 82, 85, 86], "robust": [23, 34, 82], "utilize": 23, "workflows": 23, "summarize": [23, 77], "collaborate": [23, 38, 86], "assess": [23, 38, 51, 53], "consciously": [23, 38, 72, 85], "ignore": [23, 34, 38, 85], "worthwhile": 23, "align": [23, 41], "greater": [23, 86], "chance": [23, 37, 52, 70, 75], "failure": [23, 37, 38, 51, 76, 85], "therefore": [23, 38, 39, 46, 65, 73, 74, 86, 92], "strive": [23, 38], "sign": [23, 37, 38, 76], "aligned": [23, 38, 82, 86], "fail": [23, 38, 100], "managing": [23, 38, 40, 49, 60, 73, 74, 82, 86, 88, 90, 100], "demonstrated": 23, "recommendafriendservice": 23, "imagine": [23, 73, 85], "referral": 23, "encapsulates": 23, "accounts": [23, 82, 95], "25": [23, 68], "logical": [23, 85], "necessarily": [23, 74, 76, 86], "scope": [23, 37, 38, 41, 52, 65, 74, 85, 86, 95], "respective": 23, "eventing": 23, "fired": 23, "strengthening": 23, "18": [23, 82, 85], "wrapping": 23, "thread": [23, 29], "raised": 23, "ensure": [23, 38, 51, 86], "entire": [23, 34, 75, 76, 85, 86, 100], "stays": [23, 37, 74, 75, 86], "notify": 23, "roots": [23, 85], "happens": [23, 34, 38, 70, 76, 86], "locked": 23, "risk": [23, 37, 38, 63, 70, 73, 77, 82, 86], "charged": 23, "fee": [23, 38, 46], "face": [23, 37, 38, 74, 76, 86], "applicable": [23, 38, 64, 86], "blocking": 23, "revert": [23, 38], "normal": [23, 47, 52], "disconnected": [23, 52], "intuitive": [23, 74], "cared": 23, "myself": [23, 37, 38, 85], "dispatching": 23, "handler": [23, 34], "recorded": 23, "benefits": [23, 37, 38, 51, 70, 77, 86, 94], "besides": [23, 38], "tearing": 23, "hair": 23, "domainevents": 23, "execution": [23, 86], "opinion": [23, 38], "initializing": 23, "connections": 23, "thanks": [23, 37], "andreas": 23, "books": [23, 38, 82], "practitioner": [23, 66, 82], "distlled": 23, "impossible": [23, 37, 38, 65, 70, 76], "notifications": 23, "becomes": [23, 37, 38, 40, 72, 73, 74, 85, 86], "responsible": [23, 38, 49, 51, 65, 75, 86], "behavior": [23, 26, 38, 68, 72, 75, 85, 88, 100], "communication": [23, 35, 38, 51, 52, 68, 73, 86, 119], "subscribe": [23, 34], "missing": [23, 82], "placement": 23, "payment": 23, "emails": 23, "started": [23, 38, 74, 82, 85, 86], "invoked": 23, "\u0432\u044b\u0445\u043e\u0434\u044f": 23, "channels": [23, 34, 86], "annotation": 23, "ispublic": 23, "emitting": 23, "knows": [23, 37, 39, 52, 82], "mathias": [23, 82, 92], "verraes": [23, 82, 92, 94], "sample": [23, 34, 75, 82, 85], "dotnet": [23, 82], "late": [23, 37, 38, 51, 63, 77, 86], "ends": [23, 37, 74], "scoping": 23, "dosomething": 23, "messages": [23, 34], "sent": [23, 34], "salvation": 23, "120": [23, 83], "lars": 23, "asks": 23, "didn": [23, 37, 38, 70, 74, 85], "maybe": [23, 85], "situation": [23, 37, 38, 47, 74, 76, 86], "explain": [23, 39, 41, 66], "bcs": 23, "deals": 23, "merging": [23, 94], "fire": [23, 37], "specifying": [23, 65], "merged": 23, "bc": 23, "react": [23, 37, 76], "won": [23, 37, 38, 74, 75, 85, 86], "vital": [23, 38, 73, 74], "am": [23, 38, 85], "solution": [23, 34, 38, 49, 52, 62, 70, 73, 76, 77, 82, 83, 86, 100], "suggest": [23, 75, 86], "ergo": 23, "deploying": [23, 34, 82], "enlisted": 23, "rolled": 23, "wouldn": [23, 37, 74, 85, 100], "arrives": [23, 34], "permanent": 23, "agree": [23, 38, 49, 74, 75], "ready": [23, 38, 51, 80, 82], "coincides": 23, "technology": [23, 30, 34, 38, 64, 73, 76, 77, 82, 86, 88], "choice": [23, 29, 86], "updating": 23, "transmitted": [23, 86], "gets": [23, 37, 38, 51, 73, 74, 76, 88], "routed": 23, "subscribers": [23, 34], "subscribed": 23, "aggregateroot": 23, "ensuring": [23, 38], "principal": [23, 41, 52, 86], "manager": [23, 37, 38, 46, 73, 74, 76, 86], "revisited": [23, 34, 82], "werner": [23, 34, 82], "vogels": [23, 34, 82], "amazon": [23, 34, 86], "\u0441\u0443\u0433\u0443\u0431": [23, 38, 65], "\u043f\u043e\u0434\u0440\u0430\u0437\u0434\u0435\u043b\u044f": 23, "loop": [23, 34, 72, 77, 85], "await": 23, "mediatr": 23, "amqp": 23, "rabbitmq": 23, "mentioned": 23, "conclusions": [23, 37], "\u043c\u0435\u0442\u043e\u0434\u0438\u043a": [23, 37, 38, 40, 42, 74, 75, 76, 82, 83, 85, 90, 95], "anti": [23, 37, 76, 82, 94], "corruption": 23, "\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d": [23, 38, 40, 47, 70, 74, 76, 80, 82, 85, 90, 94, 100, 102], "\u0437\u0430\u0449\u0438\u0442": [23, 38, 40, 56, 82, 88, 89, 92], "\u0447\u0430\u0441\u0442\u043e\u0442": 23, "share": 23, "occurred": [23, 34, 64], "interested": [23, 76], "parties": [23, 52, 86], "outward": 23, "subdomains": [23, 100], "emphasizes": [23, 37, 85], "word": [23, 37, 52, 75, 76, 86, 100], "term": [23, 37, 38, 52, 62, 74, 76, 85, 86, 100], "wide": [23, 38], "potential": [23, 38, 52, 70, 75, 76, 86], "broad": [23, 70], "broader": [23, 34, 86], "broadcast": 23, "forbid": 23, "delivery": [23, 34, 38, 52, 59, 60, 77, 82], "consumers": [23, 34], "\u043e\u0442\u0434\u0435\u043b\u044f": 23, "saved": [23, 70], "telling": 23, "noteworthy": 23, "conformists": 23, "wondering": 23, "consumed": 23, "\u0432\u043e\u043b\u043d": [23, 83], "\u043f\u0440\u0438\u043c": [23, 34], "consuming": [23, 34, 74], "conformist": 23, "relationship": [23, 34, 38, 64, 72, 74, 85], "recommended": [23, 60, 65, 76, 90], "iddd": [23, 82], "specifically": [23, 37], "integrating": [23, 86], "publisher": 23, "depend": [23, 75], "perhaps": [23, 34, 37, 38, 47, 75, 85], "economical": [23, 64], "consumer": [23, 34, 86], "consume": [23, 34, 74], "attributes": [23, 26, 38, 40, 51, 75], "\u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430": [23, 29, 100, 102], "\u043f\u043e\u0437\u0434\u043d": [23, 37, 56, 68, 76, 94], "\u0438\u0437\u0434\u0430\u043d": [23, 38, 64, 76, 82, 86], "\u0433\u043e\u0444": 23, "\u0438\u0432\u0435\u043d\u0442": 23, "\u043a\u0430\u0442\u0435\u0433\u043e\u0440": [23, 38, 40, 82, 83, 90, 102], "\u0440\u0435\u0437\u043e\u043d": [23, 56], "\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f": [23, 34], "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446": [23, 37, 73, 93], "\u0432\u044b\u0445\u043e\u0434": [23, 38, 47, 56, 74, 75, 86, 92], "\u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430": 23, "\u043d\u0430\u0437\u044b\u0432": [23, 73], "outbox": [23, 30], "comes": [23, 38, 70, 72, 73, 74, 75, 85, 86], "communicate": [23, 73, 100], "3rd": [23, 49, 51, 52, 53, 64, 82], "party": [23, 38, 46, 85, 86], "mail": 23, "generic": 23, "gave": [23, 41, 46, 72, 85], "fits": 23, "best": [23, 34, 37, 38, 49, 52, 53, 64, 68, 72, 74, 75, 76, 82, 85, 86, 100], "trasactional": 23, "were": [23, 34, 37, 38, 41, 47, 52, 62, 70, 73, 74, 75, 76, 85, 86, 94, 100], "introduced": [23, 38, 52, 75], "\u0441\u0432\u044f\u0437\u044b\u0432\u0430": 23, "\u043e\u043a\u043e\u043d\u0447\u0430\u043d": 23, "\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b": [23, 85], "\u0442\u0440\u0438": [23, 38, 64, 76, 82, 85, 100], "\u0443\u0442\u043e\u0447\u043d\u0435\u043d": [23, 100, 102], "persisted": 23, "ul": 23, "pl": 23, "\u043d\u0430\u0431\u043b\u044e\u0434\u0430": [23, 38, 40, 74, 75, 76, 77, 82, 85, 88, 92, 95, 102], "processed": [23, 34], "\u0441\u0441\u044b\u043b": 23, "\u043f\u0440\u0438\u0440\u0430\u0432\u043d\u0438\u0432\u0430": 23, "\u0432\u043d\u0435": [23, 30, 86], "\u043f\u0443\u0431\u043b\u0438\u043a": 23, "twitter": [23, 82], "\u0440\u0430\u0437\u044a\u044f\u0441\u043d\u0435\u043d": 23, "sth": 23, "occured": 23, "\u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430": [23, 38, 70, 74, 86], "\u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446": [23, 74, 90, 100], "\u0438\u0434\u0443\u0442": [23, 38], "pppddd": 23, "distinction": [23, 38, 46, 85], "confusion": [23, 52, 82], "lead": [23, 38, 70, 85, 86], "poor": [23, 37, 74], "crucial": [23, 100], "whereas": [23, 34, 85], "ii": [23, 85], "differentiating": 23, "limited": [23, 38, 49, 73, 77, 86, 92], "ok": [23, 37, 38, 39], "listing": [23, 85], "showed": 23, "poses": 23, "become": [23, 34, 37, 49, 51, 74, 75, 82, 85, 86, 95], "coupled": [23, 37, 74, 76, 85], "conversely": 23, "flat": 23, "correlational": 23, "typified": 23, "learned": [23, 37, 38, 76, 77, 86], "versioned": 23, "differentiator": 23, "compile": 23, "compiled": [23, 75], "illustrates": [23, 86], "sequence": [23, 34, 38], "differences": [23, 38, 85, 86, 100], "namespaces": 23, "accentuate": 23, "basically": 23, "solve": [23, 37, 38, 60, 73, 76, 82, 86, 90, 100], "scoped": 23, "eventbus": 23, "anymore": 23, "semantically": 23, "pushed": 23, "dispatcher": 23, "ioc": [23, 94], "hand": [23, 38, 77, 85, 100], "subsystems": [23, 51, 74, 86, 90], "otherwise": [23, 47], "inter": [23, 86], "commercial": [23, 38], "mailbox": [23, 34], "ideally": 23, "push": [23, 38], "generate": [23, 38, 72, 85, 86], "finally": [23, 37, 76], "mention": 23, "propagation": [23, 86], "carrying": [23, 38], "importantly": [23, 51], "tightly": [23, 38, 75], "feeling": [23, 73, 85], "seldom": 23, "chosen": [23, 38], "carefully": [23, 29, 34, 37, 38, 65, 74, 86, 88, 90, 100], "ubiquitous": [23, 38, 100], "granularity": [23, 52], "stable": [23, 38, 46, 62, 65, 77], "quickly": [23, 46, 47, 49, 51, 73, 74, 76, 82, 86], "during": [23, 37, 38, 49, 70, 75, 88, 100], "rarely": [23, 37, 38, 76, 86], "altered": [23, 76], "said": [23, 34, 37, 38, 41, 46, 65, 73, 74, 75, 85, 86, 92], "universally": 23, "heuristic": [23, 77], "closed": [23, 75], "forward": [23, 38, 47], "storing": 23, "forwarding": 23, "xa": 23, "middleware": 23, "shares": 23, "band": 23, "arrange": 23, "refer": [23, 74, 75, 85], "\u0441\u0442\u0443\u043f\u0435\u043d": [23, 73], "gof": [23, 37, 76, 85, 94], "\u043f\u043e\u0442\u043e\u043a": [23, 30, 34], "effective": [23, 37, 38, 46, 72, 74, 76, 77, 80, 82, 85], "lightweight": [23, 38, 51, 86], "sake": [23, 37, 76], "naming": [23, 85], "acknowledged": [23, 34, 38], "examples": [23, 34, 38, 51, 82, 85, 89, 93], "subscribing": 23, "registered": 23, "subscriber": 23, "notified": 23, "implies": [23, 38, 74, 75, 85, 86], "controlled": 23, "direct": 23, "considering": [23, 74], "halves": 23, "register": 23, "prior": [23, 51], "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0435\u0440\u0435\u0436\u0435\u043d": [23, 88], "breaks": [23, 77], "\u043c\u0435\u0441\u0442": [23, 38, 40, 46, 70, 72, 73, 75, 76, 83, 85, 86, 88, 90, 92, 102], "\u0438\u043b\u043b\u044e\u0437": [23, 40, 93], "\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f": 23, "\u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d": [23, 70, 102], "\u043e\u0434\u043d\u043e\u0444\u0430\u0437\u043d": 23, "delivered": [23, 34, 38, 59, 74, 77, 86], "retrieves": 23, "executes": 23, "obeying": 23, "\u0440\u0430\u0441\u0441\u0435\u0438\u0432\u0430": 23, "pretty": [23, 70], "looks": [23, 73, 74, 75], "invoke": 23, "collections": 23, "db": [23, 82], "\u043f\u0440\u0435\u0434\u043b\u043e\u0436": [23, 38, 86], "emitted": 23, "causes": [23, 34, 38], "caused": [23, 34], "timer": [23, 34], "expires": 23, "week": [23, 37, 38, 65, 72, 82, 85, 95], "month": [23, 38, 41, 65, 74, 76, 82, 86], "ending": 23, "period": [23, 34, 41], "reject": [23, 34], "frame": [23, 37], "expired": 23, "cares": [23, 73], "expiration": 23, "modeled": [23, 51], "occurrence": 23, "initiates": 23, "retained": 23, "removal": [23, 74], "record": 23, "happening": 23, "implicit": 23, "filter": 23, "consequence": [23, 76], "initiated": [23, 65], "leanpub": [23, 82], "eventstorming": [23, 76, 82], "alberto": [23, 82, 86], "brandolini": [23, 82, 86], "immutable": [23, 26, 82], "timestamp": 23, "rejected": [23, 34], "inappropriate": [23, 75], "supply": 23, "product": [23, 37, 38, 40, 41, 46, 51, 65, 74, 75, 76, 80, 85, 86, 100], "funds": 23, "history": [23, 34, 37, 76, 82], "denied": 23, "carry": [23, 29, 60, 66, 70, 73, 86, 90], "statement": [23, 52, 76, 85, 94], "verb": 23, "tense": 23, "productcreated": 23, "scrum": [23, 37, 40, 49, 51, 52, 64, 65, 66, 76, 80, 82], "releasescheduled": 23, "sprintscheduled": 23, "backlogitemplanned": 23, "backlogitemcommitted": 23, "clearly": [23, 38, 76, 82, 85], "concisely": 23, "noted": [23, 65], "earlier": [23, 29, 70, 74, 86], "characteristic": [23, 86], "previous": [23, 34, 85], "\u043f\u0440\u043e\u0448\u043b": [23, 38, 73, 94, 102], "\u0438\u043d\u0438\u0446\u0438\u0438\u0440\u043e\u0432\u0430": [23, 88], "\u043a\u043e\u043c\u043f\u0435\u043d\u0441\u0430\u0446\u0438\u043e\u043d": 23, "undo": 23, "\u043a\u043e\u043c\u043f\u0435\u043d\u0441\u0438\u0440": [23, 74, 90], "redo": 23, "moment": [23, 65, 68, 72, 85], "themselves": [23, 37, 74, 76, 86, 90], "placed": [23, 38], "undone": 23, "harmlessly": 23, "undoing": 23, "\u0440\u0430\u043c\u043a": [23, 37, 38, 46, 47, 70, 85, 92, 100, 102], "\u043f\u043e\u0441\u0442": [23, 34, 75, 83], "undesirable": 23, "roll": 23, "currently": 23, "lives": [23, 74], "probably": [23, 42, 85, 86], "failed": [23, 41], "her": [23, 38, 86], "she": 23, "tries": [23, 34], "trying": [23, 37, 74, 76, 85], "fault": 23, "tolerant": 23, "sacrifices": 23, "upsetting": 23, "customers": [23, 37, 38, 49, 52, 76, 82, 85], "orders": [23, 82], "everybody": [23, 38, 42], "inconsistent": [23, 49], "wishes": 23, "processes": [23, 37, 38, 49, 52, 59, 60, 62, 63, 64, 65, 76, 77, 82, 85, 86], "building": [23, 34, 37, 38, 46, 52, 70, 74, 76, 82, 86, 100], "commerce": [23, 37, 76], "inconsistency": 23, "\u0437\u0430\u0442\u0440\u0430\u0442": [23, 37, 38, 40, 70, 72, 86, 94], "\u0431\u0430\u0437\u0438\u0440\u043e\u0432\u0430": 23, "\u0440\u0435\u043b\u0438\u0433\u0438\u043e\u0437\u043d": 23, "\u0434\u043e\u0433\u043c\u0430\u0442\u0438\u0437\u043c": 23, "\u043e\u0441\u043d\u043e\u0432\u044b\u0432": 23, "\u0431\u0435\u0437\u0434\u0443\u043c\u043d": 23, "\u0432\u0435\u0440": [23, 83, 92, 93, 94], "\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d": 23, "\u0441\u0442\u043e\u044f": [23, 38, 83], "\u0443\u0434\u0438\u0432": 23, "\u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d": [23, 34, 92], "\u0443\u043f\u0440\u043e\u0449\u0435\u043d": [23, 38, 73, 74, 100], "\u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430": [23, 72, 83], "\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d": [23, 40, 72, 85, 92], "26": [23, 100], "\u0447\u0438\u0441\u0442\u043e\u0442": 23, "abstract": [23, 85], "machines": 23, "\u043d\u0430\u0433\u043b\u044f\u0434\u043d": [23, 38, 82, 85, 90, 93], "\u0438\u0437\u0443\u0447\u0430": [23, 65, 90], "\u0432\u044b\u0432\u043e\u0434": [23, 38, 65, 70, 75, 80, 83, 85, 86, 90, 92, 100], "\u0432\u0438\u043a\u0438\u043f\u0435\u0434": [23, 34, 75, 85, 100], "\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443": 23, "\u0431\u0443\u0444\u0435\u0440": 23, "\u0442\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u043e\u0432\u0430": 23, "pseudo": [23, 74], "random": 23, "generators": 23, "exercise": [23, 38, 39, 46, 70, 74, 86], "\u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440": 23, "\u0441\u043b\u0443\u0447\u0430\u0439\u043d": [23, 92], "\u0447\u0438\u0441\u0435\u043b": [23, 93], "\u0440\u0435\u0441\u0443\u0440\u0441": [23, 34, 38, 40, 70, 85, 86, 92, 95, 100], "\u0438\u0433\u0440\u0430": [23, 85, 86, 92, 95], "\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d": [23, 75, 89], "\u043a\u0440\u0438\u0432": [23, 37, 70, 89, 94], "\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d": [23, 42, 46, 70, 72, 73, 75, 76, 85, 86, 100, 102], "concrete": [23, 37, 62, 65, 77, 82, 85, 93], "\u0438\u0437\u0443\u0447\u0435\u043d": [23, 93], "\u0433\u043b\u0443\u0431\u043e\u043a": [23, 37, 73], "\u0441\u043f\u0435\u043a\u0442\u0440": [23, 100, 102], "\u0434\u043e\u0433\u043c\u0430\u0442\u0438\u0447\u043d": 23, "\u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442": [23, 86], "\u043e\u0442\u043a\u0430\u0442": 23, "\u0443\u0442\u0440\u0430\u0447": 23, "\u0430\u0432\u0430\u0440\u0438\u0439\u043d": [23, 86], "\u043e\u0442\u043f\u0440\u0430\u0432\u043b": [23, 34], "\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442": [23, 82, 86, 92], "chris": [23, 34, 82], "richardson": [23, 34, 82], "\u043d\u0430\u0437\u044b\u0432\u0430": [23, 37, 41, 52, 70, 74, 75, 76, 80, 86, 93, 100], "\u043f\u043e\u0441\u0432\u044f\u0449\u0430": [23, 46, 83], "spreading": 23, "news": 23, "endpoints": 23, "solutions": [23, 34, 37, 38, 70, 82, 86], "gregor": [23, 34, 38, 39, 65, 66, 75, 76, 82, 88, 92], "hohpe": [23, 34, 38, 39, 65, 66, 75, 76, 82, 88, 92], "bobby": [23, 34, 82], "woolf": [23, 34, 82], "akka": [23, 30, 34, 82], "front": [23, 29, 37, 52, 74, 76, 80], "sender": 23, "mining": 23, "\u0432\u043f\u0435\u0440\u0432": [23, 37, 75, 82], "acid": 23, "partitioned": [23, 86], "trading": [23, 38, 68, 70, 82], "dramatic": 23, "improvements": [23, 38], "acm": [23, 34], "ebay": 23, "architect": [23, 37, 38, 51, 74, 76, 82, 86], "dan": [23, 82, 88], "pritchett": 23, "2008": [23, 64, 88], "\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d": [23, 30, 34, 40, 41, 86], "\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b": [23, 34, 100], "\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432": [23, 42, 47, 70, 73, 83, 85, 86, 94], "\u043e\u0436\u0438\u0434\u0430": [23, 68, 70, 88], "causal": [23, 31, 34, 116], "arrive": [23, 34], "recognize": [23, 34, 37, 76, 86, 100], "causality": [23, 34], "wait": [23, 34, 65], "newly": [23, 34], "arrived": [23, 34], "latent": [23, 34], "superseded": [23, 34], "dismissible": [23, 34], "actors": [23, 34, 82], "prepared": [23, 34, 46, 73], "perfect": [23, 34, 77, 82], "timing": [23, 34], "reaction": [23, 34], "beforehand": [23, 34], "dealt": [23, 34, 38, 86], "gracefully": [23, 34], "routing": 23, "resequencer": [23, 34], "framework": [23, 34, 38, 49, 51, 52, 64, 75, 82], "camel": [23, 34], "\u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440": 23, "nats": [23, 34, 82], "option": [23, 34, 38, 39, 70, 74], "sessions": [23, 34, 86], "guarantees": [23, 34, 38], "session": [23, 34, 74], "timestamps": [23, 34], "receiving": [23, 34], "rejects": [23, 34], "puts": [23, 34, 37, 74], "onto": [23, 34, 86], "dominic": [23, 34, 82], "juli\u00e1n": [23, 34, 82], "dom\u00ednguez": [23, 34, 82], "grigori": [23, 34, 82], "melnik": [23, 34, 82], "fernando": [23, 34, 82], "simonazzi": [23, 34, 82], "mani": [23, 34, 82], "subramanian": [23, 34, 82], "\u043a\u043e\u043d\u043a\u0443\u0440\u0438\u0440": [23, 30, 33, 77, 118], "competing": [23, 34, 38, 77], "receivers": [23, 34], "redelivery": [23, 34], "guaranteed": [23, 34, 77, 85], "resend": [23, 34], "suppose": [23, 34, 70], "receives": [23, 34], "acknowledge": [23, 34, 37, 38, 76], "produced": [23, 34, 38, 49, 74], "sends": [23, 34], "kicks": [23, 34], "conclusion": [23, 34, 37, 70, 80, 86], "offer": [23, 34], "redeliver": [23, 34], "startup": [23, 34, 38, 46, 76], "durable": [23, 34], "stalled": [23, 34], "outstanding": [23, 34], "maxinflight": [23, 34], "resumes": [23, 34], "acking": [23, 34], "redelivered": [23, 34], "interleaved": [23, 34], "streaming": [23, 34], "187": [23, 34], "kozlovic": [23, 34], "combining": 23, "specialized": 23, "deriving": [23, 37], "capture": 23, "intensive": [23, 34, 37, 76, 82], "reliable": [23, 34, 82], "maintainable": [23, 34, 82], "kleppmann": [23, 34, 82], "\u043e\u0441\u0432\u0435\u0449\u0430": [23, 34, 40, 76, 83, 92], "reliability": [23, 34, 51, 73, 82], "operating": [23, 34, 82], "resilient": [23, 34, 37, 64, 76, 82], "laine": [23, 34, 82], "campbell": [23, 34, 82], "charity": [23, 34, 82], "majors": [23, 34, 82], "settle": [23, 30, 34], "stronger": [23, 30, 34, 38], "geo": [23, 30, 34], "replicated": [23, 30, 34], "storage": [23, 30, 34], "wyatt": [23, 30, 34], "lloyd": [23, 30, 34], "facebook": [23, 30, 34], "kaminsky": [23, 30, 34], "intel": [23, 30, 34], "labs": [23, 30, 34], "andersen": [23, 30, 34], "carnegie": [23, 30, 34], "mellon": [23, 30, 34], "bolt": [23, 30, 34], "peter": [23, 30, 34, 66, 82, 88], "bailis": [23, 30, 34], "ali": [23, 30, 34, 82], "ghodsi": [23, 30, 34], "joseph": [23, 30, 34], "hellerstein": [23, 30, 34], "ion": [23, 30, 34], "stoica": [23, 30, 34], "uc": [23, 30, 34], "berkeley": [23, 30, 34], "kth": [23, 30, 34], "royal": [23, 30, 34], "institute": [23, 30, 34, 37, 38, 52, 64, 82, 86], "detecting": [23, 34], "search": [23, 34, 51], "holy": [23, 34], "grail": [23, 34], "reinhard": [23, 34], "schwarz": [23, 34], "friedemann": [23, 34], "mattern": [23, 34], "sebastian": [23, 34], "burckhardt": [23, 34], "research": [23, 34, 38, 72, 85], "eventsourcing": [23, 34, 82], "bywater": [23, 34, 82], "vclock": [23, 34], "offers": [23, 86], "vector": [23, 34], "clock": [23, 34, 86], "clocks": 23, "recording": 23, "analyzing": [23, 62], "inherent": [23, 52, 74, 90], "partial": 23, "gustavo": [23, 34], "niemeyer": [23, 34], "info": [23, 82], "\u043e\u0431\u0437\u043e\u0440\u043d": [23, 82, 89], "guest": 23, "logs": 23, "byron": 23, "ruth": 23, "\u0443\u0432\u0438\u0434\u0435\u0442": [23, 56, 74, 85, 86], "\u0436\u0438\u0432": [23, 90], "\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a": 23, "\u0443\u043d\u0438\u0447\u0442\u043e\u0436": 23, "\u0438\u0437\u044a\u044f": [23, 86], "\u043a\u043e\u043c\u043d\u0430\u0442": [23, 100], "\u0437\u0430\u043d\u043e\u0437": 23, "\u043f\u0440\u0438\u043c\u0435\u043d": [23, 37, 72, 85], "\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430": [23, 74, 76], "\u0432\u0441\u0442\u0430\u0432\u043b": 23, "\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d": [23, 38, 51, 82, 83, 86, 88, 90, 93], "\u0436\u0438\u0437\u043d\u0435\u043d": [23, 64, 65, 74, 76, 82, 86], "\u0446\u0438\u043a\u043b": [23, 37, 41, 64, 65, 76, 82, 85, 86], "\u0443\u043c\u0435\u0441\u0442\u043d": [23, 34, 72, 85, 92, 94], "\u043f\u0435\u0440\u0435\u0445\u043e\u0434": [23, 34, 37, 46, 47, 74, 77, 85, 88, 95], "\u0437\u0430\u043c\u0435\u0442\u043d": [23, 88, 94, 100], "\u0432\u043b\u0430\u0434\u0435\u044e\u0449": [23, 86], "\u0441\u043a\u0440\u044b\u0442": [23, 29, 85], "domainobject": 23, "markremoved": 23, "registration": 23, "onus": 23, "removed": [23, 29, 52], "usual": [23, 38, 70, 74], "registers": 23, "setting": [23, 86], "dirty": [23, 74], "tedious": 23, "aspect": [23, 60, 73, 75, 76, 85, 90, 100], "nongenerated": 23, "turns": [23, 74], "suited": [23, 38], "examined": 23, "looked": [23, 70, 86], "inserted": 23, "finicking": 23, "feels": [23, 46, 47], "separates": [23, 38], "regular": 23, "cleanly": 23, "commonplace": 23, "expect": [23, 62, 73, 75, 86], "\u0432\u0441\u0442\u0430\u0432": 23, "\u043d\u0435\u043e\u0431\u0445\u043e\u0434": 23, "\u0430\u0432\u0442\u043e\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u043d": 23, "\u0432\u043b\u043e\u0436": 23, "\u043f\u0440\u0438\u0441\u0432\u043e": 23, "\u0441\u043d\u0430\u0431\u0434": 23, "istransient": 23, "\u043e\u0442\u043b\u043e\u0436\u0435\u043d": [23, 41], "\u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446": [23, 37, 70, 73, 74, 75, 77, 90, 93, 100], "\u0445\u043e\u0447": [23, 73], "\u0432\u043e\u0437\u044c\u043c": [23, 74, 92], "\u0444\u0440\u0430\u0437": [23, 37, 38, 40, 85, 86, 88, 100], "\u043f\u043e\u0441\u043b\u0443\u0436": 23, "\u043c\u043d": 23, "\u0432\u0437\u0430\u0438\u043c\u043e\u0441\u0432\u044f\u0437": [23, 86], "\u0441\u043e\u0441\u0442\u0430\u0432": [23, 38, 70, 75], "\u0432\u0441\u044f\u043a": [23, 75, 88, 92, 100], "\u0435\u0434": 23, "\u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d": [23, 38, 75, 86], "\u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432": [23, 34, 85], "\u043f\u0430\u043a\u0435\u0442\u043d": 23, "\u0438\u043c\u0435\u044e\u0449": [23, 34, 75, 100], "\u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d": [23, 38], "\u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d": [23, 37, 38, 41, 70, 75, 83, 85, 88, 90, 92], "clear": [23, 34, 37, 51, 70, 74, 76, 86, 100], "spoken": 23, "goes": [23, 37, 38, 41, 62, 74, 76, 82, 86, 95], "beyond": [23, 34, 49, 76, 82, 85, 86], "leaves": [23, 73, 85], "\u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u0434\u0448": 23, "\u043c\u0430\u0441\u0448\u0442\u0430\u0431": 23, "\u043f\u0440\u0435\u0434\u043f\u0440\u0438\u044f\u0442": [23, 100], "\u0434\u0430\u043b\u0435\u043a": [23, 82, 85, 86, 92], "\u043e\u0431\u043b\u0435\u0433\u0447\u0435\u043d": 23, "\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442": [23, 29, 75, 92], "\u0438\u0437\u0434\u0430\u0442\u0435\u043b": 23, "\u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442": [23, 30, 74], "\u0442\u0440\u0430\u043a\u0442\u043e\u0432\u043e\u043a": 23, "\u0442\u0440\u0430\u043a\u0442": 23, "\u0440\u0438\u0441": [23, 73, 86, 94, 100], "\u043f\u043b\u0430\u0441\u0442": 23, "\u043f\u0440\u0435\u0434\u0441\u0442\u043e": [23, 82, 88], "\u043f\u0435\u0440\u0435\u0440\u0430\u0431\u043e\u0442\u0430": [23, 47], "\u043f\u043e\u0441": 23, "\u0443\u0434\u0435\u043b\u044f": 23, "\u043e\u0441\u043e\u0437\u043d\u0430\u0432": 23, "footnotes": [23, 85], "v2": [23, 82], "mirror": [23, 82], "17": [23, 51, 66, 68, 70, 75, 82, 83, 85], "encapsulated": [23, 29, 82], "21": [23, 37, 70, 85], "uncovering": 23, "27": [23, 74, 75], "28": [23, 38, 74], "\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432": 26, "\u043a\u043e\u043f\u0438\u0440": 26, "\u043d\u0443\u0436\u0434\u0430": [26, 82, 86, 92], "\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446": 26, "\u043f\u043e\u0442\u0440\u0435\u0431": [26, 70, 85, 86], "\u0437\u0430\u043f\u0440\u0435\u0449\u0435\u043d": 26, "\u0437\u0430\u043c": [26, 102], "\u0443\u0433\u043e\u0434\u043d": [26, 38, 70, 85, 100], "\u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446": 26, "3\u043d\u0430\u0447\u0435\u043d": 26, "\u043f\u043e\u0432\u0440\u0435\u0436\u0434": 26, "\u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446": 26, "\u0438\u0441\u043a\u0430\u0436\u0435\u043d": [26, 38, 40, 88, 89, 92, 100], "pointer": 26, "against": [26, 42, 63, 68, 76, 85, 86], "safely": [26, 37, 74, 90], "except": [26, 52, 73, 85], "replacement": [26, 52, 86], "passes": [26, 34, 85, 86], "wandering": 26, "owner": [26, 38, 40, 51, 80, 86], "corrupts": 26, "violating": [26, 75], "avoided": [26, 38, 46], "immutability": [27, 82, 114], "dddesign": 29, "adapter": 29, "acl": 29, "translator": 29, "translate": 29, "reshaped": 29, "hydrating": 29, "languages": [29, 37, 38, 51, 75, 82], "translating": [29, 38], "adapting": 29, "shapes": [29, 76], "duplicate": [29, 46, 82], "replicating": 29, "duplicating": 29, "bad": [29, 65, 74, 75, 76, 82, 85, 88, 94], "demonstrates": [29, 38, 85, 86], "challenges": [29, 38, 88], "pm": 29, "autonomy": [29, 86], "quality": [29, 37, 38, 40, 41, 42, 46, 51, 53, 64, 65, 66, 73, 74, 75, 82, 86], "collaboration": [29, 37, 49, 76, 85, 86], "saasovation": 29, "had": [29, 37, 38, 41, 70, 72, 73, 74, 76, 77, 85, 86, 94], "imperfect": 29, "continuous": [29, 37, 38, 51, 68, 74, 75, 76, 82, 85, 86, 94], "improvement": [29, 73, 75, 86], "matters": [29, 37, 38, 52, 73, 74, 76, 86], "deliver": [29, 37, 38, 52, 62, 73, 76, 77], "outcomes": [29, 51], "choices": [29, 68], "clearer": [29, 85], "\u043e\u0442\u043b\u0438\u0447\u0438\u0442\u0435\u043b\u044c\u043d": [29, 82, 92, 100], "ports": 29, "port": 29, "\u043f\u043e\u0434\u0434\u0435\u043b\u0430": 29, "mediates": 29, "layers": [29, 76], "acting": [29, 75], "declaratively": 29, "submit": 29, "satisfaction": 29, "scenes": 29, "homepage": 29, "optimistic": 30, "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440": 30, "\u043e\u0431\u0441\u0442\u043e": [30, 75, 86], "\u043f\u043e\u043b\u043e\u0436\u0435\u043d": [30, 38, 56, 73, 74, 83, 86, 88, 92], "\u0436\u0443\u0440\u043d\u0430\u043b": 30, "\u0432\u0437\u0430\u0438\u043c\u043e\u0441\u0432\u044f\u0437\u0430": 30, "\u043f\u043e\u043c\u0435\u0447\u0430": 30, "correlationid": [30, 34], "\u043d\u0430\u0440\u0443\u0448\u0435\u043d": [30, 85], "\u043e\u0447\u0435\u0440\u0435\u0434\u043d": [30, 38, 85, 86], "\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d": [30, 34, 82], "\u043d\u0430\u043f\u0440\u0430\u0432\u043b": [30, 75], "\u043f\u0435\u0442\u043b": 30, "\u0442\u043e\u043f\u043e\u043b\u043e\u0433": [30, 83, 86], "\u043c\u0430\u0440\u0448\u0440\u0443\u0442": [30, 90], "\u043e\u0441\u0442\u0430\u0432\u043b\u044f": [30, 82, 85, 86], "\u0436\u0435\u043b\u0430": [30, 42, 46, 73, 77, 82, 86], "\u0441\u043f\u0430\u0441\u0430": 30, "\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430": 30, "\u0433\u0440\u0443\u0431": [30, 38, 86, 92], "\u043e\u0442\u0441\u044b\u043b\u0430": [30, 75, 85], "\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a": 30, "\u043a\u043e\u043c\u0438\u0442\u0435\u0442": 30, "\u0448\u043a\u043e\u043b\u044c\u043d": 30, "\u0440\u0430\u0441\u0441\u044b\u043b\u043a": 30, "e1": 30, "\u0440\u0430\u0437\u043e\u0441\u043b\u0430": 30, "\u0441\u0431\u043e\u0440": [30, 86], "\u0434\u0435\u043d\u0435\u0433": 30, "\u043f\u043e\u0434\u0430\u0440\u043e\u043a": 30, "e2": 30, "e3": 30, "\u0437\u0430\u0434\u0435\u0440\u0436\u0430": 30, "\u0432\u0435\u043a\u0442\u043e\u0440\u043d": 30, "\u0441\u043d\u0430\u0431\u0436\u0430": [30, 85], "\u043e\u0431\u043d\u0430\u0436\u0430": [30, 72], "\u0435\u0434\u0438\u043d\u043e\u0436\u0434": [30, 74], "\u043f\u043e\u0440\u044f\u0434\u043a\u043e\u0432": 30, "\u043d\u043e\u043c\u0435\u0440": [30, 34, 93], "\u043f\u043e\u043d\u0438\u0436\u0435\u043d": [30, 65], "sequential": [30, 34, 86], "\u0442\u0440\u0443\u0434\u043e\u0435\u043c\u043a": 30, "\u043c\u0438\u0433\u0440\u0430\u0446": 30, "\u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436": [30, 70, 72, 85, 88], "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430": 30, "\u043e\u0431\u0449\u0435\u043f\u0440\u0438\u043d\u044f\u0442": [30, 74], "agregate": 30, "\u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d": [30, 73, 74, 75, 90], "\u0443\u0441\u043b\u043e\u0436\u043d\u0435\u043d": [30, 70, 73, 77], "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u0446": 30, "\u0432\u044b\u0431\u043e\u0440\u043a": 30, "\u043e\u0431\u043d\u043e\u0432\u043b\u044f": 30, "\u0432\u044b\u0447\u0438\u0441\u043b\u044f": 30, "\u0441\u0434\u0432\u0438\u0433\u0430": 30, "\u0432\u044b\u043d\u0435\u0441\u0435\u043d": 30, "\u043d\u0435\u0438\u0437\u043c\u0435\u043d": [30, 38, 65, 85], "anticorruption": [31, 116], "sdlc": [32, 52, 65, 76, 80, 100, 117], "\u0441\u0430\u043c\u043e\u043e\u0431\u0443\u0447\u0435\u043d": [32, 83, 92, 93, 95, 117], "tdd": [32, 37, 72, 74, 76, 93, 94, 117], "topologies": [32, 76, 82, 86, 117], "\u043d\u0435\u043f\u0440\u043e\u0441\u0442": 34, "\u043d": [34, 38, 46, 74, 82, 83, 86, 88, 92], "\u043f\u043e\u043f\u0430\u0434\u0430": [34, 73], "\u043e\u0431\u043e\u0433\u043d\u0430": 34, "\u0438\u0437\u0434\u0435\u0440\u0436\u043a": [34, 86], "\u0441\u0431\u043e\u0440\u0449\u0438\u043a": 34, "\u043c\u0443\u0441\u043e\u0440": 34, "\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434": 34, "ack": 34, "round": [34, 86], "robin": 34, "\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a": [34, 73], "\u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d": 34, "jetstream": [34, 82], "rely": [34, 77, 85, 86], "slow": [34, 37, 38, 41, 47, 74, 76, 86], "\u043e\u0431\u0445\u043e\u0434\u043d": 34, "subject": [34, 51], "namespace": 34, "distribute": 34, "forethought": [34, 37, 76], "preserve": 34, "wildcard": 34, "subscriptions": 34, "giving": [34, 38, 85, 86, 93], "yourself": [34, 37, 47, 70, 73, 82, 85, 95], "room": [34, 37, 74, 76], "expand": 34, "telemetry": 34, "iot": 34, "devices": 34, "located": 34, "throughout": [34, 37, 52, 70, 74, 75, 76], "city": 34, "sensors": 34, "north": 34, "south": [34, 75], "east": 34, "west": [34, 38], "initially": [34, 38, 72], "grows": [34, 74, 75, 80], "exceed": [34, 64], "replace": [34, 52], "four": [34, 37, 38, 42, 74, 85, 86], "representing": [34, 85], "segment": [34, 86], "untouched": 34, "subscription": [34, 38, 46], "serially": 34, "concurrently": 34, "move": [34, 37, 62, 72, 73, 74, 76, 85], "picked": 34, "threads": 34, "\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446": [34, 86], "\u0437\u0430\u043f\u043e\u043c\u043d": [34, 38, 82, 85], "\u0441\u043e\u0446": 34, "\u0434\u0440\u0443\u0437": [34, 82], "\u0448\u043b\u0435\u0442": 34, "\u0434\u0438\u0441\u043a\u0440\u0435\u0434\u0438\u0442\u0438\u0440": 34, "\u043e\u0442\u043f\u0440\u0430\u0432\u043a": 34, "\u0445\u0440\u043e\u043d\u043e\u043b\u043e\u0433": 34, "\u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430": [34, 75], "\u043d\u0438\u0432\u0435\u043b\u0438\u0440\u043e\u0432\u0430": 34, "\u0441\u0438\u043c\u043f\u0442\u043e\u043c": [34, 100], "\u043f\u043e\u043e\u0447\u0435\u0440\u0435\u0434\u043d": 34, "\u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440": [34, 37, 40, 75, 81, 83, 92, 93, 95, 135], "lecture": [34, 82], "including": [34, 37, 52, 74, 76, 82], "exercises": [34, 82], "video": [34, 82], "dive": [34, 82], "alex": [34, 82], "petrov": [34, 82], "paradigms": [34, 82], "3d": [34, 37, 49, 51, 64, 66, 75, 76, 82, 86, 90], "andrew": [34, 82, 94], "tanenbaum": [34, 82], "maarten": [34, 82], "steen": [34, 82], "\u043a\u043e\u0441\u044f\u043a": [34, 82], "\u043c": [34, 37, 56, 73, 75, 76, 82, 83, 88, 92, 102], "\u0441\u043f\u0431": [34, 82, 88], "\u0438\u0442\u043c": [34, 82], "75": [34, 38, 73, 82], "155": [34, 82], "adam": [34, 82], "bellemare": 34, "deterministic": 34, "stream": 34, "fun": [34, 38, 47, 82], "profit": [34, 38, 82], "2013": [34, 38, 49, 82], "tyler": 34, "akidau": 34, "slava": 34, "chernyak": 34, "reuven": 34, "lax": 34, "watermarks": 34, "dataflow": 34, "correctness": 34, "massive": [34, 38, 46, 76], "unbounded": 34, "bradshaw": 34, "chambers": [34, 38], "rafael": 34, "fernandez": 34, "moctezuma": 34, "sam": [34, 77, 82, 86, 92], "mcveety": 34, "daniel": 34, "mills": [34, 86], "frances": 34, "perry": 34, "schmidt": [34, 82], "whittle": 34, "blocks": [34, 82], "\u043c\u0438\u0445\u0430": 34, "\u0442\u044e\u043b\u0435\u043d": 34, "mongodb": 34, "\u0442\u0435\u043e\u0440": [34, 75, 82, 86, 89, 102], "unmesh": 34, "joshi": [34, 86], "marc": 34, "graauw": 34, "apache": 34, "gerardo": 34, "villeda": 34, "claus": 34, "ibsen": 34, "jonathan": 34, "anstey": 34, "vaughnvernon": 34, "reactivemessagingpatterns_actormodel": 34, "latest": [34, 38], "eips": 34, "camelinaction": 34, "camelinaction2": 34, "enterpriseintegrationpatterns": 34, "\u043a\u0430\u0442\u0430\u043b\u043e\u0433": 34, "jepsen": [34, 82], "\u0448\u043f\u0430\u0440\u0433\u0430\u043b\u043a": [34, 75, 82, 89], "eip": [34, 82], "prescriptive": [34, 82], "guidance": [34, 82], "homer": [34, 82], "sharp": [34, 82, 86], "larry": [34, 75, 82], "brader": [34, 82], "masashi": [34, 82], "narumoto": [34, 82], "trent": [34, 82], "swanson": [34, 82], "samples": [34, 82], "ms": 34, "corporation": [34, 82], "\u043f\u043e\u0434\u0440\u044f\u0434": 34, "carried": [34, 38], "martinfowler": 34, "articles": [34, 82], "201701": 34, "\u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430": 34, "\u043f\u0440\u043e\u043a\u0430\u0442\u044b\u0432\u0430": 34, "\u0443\u0445\u0443\u0434\u0448\u0430": [34, 73, 75, 100], "\u043a\u0430\u0441\u043a\u0430\u0434\u043d": [34, 65, 86], "\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d": [34, 92], "\u043f\u043e\u0441\u043b\u0435\u0434": [34, 40, 77, 90, 94], "m\u0435ssaging": 34, "router": 34, "\u0434\u043e\u0431\u0438\u0432\u0430": [34, 82, 83], "\u0443\u0437\u0435\u043b": 34, "\u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0446": 34, "rmpwam": 34, "cfm": 34, "2610533": 34, "papers": [34, 82], "bolton": 34, "sigmod2013": 34, "\u043f\u0430\u0440": [34, 40, 68, 74, 85, 86], "\u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434\u043d": [34, 37, 64, 66, 82], "\u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d": [34, 38, 74, 85, 92, 94], "\u0432\u0438\u0434\u0435\u043b": [34, 88, 90], "english": [34, 38, 75, 82, 92, 100], "kaushik": [34, 82], "sathupadi": [34, 82], "\u0442\u0440\u0435\u0442": [34, 46, 52, 85, 88, 94], "\u0445\u044c\u044e\u0438\u0442\u0442": 34, "\u043f\u0440\u043e\u0442": [34, 38, 68, 72, 76, 85, 88, 90], "\u0432\u043a\u043b\u044e\u0447\u0435\u043d": [34, 86, 100, 102], "\u043f\u0440\u0438\u0431\u044b\u0432\u0430": 34, "\u0430\u043a\u0442\u043e\u0440": 34, "\u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447": 34, "\u0432\u0445\u043e\u0434\u044f": [34, 75], "\u0441\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430": 34, "\u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430": 34, "\u043f\u043e\u0441\u0442\u0443\u043f\u0430": [34, 74], "fifo": 34, "m1": 34, "m2": 34, "\u0440\u0430\u043d\u044c\u0448": [34, 47, 64, 80], "p\u0430\u0437\u0434\u0435\u043b": 34, "\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d": 34, "\u0447\u0435\u0442\u0432\u0435\u0440\u0442": [34, 38], "\u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430": [34, 40, 85], "\u043f\u043e\u0441\u0442\u0443\u043f": [34, 83], "\u043f\u0440\u0435\u0434\u0448\u0435\u0441\u0442\u0432": [34, 37, 80, 86], "\u043e\u0441\u0442\u0430\u0432": [34, 37, 73, 76, 82], "\u0432\u044b\u044f\u0441\u043d\u0435\u043d": 34, "\u043f\u043e\u0442\u0440\u0430\u0442": [34, 38], "\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430": [34, 85], "\u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u044f": 34, "alexey": [34, 82, 89, 100], "zimarev": [34, 82, 100], "occasionally": 34, "connected": [34, 38], "\u0437\u0435\u0440\u043a\u0430\u043b\u044c\u043d": 34, "\u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0446": 34, "\u0433\u0430\u0440\u0430\u043d\u0442": [34, 88], "\u0431\u0443\u0444\u0435\u0440\u0438\u0437\u043e\u0432\u0430": 34, "\u043f\u043e\u0432\u0442\u043e\u0440\u043d": [34, 66, 70, 75], "\u043f\u0435\u0440\u0435\u0441\u044b\u043b\u0430": 34, "\u043f\u043e\u0432\u0440\u0435\u0436\u0434\u0435\u043d": 34, "generalizations": 34, "packets": 34, "internet": 34, "computing": [34, 73, 75, 82], "packet": 34, "paths": 34, "damaged": 34, "optimizations": [34, 73], "pipeline": [34, 82, 86], "designate": 34, "finished": [34, 38, 85], "mean": [34, 37, 38, 46, 51, 73, 75, 76, 85], "pipelined": 34, "tradeoff": [34, 38, 74], "computation": 34, "carl": [34, 76, 86], "hewitt": [34, 82], "mailboxes": 34, "\u0440\u0430\u0432\u043d": [34, 38, 40, 42, 70, 74, 85, 100, 102], "introduce": [34, 37, 74, 100], "third": [34, 46, 85, 86], "implied": [34, 38, 52], "individual": [34, 38, 51, 85, 86], "follow": [34, 62, 72, 73, 85, 86], "routes": 34, "likely": [34, 38, 52, 73, 74, 75, 76, 86, 90], "sooner": [34, 62, 74, 85], "resulting": [34, 38, 46, 52, 65, 70, 74, 76], "subsequent": [34, 59], "referential": 34, "integrity": [34, 86], "numbered": 34, "undergo": 34, "transformation": [34, 82], "odd": 34, "output": [34, 38, 85, 86], "bringing": [34, 85], "acknowledgment": 34, "conservative": 34, "drawbacks": 34, "significantly": [34, 65, 74], "severely": 34, "underutilize": 34, "power": [34, 37, 38, 41, 74, 76, 88], "increase": [34, 37, 38, 74, 77, 86], "throttling": 34, "erase": 34, "ourselves": [34, 38], "amc": 34, "130": 34, "preserved": 34, "journal": [34, 88], "causally": 34, "node": 34, "\u0432\u0436\u0438\u0432": 34, "\u0441\u0442\u0440\u043e\u0433\u043e\u0441\u0442": 34, "\u043b\u0438\u043d\u0435\u0430\u0440\u0438\u0437\u0430\u0446": 34, "\u043f\u043e\u0432\u044b\u0448\u0435\u043d": [34, 37, 74, 85, 86, 92], "\u0432\u044b\u0441\u0442\u0443\u043f\u0430": [34, 37, 52, 88, 102], "position": 34, "\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a": 34, "\u0443\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044c\u043d": [34, 86], "\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0435\u043d": [34, 73], "\u043e\u0431\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u0441\u0442\u0432": [34, 38, 85, 92, 102], "relating": 34, "po": [34, 38], "purchase": 34, "price": [34, 39, 85], "addressed": [34, 38], "outdated": 34, "prices": 34, "exempt": 34, "looser": 34, "realities": 34, "tightening": 34, "followed": 34, "\u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d": 34, "correlation": 34, "\u043c\u0435\u0442\u0430\u0434\u0430": 34, "causationid": 34, "misunderstood": 34, "causation": 34, "responding": [34, 37, 62], "conversation": [34, 52, 72], "cheers": 34, "discuss": [34, 86], "828": 34, "projections": [34, 38, 82], "putting": [34, 70, 74, 75, 82, 100], "\u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [36, 37, 38, 52, 56, 65, 70, 76, 80, 88, 95, 100, 120], "iterative": [37, 61, 64, 65, 75, 76, 77, 82, 86, 129], "frequent": [37, 38], "inspection": [37, 51, 76], "adaptation": [37, 38, 40, 52, 62, 64, 66, 68, 70, 74, 78, 80, 85, 86, 133], "incremental": [37, 38, 61, 63, 64, 65, 70, 76, 85, 90, 129], "deliveries": 37, "evolve": [37, 52, 65], "cross": [37, 38, 76, 86], "teams": [37, 38, 46, 49, 51, 52, 64, 65, 74, 75, 76, 82, 88], "continual": 37, "feedback": [37, 38, 42, 51, 68, 85, 86], "iso": [37, 38, 49, 52, 59, 60, 62, 63, 64, 65, 76, 77, 82], "iec": [37, 38, 49, 52, 59, 60, 62, 63, 64, 65, 76, 77, 82, 92], "ieee": [37, 38, 49, 52, 59, 60, 62, 63, 64, 65, 74, 76, 77, 82, 92], "12207": [37, 49, 52, 59, 60, 62, 63, 64, 65, 76, 82], "2017": [37, 38, 49, 52, 59, 60, 62, 63, 64, 65, 76, 82, 88], "reader": [37, 49], "supposedly": 37, "family": 37, "evolved": [37, 85], "born": 37, "belief": 37, "grounded": 37, "reality": [37, 77, 100], "innovation": [37, 38, 46, 86], "yield": 37, "jeff": [37, 38, 60, 62, 65, 82, 86], "sutherland": [37, 38, 65, 82, 86], "handbook": [37, 38, 52, 64, 65, 68, 73, 74, 82, 85, 86], "variety": [37, 76, 77], "evolutionary": [37, 38, 61, 65, 74, 76, 82, 85, 129], "lifecycle": [37, 52, 64, 76, 86], "stages": [37, 59, 60, 76, 86, 92], "emphasis": [37, 76, 100], "rapid": [37, 38, 65, 74, 76, 82, 85, 86], "unlike": [37, 52], "waterfall": [37, 52, 62, 65, 76, 80], "pieces": [37, 42, 70, 73, 74, 75, 77, 86, 90], "cycles": [37, 38, 77], "sprints": [37, 76], "today": [37, 39, 65, 70, 74, 76, 85], "widely": [37, 38, 53], "forms": [37, 77, 85], "weeks": [37, 73, 74, 76], "winter": [37, 76], "getaway": [37, 76], "turned": [37, 52, 76], "upside": [37, 76], "caroline": [37, 76], "mimbs": [37, 76], "nyce": [37, 76], "contrasts": 37, "styles": [37, 76, 82, 85], "prediction": [37, 65, 68, 70, 78, 86, 133], "\u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442": [37, 38, 39, 41, 46, 64, 65, 70, 72, 73, 75, 80, 83, 86], "\u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u043d": [37, 65, 80], "\u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d": [37, 86], "\u043e\u0431\u0440\u0430\u0442\u043d": [37, 38, 40, 74, 76], "\u044d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d": [37, 38, 40, 41, 80], "\u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430": [37, 75, 86], "\u043b\u043e\u0433\u0430\u0440\u0438\u0444\u043c\u0438\u0447\u0435\u0441\u043a": [37, 80], "\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0447\u0435\u0441\u043a": [37, 38, 40, 64, 65, 66, 75, 76, 80, 86], "\u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d": [37, 65, 80, 85], "\u0433\u0440\u0430\u0444\u0438\u043a": [37, 40, 46, 56, 65, 76, 80, 82, 83, 86, 94], "\u0432\u044b\u0447\u0435\u0442": 37, "\u043f\u0440\u0435\u0432\u044b\u0441": [37, 86], "\u0432\u044b\u043d\u0443\u0436\u0434": [37, 100], "\u043d\u0430\u0438\u043c\u0435\u043d\u044c\u0448": [37, 38, 56, 75, 90, 100], "catch": [37, 74, 86], "\u0441\u043e\u0433\u043b\u0430\u0441\u043d": [37, 85, 102], "\u0437\u0430\u043a\u043e\u043d": [37, 38, 72, 73, 74, 76, 82, 88, 89, 92, 94], "\u0434\u0438\u0430\u043b\u0435\u043a\u0442\u0438\u043a": [37, 100], "\u043f\u0440\u0438\u0432\u0435\u0441\u0442": [37, 38, 56, 72, 75, 86, 100], "\u0441\u0438\u043d\u0442\u0435\u0437": [37, 100], "\u0441\u0445\u043e\u0436": [37, 74], "\u0431\u0440\u0443\u043a\u0441": [37, 38, 56, 65, 72, 92, 100], "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0438\u0432": [37, 73, 75, 92], "\u043d\u0435\u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d": [37, 38, 75, 88, 89], "\u043e\u0442\u0441\u0442\u0443\u043f\u0430": 37, "\u0438\u0442\u0435\u0440\u0430\u0446": [37, 60, 62, 65, 77, 86, 90], "\u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d": [37, 38, 72, 85, 100], "\u044d\u0432\u043e\u043b\u044e\u0446": [37, 38, 68, 85, 86, 92], "\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d": [37, 38, 40, 52, 62, 64, 65, 75, 76, 77, 80], "\u043a\u0440\u0430\u0442\u043a": [37, 38, 40, 46, 64, 67, 68, 70, 74, 75, 82, 102, 130], "brief": [37, 82], "pdsa": 37, "\u0438\u0437\u0432\u0435\u0441\u0442": [37, 75, 85, 88, 90], "1930": 37, "1957": [37, 60, 90], "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [37, 65, 88], "1968": [37, 38], "\u0443\u0434\u0435\u0448\u0435\u0432\u043b\u0435\u043d": [37, 72, 76], "\u0434\u043e\u043b\u0433": [37, 38, 40, 41, 85, 92], "\u043d\u0435\u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d": 37, "\u0431\u044b\u0441\u0442\u0440\u043e\u0440\u0430\u0441\u0442\u0443\u0449": 37, "\u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440": [37, 40, 41, 64, 65, 70, 75, 80, 82, 83, 86, 100, 102], "\u043f\u0440\u0438\u0431\u043b\u0438\u0436\u044e\u0449": 37, "\u0437\u0430\u0431\u043b\u0430\u0433\u043e\u0432\u0440\u0435\u043c\u0435\u043d": [37, 65, 68, 75, 76, 80], "bduf": [37, 40, 65, 75, 76], "empirical": [37, 80], "observation": [37, 74, 80], "years": [37, 38, 73, 74, 76, 80, 82, 86, 92], "ago": [37, 62, 74, 76, 80], "ref": [37, 80], "barryboehm": [37, 80], "economics": [37, 66, 70, 80], "prentice": [37, 80], "hall": [37, 80], "1981": [37, 80], "rises": [37, 80], "exponentially": [37, 74, 80], "phases": [37, 65, 80], "expensive": [37, 70, 74, 76, 77, 80], "water": [37, 80], "fall": [37, 38, 80], "rising": 37, "kent": [37, 38, 41, 42, 46, 47, 52, 64, 66, 68, 70, 72, 75, 76, 82, 83, 85, 86, 88, 92, 93, 94, 95], "\u043a\u043e\u043d\u0446": [37, 76, 82, 85, 88], "1990": [37, 76, 88], "\u0445": [37, 38, 74, 76], "2000": [37, 74, 75, 76, 85], "\u043e\u0431\u0440\u0435\u043b": [37, 76], "\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430": [37, 77, 85, 86, 93, 100], "rom": [37, 76], "posa": [37, 76], "ooad": [37, 76], "solid": [37, 70, 71, 76, 77, 132], "refactoring": [37, 38, 41, 45, 47, 66, 70, 72, 73, 74, 75, 76, 77, 82, 85, 93, 95, 123], "\u0443\u043d\u0438\u0444\u0438\u043a\u0430\u0446": [37, 72], "\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [37, 40], "\u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 37, "\u0441\u043e\u043a\u0440\u0430\u0442": [37, 74, 86, 92, 93], "\u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0442\u0438\u0432\u043d": [37, 83, 86, 100, 102], "\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a": [37, 38, 41, 43, 46, 68, 70, 72, 74, 75, 81, 85, 86, 88, 90, 92, 93, 94, 95, 135], "\u043f\u043e\u0440\u043e\u0433": [37, 72, 85, 86], "\u0432\u0445\u043e\u0436\u0434\u0435\u043d": [37, 72], "\u0441\u043c\u044f\u0433\u0447": 37, "\u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d": [37, 38, 56, 72, 75], "\u0432\u043e\u0437\u0434\u0435\u0439\u0441\u0442\u0432": [37, 42, 88, 90, 93], "exploration": 37, "popular": [37, 38, 51, 52, 64, 65, 66, 76, 82, 85], "kenneth": [37, 38, 51, 52, 64, 65, 66, 76, 82], "rubin": [37, 38, 51, 52, 64, 65, 66, 76, 82], "\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435\u043d": 37, "\u0430\u0434\u0430\u043f\u0442\u0430\u0446": [37, 56, 75, 76, 85, 86], "\u043f\u043e\u043b\u043e\u0433": [37, 40, 75, 76, 83], "\u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d": [37, 38, 65, 75, 76], "\u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d": [37, 65, 75, 76, 90], "\u0430\u0441\u0438\u043c\u043f\u0442\u043e\u0442": [37, 65, 75], "\u0437\u0430\u0432\u0438\u0441\u0435\u043b": [37, 76], "\u043e\u0442\u043a\u043b\u0430\u0434\u044b\u0432\u0430": [37, 40, 68, 76], "\u043d\u0430\u0438\u0431\u043e\u043b\u044c\u0448": [37, 38, 47, 68, 76, 94, 100], "\u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d": [37, 68, 76, 85, 88, 92], "\u043f\u0440\u043e\u0434\u0443\u043a\u0442": [37, 38, 42, 65, 76, 86, 100], "paid": 37, "whatnot": 37, "got": [37, 74, 85, 86], "somewhere": [37, 70, 76], "rise": [37, 75, 85], "overtime": 37, "rose": 37, "slowly": [37, 47], "reaching": 37, "asymptote": 37, "tomorrow": [37, 38, 70], "draws": 37, "dramatically": [37, 85], "\u0430\u0441\u0438\u043c\u0442\u043e\u0442": [37, 76], "284": 37, "\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a": [37, 64, 93], "\u0432\u044b\u0441\u0448": 37, "\u0432\u044b\u0433\u043e\u0434\u0441\u043a": [37, 82], "\u0430\u0432": 37, "\u043b\u0438\u043d": [37, 73, 92, 94], "l": [37, 62, 65, 75, 82, 85, 88], "\u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d": 37, "\u043c\u043a": 37, "\u0447\u0435\u0440\u0442": [37, 38, 73], "297": 37, "\u043d\u0443\u043b": 37, "\u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d": [37, 75, 76, 86, 94, 100], "\u043e\u0441": 37, "\u0430\u0431\u0441\u0446\u0438\u0441\u0441": 37, "\u0440\u0430\u0437\u044b\u0441\u043a\u0430\u043d": 37, "\u0438\u0449": 37, "lim": 37, "\u0432\u043f\u0440\u0430\u0432": 37, "299": 37, "\u0444\u0438\u043b\u043e\u0441\u043e\u0432\u0441\u043a": 37, "\u043d\u0430\u043f\u0440\u044f\u0436\u0435\u043d": [37, 41, 70, 73, 77, 83, 88], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u0435\u043b": [37, 38, 39, 40, 41, 100], "\u043c\u043e\u0440\u0430\u043b\u044c\u043d": [37, 94, 95], "\u043a\u043b\u0438\u043c\u0430\u0442": [37, 94], "\u043c\u044f\u0433\u043a": [37, 38, 75], "ultimately": [37, 76], "mushroomed": [37, 76], "pair": [37, 56, 76, 85], "taken": [37, 76], "developer": [37, 38, 46, 49, 52, 53, 76, 82, 85, 86], "freed": [37, 76], "baggage": [37, 73, 76], "dilbertesque": [37, 76], "corporations": [37, 76], "early": [37, 38, 41, 46, 51, 52, 63, 65, 76, 77, 80, 85, 86], "he": [37, 38, 51, 73, 74, 76, 82, 85, 86, 92, 95], "estimated": [37, 38, 76], "effort": [37, 38, 46, 49, 51, 70, 74, 75, 76, 86, 100], "his": [37, 38, 73, 74, 76, 82, 83, 85, 86, 92, 94, 95], "reassigned": [37, 76], "programmer": [37, 38, 72, 73, 74, 75, 76, 82, 85, 86, 92, 94, 95], "beginning": [37, 52, 76, 85, 86], "twelve": [37, 74, 76, 86], "felt": [37, 76], "terrible": [37, 76], "boss": [37, 41, 76], "harangued": [37, 76], "somewhat": [37, 76, 77, 86], "despondent": [37, 76], "realized": [37, 76], "estimate": [37, 70, 76, 80], "accurate": [37, 49, 76, 100], "indeed": [37, 38, 49, 62, 65, 74, 75, 76, 85, 86], "standard": [37, 52, 64, 82, 86], "fixed": [37, 38, 73, 76, 85], "mindset": [37, 62, 76], "frequently": [37, 38, 46, 49, 51, 62, 75, 76, 86], "plagues": [37, 76], "industry": [37, 39, 51, 74, 76, 82, 85, 95], "marketing": [37, 38, 76, 100], "impose": [37, 73, 74, 76], "irrational": [37, 76], "demands": [37, 76], "imposition": [37, 76], "corporate": [37, 76, 82], "organizations": [37, 38, 76, 86], "economy": [37, 76], "aggressively": [37, 76], "era": [37, 76], "companies": [37, 38, 76], "dilbert": [37, 76], "manifestations": [37, 76], "arcane": [37, 76], "policies": [37, 75, 76], "freedom": [37, 76], "inanities": [37, 76], "attracts": [37, 76], "proponents": [37, 76, 85], "methodologies": [37, 64, 76], "scares": [37, 76], "begeebers": [37, 76], "shit": [37, 76], "professional": [37, 38, 52, 64, 73, 74, 76, 82, 85, 95], "paper": [37, 76, 85, 94], "traditionalists": [37, 76], "scare": [37, 76], "bureaucrats": [37, 76], "happy": [37, 68, 76], "pushing": [37, 38, 75, 76], "timely": [37, 64, 76, 86], "tangible": [37, 76], "promised": [37, 76], "places": [37, 70, 76, 100], "hide": [37, 73, 76, 85, 86], "movement": [37, 76, 85], "methodology": [37, 62, 65, 76, 82], "restore": [37, 76], "credibility": [37, 76], "balance": [37, 38, 76, 77, 86], "embrace": [37, 73, 76], "diagram": [37, 38, 51, 76, 100], "dusty": [37, 76], "tomes": [37, 76], "plan": [37, 38, 60, 62, 76, 86, 90], "limits": [37, 38, 74, 76, 86, 90], "turbulent": [37, 76], "brand": [37, 76], "xp": [37, 42, 46, 47, 52, 66, 68, 70, 73, 76, 82, 85, 86], "hackers": [37, 76], "ignorant": [37, 76], "hacker": [37, 76], "manifesto": [37, 38, 62, 65, 73, 75, 76], "helped": [37, 86], "rethink": 37, "priorities": [37, 38], "humanize": 37, "dave": [37, 76, 85], "\u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a": 37, "rights": [37, 38], "\u0442\u0440\u0443\u0434": [37, 56, 68, 83, 86, 88, 92], "\u043f\u0441\u0438\u0445\u043e\u043b\u043e\u0433": [37, 38, 75, 82, 83, 85, 88, 94], "\u044d\u0440\u0443\u0434\u0438\u0440\u043e\u0432\u0430\u043d": 37, "\u0444\u0438\u043b\u043e\u0441\u043e\u0444": [37, 56, 92, 102], "\u043c\u0435\u043d\u0435\u0434\u0436\u043c\u0435\u043d\u0442": [37, 40, 83, 86, 95], "overall": [37, 51, 70, 76, 77, 86], "progress": [37, 41, 47, 74, 86, 94], "proven": 37, "repeatable": [37, 72, 85], "tests": [37, 38, 45, 46, 49, 51, 52, 66, 70, 73, 74, 82, 85, 86, 123], "substitute": 37, "functionality": [37, 38, 46, 47, 49, 51, 52, 60, 63, 74, 77, 82, 85], "paying": [37, 41, 85], "exorbitant": 37, "schedule": [37, 38, 46, 60, 74, 86], "reduce": [37, 38, 73, 74, 76, 82, 85, 90], "cancel": 37, "reflecting": [37, 38], "declarations": 37, "priority": [37, 38, 51], "ask": [37, 38, 70, 74, 85, 86, 88], "peers": 37, "managers": [37, 38, 80], "estimates": [37, 38, 60, 65, 73], "responsibilities": [37, 38], "assigned": [37, 86], "snowbird": [37, 38], "meeting": [37, 38, 51], "heal": [37, 38], "divide": [37, 38, 60, 86, 90], "ward": [37, 38, 41, 74, 82, 85], "cunningham": [37, 38, 41, 74, 82, 85], "ron": [37, 38, 85], "jeffries": [37, 38, 85], "basics": [37, 38, 82], "\u0437\u0430\u0449\u0438\u0442\u043d": 37, "\u0441\u043f\u0440\u043e\u0432\u043e\u0446\u0438\u0440\u043e\u0432\u0430": [37, 92], "\u0441\u0442\u0440\u0430\u0445": [37, 38, 83], "declaration": [37, 76], "independence": [37, 76, 86], "risky": [37, 38], "fears": [37, 38], "develop": [37, 38, 41, 49, 51, 73, 74, 77, 82, 86, 92], "effectively": [37, 38, 66, 70, 74, 82, 86], "laws": [37, 38, 72, 74, 88], "governments": [37, 38], "taxes": [37, 38], "fear": [37, 38, 85], "liberty": 37, "pursuit": [37, 73], "happiness": 37, "secure": [37, 82], "instituted": [37, 38, 73], "men": [37, 86], "powers": 37, "consent": 37, "governed": 37, "profundity": 37, "distract": [37, 38], "afraid": [37, 85, 88], "losing": 37, "token": [37, 41], "asked": [37, 74, 76], "pay": [37, 41, 85], "little": [37, 38, 49, 73, 74, 75, 76, 82, 85, 86, 88, 95], "surrender": 37, "career": [37, 74, 83], "techies": 37, "meaningful": [37, 75], "plans": [37, 49, 62, 65, 76], "fairy": 37, "tales": 37, "told": 37, "stupid": [37, 73], "falling": 37, "technically": [37, 38, 85], "authority": [37, 38], "definitions": [37, 51, 82], "sacrifice": 37, "deadlines": [37, 74], "nestled": 37, "white": [37, 82], "capped": 37, "mountains": 37, "ski": 37, "resort": 37, "group": [37, 38, 46, 74, 75, 82, 86, 88], "rebels": 37, "gathered": [37, 38], "2001": [37, 92], "\u043c\u0435\u0442\u043a": [37, 70], "\u0432\u044b\u0440\u0430\u0436": [37, 40, 77, 86], "\u043a\u0435\u043d\u0442": [37, 82, 85], "\u0431\u0435\u043a": [37, 82, 85], "continued": 37, "beauty": [37, 75], "maintenance": [37, 38, 49, 73, 74, 86, 100], "europe": [37, 100], "youtu": 37, "ybytgii151g": 37, "9808": 37, "\u0442\u0430\u043b\u0430\u043d\u0442": [37, 73, 83], "\u043a\u0440\u0438\u0441\u0442\u0430\u043b\u043b\u0438\u0437\u0430\u0446": [37, 83, 91, 95, 138], "\u043f\u0440\u0435\u0432\u0440\u0430\u0442": [37, 38, 75, 83, 88, 91, 95, 138], "\u043d\u0435\u043e\u0431\u044b\u0447\u0430\u0439\u043d": 37, "c\u043f\u0438\u0441\u043e\u043a": 37, "\u043e\u0448\u0435\u043b\u043e\u043c\u043b\u044f": 37, "\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442": [37, 75], "curve": [37, 65, 74, 75, 82], "fix": [37, 38, 46, 47, 73, 74, 85], "ironic": 37, "ad": [37, 74], "hoc": [37, 74], "phase": [37, 52, 65, 72, 76, 85], "exponentiation": 37, "exponential": [37, 65], "conveys": 37, "planned": [37, 62, 76, 77], "mistakes": [37, 76, 86], "assumption": [37, 38, 85], "flatten": 37, "flattening": 37, "enabled": [37, 49], "exploited": 37, "exploit": 37, "flattened": 37, "controversy": 37, "criticize": 37, "exploitation": 37, "enabling": [37, 38, 86], "criticisms": 37, "stem": 37, "critics": 37, "exploiting": 37, "burned": 37, "dead": [37, 60, 66, 72, 73, 74, 85, 90, 94], "\u043f\u0440\u0435\u0434\u043f\u043e\u0441\u044b\u043b\u043e\u043a": 37, "\u0445\u0440": [37, 38, 42, 46, 47, 68, 70, 85], "\u043f\u0440\u0435\u0434\u043f\u043e\u0441\u044b\u043b\u043a": 37, "\u0432\u043d\u0435\u0441\u0435\u043d": [37, 70], "\u0440\u0430\u0441\u0442\u0435\u0442": [37, 86, 95], "\u043c\u0435\u0434\u043b\u0435\u043d": [37, 47, 89], "\u0441\u0440\u043e\u043a": [37, 38, 46, 70, 86], "\u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a": [37, 73, 74, 86, 90], "\u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430": [37, 41, 83, 85, 88], "\u043e\u0442\u043b\u043e\u0436": [37, 40], "\u0437\u0430\u0432\u0442\u0440": [37, 38, 41, 70], "\u0440\u0430\u0437\u0432\u0435\u044e\u0442": 37, "\u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0443\u0442": 37, "\u043e\u0431\u043e\u0439\u0434\u0435\u0442": [37, 70], "\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u044c\u043a": 37, "\u0441\u0443\u043c\u043c": [37, 41, 65], "\u0441\u043e\u0439\u0434\u0435\u0442": 37, "\u043f\u044b\u0442": [37, 82], "\u043f\u0440\u0435\u0434\u0443\u0433\u0430\u0434\u0430": 37, "\u0434\u0435\u0448\u0435\u0432": 37, "\u0440\u0438\u0441\u043a\u043d\u0443\u0442": 37, "premises": 37, "act": [37, 76], "differently": [37, 38, 41, 51, 70, 74, 76, 85], "defer": [37, 38, 39, 51], "greatest": [37, 38, 74], "hopes": [37, 74], "anticipate": [37, 49, 76], "simplified": [37, 86], "steep": 37, "ruinously": 37, "crazy": [37, 73], "charge": [37, 38], "ahead": [37, 70], "careful": [37, 73], "cheap": [37, 38, 85, 86, 94], "reduced": [37, 38, 46, 73, 74, 85, 86, 90], "outweighs": 37, "\u043f\u0440\u043e\u0438\u0437\u043d\u0435\u0441": 37, "\u0432\u0441\u0442\u0440\u0435\u0447": [37, 75], "\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u043d": 37, "\u0447\u0430\u0441\u0442\u043d": [37, 92, 100], "engineers": [37, 38, 65, 73, 86], "growth": 37, "economies": 37, "kick": 37, "wildly": 37, "incorrect": [37, 38], "attention": [37, 47, 72, 74, 85], "excellence": [37, 74], "enhances": [37, 38, 74], "agility": [37, 49, 51, 64, 66, 74, 82, 86], "nature": [37, 38, 73, 76, 86], "facilitate": [37, 38, 49, 76], "efficient": [37, 38, 72, 73, 76, 85], "comparison": [37, 76], "managed": [37, 38, 39, 64, 76, 86], "continuum": [37, 76], "seek": [37, 76], "total": [37, 41, 76, 85, 86], "rework": [37, 74, 76], "points": [37, 38, 42, 74, 75, 76, 82, 86], "baselining": [37, 76], "traced": [37, 76], "welcome": 37, "harness": [37, 38], "competitive": [37, 74], "agreed": 37, "captured": [37, 51, 76], "adaptiveness": 37, "oh": [37, 74], "finalist": 37, "adaptive": [37, 62, 65, 76], "predictive": [37, 62, 65, 76], "\u0432\u044b\u0441\u043a\u0430\u0437\u044b\u0432\u0430": 37, "primarily": [37, 76, 86], "dominant": [37, 38], "90s": [37, 74], "00s": 37, "became": [37, 85, 86], "noughties": 37, "catalyst": 37, "\u0441\u043e\u0441\u0442\u043e": [37, 38, 46, 72, 85, 86, 100, 102], "\u0437\u0430\u0431\u044b\u0432\u0430": [37, 38, 85], "\u0440\u044b\u043d\u043a": [37, 38, 39, 76, 83, 92], "\u043d\u0435\u0442\u0440\u0443\u0434\u043d": 37, "\u043d\u0435\u0434\u0430\u043b\u0435\u043a": 37, "\u0443\u0440\u043e\u0431\u043e\u0440\u043e\u0441": [37, 74, 75], "2015": [37, 38, 52, 64, 82, 88], "keynote": [37, 66, 74, 76], "adopt": [37, 51, 86], "consistently": 37, "velocity": [37, 38, 76, 83], "debt": [37, 38, 39, 43, 46, 66, 70, 74, 86, 121], "accumulated": [37, 92], "starts": [37, 74, 77], "grind": [37, 38], "halt": [37, 38], "far": [37, 38, 65, 74, 76, 85, 86, 100], "stuck": [37, 74], "clue": 37, "bernstein": 37, "\u0443\u0437\u043d\u0430": [37, 38, 70, 75, 77, 86, 88, 94], "ken": [37, 38, 52, 76], "schwaber": [37, 38, 52, 76], "\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d": [37, 73], "\u0431\u0440\u0430\u0442": [37, 68], "\u0443\u0441\u043a\u043e\u0440": 37, "\u0441\u0442\u0440\u0430\u0434\u0430": [37, 38, 83], "\u043f\u043e\u0441\u0442\u043e\u044f": [37, 38, 68, 72, 74, 82, 85, 88], "\u0442\u0435\u043c\u043f": [37, 38, 70, 72, 74, 86], "did": [37, 38, 41, 60, 72, 74, 85, 86, 90], "convinced": 37, "him": [37, 86], "spread": 37, "downside": [37, 70], "suffer": [37, 74], "lack": [37, 86], "sustainable": [37, 82], "trenches": [37, 38, 82], "henrik": [37, 38, 82, 86], "kniberg": [37, 38, 82, 86], "\u0440\u0435\u0434\u0430\u043a\u0446": [37, 38, 41, 46, 56, 60, 73, 74, 77, 90, 92], "\u0430\u043b\u0435\u043a\u0441\u0435": [37, 38], "\u043a\u0440\u0438\u0432\u0438\u0446\u043a": [37, 38], "2004": [37, 56, 82, 92], "\u0433": [37, 82, 90, 92, 102], "\u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433": [37, 82, 92], "\u043f\u043e\u0437\u0432\u043e\u043b\u044c\u0442": [37, 72, 85], "education": [37, 52, 64, 73, 82], "skimp": 37, "productivity": [37, 38, 46, 74, 86], "responsiveness": 37, "stranding": 37, "fluency": 37, "stress": [37, 38, 74, 85], "worry": [37, 85], "reworking": [37, 38, 74, 85], "reducing": [37, 72, 74, 82, 85], "manageable": [37, 77], "levels": [37, 38, 65, 74, 75, 76, 77, 85], "prohibitive": 37, "usage": [37, 74], "disaster": [37, 74], "aggregation": [37, 74, 90], "harder": [37, 68, 70, 74, 76], "argue": [37, 74], "leads": [37, 38, 62, 74, 77, 85], "deteriorates": [37, 74], "ability": [37, 38, 74, 75, 86], "entropy": [37, 74], "worse": [37, 70, 73, 74, 86], "bugs": [37, 38, 73, 74, 85], "breed": [37, 74], "kill": [37, 74], "nightmare": [37, 74], "poorly": [37, 38, 74], "\u0443\u0434\u0430\u0447\u043d": [37, 64, 73], "\u0432\u044b\u0441\u043a\u0430\u0437\u0430": 37, "grady": [37, 64, 75, 76, 82, 90], "booch": [37, 64, 75, 76, 82, 90], "provided": [37, 49, 76], "imply": [37, 38, 76], "duties": [37, 38, 76], "claims": [37, 38, 46, 74, 76, 86], "loosely": [37, 76], "composed": [37, 72, 74, 75, 76, 100], "reasoned": [37, 76], "wiggle": [37, 76], "refactorings": [37, 38, 46, 76, 82, 85], "ruining": [37, 76], "grow": [37, 47, 73, 76, 80], "incrementally": [37, 76, 77, 86], "matures": [37, 76], "decomposability": [37, 76], "concerns": [37, 38, 51, 74, 76, 85, 86, 90], "near": [37, 38, 74, 76], "modifiability": [37, 38, 40, 64, 66, 75, 76], "tactics": [37, 76], "self": [37, 38, 40, 76, 86, 88], "evident": [37, 76], "cutting": [37, 38, 76, 86], "obvious": [37, 38, 51, 74, 76, 85], "communicated": [37, 51, 76], "defended": [37, 76], "whatever": [37, 38, 73, 76, 85], "socialize": [37, 76], "len": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "bass": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "paul": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "clements": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "rick": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "kazman": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "c\u043c": [37, 76, 77], "\u043f\u0440\u0435\u043e\u0431\u043b\u0430\u0434\u0430\u043d": 37, "\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u043a": [37, 38, 40, 46, 67, 68, 70, 72, 74, 75, 130], "\u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0440\u043e\u0447\u043d": [38, 40, 46, 73, 74, 85, 90], "\u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d": [38, 40, 46], "\u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d": [38, 83, 92], "\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442": [38, 72, 77, 82, 83, 88, 91, 94, 100, 138], "\u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d": [38, 56, 76, 82, 83, 85, 88, 92, 102], "\u043e\u0431\u0449\u0435\u0441\u0442\u0432": 38, "\u043f\u043e\u0434\u043a\u0440\u0435\u043f\u043b\u0435\u043d": 38, "\u043c\u0438\u0444": [38, 85, 100], "\u0440\u0438\u0442\u0443\u0430\u043b": [38, 75], "\u043d\u0430\u043a\u0430\u0437\u0430\u043d": 38, "\u043d\u0430\u0433\u0440\u0430\u0434": 38, "\u0443\u0432\u0430\u0436\u0435\u043d": [38, 42, 83], "\u043d\u0443\u0436\u0434": 38, "\u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446": [38, 68, 82, 100, 102], "simplicity": [38, 71, 74, 76, 90, 132], "\u0445\u0440\u0430\u0431\u0440\u043e\u0441\u0442": 38, "courage": 38, "goals": [38, 46, 51, 86], "conflict": [38, 76, 85], "social": [38, 75, 82, 85, 86, 88], "societies": 38, "developing": [38, 72, 74, 76, 82, 86, 100], "sets": 38, "backed": 38, "rituals": [38, 75], "punishments": 38, "rewards": 38, "humans": [38, 65, 74, 90], "\u0441\u043f\u0443\u0441\u0442": [38, 70], "\u0443\u043f\u043e\u043c\u0438\u043d\u0443\u0432": 38, "puzzled": 38, "wild": 38, "heavily": [38, 75, 82], "tilted": 38, "towards": [38, 82], "geek": 38, "balanced": 38, "revenue": [38, 70], "struggle": 38, "personalities": 38, "sighted": 38, "visionary": 38, "thinking": [38, 40, 41, 62, 66, 72, 74, 76, 82, 85, 94], "economic": [38, 66, 74], "survive": 38, "greed": 38, "wonder": [38, 70], "refactor": [38, 46, 47, 51, 70, 85], "tension": 38, "advancing": 38, "pressures": 38, "manufacturing": 38, "irregularities": 38, "evils": 38, "distractions": 38, "lie": [38, 80], "sprint": [38, 51, 86], "stuff": [38, 74, 85], "smooth": 38, "postpone": [38, 68], "resolving": 38, "fixing": [38, 39, 73], "believe": [38, 86], "market": [38, 39, 65, 74, 86], "benefit": [38, 52, 74, 80, 86, 90], "worth": [38, 46, 66, 70, 74, 76, 85], "displace": 38, "generating": [38, 70, 82], "mcconnell": [38, 41, 60, 75, 76, 77, 82, 83, 86, 90, 95], "mcc96": 38, "stumbling": 38, "arounds": 38, "drag": 38, "impediments": 38, "steve": [38, 41, 60, 75, 77, 82, 83, 86, 90, 95], "studies": 38, "38": [38, 82], "42": 38, "1996": [38, 74, 90], "august": [38, 82], "spirit": [38, 73], "game": [38, 68], "coplie": 38, "81": [38, 74, 90], "whack": 38, "mole": 38, "frustration": [38, 70], "amongst": 38, "perception": [38, 74], "sold": 38, "wasted": [38, 49], "occupying": 38, "months": [38, 46, 62, 65, 70, 74, 75, 82, 86, 95], "refactored": [38, 85], "elegant": [38, 73, 85], "shiny": 38, "sell": [38, 39, 46], "continue": [38, 74], "employ": 38, "aspects": [38, 70, 100], "firstly": 38, "learn": [38, 41, 62, 65, 73, 75, 82, 85], "justify": [38, 74], "secondly": 38, "justifying": [38, 46, 74], "ongoing": [38, 42, 46, 73], "\u0447\u0435\u0442\u044b\u0440\u0435\u0445": [38, 83, 86, 89], "\u0438\u043d\u043e\u0433\u0434": [38, 40, 41, 68, 70, 73, 74, 77, 83, 85, 90, 93], "\u0432\u0441\u0442\u0440\u0435\u0442": [38, 53], "iron": [38, 65], "triangle": [38, 65], "\u0442\u0440\u0435\u043c": 38, "barnes": 38, "phd": 38, "sketched": 38, "corners": 38, "began": [38, 73], "\u0442\u043e\u0436\u0434\u0435\u0441\u0442\u0432\u0435\u043d": 38, "\u0441\u043e\u0441\u0442\u0430\u0432\u043d": 38, "\u0437\u0430\u0440": [38, 92], "\u043d\u0435\u043b\u0438\u043d\u0435\u0439\u043d": 38, "\u043a\u0432\u0430\u0434\u0440\u0430\u0442": 38, "diamond": 38, "duncan": 38, "haughey": 38, "\u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a": [38, 65], "\u043e\u0441\u043d\u043e\u0432\u043e\u043f\u043e\u043b\u0430\u0433\u0430": 38, "\u0442\u0435\u0445\u043d\u0430\u0440": 38, "\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440": [38, 85], "\u0431\u0438\u0437\u043d\u0435\u0441\u043c": 38, "\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d": [38, 72, 83, 85, 93, 100], "\u0432\u043b\u0430\u0441\u0442": 38, "modes": 38, "suffers": 38, "splitting": [38, 76], "frederick": [38, 65, 82, 86], "brooks": [38, 65, 82, 86, 94], "\u0431\u0435\u0441\u0442\u0441\u0435\u043b\u043b\u0435\u0440": 38, "\u043c\u0438\u0444\u0438\u0447\u0435\u0441\u043a": [38, 65], "\u043c\u0435\u0441\u044f\u0446": [38, 40, 46, 65, 74, 86], "\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446": 38, "\u043e\u0442\u0434\u0435\u043b": 38, "\u043d\u0435\u0434\u043e\u0440\u043e\u0433": 38, "\u0441\u0434\u0435\u0440\u0436\u0430": 38, "\u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0442\u0435\u043b\u044c\u0441\u043a": 38, "\u044d\u043d\u0442\u0443\u0437\u0438\u0430\u0437\u043c": [38, 83], "fast": [38, 51, 73, 74, 76, 82, 86], "discipline": [38, 64, 73, 76, 82, 86], "bounds": 38, "inventive": 38, "enthusiasm": 38, "mythical": [38, 65, 82, 86], "man": [38, 65, 75, 82, 86], "essays": [38, 65, 82, 86], "anniversary": [38, 65, 82, 86], "jr": [38, 65, 82, 86], "\u0447\u0440\u0435\u0437\u043c\u0435\u0440\u043d": 38, "\u0431\u0435\u043b": [38, 85], "\u0432\u043e\u0440\u043e\u0442\u043d\u0438\u0447\u043a": 38, "\u043f\u043e\u0434\u0433\u043e\u043d\u044f": [38, 46], "\u0441\u0443\u043f\u0435\u0440\u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d": 38, "\u043f\u043e\u043f\u0440\u043e\u0431\u0443": [38, 86], "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d": 38, "\u043f\u043e\u043b\u043d\u043e\u043c\u043e\u0447": [38, 40, 51, 86, 88], "\u043f\u0440\u0438\u043a\u043b\u0430\u0434\u044b\u0432\u0430": 38, "\u0433\u0435\u043d\u0435\u0440\u0438\u0440": [38, 85], "\u043e\u0442\u0434\u0430\u0447": [38, 42], "suits": [38, 76], "technologies": 38, "interesting": [38, 74, 76, 85, 86], "edge": 38, "haven": [38, 74, 75], "scenario": [38, 49, 52], "risks": [38, 47, 65, 70], "delivering": [38, 62, 65, 82], "strains": 38, "cover": [38, 86], "release": [38, 49, 51, 73, 74, 75, 82, 85, 86], "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442": [38, 40, 68, 74, 85, 86, 90, 93], "\u0441\u0435\u0440\u0434\u0446": 38, "\u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d": [38, 47, 86], "\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430": 38, "\u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442": [38, 93, 94], "\u0440\u0430\u0431\u043e\u0442\u043d\u0438\u043a": [38, 86], "\u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a": [38, 70, 74, 85], "\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d": 38, "\u043d\u0430\u0434\u043e\u0431\u043d": [38, 47], "programmers": [38, 68, 72, 73, 74, 75, 82, 85, 86, 90], "headed": 38, "roles": [38, 86], "\u043f\u043e\u0434\u0441\u043a\u0430\u0437\u0430": 38, "\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432": [38, 82, 90], "\u0440\u0435\u043c\u0435\u0441\u043b": 38, "\u043f\u043e\u0434\u0432\u043e\u0434": 38, "\u043c\u043d\u0435\u043d": [38, 51, 56, 72, 74, 75, 85, 94], "\u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d": [38, 82, 86, 95, 102], "\u0430\u0444\u043e\u0440\u0438\u0437\u043c": 38, "\u0445\u0443\u0434\u043e\u0436\u043d\u0438\u043a": [38, 73], "\u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430": [38, 52], "\u0443\u0436\u0430\u0441\u043d": 38, "\u0441\u0442\u0440\u043e\u0435\u043d": 38, "\u0431\u044e\u0434\u0436\u0435\u0442": 38, "\u0432\u0435\u043b\u0438\u043a": [38, 70, 83, 86, 100], "\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d": [38, 75], "\u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a": [38, 72, 73, 85, 86], "\u0430\u043a\u0442\u0438\u0432\u043d": [38, 56, 75, 76, 80, 85, 86, 92], "\u0431\u0430\u0445": 38, "\u0435\u0434\u0432": [38, 102], "\u0435\u0436\u0435\u043d\u0435\u0434\u0435\u043b\u044c\u043d": 38, "\u0438\u0437\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430": 38, "\u043a\u0430\u043d\u0442\u0430\u0442": 38, "\u0443\u0432\u0435\u0440": [38, 47, 74, 85], "\u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440": 38, "stretch": 38, "\u0436\u0435\u0441\u0442\u043a": [38, 85], "\u043d\u0430\u043b\u043e\u0436\u0435\u043d": 38, "360": [38, 86], "\u043f\u0440\u0438\u043d\u0435\u0441\u043b": 38, "\u0443\u0441\u0438\u043b\u0438\u0432\u0430": [38, 56, 92], "\u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b": 38, "\u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u0432\u0430": 38, "\u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0442\u0435\u043b\u044c\u043d": 38, "\u0431\u044c\u0435\u0442": 38, "\u043e\u0431\u0434\u0443\u043c\u044b\u0432\u0430\u043d": [38, 85], "arts": [38, 86], "crafts": 38, "art": [38, 73, 82, 86], "artist": 38, "aphorism": 38, "liberating": 38, "worst": [38, 76], "buildings": 38, "budget": [38, 62], "purposes": [38, 73], "served": [38, 51], "bach": 38, "creative": [38, 86], "hardly": 38, "squelched": 38, "necessity": 38, "cantata": 38, "constrained": [38, 51], "constraints": [38, 51, 52, 65, 76, 86], "imposed": [38, 76, 86], "beneficial": [38, 77], "similarly": [38, 85], "observe": 38, "provision": 38, "cramps": 38, "focus": [38, 49, 51, 73, 74, 85, 90, 100], "inventions": 38, "unconstrained": 38, "thought": [38, 72, 74, 76, 85, 86], "debate": 38, "shrift": 38, "englebart": 38, "augmenting": 38, "intellect": 38, "afips": 38, "conference": [38, 74, 76], "proceedings": [38, 74], "joint": 38, "san": [38, 74], "francisco": [38, 74], "dec": 38, "pp": 38, "395": 38, "410": 38, "resume": 38, "\u0431\u0435\u0437\u043e\u0431\u043e\u0441\u043d\u043e\u0432\u0430": 38, "\u043f\u0435\u0440\u0435\u0443\u0441\u043b\u043e\u0436\u043d\u044f": 38, "\u043e\u0442\u043c\u0435\u0442\u043a": [38, 85], "\u0443\u0449\u0435\u043c\u043b": 38, "\u0437\u0430\u0433\u043d\u0438\u0432\u0430": 38, "\u0434\u0435\u0433\u0440\u0430\u0434\u0438\u0440": 38, "\u0434\u0438\u043a\u0442\u043e\u0432\u0430": 38, "\u0442\u044b": [38, 56, 83], "\u0442\u0435\u0431": 38, "\u0434\u0430\u0434\u0443\u0442": 38, "\u0440\u0430\u0431\u043e\u0447": [38, 40, 86, 100], "\u0441\u0442\u0430\u043d\u0446": 38, "\u043d\u0430\u0438\u0432\u044b\u0441\u0448": 38, "\u0441\u043a\u043e\u0442\u0438\u043d": 38, "\u043b\u0435\u043d\u0438\u0432": 38, "\u043f\u0440\u0435\u0434\u043f\u0438\u0441\u044b\u0432\u0430": 38, "\u0432\u043e\u0437\u0440\u0430\u0437": 38, "\u043f\u0440\u0438\u043d\u0443\u0434": 38, "\u043f\u043e\u043d\u0443\u0440": 38, "\u0433\u043e\u043b\u043e\u0432": [38, 82, 85, 94], "\u043d\u0435\u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c": [38, 82], "\u043f\u043e\u0441\u0442\u0430\u0432": [38, 86, 92], "\u043f\u0440\u0438\u0440\u043e\u0434": [38, 74], "\u043e\u0431\u0434\u0443\u043c\u044b\u0432\u0430": [38, 72, 85], "\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440": 38, "\u043e\u0441\u043c\u044b\u0441\u043b\u0438\u0432\u0430": 38, "\u043e\u043a\u0430\u0437\u044b\u0432\u0430": [38, 40, 72, 74, 75, 77, 80, 82, 85, 86, 88, 95, 102], "\u0440\u0438\u0441\u043a\u043e\u0432\u0430": 38, "feel": [38, 42, 46, 47, 83, 85], "fit": [38, 72, 74, 76, 85, 86, 100], "dictate": 38, "workstations": 38, "highest": [38, 49, 74, 90], "trouble": [38, 69, 70, 74, 76, 86, 131], "buster": [38, 89], "specifies": 38, "dutifully": 38, "heads": [38, 74, 100], "entail": 38, "poorest": 38, "somehow": 38, "riskier": [38, 51], "\u0432\u0430\u0439\u043d\u0431\u0435\u0440\u0433": 38, "\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440": [38, 40, 46], "\u043f\u043e\u0441\u0442\u0440\u0430\u0434\u0430": [38, 74], "weinberg": [38, 82], "gone": [38, 86], "awry": 38, "combined": [38, 75], "found": [38, 62, 65, 74, 82, 86, 90], "58": 38, "essence": [38, 65, 85, 94], "\u0438\u0441\u0442\u043e\u0440": [38, 64, 73, 75, 83, 88], "\u043d\u0435\u0443\u0434\u0430\u0447\u043d": [38, 82, 83], "\u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0437\u0438\u0440\u043e\u0432\u0430": 38, "backlog": [38, 51, 86], "\u0442\u0435\u043f\u043b": 38, "\u043d\u0435\u0441\u043e\u043c\u043d\u0435\u043d": 38, "\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446": [38, 76, 86], "\u0448\u0442\u0443\u043a": [38, 85], "\u0441\u043f\u0435\u0440\u0432": [38, 82], "\u0440\u0435\u0430\u043b\u0438\u0437\u0443": [38, 65, 70, 72, 85], "\u043a\u043e": [38, 70, 72, 77, 83, 85], "\u043f\u0440\u0438\u0431\u044b\u043b\u044c\u043d": 38, "\u043f\u0440\u0438\u043a\u0440\u0443\u0442": 38, "\u043a\u043e\u043d\u0444\u0435\u0442\u043a": 38, "\u043e\u043a": 38, "\u043a\u043e\u043c\u043f\u0435\u0442\u0435\u043d\u0442": 38, "\u0438\u0434\u0442": [38, 74], "experimented": 38, "stories": [38, 49, 51, 52, 53, 73, 77, 82, 85], "tried": [38, 65], "treating": 38, "prioritized": [38, 62, 86], "apples": [38, 76], "oranges": 38, "yeah": 38, "guys": 38, "driving": 38, "shall": [38, 76], "candy": 38, "concluded": 38, "qualified": 38, "notice": [38, 46, 68], "groups": [38, 74, 77], "tackle": [38, 41, 60, 82, 90], "plenty": [38, 41, 85], "conflicting": 38, "negotiating": [38, 82], "relies": 38, "ensures": [38, 74, 100], "\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430": [38, 74, 75, 85, 86], "\u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0430": [38, 72], "\u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432": [38, 46, 72, 74, 77, 90], "\u0432\u0441\u0435\u043e\u0431\u0449": 38, "\u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430": 38, "\u043e\u0431\u0440\u0435\u0447": [38, 42], "\u043f\u0440\u043e\u0432\u0430": 38, "tricky": 38, "expound": 38, "pressure": 38, "mounts": 38, "discarded": [38, 62], "doomed": [38, 42, 76], "darkness": 38, "\u0432\u0437\u0430\u0438\u043c\u043e\u043a\u043e\u043c\u043f\u0435\u043d\u0441\u0438\u0440\u043e\u0432\u0430": 38, "\u043f\u0435\u0440\u0435\u043a\u043e\u0441": 38, "evolvability": [38, 40], "flexibility": [38, 40, 60, 70], "modularity": [38, 40, 74], "testabilty": [38, 40], "deployability": [38, 40], "\u0441\u0442\u0435\u0439\u043a\u0445\u043e\u043b\u0434\u0435\u0440": [38, 40, 51, 86], "\u0430\u043d\u0430\u043b\u0438\u0437": [38, 72, 76, 82, 85, 86, 100, 102], "identified": [38, 51, 86], "established": [38, 51], "consensus": 38, "stakeholders": [38, 39, 49, 51, 66, 75, 77, 80, 82], "medium": 38, "intended": [38, 49, 59, 60, 65, 100], "candidates": 38, "regarding": [38, 65], "alternatives": 38, "prioritization": 38, "facilitates": 38, "basis": [38, 86], "negotiation": 38, "allocation": 38, "requiring": [38, 51, 86], "mutually": [38, 77], "incompatible": 38, "desired": 38, "consult": 38, "reach": [38, 74, 85], "contractual": 38, "traceable": 38, "resolution": [38, 65], "subcategory": 38, "29148": [38, 52, 64, 65, 77, 82], "analyze": [38, 49], "\u0437\u0440\u0435\u043b": [38, 82, 83], "\u0441\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430": [38, 40], "4th": [38, 64, 77, 82, 86], "\u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430": [38, 76, 86], "\u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d": [38, 76, 86], "evaluation": [38, 70, 82], "lae": 38, "mini": 38, "qaw": [38, 51], "42030": [38, 82], "\u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d": [38, 102], "\u0440\u0430\u0437\u043e\u0431\u0440\u0430": 38, "\u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d": 38, "\u043d\u0435\u0438\u0437\u0431\u0435\u0436\u043d": [38, 92], "\u043a\u043e\u0440\u0440\u0435\u043b\u0438\u0440": 38, "\u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430": 38, "\u043f\u0440\u043e\u0442\u0438\u0432\u043d": [38, 41, 47], "\u0432\u043f\u043e\u043b\u043d": [38, 72, 77, 83, 85, 88], "\u043f\u0435\u0440\u0435\u0440\u0430\u0441\u0442": 38, "\u043d\u0435\u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d": 38, "\u043c\u0435\u0436\u043b\u0438\u0447\u043d\u043e\u0441\u0442\u043d": 38, "\u043f\u043e\u0442\u0435\u0440": [38, 56, 85], "\u043a\u0430\u0434\u0440": [38, 56], "\u0445\u0443\u0434\u0448": [38, 83], "\u043f\u043e\u043c\u0435\u0441\u0442": [38, 100], "\u043a\u043e\u043c\u043f\u0435\u0442\u0435\u043d\u0446": [38, 56], "\u043e\u0434\u043d\u043e\u0441\u0442\u043e\u0440\u043e\u043d": 38, "unilaterally": 38, "decide": [38, 41, 51, 65, 68, 72, 75, 85], "\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c": 38, "\u0438\u0433\u0440": [38, 40], "\u0442\u0440\u0435\u0445": [38, 46, 86], "\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440": 38, "\u043f\u043e\u043b\u0430\u0433\u0430": [38, 40, 85, 92], "\u0437\u0430\u0434\u0430\u043d": [38, 74, 86, 90], "\u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d": [38, 86, 94, 100], "\u0447\u0438\u0441\u043b\u0435\u043d": [38, 76, 86, 88], "\u043e\u0431\u0449\u0435\u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d": 38, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434": [38, 86, 92], "\u043d\u0435\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d": 38, "\u0443\u0441\u043f\u0435\u0432": 38, "\u0441\u0434\u0430\u0442": 38, "\u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d": [38, 100], "\u043d\u0435\u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c": 38, "\u0432\u0445\u043e\u0434\u043d": [38, 65], "played": [38, 74], "resultant": 38, "fourth": [38, 86], "exactly": [38, 51, 73, 75, 76, 100], "standards": [38, 42, 49, 51, 74, 92], "crappy": 38, "everyone": [38, 65, 73, 82, 88, 95], "inputs": [38, 85], "\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d": [38, 92], "\u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442": [38, 41, 85], "\u0431\u043e\u0440\u043e\u043b": 38, "slower": [38, 72, 85], "demanding": [38, 76], "lowering": 38, "biggest": [38, 74], "surprises": [38, 63], "measured": [38, 74], "defects": [38, 73, 74, 77, 85], "desirable": [38, 51, 76], "effectiveness": [38, 86], "apparent": [38, 86], "purely": [38, 72, 85, 93, 100], "factor": [38, 74, 76, 85, 86], "proud": 38, "talking": [38, 74, 75, 85], "mediocre": [38, 86], "home": [38, 74, 86, 96], "weekends": 38, "fancy": [38, 85], "ironwork": 38, "blacksmith": 38, "met": [38, 51], "controlling": 38, "chooses": 38, "steering": 38, "precisely": [38, 65], "advance": 38, "lever": 38, "weekly": [38, 82], "quarterly": 38, "choosing": [38, 88], "concern": [38, 60, 86, 90], "excuse": 38, "inaction": 38, "finish": 38, "evolution": [38, 59, 68, 85, 86], "solving": [38, 60, 72, 85, 90, 100], "demonstration": 38, "efficiently": [38, 85], "safe": [38, 47, 49, 51, 52, 64, 65, 74, 76, 82, 83, 88, 90], "annotated": 38, "bibliography": 38, "reading": [38, 74, 76, 82, 85, 90, 94, 95], "adds": [38, 70, 76, 100], "richness": 38, "suggestions": [38, 86], "jane": [38, 77], "wood": 38, "denise": 38, "silver": [38, 86], "wiley": [38, 76], "sons": 38, "1995": 38, "isbn": [38, 82], "0471042994": 38, "jad": 38, "facilitators": 38, "directing": 38, "fade": [38, 46], "away": [38, 51, 73, 74, 85, 86], "document": [38, 49, 51, 52, 64, 76, 77], "facilitated": 38, "professionals": [38, 46, 73, 74], "neutral": 38, "hostile": 38, "atmosphere": 38, "specially": 38, "trained": [38, 86], "unbiased": 38, "facilitator": 38, "political": 38, "stake": 38, "stay": [38, 74], "psychologically": 38, "players": 38, "guardian": 38, "deliverables": [38, 64], "achieved": [38, 73, 74, 75, 90], "leader": [38, 82], "ties": 38, "department": [38, 100], "company": [38, 76], "training": [38, 52, 64, 74, 82, 86], "facilitation": 38, "attached": 38, "jennerich": 38, "\u0441\u0433\u043b\u0430\u0436\u0438\u0432\u0430\u043d": 38, "payoff": [38, 40, 66, 70, 75], "yagni": [38, 40, 46, 49, 66, 68, 69, 74, 75, 76, 85, 131], "\u043f\u0435\u0440\u0435\u0448\u0435\u043b": 38, "\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440": 38, "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0442\u043e\u0440": [38, 75], "profound": 38, "cut": [38, 76, 86], "ruin": 38, "reputations": 38, "ethics": 38, "dean": [38, 49, 51, 52, 64, 65, 82, 86], "leffingwell": [38, 49, 51, 52, 64, 65, 82, 86], "\u0432\u043e\u0437\u043b\u0430\u0433\u0430": [38, 75, 88], "vision": [38, 52, 64, 76, 86], "representative": [38, 86, 100], "challenge": [38, 73, 75, 86], "expectations": [38, 64, 86], "merge": [38, 73, 94], "diverse": 38, "voices": 38, "facilitating": 38, "leading": [38, 49, 51, 64, 74, 82, 86, 88, 90], "mix": [38, 85, 86], "programs": [38, 51, 52, 64, 65, 72, 73, 74, 82, 85, 90], "\u043d\u0435\u0439\u0442\u0440\u0430\u043b\u0438\u0442\u0435\u0442": 38, "\u0441\u0444\u0435\u0440": [38, 102], "\u0444\u0438\u043d\u0430\u043d\u0441\u043e\u0432": [38, 70, 90, 92], "\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d": [38, 52, 53, 86], "maximizing": [38, 73], "\u043f\u043e\u043b\u0438\u0441\u0435\u043c\u0430\u043d\u0442\u0438\u0447\u0435\u0441\u043a": 38, "\u0433\u0430\u0439\u0434": [38, 51, 75], "master": [38, 82, 89], "\u0432\u0435\u0441\u044c\u043c": [38, 70, 73, 74, 75, 92, 102], "\u043c\u0435\u043d\u044f": [38, 47, 74, 85, 88], "funding": 38, "maximizes": [38, 76, 86], "roi": [38, 82], "accountable": [38, 86], "measure": [38, 46, 62, 64, 74, 75], "twice": [38, 74], "half": [38, 74, 85], "jeffrey": [38, 82], "deciding": [38, 39, 65], "continually": [38, 41, 73], "prioritizing": [38, 86], "refining": [38, 62, 80], "loss": [38, 82], "assuming": [38, 85], "lowest": [38, 74, 75], "continuously": [38, 85, 86], "\u0448\u0438\u0440": [38, 94], "evidence": [38, 49], "organization": [38, 75, 76, 85, 86, 88, 100], "\u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f": [38, 70, 75, 80, 85, 92, 102], "innovate": 38, "hire": 38, "oversee": 38, "pressing": 38, "agendas": 38, "slows": [38, 74], "profitability": 38, "questions": [38, 72, 88], "awkward": 38, "organizationally": 38, "incentive": 38, "positive": [38, 42, 85], "\u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430": [38, 83], "\u043b\u0438\u0446": [38, 83, 86], "\u043f\u0440\u0435\u0434\u0432\u0437": 38, "\u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e\u0432\u0430": [38, 40], "2011": [38, 46, 52, 82, 88, 92], "\u043d\u0430\u0432\u044f\u0437\u044b\u0432\u0430": 38, "\u043e\u0441\u0442\u0430\u0432\u043b": [38, 47], "\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d": [38, 49], "xp1": 38, "organizing": [38, 51, 82, 86], "increments": [38, 60, 63], "releasable": 38, "\u0432\u044b\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043d": [38, 86, 102], "\u043f\u0443\u0442\u0430\u043d\u0438\u0446": 38, "led": [38, 86], "proxy": 38, "dev": 38, "objective": 38, "accountabilities": 38, "sm": 38, "guides": 38, "xp2": 38, "decrease": [38, 74, 86], "\u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d": 38, "deviate": 38, "unacceptable": 38, "materials": [38, 86], "adjusted": 38, "adjustment": 38, "deviation": 38, "\u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0434": 38, "\u0434\u0438\u0441\u0431\u0430\u043b\u0430\u043d\u0441": [38, 40, 72], "empowered": [38, 40], "transparency": 38, "deployed": [38, 75], "regression": [38, 51, 85], "meet": [38, 59, 65, 74, 75], "reminded": 38, "review": [38, 49, 51, 57, 74, 82, 86, 88, 90, 100, 127], "viewing": 38, "presume": 38, "written": [38, 47, 49, 62, 72, 85, 100], "tested": [38, 47, 49], "demonstrate": [38, 73, 82], "viewer": 38, "\u0443\u0441\u0442\u0440\u0430\u043d\u0435\u043d": [38, 83, 86, 88], "\u0446\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 38, "\u0438\u043d\u0441\u043f\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u043c": 38, "entireorganization": 38, "respect": [38, 42, 74, 85], "inspectable": 38, "increment": [38, 51], "\u0438\u043d\u0441\u043f\u0435\u043a\u0442\u0438\u0440": 38, "inspect": 38, "adjust": 38, "\u043c\u0430\u043b\u0435\u043d\u044c\u043a": [38, 86, 95], "\u0437\u0430\u0447": [38, 75, 92], "1993": [38, 65], "leadership": [38, 82, 88], "figuring": 38, "plotted": 38, "figured": 38, "daily": [38, 74, 86], "stand": [38, 47, 70], "400": [38, 74], "percent": [38, 74, 85, 95], "admittedly": 38, "qualities": 38, "inspiration": 38, "came": [38, 85], "toyota": 38, "chief": [38, 86], "engineer": [38, 85], "corolla": 38, "camry": 38, "draw": [38, 76], "talents": 38, "specializing": 38, "chassis": 38, "electrical": [38, 49, 82], "capable": 38, "car": 38, "thinks": [38, 76, 85], "legendary": [38, 85, 94], "shusas": 38, "leaders": [38, 82, 85, 86], "reports": [38, 73, 74], "report": [38, 74, 86], "anyone": [38, 62, 73, 74, 88, 90], "appraisals": 38, "promotions": 38, "persuasion": 38, "coercion": 38, "wanted": [38, 86], "embody": 38, "shook": 38, "quoting": 38, "marine": 38, "corps": 38, "rooted": 38, "organizational": [38, 49, 86, 88], "evil": 38, "misunderstanding": 38, "rampant": 38, "consciousness": 38, "realize": [38, 52, 74, 85], "remarkable": 38, "february": 38, "2009": [38, 73, 83, 86, 102], "vietnam": 38, "agreeing": 38, "servant": 38, "persuade": 38, "cajole": 38, "thirty": 38, "fill": 38, "skill": [38, 73, 85], "days": [38, 74, 76, 85], "knew": [38, 70, 73, 86], "deeply": [38, 85], "buying": [38, 39], "thoughts": [38, 72, 85], "valued": 38, "\u043d\u0435\u043f\u043e\u043d\u0438\u043c\u0430\u043d": [38, 70, 83], "\u043d\u0430\u0434\u043b\u0435\u0436\u0430": [38, 41], "\u0441\u043d\u0438\u043c\u0430": [38, 86, 95], "\u043f\u043e\u043b\u0430\u0433": [38, 83], "\u0434\u0435\u043b\u0435\u0433\u0438\u0440": 38, "\u0443\u0432": [38, 56], "\u043f\u0430\u0434\u0435\u043d": [38, 40, 86], "\u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0430": 38, "\u043f\u0435\u0440\u0435\u043b\u043e\u0436": 38, "\u0432\u0438\u043d": 38, "\u043a\u0430\u0434\u0440\u043e\u0432": 38, "\u0442\u0440\u0435\u0437\u0432": 38, "\u043d\u0435\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [38, 40, 51, 53], "nfr": [38, 51], "\u043f\u0440\u043e\u044f\u0432\u043b\u0435\u043d": [38, 73, 92, 94], "\u043b\u043e\u0432\u0443\u0448\u043a": [38, 40], "\u0438\u0441\u043f\u0440\u0430\u0432": [38, 46, 47, 92], "\u0432\u044b\u0433\u043e\u0434\u043d": [38, 68, 70, 92], "\u0441\u043c\u043e\u0442\u0440\u0435\u0442": 38, "\u0432\u0435\u043b\u0438\u0447\u0438\u043d": [38, 41, 47, 86, 93], "\u043f\u0430\u0434\u0430": [38, 40, 83], "\u0441\u043a\u043e\u0440\u043e\u0441\u0442": [38, 40, 72, 74, 82, 85, 86, 95, 100], "shoup": 38, "vp": [38, 74], "stitch": [38, 74, 75], "\u043e\u0442\u043b\u0438\u0447\u0430": [38, 40, 52, 70, 76, 85, 86, 92, 94], "\u0432\u043e\u0441\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d": 38, "\u0434\u043e\u0440\u043e\u0436": [38, 65, 70], "\u0441\u0433\u043b\u0430\u0434": [38, 40], "\u043f\u043e\u0434\u043c\u0435\u043d": 38, "\u043d\u0435\u0432\u0435\u0440\u043d": [38, 83], "\u043f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430": [38, 74], "\u0443\u0433\u043e\u0434": 38, "\u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u043e\u0432\u0430": [38, 76], "\u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440": [38, 75], "\u0436\u0435\u0440\u0442\u0432\u0443": [38, 70], "insights": [38, 77, 92], "stephany": 38, "bellomo": 38, "ian": [38, 82], "gorton": 38, "september": [38, 74], "october": [38, 46], "32": [38, 72, 85, 94], "45": [38, 74, 85], "longer": [38, 41, 62, 74, 75, 76, 85], "hit": [38, 73], "wall": [38, 82], "cumulative": [38, 74], "unplanned": [38, 77], "unreliable": 38, "consequently": [38, 85], "renewed": 38, "address": [38, 46], "31": 38, "considerable": [38, 86], "relatively": 38, "emerged": 38, "allocating": [38, 77], "iterations": [38, 51, 62, 76, 77, 86], "checklists": 38, "retrospectives": 38, "major": [38, 49, 51, 65, 73, 86], "foundation": [38, 62, 65, 77, 82, 85], "qa": [38, 86], "ramifications": 38, "insecure": 38, "nord": [38, 82], "ozkaya": 38, "study": [38, 51, 74, 82, 86, 88], "fielding": 38, "speed": [38, 74, 86], "stability": 38, "international": [38, 82], "h": [38, 65, 82, 86, 90], "klein": 38, "discover": [38, 88], "elicitation": [38, 52, 82], "thijmen": 38, "gooijer": 38, "keeling": 38, "chaparro": 38, "participants": 38, "mario": 38, "barbacci": 38, "ellison": 38, "charles": [38, 82], "weinstock": 38, "william": [38, 46, 66, 70, 73, 82, 85, 92, 95], "ibm": [38, 74, 82, 86], "wish": [38, 74, 76, 80], "allowing": [38, 74], "amount": [38, 49, 73, 74, 86, 90], "iteration": [38, 49, 51, 62, 65, 72, 76, 77, 86], "\u0442\u0435\u0445\u043d\u0438\u043a": [38, 73, 82], "\u043c\u0435\u043b\u043a": [38, 86], "\u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430": 38, "\u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d": 38, "\u0431\u0435\u043a\u043b\u043e\u0433": 38, "\u0432\u0438\u0434\u0438\u043c": [38, 88], "\u0434\u043e\u0433\u043e\u0432\u0430\u0440\u0438\u0432\u0430": [38, 86], "\u043f\u0440\u0430\u0432\u0438\u043b": [38, 41, 47, 72, 83, 85], "\u043f\u0440\u0438\u0434\u0443\u043c\u044b\u0432\u0430": [38, 75], "\u0438\u043d\u0442\u0443\u0438\u0446": 38, "\u0441\u043f\u0440\u043e\u0441": [38, 74], "\u0440\u0435\u0442\u0440\u043e\u0441\u043f\u0435\u043a\u0442\u0438\u0432": 38, "\u0435\u043c\u043a\u043e\u0441\u0442": 38, "\u0441\u043f\u0440\u0438\u043d\u0442": [38, 46, 86], "\u0443\u0448\u043b": 38, "\u0438\u043d\u0432\u0435\u0441\u0442\u0438\u0446": 38, "embedded": [38, 85], "spent": [38, 72, 73, 74], "gut": 38, "retro": 38, "restructuring": [38, 46, 86], "strongly": [38, 46], "promote": [38, 46], "justification": [38, 46, 75], "codebase": [38, 46], "contrary": [38, 46, 75, 76], "whatsoever": [38, 46], "restructure": [38, 46], "opportunity": [38, 46, 85], "constitutes": [38, 46, 51], "documented": [38, 46, 49], "ries": [38, 46], "incumbent": [38, 46], "monetary": [38, 46], "seven": [38, 46, 74, 86, 90], "deploy": [38, 46, 52, 82, 86], "escalated": [38, 46], "pain": [38, 46, 85], "annual": [38, 46], "million": [38, 46, 74], "annum": [38, 46], "productive": [38, 46, 74, 86], "notoriously": [38, 46], "improving": [38, 46, 66, 70, 73, 74, 80, 82, 85, 86, 95], "january": [38, 46, 100], "addison": [38, 46, 74, 82, 90], "wesley": [38, 46, 74, 82, 90], "constant": [38, 46, 73, 82, 85, 90, 93], "radically": [38, 46], "businesses": [38, 46], "portfolio": [38, 46, 86], "penguin": [38, 46], "\u043f\u043e\u0441\u0432\u044f\u0442": 38, "\u0432\u0441\u0435\u043c\u0438\u0440\u043d": 38, "\u043e\u0431\u044a\u044f\u0441\u043d": [38, 82], "\u0444\u043e\u043d\u0434\u043e\u0432": [38, 39], "\u043e\u043f\u0446\u0438\u043e\u043d": [38, 39], "\u043c\u0435\u0442\u0430\u0444\u043e\u0440": [38, 40, 41, 74, 86], "\u043f\u0440\u043e\u0446\u0435\u043d\u0442": [38, 39, 43, 66, 82, 121], "technicaldebt": [38, 41], "\u0434\u0435\u0433\u0440\u0430\u0434\u0430\u0446": [38, 70], "\u0432\u043e\u0437\u043d\u0438\u043a": 38, "\u0441\u043c\u043e\u0433\u043b": 38, "\u0434\u043d\u044f": [38, 90], "\u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u043d": 38, "\u0434\u043d\u0435": [38, 76], "tracked": 38, "switched": 38, "confused": 38, "worked": 38, "politics": 38, "\u043a\u043e\u043c\u043f\u0430\u043d": [38, 40, 41, 73, 83, 86, 88, 92, 100], "\u043a\u043e\u043b\u044b\u0431\u0435\u043b": [38, 41], "\u043e\u0442\u043a\u0443\u0434": [38, 41, 90], "\u0432\u044b\u0448\u043b": [38, 41, 72, 75, 76, 86], "\u043e\u0442\u0441\u0442\u0430\u0438\u0432\u0430": 38, "\u0441\u043e\u0440\u0432\u0430": 38, "\u0432\u0438\u043d\u043e\u0432\u0430\u0442": 38, "\u043e\u0431\u0432\u0438\u043d": 38, "\u043a\u0430\u0440\u0430\u043d\u0434\u0430\u0448": 38, "\u0443\u0447\u0435\u0441\u0442": 38, "\u043d\u0430\u043a\u043e\u043d\u0435\u0446": [38, 46, 83], "\u0432\u044b\u0434\u0430": [38, 73], "\u0438\u043d\u0434\u0443\u043b\u044c\u0433\u0435\u043d\u0446": 38, "\u0441\u043d\u0438\u0436\u0435\u043d": [38, 52, 74, 75, 76, 83, 85, 88, 100], "\u043e\u0442\u043e\u0437\u0432\u0430": 38, "\u043e\u0441\u0442\u0430\u043d\u0443\u0442": 38, "\u043d\u0430\u0435\u0434\u0438\u043d": [38, 86], "\u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f": [38, 74, 94], "\u043e\u0442\u0437\u044b\u0432\u0430": 38, "\u0441\u0442\u0430\u0432": [38, 76, 85], "\u043f\u0435\u0440\u0441\u043e\u043d": 38, "\u0434\u043e\u043b\u0436\u043d\u043e\u0441\u0442": 38, "\u0432\u0435\u0447\u043d": [38, 83], "\u043d\u0430\u0441\u0442\u0430\u0438\u0432\u0430": [38, 85, 88, 92], "\u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0438\u0446\u0438\u0440": 38, "\u0441\u0430\u043c\u043e\u0437\u0432\u0430\u043d\u0446": [38, 83, 89, 95], "\u0445\u0432\u0430\u0442": [38, 92], "\u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0446": 38, "\u043d\u0435\u0443\u0432\u0435\u0440\u0435\u043d": 38, "\u043f\u043e\u0434\u043a\u0440\u0435\u043f\u043b": 38, "\u043e\u043f\u044b\u0442": [38, 46, 74, 82, 83, 85, 92, 94, 100], "\u043e\u0431\u043e\u0441\u043d\u043e\u0432\u0430": [38, 92], "\u0441\u043f\u043e\u0441\u043e\u0431\u043d": [38, 56, 60, 68, 70, 72, 74, 75, 83, 85, 88, 90, 92, 95], "\u0432\u044b\u0441\u043e\u043a\u043e\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d": [38, 75, 83], "\u0437\u0430\u043f\u0438\u043b": 38, "\u043e\u0441\u044f\u0437\u0430": 38, "\u0444\u0438\u0447": [38, 56], "\u043f\u0440\u0438\u0437\u0440\u0430\u0447\u043d": 38, "\u043d\u043e\u0431\u0435\u043b\u0435\u0432\u0441\u043a": [38, 94], "\u043b\u0430\u0443\u0440\u0435\u0430\u0442": [38, 94], "\u0434\u0430\u043d\u0438\u044d\u043b": [38, 94], "\u043a\u0430\u043d\u0435\u043c\u0430": [38, 94], "\u043f\u0438\u043a": [38, 94], "\u043a\u043e\u043d\u0435\u0446": [38, 94], "\u043d\u0435\u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d": [38, 94], "\u044d\u043c\u043e\u0446": [38, 94], "\u043d\u0435\u0434\u043e\u043e\u0446\u0435\u043d\u0438\u0432\u0430": 38, "unacknowledged": 38, "secures": 38, "inalienable": 38, "culture": [38, 75, 86], "courageous": 38, "huddle": 38, "fortress": 38, "walls": 38, "adopted": [38, 86], "cannonades": 38, "battlements": 38, "reviews": [38, 49, 82, 86, 94], "moats": 38, "crocodiles": 38, "torture": 38, "huge": [38, 85, 100], "pots": 38, "boiling": 38, "oil": 38, "tear": [38, 85], "impede": 38, "protecting": 38, "\u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d": [38, 89], "\u0432\u0435\u043b\u0438\u043a\u043e\u0432\u0430\u0442": 38, "nonfunctional": [38, 50, 52, 86, 125], "selling": [38, 41, 43, 66, 121], "\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d": [38, 43, 65, 66, 75, 76, 82, 83, 86, 89, 90, 91, 92, 93, 121, 138], "emacsway_log": [38, 92, 100], "488": 38, "techdebt": 38, "393": 38, "552": 38, "157": 38, "\u0443\u0432\u0438\u0434\u0435\u043b": 39, "\u0434\u043e\u043d\u0435\u0441\u0442": [39, 41, 56], "\u0442\u0435\u0440\u043c\u0438\u043d\u043e\u043b\u043e\u0433": 39, "\u0440\u0430\u0437\u044a\u044f\u0441\u043d\u044f": [39, 52, 66, 70], "obligation": 39, "buy": [39, 86], "instrument": 39, "american": [39, 75], "stock": [39, 82], "derivatives": 39, "doubt": 39, "cleared": 39, "fischer": [39, 82], "black": [39, 66, 74, 82], "myron": 39, "scholes": [39, 66], "compute": 39, "famous": 39, "formula": 39, "establishing": [39, 86], "strike": 39, "purchased": 39, "tied": 39, "exercising": 39, "slightly": 39, "originates": 39, "deferring": [39, 66], "nobel": [39, 66], "prize": [39, 66], "economists": [39, 66], "surprisingly": [39, 66], "\u043f\u0440\u0438\u0445\u043e\u0434": [40, 70, 72, 73, 74, 85, 89, 90], "\u0441\u043a\u043b\u043e\u043d": [40, 68, 83], "\u043f\u043e\u0440\u044f\u0434\u043e\u043a": [40, 74, 82], "\u0443\u0434\u0435\u0448\u0435\u0432": [40, 65], "\u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043b\u044c\u043d": [40, 82], "\u0444\u043e\u043d": [40, 56, 88, 92, 102], "\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0447\u0435\u0441\u043a": [40, 41, 83], "\u0443\u0447\u0435\u0431\u043d\u0438\u043a": [40, 64, 82], "\u0432\u0443\u0437": [40, 41, 82], "\u0438\u0437\u0434": [40, 82, 88], "\u0433\u043b\u0443\u0445": [40, 82], "\u043e\u0441\u0432\u0435\u0449": 40, "\u0448\u0430\u0445\u043c\u0430\u0442": 40, "\u043e\u043f\u0440\u043e\u0432\u0435\u0440\u0436\u0435\u043d": 40, "\u0438\u0433\u0440\u043e\u043a": 40, "\u0444\u0438\u0433\u0443\u0440": 40, "\u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430": 40, "\u0434\u0432\u0438\u0433\u0430": [40, 74, 85], "\u0431\u0435\u0437\u0431\u043e\u043b\u0435\u0437\u043d\u0435\u043d": [40, 85], "\u0438\u0441\u043a\u043b\u044e\u0447\u0430": 40, "\u0432\u044b\u0440\u0430\u0441\u0442": 40, "\u043f\u0443\u043d\u043a\u0442": [40, 76], "\u0444\u043e\u0440\u043c\u0438\u0440": [40, 56, 86, 92, 100], "\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430": [40, 86, 92, 100], "\u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0430": 40, "\u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a": [40, 41, 85], "\u0441\u043f\u0438\u0440\u0430\u043b\u044c\u043d": [40, 65, 86], "\u043f\u043e\u0434\u043a\u0440\u0435\u043f\u043b\u044f": 40, "\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433": 40, "\u0438\u043d\u0434\u0438\u043a\u0430\u0442\u0438\u0432\u043d": 40, "\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b": [40, 75], "\u0437\u0434\u043e\u0440\u043e\u0432": [40, 77, 85], "\u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430": [40, 92], "\u043c\u043e\u0437\u0433": [40, 75, 85, 88, 95], "\u0441\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u043d": [40, 94], "\u043f\u0435\u0440\u0435\u0441\u0442\u0440\u0430\u0445\u043e\u0432\u043a": 40, "\u043e\u0442\u0447\u0430\u0441\u0442": 40, "\u0441\u043a\u0430\u0442": 40, "\u043d\u0435\u043e\u043f\u0440\u0430\u0432\u0434\u0430": [40, 72], "\u043e\u0432\u0435\u0440\u0438\u043d\u0436\u0438\u043d\u0438\u0440\u0438\u043d\u0433": 40, "\u0441\u043a\u043b\u043e\u043d\u044f": 40, "\u043e\u0440\u0433": 40, "\u043c\u0443\u0441\u043e\u0440\u043d\u0438\u043a": 40, "\u0443\u043f\u043e\u0434\u043e\u0431\u043b\u044f": 40, "\u0434\u0435\u043c\u043e\u0440\u0430\u043b\u0438\u0437": 40, "\u043a\u043e\u043c\u043f\u0435\u0442\u0435\u043d\u0442\u043d": [40, 92], "\u043e\u043f\u0440\u0430\u0432\u0434\u0430\u043d": 40, "\u043f\u043e\u043a\u0430\u0436": 40, "\u0441\u0442\u043e\u0440": 40, "\u0432\u044b\u0431\u0440\u043e\u0441": 40, "\u043f\u043b\u0430\u043d": [40, 60, 65, 70, 86, 90, 95], "\u043f\u043e\u0441\u0442\u043e\u044f\u043d\u0441\u0442\u0432": [40, 95], "\u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u0435\u043b\u044c\u043d": 40, "\u0432\u0430\u0440\u0438\u0430\u0442\u0438\u0432\u043d": 40, "\u0443\u0441\u043b\u043e\u0432\u043d": [40, 100], "\u043e\u0431\u043e\u0431\u0449\u0430": [40, 72, 92], "\u043f\u0435\u0440\u0435\u0444\u0440\u0430\u0437\u0438\u0440\u0443": 40, "\u0432\u044b\u043a\u0438\u043d\u0443\u0442": 40, "\u0447\u0443\u0432\u0441\u0442\u0432\u0443\u0435\u0442": 40, "\u0437\u0430\u043f\u0440\u044f\u0433\u0430": 40, "\u0435\u0445\u0430": 40, "\u043e\u0442\u043b\u0430\u0436\u0435\u043d": [40, 86], "\u0440\u0435\u0434\u043a": [40, 82, 92], "\u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430": [40, 85], "\u043e\u043a\u0443\u043f": 40, "\u0437\u0430\u0442\u044f\u0433\u0438\u0432\u0430": 40, "\u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d": [40, 74, 90], "\u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447": [40, 74, 85, 90], "\u043d\u0435\u0439\u0442\u0440\u0430\u043b\u044c\u043d": 40, "\u0432\u0441\u0442\u0430\u0435\u0442": [40, 75], "\u0440\u0430\u0437\u043e\u0433\u0440\u0435\u0432\u0430": 40, "\u043f\u0435\u0440\u0435\u0442\u044f\u0433\u0438\u0432\u0430\u043d": 40, "\u043e\u0434\u0435\u044f": 40, "\u043f\u0440\u0435\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d": 40, "\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d": 40, "\u0440\u0430\u0437\u043d\u043e\u0441": 40, "\u0434\u043e\u043b\u044c\u0448": 40, "\u043f\u043e\u0434\u0430\u0432\u043d": 40, "\u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0442\u0438\u0432\u043d": 41, "\u043a\u0430\u0441\u0430": 41, "\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d": 41, "\u0443\u043c\u0435\u0442": [41, 56, 76, 82, 83, 88, 90], "\u043f\u0440\u043e\u0434\u0430": 41, "\u043d\u0430\u0445\u043e\u0434\u044f": 41, "\u0431": [41, 77, 82, 88, 102], "\u0431\u0430\u043b\u0430\u043d\u0441": [41, 46, 65, 72, 73, 86, 100], "\u043e\u0441\u0442\u0440\u043e\u0442": 41, "\u0431\u044b\u0432\u0448": 41, "\u043d\u0430\u0440\u044f\u0434": [41, 85], "\u0432\u044b\u044f\u0432\u043b\u0435\u043d": 41, "\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0435\u043d": [41, 93], "\u043f\u043e\u0432\u0435\u0437\u043b": 41, "\u0437\u043d\u0430\u043a\u043e\u043c": [41, 51, 73, 82, 83, 85], "\u043f\u043e\u043c\u043e\u0447": 41, "\u043c\u0435\u043d\u0442\u0430\u043b\u0438\u0442\u0435\u0442": 41, "\u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u043d": [41, 52, 65], "\u043f\u043e\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430": 41, "cruft": 41, "loan": 41, "burden": [41, 74, 86], "rush": 41, "analogy": 41, "borrowing": [41, 69, 70, 76, 131], "credit": [41, 51], "card": [41, 46, 51, 74], "income": 41, "purchasing": 41, "zero": [41, 51], "reorganizing": 41, "contain": [41, 60, 65, 74, 75, 86, 90], "efforts": [41, 65, 77], "explains": [41, 74], "coined": 41, "wycash": 41, "digitalk": 41, "smalltalk": [41, 72, 82, 85], "accumulate": 41, "learnings": 41, "along": [41, 70, 72, 75, 76, 85, 86], "explanation": 41, "gonna": [41, 49], "stumble": 41, "disagreement": 41, "\u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442": [41, 56, 85], "\u0442\u0435\u043b": [41, 83, 85], "\u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a": 41, "\u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441": 41, "n": [41, 53, 74, 75, 82, 86, 88, 102], "\u0441\u0442\u0435\u043f\u0435\u043d": [41, 68, 74, 85, 94], "\u0446\u0435\u043d": [41, 70, 77, 88], "\u043e\u0431\u043b\u0438\u0433\u0430\u0446": 41, "\u043f\u043e\u043a\u0443\u043f\u043a": 41, "\u0441\u043e\u0442": [41, 74], "\u0434\u043e\u043b": [41, 56, 73, 76, 92], "\u0432\u044b\u043f\u043b\u0430\u0442": 41, "\u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430": 41, "\u0434\u043e\u0445\u043e\u0434\u043d": 41, "bankiros": 41, "\u043d\u0430\u043a\u043e\u043f\u043b\u0435\u043d": 41, "\u0442\u0435\u0445\u0434\u043e\u043b\u0433": 41, "\u044d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0442": 41, "\u0431\u0435\u0437\u043e\u0431\u0438\u0434\u043d": 41, "\u0430\u0441\u0441\u043e\u0446\u0438\u0438\u0440": 41, "\u0430\u043a\u0430\u0434\u0435\u043c\u0438\u0447\u0435\u0441\u043a": 41, "\u0437\u0430\u0434\u043e\u043b\u0436\u0435\u043d": 41, "\u0446\u0435\u043d\u0442\u0440": 41, "\u043e\u0442\u0440\u0430\u0436\u0435\u043d": [41, 102], "\u0442\u0440\u0430\u0434\u0438\u0446": 41, "\u0431\u0435\u0437\u043f\u0440\u043e\u0446\u0435\u043d\u0442\u043d": 41, "\u0432\u0437\u0430\u0438\u043c\u043e\u0432\u044b\u0440\u0443\u0447\u043a": 41, "\u0437\u0430\u0440\u043f\u043b\u0430\u0442": 41, "\u044f\u0432\u043b\u0435\u043d": [41, 74, 75, 76, 77, 85, 94, 100], "\u0434\u0440\u0443\u0436\u0435\u0441\u043a": 41, "\u043d\u0435\u0441\u0435\u0442": [41, 73], "\u043d\u0435\u0434\u043e\u043f\u043e\u043d\u0438\u043c\u0430\u043d": [41, 75], "uninteresting": 41, "judge": 41, "1k": 41, "looking": [42, 72, 74, 75, 85], "henry": 42, "ford": [42, 82, 85, 92], "\u0447\u0443\u0432\u0441\u0442\u0432": [42, 56, 83, 88, 92], "\u0436\u0435\u0440\u0442\u0432\u0443\u0435\u0442": 42, "\u0432\u0441\u0442\u0443\u043f": 42, "\u0434\u0435\u043c\u043e\u0440\u0430\u043b\u0438\u0437\u0430\u0446": 42, "\u043d\u0430\u0447\u043d\u0435\u0442": [42, 47], "\u0434\u0430\u0432": 42, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432": [42, 80, 86, 92], "\u0431\u0440\u0430\u043a\u043e\u0432\u0430": 42, "\u043e\u0442\u043a\u0430\u0436\u0435\u0442": 42, "\u043f\u0435\u0440\u0435\u0441\u043c\u043e\u0442\u0440": 42, "\u0434\u043e\u0431\u044c\u0435\u0442": 42, "\u043f\u043e\u0442\u0435\u0440\u044f": 42, "deliberately": [42, 85], "downgrade": 42, "demoralization": 42, "crap": 42, "overwhelm": 42, "temporarily": [42, 74], "testing": [42, 46, 47, 51, 62, 74, 76, 82, 85, 86], "reviewing": [42, 94], "sticking": 42, "\u0433\u043b\u0443\u0431\u0436": 42, "\u0437\u0430\u0431\u043e\u0442": 42, "\u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d": [42, 75], "\u0441\u043e\u0447\u0443\u0432\u0441\u0442\u0432": 42, "\u0442\u0440\u0435\u043d": 42, "\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432": 42, "\u0433\u043b\u0430\u0434\u043a": [42, 83], "\u0441\u043f\u0430\u0441\u0442": 42, "\u043f\u043e\u0437\u0438\u0442\u0438\u0432\u043d": [42, 85, 100], "\u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432": 42, "lies": [42, 85, 86], "surface": [42, 73], "sensitive": [42, 53], "compassion": 42, "lubrication": 42, "minimal": [42, 49, 73, 75], "passion": 42, "manipulative": 42, "enjoying": 42, "\u043c\u043e\u0442\u0438\u0432\u0430\u0446": [43, 72, 73, 75, 82], "\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u043d": [44, 46, 66, 70, 122], "\u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430": [46, 47], "\u0441\u043e\u0430\u0432\u0442\u043e\u0440": 46, "brant": [46, 66, 70, 73, 82, 85, 95], "opdyke": [46, 66, 70, 73, 82, 85, 95], "roberts": [46, 66, 70, 73, 82, 85, 95], "\u0441\u0442\u0438\u043b": [46, 72, 73, 85], "\u0441\u0442\u0430\u0440": [46, 47, 65, 74, 75, 76, 88], "\u0437\u0430\u0445\u043e\u0447\u0435\u0442": 46, "\u043c\u043e\u0434\u0435\u0440\u043d\u0438\u0437\u0430\u0446": 46, "\u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d": [46, 77, 92], "\u0431\u0443\u0434\u044c\u0442": [46, 73], "\u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": [46, 72, 74, 77, 82, 85, 86], "\u0437\u0430\u043f\u0443\u0442\u0430": [46, 93], "\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d": 46, "\u0440\u0430\u0437\u0431\u0440\u043e\u0441\u0430": 46, "\u0441\u043e\u0431\u0440\u0430": 46, "\u0432\u043e\u0435\u0434\u0438\u043d": 46, "\u0441\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440": 46, "\u0437\u0430\u043f\u0438\u0448": 46, "\u0440\u0430\u0437\u0432\u0435\u0441\u044c\u0442": 46, "\u0443\u0441\u0442\u0440\u043e": [46, 77, 83], "\u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d": 46, "\u0432\u0435\u0441\u0435\u043b": 46, "\u0432\u0435\u0447\u0435\u0440\u0438\u043d\u043a": 46, "\u0442\u043e\u0440\u0436\u0435\u0441\u0442\u0432\u0435\u043d": 46, "\u0441\u043e\u0436\u0433": 46, "\u0445\u043e\u0440\u043e\u0448\u0435\u043d\u044c\u043a": 46, "\u0432\u044b\u043f": 46, "\u0437\u0430\u043a\u0443\u0441": 46, "\u0440\u0430\u0441\u0442\u0432\u043e\u0440": 46, "\u0432\u043e\u0437\u0434\u0443\u0445": [46, 74, 85, 90], "tangled": 46, "inheritance": 46, "hierarchy": 46, "piece": [46, 74, 85, 90], "scattered": [46, 74], "unify": 46, "cards": 46, "display": 46, "prominently": 46, "nibbling": 46, "ceremoniously": 46, "burn": 46, "eat": [46, 82], "drink": 46, "demand": [46, 47], "visit": [46, 47], "activities": [46, 60, 62, 64, 74, 76, 77, 82, 85, 86], "\u0434\u043e\u043d": 46, "\u0440\u043e\u0431\u0435\u0440\u0442\u0441": 46, "\u043e\u0434\u043d\u0430\u0436\u0434": 46, "\u043c\u043e\u0440\u0449": 46, "\u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d": 46, "wince": 46, "duplication": [46, 76], "baseball": 46, "strikes": 46, "\u043a\u0440\u0430\u0441\u0438\u043a\u043e\u0432": [46, 74], "\u0442\u0440\u0438\u0433\u0443\u0431": [46, 74], "\u043f\u043e\u0434\u0440\u044b\u0432\u043d": 46, "\u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d": [46, 73, 85, 89, 92, 100], "\u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b": [46, 82, 83], "\u0441\u043d\u0430\u0447\u0430": [46, 47, 73, 74, 77, 83], "\u0443\u0434\u0430\u0441\u0442": [46, 74, 86], "advice": [46, 85, 92], "subversive": 46, "rapidly": [46, 74, 86], "suit": [46, 73, 86], "quicker": [46, 72, 85], "bug": [46, 47, 74], "fastest": [46, 74], "\u043c\u0430\u043a\u043a\u0430\u0432\u0435\u0435\u0432": [46, 70, 85], "\u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430": [46, 74, 95], "\u0440\u0435\u043b\u0438\u0437": [46, 86], "\u044e\u043d": 47, "\u0442\u0435\u0441\u0442": [47, 72, 74, 85], "xunit": [47, 73, 82, 85], "sunit": 47, "\u043f\u0440\u0438\u0441\u0442\u0443\u043f": [47, 74, 82], "\u0441\u0442\u0430\u043d\u0435\u0442": [47, 85], "\u0440\u0430\u0437\u043e\u0447\u0430\u0440\u043e\u0432\u044b\u0432\u0430": [47, 70], "\u043f\u0443\u0433\u0430": 47, "\u043e\u043f\u0430\u0441\u0435\u043d": [47, 85], "\u0448\u0430\u0433": [47, 83, 88, 90], "\u043a\u0430\u0440\u0442\u0438\u043d": [47, 74, 77, 85, 86, 88, 100], "\u0437\u0430\u0434\u0443\u043c\u044b\u0432\u0430": [47, 70, 74], "\u0432\u043d\u0435\u0441\u0442": [47, 56, 74], "\u043f\u0440\u0438\u044f\u0442\u043d": 47, "\u0442\u0435\u043c\u043d\u043e\u0442": [47, 83], "\u0441\u043e\u043b\u043d\u0435\u0447\u043d": 47, "\u043b\u043e\u0432": 47, "\u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u044f": 47, "\u043e\u0431\u0440\u0435\u0441\u0442": 47, "\u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u0438\u0432\u043d": [47, 93], "\u043d\u0430\u0447\u043d\u0443\u0442": [47, 92], "\u0441\u043a\u0430\u043f\u043b\u0438\u0432\u0430": 47, "\u0441\u0442\u0440\u0430\u0448\u043d": [47, 83], "\u0447\u0443\u0434\u043e\u0432\u0438\u0449": 47, "\u0432\u044b\u043f\u0440\u044b\u0433\u043d\u0443\u0442": 47, "\u043f\u0440\u0435\u0436\u043d": [47, 76, 85], "\u043e\u0446\u0435\u043d": [47, 70], "\u0441\u043e\u0431\u043b\u0430\u0437\u043d": 47, "\u043d\u0430\u043f\u0438\u0448": 47, "\u043d\u0430\u043c\u0435\u0440": [47, 74], "\u0443\u0447\u0430\u0441\u0442\u043e\u043a": [47, 95], "\u0437\u0430\u043c\u0435\u0434\u043b": [47, 72, 85], "\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442": 47, "\u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430": 47, "\u043e\u0431\u043e\u0437\u0440\u0438\u043c": [47, 102], "\u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430": [47, 85], "\u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442": [47, 74], "\u0431\u0443\u0434\u0442": 47, "frustrating": 47, "area": [47, 73, 100], "shifting": 47, "scary": 47, "picture": [47, 51, 74, 77, 85], "confidence": [47, 70, 74, 85], "night": 47, "avoiding": [47, 75, 82], "resist": 47, "tendency": [47, 85], "96in": 47, "dark": [47, 76, 82], "unknown": 47, "magnitude": 47, "untested": 47, "attract": 47, "thoroughly": [47, 65], "\u0441oncerns": [48, 124], "\u0438\u0441\u0447\u0435\u0440\u043f\u044b\u0432\u0430": 49, "\u0441\u0430\u043c\u043e\u043e\u0440\u0433\u0430\u043d\u0438\u0437": [49, 86, 88], "practitioners": 49, "discussions": [49, 76], "babok": [49, 52, 64, 82], "actual": [49, 52, 75, 85], "bas": 49, "precision": 49, "conversations": 49, "iiba": 49, "encourage": 49, "minimum": 49, "accurately": [49, 73, 74, 80], "testers": [49, 82, 85, 86], "satisfy": [49, 64, 75, 76], "regulations": 49, "riskiest": [49, 63], "karl": [49, 52, 53, 82], "wiegers": [49, 51, 52, 53, 82], "emphatically": 49, "audience": 49, "ain": 49, "sufficient": [49, 70, 76, 86], "intent": [49, 73, 74], "obsolete": [49, 52, 86], "digital": [49, 82], "mechanical": [49, 72, 85], "property": 49, "knaster": [49, 51, 64, 82, 86], "preparation": 49, "artifacts": [49, 52, 73, 76, 82, 86], "transform": [49, 82], "narrative": 49, "preparing": 49, "packages": [49, 74, 90], "briefing": 49, "infrequent": 49, "milestone": 49, "meets": [49, 75, 86], "informal": 49, "completing": 49, "operator": 49, "baselines": 49, "versions": [49, 62, 65], "reuse": 49, "configuration": [49, 76, 86], "verification": [49, 59, 60, 85], "incident": 49, "bidirectional": 49, "automated": [49, 51, 85, 86], "measurement": 49, "atam": 51, "\u043f\u043e\u0439\u043c\u0435\u0442": 51, "k": [51, 74, 82], "wigers": 51, "\u0442\u043e\u043f\u043e\u0432": 51, "\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a": [51, 53, 86], "alongside": 51, "desk": 51, "technician": 51, "respond": [51, 60], "frustrated": 51, "hang": 51, "implications": 51, "efficiency": [51, 74, 85, 86], "deteriorate": 51, "corrective": 51, "quantify": 51, "stated": [51, 85], "keyword": 51, "preferably": 51, "pertinent": 51, "satisfied": 51, "satisfying": 51, "distinguish": [51, 82, 85, 95], "delight": 51, "disappointment": 51, "\u043f\u043e\u0434\u0440\u0430\u0437\u0434\u0435\u043b": 51, "beatty": 51, "\u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0437\u0430\u0446": 51, "\u0432\u044b\u0431\u0438\u0432\u0430": [51, 94], "\u043f\u043e\u0447\u0432": [51, 72, 82, 88, 91, 94, 138], "\u043e\u0442\u043e\u0440\u0432\u0430": [51, 75], "\u043b\u043e\u0431\u0431\u0438\u0440\u043e\u0432\u0430\u043d": 51, "nfrs": [51, 86], "\u043e\u0444\u0444": 51, "\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430": [51, 77], "\u0434\u0435\u043b\u0435\u0433\u0438\u0440\u043e\u0432\u0430": 51, "\u043f\u043e\u0441\u043c\u043e\u0442\u0440": [51, 56, 72, 73, 86, 88, 90], "enlist": 51, "assistance": [51, 86], "smes": 51, "incomplete": [51, 59, 65], "existence": [51, 64], "checklist": [51, 53], "browsers": 51, "prime": 51, "inclusion": 51, "browser": 51, "listed": 51, "recommend": 51, "waiting": [51, 70], "defers": 51, "critical": [51, 74, 76, 82], "relate": [51, 75, 82], "usability": 51, "maintainability": [51, 66, 75], "portability": 51, "\u0441\u043e\u0448\u043b": 51, "illustrated": 51, "appears": 51, "relevant": [51, 53, 76, 100], "affected": 51, "persisting": 51, "details": [51, 60, 65, 74, 77, 90], "throw": 51, "memorialized": 51, "1000": [51, 74], "simulated": 51, "suite": [51, 85], "excellent": 51, "accidentally": 51, "bottleneck": 51, "discovered": [51, 72, 85, 86], "forget": [51, 68], "fi": [51, 85], "remembers": 51, "treated": 51, "pci": 51, "compliance": [51, 77, 86], "security": [51, 86], "localize": 51, "supported": 51, "cfo": 51, "surely": [51, 85], "organized": [51, 82, 86, 100], "enterprises": [51, 64, 82, 86], "tooling": [51, 86], "central": 51, "scheduling": [51, 82, 86], "burndown": 51, "reporting": 51, "privileges": [51, 75], "granted": 51, "visibility": 51, "fosters": 51, "comments": 51, "interaction": [51, 52, 72, 73], "supplementary": 51, "auxiliary": 51, "rup": [51, 52, 65, 76, 86], "agilists": 51, "favor": [51, 85], "comprehensive": [51, 76], "supplemental": 51, "specif": 51, "cation": 51, "amounts": 51, "shippable": 51, "milestones": 51, "mandatory": [51, 52], "cations": 51, "epic": [51, 52, 82], "juha": [51, 52, 82, 86], "markus": [51, 52, 82, 86], "aalto": [51, 52, 82, 86], "syrs": 52, "15288": [52, 64, 82], "translates": 52, "expresses": 52, "lists": [52, 82, 85], "convey": [52, 100], "\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d": [52, 85, 92], "compiling": 52, "inventory": 52, "placeholders": 52, "pbis": 52, "currency": 52, "expressing": [52, 85], "traditionally": 52, "statements": [52, 77], "uml": [52, 75, 82], "workhorses": 52, "\u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d": [52, 75, 82], "express": 52, "emphasizing": 52, "verbal": 52, "cohn": [52, 76, 82, 83, 88, 92], "advantages": [52, 76, 85], "\u0441\u0435\u043c\u0430\u043d\u0442\u0438\u0447\u0435\u0441\u043a": [52, 65, 102], "\u043d\u0435\u0434\u043e\u0441\u0442\u0438\u0436\u0438\u043c": 52, "steered": 52, "dictionary": [52, 75], "obligatory": 52, "carries": 52, "connotation": 52, "absolutism": 52, "permanence": 52, "inhibitors": 52, "thousand": 52, "envisioned": 52, "80": [52, 74, 85], "weren": 52, "estimation": [52, 80, 82], "perspectives": [52, 82], "interact": [52, 72, 74, 86], "combine": 52, "extend": [52, 75], "\u0430\u043a\u0446\u0435\u043d\u0442": [52, 100], "\u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0430": 52, "accepts": 52, "determined": [52, 65, 86], "emerge": [52, 86], "develops": [52, 86], "intermediate": [52, 85], "releases": [52, 73, 82, 86], "phone": 52, "dials": 52, "covers": 52, "variants": 52, "obtained": 52, "differs": 52, "lay": 52, "claim": 52, "achieving": [52, 74, 76, 86], "collected": 52, "progresses": [52, 65], "absolute": 52, "literature": [52, 82], "suggests": [52, 73, 85, 86], "blasts": 52, "presents": 52, "imagination": 52, "authors": 52, "constantly": [52, 74, 76], "criticism": 52, "gathering": [52, 75], "\u0443\u0442\u043e\u0447\u043d\u044f": 52, "ireb": [52, 64, 82], "certified": [52, 64, 82], "advanced": [52, 64, 82], "\u0430\u043a\u0440\u043e\u043d\u0438\u043c": 53, "invest": [53, 85], "independent": [53, 72, 74, 86, 90], "negotiable": 53, "estimable": 53, "acronym": 53, "alliance": 53, "\u0430\u043a\u0440\u043e\u043d": 53, "\u0437\u043d\u0430\u043a": [53, 76, 93], "mnemonic": 53, "measurable": 53, "attainable": [53, 75], "\u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446": 53, "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442": [56, 65, 76, 80, 86, 94], "\u043a\u043e\u043d\u0435\u0441\u0435\u043d\u0441\u0443\u0441": 56, "\u043e\u0431\u043e\u044e\u0434\u043d": 56, "\u0443\u0449\u0435\u0440\u0431\u043d": [56, 88, 92], "\u0433\u0440\u0430\u043c\u043e\u0442\u043d": [56, 64, 74, 75, 76, 83, 86, 90], "\u0441\u043f\u0438\u043a\u0435\u0440": [56, 92, 95], "\u0437\u043e\u043d": [56, 92, 100], "\u043a\u043e\u043c\u0444\u043e\u0440\u0442": [56, 85, 92], "\u0430\u0433\u0440\u0435\u0441\u0441\u0438\u0432\u043d": 56, "\u043f\u043e\u043f\u044b\u0442\u043e\u043a": [56, 88, 92], "\u0434\u0438\u0441\u043a\u0440\u0435\u0434\u0438\u0442\u0430\u0446": 56, "\u043d\u0435\u0443\u0434\u043e\u0431\u043d": 56, "\u043c\u0430\u043b": [56, 74, 82, 83, 85, 100], "\u043d\u0435\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0438\u0432": [56, 92], "\u043f\u0443\u0441\u0442": [56, 82, 83, 92, 102], "\u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a": [56, 70], "\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u0446": [56, 82], "\u0441\u043e\u043f\u0435\u0440\u043d\u0438\u0447\u0435\u0441\u0442\u0432": 56, "\u043b\u0438\u0434\u0435\u0440\u0441\u0442\u0432": 56, "\u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430": [56, 92], "\u044d\u043d\u0446\u0438\u043a\u043b\u043e\u043f\u0435\u0434\u0438\u0447\u0435\u0441\u043a": [56, 92], "\u0441\u043b\u043e\u0432\u0430\u0440": [56, 75, 92, 100], "\u0433\u0430\u0440\u0434\u0430\u0440\u0438\u043a": [56, 92], "\u0438\u0432\u0438\u043d": [56, 92], "\u043a\u043e\u043d\u0444\u043e\u0440\u043c\u0438\u0437\u043c": [56, 88], "\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430": 56, "\u043f\u043e\u044f\u0441\u043d": [56, 70], "\u043f\u0440\u0435\u043a\u0440\u0430\u0442": 56, "\u043f\u0440\u0435\u043d": 56, "\u043d\u0435\u0441\u043e\u0433\u043b\u0430\u0441\u043d": 56, "\u0438\u0440\u0440\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [56, 88, 89, 94], "\u0443\u0441\u0438\u043b\u0435\u043d": [56, 88, 89, 94], "\u0440\u0430\u0441\u0441\u0442\u0430": 56, "\u043f\u0440\u043e\u0434\u0435\u043b\u0430": 56, "\u0434\u0435\u043c\u043e\u0442\u0438\u0432\u0430\u0446": 56, "\u0442\u0435\u043a\u0443\u0447\u043a": 56, "\u0443\u043f\u0443\u0449\u0435\u043d": [56, 70], "\u0441\u0434\u0432\u0438\u0433": 56, "\u0440\u044b\u043d\u043e\u043a": [56, 75, 86], "\u043f\u0440\u043e\u0441\u0442\u0430\u0438\u0432\u0430\u043d": 56, "\u043d\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d": 56, "\u0432\u0430\u043a\u0430\u043d\u0441": 56, "\u043e\u0442\u0432\u043b\u0435\u043a\u0430\u043d": 56, "\u043e\u043f\u044b\u0442\u043d": [56, 65, 76, 80, 85, 100], "\u043e\u0431\u0443\u0447\u0435\u043d": [56, 75, 86, 88, 89, 91, 93, 138], "\u043e\u0441\u0432\u043e\u0435\u043d": [56, 82, 94, 95], "\u0441\u043e\u0438\u0441\u043a\u0430\u0442\u0435\u043b": [56, 94], "\u0440\u0435\u0432\u044c\u044e\u0435\u0440": 56, "\u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430": [56, 73], "\u0438\u043d\u0441\u043f\u0435\u043a\u0446": 56, "\u043f\u0440\u043e\u0432\u0435\u0441\u0442": [56, 85, 88, 92], "\u0430\u043d\u0430\u043b\u043e\u0433": [56, 85, 90, 100, 102], "\u044d\u043c\u043f\u0438\u0440\u0438\u0447\u0435\u0441\u043a": [56, 65, 76, 80, 92], "\u0441\u0440\u043e\u0434\u043d": 56, "\u0445\u043e\u0436\u0434\u0435\u043d": [56, 94], "\u043e\u0449\u0443\u043f": 56, "\u043a\u0443\u0434": [56, 92], "\u0434\u043e\u0431\u0440\u0430": 56, "\u043f\u0440\u043e\u0438\u0441\u043f\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430": 56, "\u043f\u043e\u0442\u0440\u043e\u0433\u0430": 56, "\u0440\u0430\u0441\u0448\u0438\u0440": [56, 92], "\u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442": [56, 65, 73, 76, 95], "\u0440\u0443\u043b": [56, 92], "\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446": [56, 74], "\u0432\u043e\u0436\u0434\u0435\u043d": [56, 92], "\u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442": [56, 92], "\u0431\u0443\u0441\u0438\u043d\u043a": 56, "dr": [56, 82], "deming": 56, "red": [56, 85], "bead": 56, "experiment": [56, 86], "\u043d\u0430\u0440\u043e\u0434\u043d": [56, 65, 83, 85, 89], "\u043f\u043e\u0441\u043b\u043e\u0432\u0438\u0446": [56, 65, 85, 89], "\u0443\u0441\u043b\u044b\u0448\u0430": [56, 74, 75, 82], "mobbing": [56, 94], "\u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d": [56, 85], "\u0436\u0430\u043b\u043a": 56, "\u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430": 56, "allocates": [59, 60], "reworked": 59, "portion": 60, "inaccurate": [60, 65], "patton": [60, 62], "associates": [60, 62], "\u0432\u043b\u0430\u0441\u0442\u0432": [60, 90], "\u044d\u0434\u0441\u0433\u0435\u0440": [60, 90], "\u0434\u0435\u0439\u043a\u0441\u0442\u0440": [60, 74, 90, 92], "\u043f\u0440\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c": [60, 90], "\u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440": [60, 90], "\u043f\u043e\u043f\u0430\u0434\u0435\u0442": [60, 90], "\u0442\u0443\u043f\u0438\u043a": [60, 90], "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u043d": [60, 90], "\u0443\u043b\u0443\u0447\u0448\u0435\u043d": [60, 74, 75, 85, 86, 90], "\u043c\u043e\u0449\u043d": [60, 85, 86, 90], "\u0441\u043e\u0432\u0435\u0442\u043e\u0432\u0430": [60, 83, 90], "\u043f\u043e\u0439\u043c": [60, 90], "\u0441\u043e\u0441\u0442\u0430\u0432\u044c\u0442": [60, 90], "\u043e\u0433\u043b\u044f\u043d": [60, 90], "polya": [60, 90], "conquer": [60, 86, 90], "edsger": [60, 90, 92], "dijkstra": [60, 74, 90, 92], "pointed": [60, 74, 76, 90], "skull": [60, 73, 74, 90, 92], "applies": [60, 77, 90, 100], "areas": [60, 90, 100], "individually": [60, 90], "iterate": [60, 77, 86, 90], "refinement": [60, 65, 90], "devise": [60, 90], "2d": [60, 75, 82, 90], "ed": [60, 75, 90], "nj": [60, 75, 90], "press": [60, 74, 75, 82, 88, 90], "\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u043a": [60, 73, 74, 77, 90], "\u0442\u043e\u0440\u0433\u043e\u0432": [60, 73, 74, 77, 90], "\u0434\u043e\u043c": [60, 73, 74, 77, 90], "spiral": [61, 65, 129], "cyclic": 62, "prototyping": [62, 65], "repeatedly": 62, "refined": 62, "ronald": [62, 65, 82, 85], "graham": [62, 65, 82, 85], "donald": [62, 65, 82, 85, 88], "knuth": [62, 65, 82, 85], "oren": [62, 65, 82, 85], "patashnik": [62, 65, 82, 85], "\u0432\u0445\u043e\u0434": [62, 82], "final": [62, 75, 77, 86, 100], "subset": [62, 65, 74], "fluid": 62, "firm": [62, 82, 95], "clarify": [62, 65], "shift": [62, 65, 75], "dividing": [62, 74, 90], "ten": [62, 73, 74, 76, 86], "expecting": [62, 72, 85], "closely": [62, 75], "regardless": [62, 86], "regularly": 62, "agilealliance": 62, "variation": 63, "developmental": [63, 77], "proposes": [63, 86], "protection": 63, "occurring": [63, 74], "traits": 64, "fashion": 64, "observed": 64, "virtually": [64, 74], "encountered": 64, "noticeably": 64, "absent": 64, "strong": [64, 75, 85, 86], "maksimchuk": [64, 82], "engle": [64, 82], "bobbi": [64, 82], "ph": [64, 68, 82], "jim": [64, 82, 85], "conallen": [64, 82], "kelli": [64, 82], "houston": [64, 82], "\u043e\u0442\u043b\u0430\u0436": 64, "4cio": [64, 82], "sebok": [64, 75, 82], "mellarius": [64, 82, 92], "\u0441\u0430\u043c\u043e\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d": [64, 82, 86], "quick": [64, 74, 76], "itabok": [64, 82], "incose": [64, 82], "pmbok": [64, 82, 86], "pmi": [64, 82], "15289": [64, 82], "24765": [64, 82], "vocabulary": [64, 82], "9000": [64, 82], "2005": [64, 82, 83], "33001": [64, 82], "\u0433\u043e\u0441\u0442": 64, "\u0440": [64, 82], "\u0438\u0441": [64, 82], "\u043c\u044d\u043a": [64, 82], "2010": [64, 76, 82, 83, 88], "\u0438\u043d\u0436\u0435\u043d\u0435\u0440": [64, 73, 82, 86], "57193": [64, 82], "2016": [64, 80, 82, 88, 100], "perplexed": [64, 82], "barry": [64, 82], "boehm": [64, 82], "turner": [64, 82], "\u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 64, "\u0430\u0441\u043f\u0435\u043a\u0442": [64, 74, 77, 82, 90, 94, 100], "pediction": 64, "disciplined": [64, 82, 85], "scaled": [64, 76], "situations": [64, 76], "harmonized": 64, "identical": [64, 85], "specialization": 64, "products": [64, 85], "crystal": [65, 76], "balls": [65, 74, 85, 90], "predict": [65, 70], "competition": 65, "announcement": 65, "unanticipated": [65, 74], "crop": [65, 74], "direction": [65, 70, 73, 86], "furthermore": 65, "uncertain": [65, 76], "guessing": [65, 68], "spending": [65, 74, 86], "eight": 65, "fantasy": 65, "downfall": 65, "constructed": 65, "\u0433\u043b\u0430\u0437": [65, 74, 86, 88, 95], "\u0431\u043e": [65, 83, 85, 90, 93], "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0432\u0435\u0441": 65, "\u043d\u0430\u0443\u0447\u043d": [65, 75, 89, 92], "\u0442\u044b\u043a": 65, "\u0433\u0438\u043f\u043e\u0442\u0435\u0437": [65, 74], "\u0438\u043d\u0441\u043f\u0435\u043a\u0442\u0438\u0440\u0443": 65, "\u0430\u0434\u0430\u043f\u0442\u0438\u0440\u0443": 65, "\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d": [65, 85, 86], "\u0438\u043d\u043a\u0440\u0435\u043c": 65, "\u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u0442": 65, "\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d": 65, "\u0438\u0441\u0447\u0435\u0437\u0430": 65, "\u043f\u043e\u043d\u0438\u0436\u0430": 65, "\u0441\u043c\u0435\u0449\u0430": 65, "irreversible": 65, "acquire": [65, 85], "declines": 65, "likelihood": 65, "increasing": [65, 70], "certainty": [65, 100], "\u043d\u0435\u043e\u0442\u044a\u0435\u043c\u043b\u0435\u043c": 65, "\u0433\u0438\u0431\u0440\u0438\u0434\u043d": 65, "\u0441\u043e\u043e\u0442\u043d\u043e\u0448\u0435\u043d": [65, 74, 85], "\u0441\u0438\u0442\u0443\u0430\u0442\u0438\u0432\u043d": 65, "builders": 65, "extraction": 65, "assert": [65, 85], "exact": [65, 85], "promising": 65, "technological": 65, "attacks": 65, "accidents": 65, "deliverable": 65, "vast": [65, 74], "majority": [65, 74], "glibly": 65, "\u0437\u0430\u0440\u0430\u043d": [65, 70, 74], "\u043a\u0430\u0440\u0442\u0438\u043d\u043a": [65, 74], "\u0432\u0435\u0440\u0448\u0438\u043d": [65, 73, 77], "\u0432\u0432\u0435\u0440\u0445": [65, 77, 83], "fixes": 65, "varies": [65, 86], "friend": [65, 76], "foe": [65, 76], "alone": [65, 85], "sufficiently": 65, "needing": [65, 74], "tbs": 65, "tbr": 65, "clauses": 65, "tbx": 65, "designations": 65, "timeframe": 65, "incompletely": 65, "\u043d\u0435\u043f\u043e\u043b\u043d\u043e\u0442": 65, "srs": 65, "revisions": 65, "foreseen": 65, "inevitable": 65, "std": 65, "830": 65, "1998": [65, 75], "\u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a": [65, 102], "\u043d\u0438\u043a\u043e": 65, "annex": 65, "retrofitting": [66, 70], "9th": [66, 82], "roger": [66, 82], "pressman": [66, 82], "bruce": [66, 82], "swebok": [66, 82], "draft": [66, 82], "delay": [66, 70], "repair": [66, 70], "removing": [66, 70], "quadrant": [66, 70, 74, 85], "stamina": [66, 74], "hypothesis": [66, 74], "\u0442\u0435\u043f\u043b\u044f\u043a": [66, 70, 75, 82, 94], "\u0442\u0438": [66, 75], "\u043c\u0438\u043d\u0443\u0442\u043d": 66, "sig": 66, "sqale": 66, "identification": 66, "strecansky": 66, "stanislav": [66, 100, 102], "chren": 66, "bruno": 66, "rossi": 66, "\u043b\u0435\u0434\u043e\u043a\u043e\u043b": [66, 73, 74, 88, 91, 93, 95, 138], "\u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442": [68, 74, 90, 92, 94], "\u043f\u0440\u043e\u0434\u0443\u043c\u044b\u0432\u0430": 68, "\u0440\u044f\u0434\u043e\u0432": 68, "\u0443\u043c\u043d": [68, 70], "\u043e\u0432\u043b\u0430\u0434\u0435\u0432\u0430": 68, "\u043f\u043e\u043c\u0435\u043d\u044f": 68, "\u0443\u043c\u0435\u043d": [68, 73, 82, 83], "\u0434\u0430\u043b\u044c\u043d\u043e\u0432\u0438\u0434\u043d": [68, 73], "\u0442\u0435\u0441\u043d": [68, 85, 86], "hardest": 68, "\u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u043d": [68, 74, 90], "\u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430": [68, 82], "\u0447\u0430\u0441\u0442\u0435\u043d\u044c\u043a": [68, 82], "\u0441\u0435\u0440\u044c\u0435\u0437\u043d": [68, 75], "\u043c\u0435\u0448\u0430": [68, 75, 85, 100], "contribute": 68, "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0441\u043a": [68, 74], "\u0438\u043d\u0441\u0442\u0438\u043d\u043a\u0442": 68, "\u043f\u0440\u0438\u0432\u044b\u043a\u043b": [68, 85], "\u0441\u0447\u0430\u0441\u0442\u043b\u0438\u0432": [68, 88], "\u0443\u0432\u0435\u0441\u0442": 68, "\u0440\u0430\u0437\u043c\u044b\u0448\u043b\u0435\u043d": [68, 72, 74, 85, 86], "\u043e\u0442\u0443\u0447": 68, "\u043d\u0435\u043f\u0440\u0438\u044f\u0442\u043d": 68, "\u0432\u0437\u0430\u0439\u043c": 68, "\u0431\u0430\u0431\u0443\u0448\u043a": 68, "instincts": 68, "habit": [68, 73], "anticipating": 68, "sideways": 68, "fortunately": 68, "folks": 68, "unlearn": 68, "grandmother": 68, "smarter": [68, 85], "lazy": [68, 82], "irresponsible": 68, "lets": [68, 72, 73, 85], "premature": [68, 74], "suboptimal": 68, "mental": [68, 74, 90], "craftsmanship": [68, 73, 74, 82, 85], "\u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430": [70, 72, 85, 89], "\u043f\u043e\u0447\u0442": [70, 72, 73, 75, 85], "\u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d": 70, "\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u043d": [70, 86], "\u043d\u0435\u043f\u0440\u0435\u043e\u0434\u043e\u043b\u0438\u043c": 70, "\u0432\u043f\u0440\u043e\u043a": 70, "\u043d\u0435\u0432\u043e\u0441\u0442\u0440\u0435\u0431\u043e\u0432\u0430": 70, "\u043f\u0440\u0438\u0447\u0438\u043d\u044f": 70, "\u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d": 70, "\u0442\u0438\u043c\u043b\u0438\u0434": 70, "\u043e\u0431\u0440\u0430\u0437\u043d": 70, "\u043f\u043e\u043b\u043a\u043e\u0432\u043e\u0434\u0446": 70, "\u0433\u0440\u043e\u0448": 70, "\u0441\u043e\u043b\u0434\u0430\u0442": 70, "\u0443\u043c\u0435\u044e\u0442": 70, "\u0441\u0442\u0440\u0435\u043b\u044f": 70, "\u0432\u044b\u0440\u043e\u0441\u043b": 70, "emergent": [70, 76, 85], "\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433": [70, 72, 74, 75, 85], "\u0438\u0441\u043a\u0430": [70, 75, 82], "\u0434\u043e\u0440\u043e\u0433\u043e\u0441\u0442\u043e\u044f": 70, "\u0432\u044b\u0434\u0435\u0440\u0436\u0430": [70, 83], "\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u0442": [70, 85], "\u043f\u043b\u0430\u0442": 70, "\u043f\u0435\u0440\u0435\u043d\u0430\u0446\u0435\u043b\u0438\u0432\u0430": 70, "\u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430": [70, 85], "\u0434\u043e\u0441\u0442\u0438\u0447": [70, 74, 100], "\u043d\u0430\u0443\u0447": [70, 83], "\u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430": [70, 90], "\u043f\u043e\u0434\u0434\u0430": 70, "\u043f\u0435\u0440\u0435\u0441\u0442\u0430": [70, 85], "\u0443\u0432\u0435\u0440\u0435\u043d": [70, 85], "foresee": 70, "flex": 70, "forced": [70, 77], "designs": [70, 77, 85, 86], "stressful": [70, 85], "\u043b\u0430\u043a\u043c\u0443\u0441\u043e\u0432": 70, "\u0431\u0443\u043c\u0430\u0436\u043a": 70, "\u043b\u0438\u043d\u0435\u0439\u043d": [70, 74, 86], "\u0443\u0441\u043b\u043e\u0436\u0435\u043d": 70, "\u0438\u0437\u043b\u0438\u0448\u043d": [70, 85], "\u043a\u043e\u0441\u0432\u0435\u043d": [70, 72], "\u043e\u0434\u0438\u043d\u043e\u0447\u043a": [70, 74, 92], "\u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d": [70, 100], "npv": 70, "\u043a\u0430\u043a\u043e\u0432": 70, "\u0433\u043e\u0442": [70, 83, 95], "\u0437\u0430\u043f\u043b\u0430\u0442": 70, "\u0441\u043e\u0431\u0435\u0440\u0435\u0442": 70, "\u043f\u043e\u0434\u043e\u0436\u0434\u0435\u0442": 70, "\u0441\u0440\u0435\u0434\u043d": [70, 76, 85, 86], "\u043f\u0440\u043e\u0446\u0435\u043d\u0442\u043d": 70, "\u0441\u0442\u0430\u0432\u043a": 70, "\u043e\u043a\u043e\u043b": [70, 85, 93, 100], "\u0433\u043e\u0434\u043e\u0432": 70, "\u0443\u0447\u0435\u0442": [70, 82], "\u0438\u0441\u043a\u043e\u043c": 70, "87": 70, "\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d": [70, 85], "\u0433\u043e\u0434\u0438\u0447\u043d": 70, "\u043e\u0436\u0438\u0434\u0430\u043d": 70, "\u043e\u0436\u0438\u0434": [70, 72, 85], "\u0438\u043d\u0432\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430": 70, "\u0434\u0435\u043d\u044c\u0433": 70, "nvp": 70, "\u0437\u0430\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": 70, "\u043f\u0440\u0438\u0431\u044b\u043b": 70, "\u0441\u044d\u043a\u043e\u043d\u043e\u043c": [70, 74, 76, 85], "\u0438\u0437\u0431\u0430\u0432": [70, 82, 85], "\u043d\u0435\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d": 70, "merrily": 70, "wasn": [70, 85, 86], "vary": [70, 72, 73, 86], "calculator": 70, "cranks": 70, "investing": 70, "uncertainy": 70, "zilch": 70, "worthless": 70, "jargon": [70, 76], "\u043f\u043b\u044e\u0441": [70, 85], "expending": 70, "piracy": 70, "pricing": 70, "sales": [70, 100], "weather": 70, "storm": 70, "presumptive": 70, "insurance": 70, "imposes": 70, "debug": 70, "delayed": 70, "difficulties": 70, "\u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d": [70, 90], "\u043d\u0430\u0439\u0434\u0435\u0442": [70, 77], "\u0440\u043e\u0432\u043d": [70, 85, 90], "\u0441\u0442\u0435\u0440\u0435\u0442": 70, "\u043f\u043e\u0440\u043e\u0448\u043e\u043a": 70, "\u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442": 70, "\u043f\u0440\u0438\u043d\u044f": [70, 72, 83, 85, 92], "\u043e\u043a\u0430\u0436": 70, "\u0438\u043d\u0435\u0440\u0446": [70, 83], "\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c": 70, "\u043f\u0440\u043e\u0432\u0438\u0434\u0435\u0446": 70, "\u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430": [70, 73, 77], "\u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430": [70, 74, 82], "\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430": 70, "probability": 70, "knowing": [70, 85], "conclude": 70, "concludes": 70, "troubles": 70, "thereof": 70, "inertia": 70, "guesser": 70, "\u043f\u0440\u0438\u043d\u043e\u0441": 72, "\u0437\u043b\u043e\u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f": [72, 92], "\u043c\u043e\u043b\u043e\u0442\u043a": 72, "\u0433\u0432\u043e\u0437\u0434": 72, "\u0437\u0430\u0431": 72, "\u043f\u0430\u043b\u044c\u0446": [72, 85], "\u043e\u0442\u0431": 72, "\u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430": [72, 75, 86], "promotes": [72, 73, 86], "keeping": [72, 73, 74, 85, 86, 90], "independently": [72, 73, 86], "\u043b\u0435\u043a\u0430\u0440\u0441\u0442\u0432": 72, "\u0445\u0443\u0436": [72, 75, 83, 86], "\u0431\u043e\u043b\u0435\u0437\u043d": 72, "\u043e\u043f\u0440\u0430\u0432\u0434\u044b\u0432\u0430": 72, "\u0432\u043d\u043e": 72, "\u043f\u0440\u0438\u0432\u043d\u043e\u0441\u0438\u043c": 72, "\u0437\u043b\u043e\u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d": 72, "\u043f\u0435\u0440\u0435\u0443\u0441\u043b\u043e\u0436\u0435\u043d": 72, "\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0437\u0430\u0446": [72, 82, 92], "\u0432\u044b\u0434\u0443\u043c\u044b\u0432\u0430": 72, "\u043d\u0435\u0437\u043d\u0430\u043d": 72, "\u043d\u0435\u043e\u0441\u043e\u0437\u043d\u0430": [72, 85], "\u0443\u043b\u0443\u0447\u0448": [72, 74, 85, 86], "\u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430": 72, "\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440": [72, 85, 86], "\u0432\u043f\u0438\u0441\u044b\u0432\u0430": [72, 85], "\u044d\u043d\u0435\u0440\u0433": [72, 85, 90], "\u043c\u043d\u043e": [72, 74, 85], "\u043f\u0440\u043e\u0448\u0435\u0441\u0442\u0432": [72, 76, 85], "\u043d\u0435\u0434\u0435\u043b": [72, 74, 85], "\u0441\u043b\u0435\u0442\u0430": [72, 85], "\u0440\u0430\u0437\u043c\u044b\u0448\u043b\u044f": [72, 85], "\u043f\u0440\u0438\u0434": [72, 85], "\u0440\u043e\u0431\u0435\u0440\u0442": [72, 85], "\u043c\u0430\u0440\u0442\u0438\u043d": [72, 75, 85, 92], "\u0443\u0434\u0438\u0432\u043b\u044f": [72, 85], "\u043a\u0430\u0436\u0443\u0442": [72, 85], "\u0434\u043e\u0432\u0435\u0440\u044f": [72, 85], "\u043f\u0440\u0435\u0434\u0447\u0443\u0432\u0441\u0442\u0432": [72, 85], "\u043e\u0444\u043e\u0440\u043c": [72, 85], "noticed": [72, 85], "hope": [72, 85], "rote": [72, 75, 85], "redebating": [72, 85], "exception": [72, 85], "creativity": [72, 85], "stopping": [72, 85], "ripping": [72, 85], "fingertips": [72, 85], "pause": [72, 85], "bigger": [72, 73, 77, 85], "variant": [72, 85], "drive": [72, 85], "surprising": [72, 85, 86], "sensible": [72, 85], "\u0430\u043d\u0434\u0436\u0430": [72, 85], "\u043f\u0435\u0447\u0430": [72, 86], "heinemeier": 72, "hansson": 72, "\u043f\u0440\u043e\u0447\u0438\u0442\u0430": [72, 74, 82], "rails": 72, "ror": 72, "\u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442": 72, "\u0444\u043e\u043a\u0443\u0441": [72, 74, 76], "\u043f\u0440\u0438\u0440\u043e\u0441\u0442": [72, 85, 94], "\u0432\u0438\u0440\u0443\u0441\u043d": 72, "\u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d": 72, "\u0442\u0438\u043f\u043e\u0432": 72, "\u043f\u043e\u0443\u0447\u0438\u0442\u0435\u043b\u044c\u043d": 72, "\u0441\u0435\u0440\u0438\u0430": [72, 85], "badri": 72, "janakiraman": 72, "\u043e\u0447\u0435\u0432\u0438\u0434": 72, "mundane": 72, "repetitive": [72, 74], "truly": [72, 74], "unique": [72, 76, 100], "structured": [72, 74, 75, 76, 82, 86], "readers": 72, "commonality": 72, "verify": [72, 85], "\u043f\u0435\u0440\u0444\u0435\u043a\u0446\u0438\u043e\u043d\u0438\u0437\u043c": 73, "overengineering": 73, "imperative": [73, 76, 90], "\u043f\u0440\u0438\u0432\u043d\u0435\u0441\u0435\u043d": 73, "\u0433\u0435\u0440\u043e\u0438\u0447\u0435\u0441\u043a": 73, "\u0430\u0432\u0438\u0430\u0446\u0438\u043e\u043d": 73, "\u043f\u043e\u0436\u0430\u043b": [73, 88], "\u0441\u0430\u043c\u043e\u043b\u0435\u0442": 73, "62": 73, "skyships": 73, "\u043e\u0433\u0440\u043e\u043c\u043d": [73, 75, 82, 95], "\u043c\u0435\u0436\u043a\u043e\u043d\u0442\u0438\u043d\u0435\u043d\u0442\u0430\u043b\u044c\u043d": 73, "\u043b\u0430\u0439\u043d\u0435\u0440": 73, "\u043c\u0443\u0441\u043a\u0443\u043b\u044c\u043d": 73, "\u043f\u0438\u043b\u043e\u0442": [73, 86], "\u0431\u0435\u0437\u0431\u0443\u0441\u0442\u0435\u0440\u043d": 73, "\u0443\u0441\u0438\u043b\u0438\u0442\u0435\u043b": 73, "\u043f\u0440\u0438\u0432\u043d\u0435\u0441\u0442": 73, "\u0437\u0430\u0434\u043d": [73, 92], "\u0448\u0442\u0430\u043d\u0433": [73, 90], "kiss": [73, 82], "\u043f\u0440\u0435\u0434\u043a\u0440\u044b\u043b\u043a": 73, "\u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a": 73, "\u0437\u0443\u0431": 73, "\u043f\u0435\u0440\u0435\u0434\u043d": 73, "\u043a\u0440\u043e\u043c\u043a": 73, "\u043a\u0440\u044b\u043b": 73, "\u044f\u0440\u043a": [73, 92], "\u0432\u043e\u0431\u0440\u0430": 73, "\u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 73, "\u043d\u0430\u0440\u0430\u0431\u043e\u0442\u043a": 73, "\u0438\u0434\u0435\u043e\u043b\u043e\u0433": [73, 82], "\u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d": 73, "\u043c\u0430\u0433\u0438\u0441\u0442\u0440\u0430\u043b\u044c\u043d": 73, "\u043f\u0435\u0440\u0435\u0432\u043e\u0437\u043e\u043a": 73, "\u0441\u0441\u0441\u0440": 73, "\u0438\u043b\u044c\u044e\u0448\u0438\u043d": 73, "\u043f\u0430\u0441\u0441\u0430\u0436\u0438\u0440\u0441\u043a": 73, "\u0442\u0440\u0430\u043d\u0441\u043a\u043e\u043d\u0442\u0438\u043d\u0435\u043d\u0442\u0430\u043b\u044c\u043d": 73, "\u0432\u044b\u0448\u0435\u0434\u0448": 73, "\u0432\u043e\u0437\u0434\u0443\u0448\u043d": [73, 86], "1967": 73, "62\u043c": 73, "\u0441\u0442\u0430\u0432\u0448": [73, 83], "\u0444\u043b\u0430\u0433\u043c\u0430\u043d": 73, "\u0430\u044d\u0440\u043e\u0444\u043b\u043e\u0442": 73, "\u043f\u0440\u0438\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d": 73, "\u043f\u0440\u0438\u0441\u0443\u0449": 73, "\u0443\u043f\u043e\u0440\u0441\u0442\u0432": 73, "\u043d\u0430\u0434\u0435\u0436\u043d": 73, "\u0441\u043e\u0447\u0435\u0442\u0430\u043d": [73, 82, 85], "\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0447\u043d": [73, 76], "\u0431\u043e\u0435\u0432": [73, 83, 93], "\u0432\u043e\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u043d": 73, "\u0433\u0435\u043d\u0435\u0440\u0430\u043b\u044c\u043d": 73, "\u0430\u043a\u0430\u0434\u0435\u043c\u0438\u043a": 73, "\u044f\u043a\u043e\u0432\u043b": 73, "\u043e\u0442\u043c\u0435\u0447\u0430": 73, "\u043c\u0430\u0441\u0442\u0435\u0440": [73, 93], "\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u043e\u043d": 73, "\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u043c": 73, "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0441\u043a": 73, "\u0431\u044e\u0440": 73, "\u0432\u043e\u043f\u043b\u043e\u0449": 73, "\u0442\u0432\u043e\u0440\u0446": 73, "\u043c\u0430\u0448\u0438\u043d": [73, 82], "\u0441\u044b\u0433\u0440\u0430": 73, "\u0432\u043e\u0435\u043d": [73, 83], "\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0441\u043a": 73, "\u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442": 73, "\u0437\u0430\u043d\u044f": [73, 83], "\u0434\u043e\u0441\u0442\u043e\u0439\u043d": [73, 82, 83], "\u043e\u0442\u0435\u0447\u0435\u0441\u0442\u0432\u0435\u043d": 73, "\u0430\u0432\u0438\u0430\u0446": 73, "\u043f\u043b\u0430\u043d\u0435\u0440": 73, "\u043f\u043e\u043b\u0435\u0442\u043d": 73, "\u043a\u0433": [73, 83], "160": 73, "\u0438\u0441\u043f\u044b\u0442\u0430": 73, "\u043f\u043e\u043b\u0435\u0442": [73, 86, 92], "\u0434\u0435\u0441\u044f\u0442\u043a": [73, 82], "\u043d\u0435\u043f\u0440\u0435\u0432\u0437\u043e\u0439\u0434\u0435\u043d": 73, "\u043b\u0435\u0442\u043d": 73, "\u0431\u0438\u043e\u0433\u0440\u0430\u0444": [73, 83], "\u043f\u0430": 73, "\u043e\u0430\u043a": 73, "\u043f\u043e\u0441\u043b\u0443\u0448": 73, "\u043e\u0440\u0443\u0436\u0435\u0439\u043d": 73, "\u0430\u0432\u0442\u043e\u043c\u0430\u0442": 73, "\u043a\u0430\u043b\u0430\u0448\u043d\u0438\u043a": 73, "\u0436\u0443\u0440\u043d\u0430\u043b\u0438\u0441\u0442": 73, "\u0433\u0430\u0437\u0435\u0442": 73, "metro": 73, "\u043c\u043e\u0441\u043a\u0432": 73, "\u043f\u043e\u0441\u043b\u0443\u0448\u0430": 73, "\u0435\u0444\u0438\u043c\u043e\u0432\u0438\u0447": 73, "\u0440\u0435\u043f\u0438\u043d": 73, "\u0438\u0441\u0447\u0438\u0441\u043b\u044f": 73, "\u0441\u0438\u043c\u0432\u043e\u043b": [73, 74, 85], "\u043f\u043e\u043f\u0440\u043e\u0431": [73, 86], "echo": 73, "perl": 73, "\u0432\u0437\u0434\u0443\u043c\u0430": 73, "rm": 73, "rf": 73, "\u0430\u0431\u0437\u0430\u0446": 73, "battle": [73, 90], "elegance": [73, 85], "unpopular": 73, "appreciated": 73, "prerequisite": 73, "virtue": 73, "appreciate": 73, "sells": 73, "1984": 73, "ewd896": 73, "\u043e\u0441\u043e\u0437\u043d\u0430": [73, 82, 88, 92, 100], "\u0447\u0435\u0440\u0435\u043f": [73, 92], "\u0441\u043a\u0440\u043e\u043c\u043d\u043e\u0441\u0442": 73, "competent": [73, 82, 92, 95], "strictly": [73, 92], "humility": [73, 92], "1972": [73, 74, 86, 90, 92], "\u0438\u043c\u043f\u0435\u0440\u0430\u0442\u0438\u0432": [73, 74, 90], "\u043f\u043e\u0434\u0430\u0432\u043b\u0435\u043d": [73, 74, 90], "\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d": [73, 74, 82, 90], "greatly": [73, 74, 90], "aided": [73, 74, 90], "brain": [73, 74, 85, 88, 89, 90], "accidental": [73, 74, 75, 90], "proliferating": [73, 74, 90], "needlessly": [73, 74, 90], "disciplines": 73, "beneath": 73, "understands": 73, "coherent": 73, "reflects": 73, "minded": 73, "perfection": 73, "afford": [73, 77, 82], "remains": [73, 76, 86], "toolbox": 73, "fewer": [73, 74, 85, 90], "handful": 73, "mastery": [73, 82], "annals": 73, "owed": 73, "lines": [73, 74, 75, 85, 86, 94], "gotten": 73, "complicated": [73, 74, 75, 90, 100], "taste": [73, 76], "rolling": 73, "travel": 73, "light": [73, 76], "intellectual": 73, "nomads": 73, "tents": 73, "herd": 73, "anticipated": 73, "hot": 73, "climate": 73, "shifts": 73, "traveling": 73, "meetings": [73, 88], "lengthy": 73, "fulfill": 73, "refine": [73, 77, 85, 86], "impressed": 73, "dissatisfied": 73, "habits": [73, 82, 88, 95], "proportion": 73, "stop": [73, 76], "struggling": 73, "defect": [73, 74, 85], "improved": 73, "hours": [73, 74, 82, 86, 95], "dedicated": [73, 86], "lots": [73, 86], "intervention": 73, "hour": [73, 74, 82, 95], "steady": 73, "60": 73, "seventy": 73, "twenty": [73, 74], "66": 73, "minor": 73, "stopped": [73, 85], "digging": 73, "climb": 73, "eliminating": [73, 74], "excess": 73, "chip": [73, 88], "brighten": 73, "corner": 73, "objection": 73, "cleanup": 73, "wasting": 73, "interruptions": 73, "cleaning": 73, "mode": [73, 85, 86, 95], "saying": [73, 80], "vested": 73, "abandon": 73, "coder": [73, 74, 82, 85], "conduct": [73, 85], "destination": 73, "enquiry": 73, "frozen": 73, "straightforward": 73, "ease": [73, 85, 86], "articulated": 73, "optimal": 73, "tempt": 73, "messy": 73, "unprincipled": 73, "inventor": 73, "author": [73, 74, 76, 85, 88], "eventlet": 73, "readability": [73, 74], "excessively": 73, "clever": 73, "\u0441\u0443\u043f\u0435\u0440\u0433\u0435\u043d": 73, "\u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0435\u0442": 73, "\u0433\u0435\u043d": 73, "super": 73, "genius": 73, "mistake": [73, 75], "\u043f\u0440\u0438\u0432\u044f\u0437\u0430": 73, "\u0441\u0442\u043e\u043b\u0431": 73, "\u0437\u0430\u0431\u043b\u0443\u0434": 73, "\u0434\u0443\u0445\u043e\u0432\u043d": 73, "\u043b\u044e\u0441": 73, "\u043c\u0430\u043b\u043e\u0440": 73, "\u043d\u0435\u043a\u043e\u0433\u0434": 74, "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u043e\u0432\u0430\u043d": [74, 75, 85], "91": [74, 85], "\u0431\u043e\u0440\u044c\u0431": [74, 83, 85, 88, 92], "\u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440": [74, 85], "\u0443\u0445\u043e\u0434": [74, 83], "\u0434\u043e\u0432\u043e\u0434": [74, 75], "\u0437\u0430\u043f": 74, "\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 74, "90": [74, 76, 95], "\u043d\u0430\u0436\u0430\u0442": 74, "\u043a\u043b\u0430\u0432\u0438\u0448": 74, "\u043f\u0440\u043e\u0440\u0430\u0431\u043e\u0442\u0430": 74, "\u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442": [74, 92, 100], "\u0432\u0435": [74, 82, 85, 92], "\u0441\u043b\u043e\u0432\u043d": 74, "\u0443\u0441\u043a\u043e\u0440\u0435\u043d": [74, 85], "\u043a\u0438\u043d": 74, "\u043f\u043e\u0442\u0440\u044f\u0441\u0430": 74, "\u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a": 74, "\u0431\u043e\u0431": [74, 75], "\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446": 74, "\u0441\u043d\u043e\u0432": 74, "\u0441\u0442\u0438\u0440\u0430": 74, "\u0437\u0430\u043d\u043e\u0432": [74, 77], "\u043f\u043e\u043b\u043e\u0432\u0438\u043d": [74, 92], "\u043f\u0440\u043e\u043a\u0440\u0443\u0447\u0438\u0432\u0430": 74, "\u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430": [74, 86], "\u0441\u0442\u0435\u0440\u0442": 74, "\u0441\u0443\u0431\u043a\u043b\u0430\u0441\u0441": 74, "\u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f": 74, "\u0441\u0442\u043e\u043b": [74, 75, 94], "\u0443\u0439\u0442": 74, "\u043e\u043a\u0440\u0443\u0436\u0430": [74, 83, 100], "\u0441\u043e\u0431\u0438\u0440\u0430": [74, 86, 92, 93], "\u0441\u043f\u0440\u0430\u0432": [74, 83, 85, 94, 100], "\u043f\u043e\u0437\u0430\u0431\u043e\u0442\u044c\u0442": 74, "80s": 74, "track": 74, "keystroke": 74, "movie": 74, "fascinating": 74, "playback": 74, "scrolling": 74, "navigating": 74, "enters": 74, "scrolls": 74, "pauses": 74, "check": [74, 85], "initialization": 74, "begins": [74, 77], "ooops": 74, "erasing": 74, "typed": 74, "erases": 74, "erased": 74, "pops": 74, "subclass": 74, "overridden": 74, "drift": 74, "ratio": 74, "escape": 74, "surrounding": 74, "\u043c\u0430\u0442\u0432\u0435": [74, 85], "constructing": 74, "deficiencies": 74, "hoare": 74, "\u043e\u0445\u0432\u0430\u0442": [74, 90, 92, 94], "\u0432\u0441\u044e": [74, 77, 83, 90], "\u0441\u0432\u043e\u0435\u043e\u0431\u0440\u0430\u0437\u043d": [74, 90], "\u0443\u043c\u0441\u0442\u0432\u0435\u043d": [74, 85, 90], "\u0436\u043e\u043d\u0433\u043b\u0438\u0440\u043e\u0432\u0430\u043d": [74, 90], "\u0443\u0440\u043e\u043d": [74, 90], "\u0434\u043e\u043f\u0443\u0441\u0442": [74, 85, 86, 90, 100], "\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d": [74, 90], "\u043f\u043e\u0434\u0441\u0438\u0441\u0442\u0435\u043c": [74, 90], "\u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c": [74, 85, 86, 90, 93, 100], "\u0430\u0433\u0440\u0435\u0433\u0430\u0446": [74, 90], "\u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0442": [74, 90], "\u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432": [74, 77, 82, 90], "cram": [74, 90], "skulls": [74, 90], "organize": [74, 90], "juggling": [74, 90], "air": [74, 85, 90], "drop": [74, 76, 90], "comprehending": [74, 90], "workload": [74, 75, 90], "bottom": [74, 78, 90, 133], "compensate": [74, 90], "limitations": [74, 90], "\u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430": [74, 90], "\u0434\u0438\u0441\u043a\u0440\u0435\u0442\u043d": [74, 90], "miller": [74, 90], "1956": [74, 90], "\u0441\u0435\u043c": [74, 82, 85, 86, 90, 92], "\u043f\u043e\u0434\u0443\u043c\u0430": [74, 76, 90], "riel": [74, 90], "decomposed": [74, 86, 90], "magical": [74, 86, 90], "plus": [74, 90], "minus": [74, 90], "psychological": [74, 85, 90], "63": [74, 90], "97": [74, 90], "arthur": [74, 82, 90], "heuristics": [74, 82, 90], "ma": [74, 90], "\u0438\u0437\u0440\u0435\u0447\u0435\u043d": 74, "ninio": 74, "extinction": 74, "illusion": [74, 86], "dots": 74, "stevens": 74, "variations": 74, "hermann": 74, "grid": 74, "29": [74, 100], "1209": 74, "1217": 74, "akiyoshi": 74, "kitaoka": 74, "\u043c\u0438\u043b\u043b\u0435\u0440": [74, 85], "\u0440\u0435\u0446\u0435\u043f\u0442\u043e\u0440": 74, "\u0441\u0435\u0442\u0447\u0430\u0442\u043a": 74, "\u043d\u0435\u0441\u043f\u043e\u0441\u043e\u0431\u043d": 74, "\u043f\u0435\u0440\u0435\u043d\u043e\u0441\u043d": 74, "eye": 74, "receptors": 74, "stimulated": 74, "influenced": [74, 75], "neighboring": 74, "receptor": 74, "perceiving": 74, "stimulation": 74, "nearby": 74, "\u0438\u0437\u0431\u0438\u0440\u0430\u0442\u0435\u043b\u044c\u043d": 74, "\u0432\u043e\u0441\u043f\u0440\u0438\u044f\u0442": [74, 83, 88, 89], "\u043f\u0435\u0440\u0438\u0444\u0435\u0440\u0438\u0439\u043d": 74, "\u0432\u0438\u0434\u0435\u0442": [74, 90], "\u0441\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430": [74, 75, 76, 85, 86], "\u043e\u043f\u0442\u0438\u0447\u0435\u0441\u043a": 74, "\u0441\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440\u043e\u0432\u0430": [74, 85, 95], "\u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446": [74, 77, 85, 86], "\u043f\u0435\u0440\u0435\u0432\u0435\u0441": 74, "\u0432\u043c\u0435\u0449\u0430": 74, "elucidated": [74, 75], "mid": [74, 75], "70s": [74, 75], "yourdon": [74, 75], "constantine": [74, 75], "cascading": 74, "propensity": 74, "transitively": 74, "skips": 74, "loads": [74, 86], "decomposition": [74, 77, 82, 85], "monolith": [74, 75, 76, 82, 86, 89, 93], "micro": [74, 82], "adapted": [74, 76, 85], "blind": 74, "sided": 74, "novel": 74, "article": [74, 76, 82], "coded": 74, "protocol": [74, 82, 85], "navigate": 74, "manure": 74, "pile": 74, "aromatically": 74, "\u043d\u0435\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a": 74, "cheaper": [74, 85], "tradable": 74, "graph": [74, 82], "plots": 74, "imaginary": 74, "stereotypical": 74, "enabler": 74, "perceive": 74, "reduces": [74, 85], "lowers": 74, "sadly": 74, "countless": 74, "talked": 74, "professionalism": 74, "moralistic": 74, "dooming": 74, "annoying": 74, "crufty": 74, "misses": 74, "negative": [74, 86], "crafted": [74, 100], "unusual": 74, "absorb": [74, 86], "maximum": 74, "\u0443\u0434\u043e\u0431\u043e\u0447\u0438\u0442\u0430\u0435\u043c": 74, "\u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d": [74, 86, 100], "\u043e\u0431\u0449\u0430": [74, 86], "\u0441\u043b\u044b\u0448": [74, 85], "\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442": 74, "\u0432\u043f\u0435\u0440\u0435\u0434": [74, 85], "\u0432\u043f\u0438\u0441\u0430": 74, "\u043a\u043e\u0434\u043e\u0432": [74, 82, 83, 88], "\u0441\u0435\u0440": [74, 83, 85], "\u043d\u0430\u0432\u044b\u043a": [74, 83, 95], "\u0430\u0440\u0445\u0435\u043e\u043b\u043e\u0433": 74, "\u0437\u0430\u043c\u0435\u0434\u043b\u044f": [74, 76, 85], "\u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430": [74, 85], "\u043f\u0441\u0435\u0432\u0434\u043e\u0433\u0440\u0430\u0444\u0438\u043a": 74, "\u043e\u043f\u0438\u0440": [74, 77], "\u043c\u043e\u0434\u0443\u043b\u044c\u043d": 74, "\u043f\u043e\u043d\u044f\u0442": [74, 75, 83, 93, 100, 102], "\u043e\u0442\u043b\u0430\u0434\u043a": [74, 85, 86], "\u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430": [74, 75, 88], "\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c": [74, 86], "\u0441\u0442\u043e\u0439\u043a\u043e\u0441\u0442": 74, "\u0441\u043e\u0437\u0434\u0430\u0432": 74, "\u0434\u043e\u043a\u0430\u0437\u0430": [74, 75, 86, 88, 102], "\u043f\u043e\u0434\u0441\u043a\u0430\u0437\u044b\u0432\u0430": 74, "\u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c": 74, "\u043a\u0430\u0440\u044c\u0435\u0440": [74, 83], "\u0434\u0432\u0430\u0434\u0446\u0430": 74, "\u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442": 74, "\u0443\u043f\u0430\u0434\u043a": 74, "\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430": [74, 75, 83, 85], "\u0443\u043b\u0443\u0447\u0448\u0430": [74, 85, 94], "sounds": [74, 76], "counterintuitive": 74, "talk": [74, 86], "improves": [74, 85], "theseimprove": 74, "hear": [74, 75], "patches": 74, "covering": 74, "archaeology": 74, "blank": 74, "slate": 74, "visualize": 74, "affairs": 74, "pseudograph": 74, "leverage": [74, 86], "debugging": [74, 85, 86], "conventional": 74, "wrote": [74, 92], "decay": 74, "virtuous": 74, "earliest": [74, 76], "misconception": [74, 76], "manifests": [74, 76], "becoming": [74, 76, 82], "kills": [74, 75], "\u0441\u0442\u0440\u0430\u043d": [74, 75, 88], "\u043d\u0430\u0441\u0442\u0430\u0438\u0432": 74, "\u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430": 74, "\u0438\u043d\u0442\u0435\u0440\u0432\u0430": 74, "\u043b\u0438\u043f\u0448": 74, "\u0441\u043e\u043c\u043d\u0435\u043d": 74, "\u043f\u043e\u0434\u0447\u0438\u0441\u0442": 74, "\u0438\u0437\u043c\u0435\u0440\u0435\u043d": [74, 86], "\u043d\u0430\u0434\u0435\u0435\u0442": 74, "\u0437\u0430\u043a\u0440": 74, "\u043e\u0442\u0434\u0435\u043b\u043a": 74, "\u0443\u0432\u0435\u043b\u0438\u0447": [74, 76, 85, 86, 100], "\u0447\u0440\u0435\u0437\u0432\u044b\u0447\u0430\u0439\u043d": 74, "insisting": [74, 85], "episode": 74, "mess": 74, "prohibitively": 74, "unable": [74, 76], "listen": [74, 88], "indefinitely": 74, "forgiving": 74, "victim": 74, "organizes": 74, "operates": [74, 86], "deadline": 74, "bay": 74, "succumb": 74, "temptation": 74, "oxymoron": 74, "utopian": 74, "lifetime": [74, 75], "\u043f\u043e\u043c\u0435\u0448\u0430": 74, "\u043f\u0440\u0435\u0436\u0434\u0435\u0432\u0440\u0435\u043c\u0435\u043d": 74, "recall": 74, "saps": 74, "peoplepower": 74, "average": 74, "50": [74, 93], "noncoding": 74, "seemingly": 74, "nonprogrammer": 74, "tester": 74, "administrative": 74, "factored": [74, 85], "correcting": [74, 86], "naive": [74, 85], "importance": 74, "prerequisites": 74, "shortening": 74, "confirmed": 74, "involving": [74, 75], "nasa": 74, "laboratory": 74, "increased": 74, "assurance": 74, "decreased": 74, "rate": [74, 77, 86], "overalldevelopment": 74, "1987": 74, "findings": 74, "shortest": 74, "schedules": 74, "jones": [74, 75, 76, 82], "capers": 74, "assessments": 74, "benchmarks": 74, "holds": 74, "1985": [74, 88], "166": 74, "averaged": 74, "220": 74, "median": 74, "demarco": [74, 75, 76], "lister": 74, "slowest": 74, "shows": [74, 76, 86], "watts": 74, "humphrey": 74, "tsp": 74, "06": 74, "focuses": [74, 82], "weber": 74, "2003": 74, "morales": 74, "alexandra": 74, "consummate": 74, "coach": 74, "father": 74, "cmm": 74, "sd": 74, "cleanroom": 74, "confirm": 74, "checked": 74, "000": [74, 85], "740": 74, "closer": 74, "250": 74, "300": 74, "cusumano": 74, "worldwide": 74, "november": [74, 88], "december": 74, "34": 74, "savings": 74, "devoted": 74, "worthy": 74, "conducted": 74, "fjelstad": 74, "hamlen": 74, "1979": [74, 75, 88], "respondents": 74, "48": 74, "philadelphia": 74, "reprinted": 74, "parikh": 74, "zvegintzov": 74, "eds": 74, "los": 74, "alamitos": 74, "ca": [74, 76], "cs": 74, "1983": [74, 92], "\u0430\u043d\u0435\u043a\u0434\u043e\u0442": 74, "\u043c\u0443\u0436\u0438\u043a": 74, "\u043b\u0435\u0441": [74, 75], "\u0440\u0443\u0431": [74, 90], "\u043f\u0440\u0438\u0432\u0435\u0442": 74, "\u0440\u0443\u0431\u043b": 74, "\u0431\u0435\u043d\u0437\u043e\u043f": 74, "\u043f\u0440\u043e\u0447\u0442": 74, "\u0438\u0441\u0441\u043b\u0435\u0434\u0443": 75, "\u0441\u043e\u0436\u0430\u043b\u0435\u0435\u0442": 75, "historically": 75, "rephrase": 75, "cohesive": [75, 100], "binds": [75, 100], "symptoms": 75, "\u043d\u0435\u043d\u0430\u043c\u043d": 75, "heard": [75, 85], "unworkable": 75, "impractical": 75, "utter": 75, "nonsense": 75, "2002": [75, 76, 83], "\u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d": 75, "tom": [75, 76], "meilir": 75, "relatedness": 75, "demarco79": 75, "310": 75, "jones88": 75, "englewood": 75, "cliff": 75, "1988": 75, "newkirk": [75, 82], "koss": [75, 82], "\u0432\u0435\u0434\u0435\u0442": [75, 86], "\u0442\u0430\u043a\u043e\u0432": 75, "\u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d": [75, 86, 89], "\u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a": [75, 95, 102], "\u0441\u043e\u0435\u0434\u0438\u043d\u044f": 75, "\u0440\u0430\u0441\u0447\u043b\u0435\u043d\u044f": 75, "\u043e\u0441\u043c\u044b\u0441\u043b\u0435\u043d": [75, 92], "partitioning": [75, 86], "conventions": 75, "apart": 75, "conceptual": [75, 86], "reveals": 75, "lose": [75, 85, 86], "chunk": 75, "\u043f\u0435\u0440\u0435\u0443\u0441\u043b\u043e\u0436\u043d": [75, 100], "\u043a\u0440\u0438\u0442\u0438\u043a": [75, 83, 94], "\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 75, "\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0441\u0442\u0432": 75, "\u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u0438\u0432\u043d": 75, "\u0442\u0435\u0440\u0440\u0438\u0442\u043e\u0440\u0438\u0430\u043b\u044c\u043d": 75, "\u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432": 75, "\u0433\u0440\u0430\u0436\u0434\u0430\u043d": 75, "\u0434\u0432\u043e\u0439\u043d": [75, 83], "\u043d\u0435\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430": 75, "\u0432\u043e\u0441\u0445\u043e\u0434": 75, "inline": 75, "\u043e\u0442\u0431\u0438\u0440\u0430": [75, 100], "\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430": 75, "\u043f\u043e\u043d\u0438\u0436": 75, "\u043c\u043d\u043e\u0433\u043e\u0447\u0438\u0441\u043b\u0435\u043d": [75, 95], "\u0434\u0438\u0441\u0442\u0438\u043b\u043b\u0438\u0440\u043e\u0432\u0430": 75, "\u043a\u0443\u0441\u043e\u0447\u043a": 75, "\u043f\u0440\u0438\u043c\u0435\u0441": 75, "\u0441\u0438\u0445": 75, "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u043b\u043e\u0436\u043d": [75, 92], "active": 75, "corollary": 75, "gather": 75, "restated": 75, "multiples": 75, "reusability": 75, "confined": 75, "redeploy": 75, "revalidated": 75, "redeployed": 75, "prompts": 75, "bound": [75, 86], "physically": 75, "belong": 75, "minimizes": 75, "releasing": 75, "revalidating": 75, "redeploying": 75, "experienced": [75, 85], "amplifies": 75, "lesson": 75, "restricted": 75, "kitty": 75, "smallest": 75, "jar": 75, "gem": 75, "dlls": 75, "aggregations": [75, 77], "binary": [75, 82], "interpreted": [75, 100], "granule": 75, "\u043c\u043d\u043e\u0433\u043e\u043e\u0431\u0440\u0430\u0437\u043d": 75, "\u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442": [75, 83], "\u0437\u0430\u043f\u0443\u0442\u0430\u043d": 75, "\u0430\u0441\u0442": 75, "\u0445\u0430\u0440\u0432\u0435\u0441\u0442": 75, "\u044e": 75, "\u0433\u043e\u043b\u043e\u0432\u0438\u043d": 75, "\u043f\u0435\u0440": [75, 82, 88], "\u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0437": [75, 92], "\u043f\u0435\u0440\u0435\u043f\u043b\u0435\u0442\u0430": 75, "\u0441\u0432\u043e\u0439\u0441\u0442\u0432": [75, 100, 102], "\u0442\u043e\u043b\u043a\u043e\u0432": [75, 92], "\u0435\u0444\u0440\u0435\u043c\u043e\u0432": 75, "\u0444": [75, 82, 92, 100], "plex": 75, "k\u014fm": 75, "pl\u0115ks": 75, "complexus": 75, "complecti": 75, "entwine": 75, "comprise": 75, "plectere": 75, "twist": 75, "akin": 75, "plicare": 75, "plait": 75, "composite": 75, "gratitude": 75, "army": 75, "universe": 75, "locke": 75, "intricate": 75, "motions": 75, "heavens": 75, "calculated": 75, "whewell": 75, "fraction": 75, "ordinary": 75, "integers": 75, "syn": 75, "assemblage": 75, "complication": 75, "parable": [75, 76], "wedding": 75, "supper": 75, "comprehends": 75, "blessings": 75, "exhibited": 75, "gospel": 75, "geom": 75, "straight": 75, "relation": 75, "constitute": 75, "congruency": 75, "surfaces": 75, "webster": 75, "1913": 75, "connoisseur": 75, "wordsmiths": 75, "\u0432\u043d\u043e\u0441\u044f": 75, "\u043e\u043a\u0443\u043f\u0430": [75, 86], "\u0444\u043e\u0440\u043c\u0438\u0440\u0443": 75, "structural": [75, 85, 86], "adapt": [75, 76, 85], "\u0442\u0435\u043e\u0440\u0435\u0442\u0438\u043a": [75, 95], "\u0438\u043b\u043b\u044e\u0437\u043e\u0440\u043d": 75, "\u043c\u0438\u0440\u043a": 75, "\u043d\u0435\u0436\u0438\u0437\u043d\u0435\u0441\u043f\u043e\u0441\u043e\u0431\u043d": 75, "\u043e\u0431\u043e\u0441\u043d\u043e\u0432\u0430\u043d": [75, 89, 92], "\u0441\u043a\u0440\u044b\u0432\u0430": 75, "\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440\u0441\u043a": 75, "\u0435\u0434\u0438\u043d\u043e\u0434\u0443\u0448\u043d": 75, "\u0443\u0432\u0430\u0436\u0438\u0442\u0435\u043b\u044c\u043d": 75, "\u043c\u0430\u043d\u0435\u0440": 75, "\u0434\u043e\u043d\u0435\u0441\u0435\u043d": [75, 92], "\u043f\u0440\u0438\u043d": [75, 83, 88], "\u0430\u0434\u0430\u043f\u0442\u0438\u0432\u043d": 75, "\u0432\u044b\u043f\u0443\u0441\u0442": [75, 86], "\u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430": [75, 85, 86], "\u0435\u0434\u0438\u043d\u043e\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a": 75, "\u043f\u0440\u043e\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430": 75, "\u043f\u0440\u0438\u0437\u0432\u0430": [75, 76], "\u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432": 75, "\u0441\u0438\u0442\u0443\u0430\u0446\u0438\u043e\u043d": 75, "\u0431\u0435\u0441\u043f\u0435\u0447\u043d": 75, "\u043e\u0442\u0440\u044b\u0432\u0430": 75, "\u043d\u0430\u0432\u044f\u0437\u044b\u0432\u0430\u043d": 75, "\u0443\u0431\u0438\u0432\u0430": 75, "\u043a\u0443\u043b\u044c\u0442\u0443\u0440": [75, 83, 93], "\u0437\u0430\u0434\u0430\u0432\u0430\u043d": 75, "\u0432\u043e\u0432\u043b\u0435\u0447\u0435\u043d": 75, "\u043f\u0440\u0438\u0434\u0443\u043c\u0430": [75, 85], "\u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432": [75, 82], "adequate": 75, "situational": 75, "blithely": 75, "claiming": 75, "disconnects": 75, "questioning": 75, "engagement": 75, "\u043e\u0441\u043e\u0437\u043d\u0430\u0432\u0430": 75, "\u0444\u0438\u0434\u0431\u044d\u043a": 75, "\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430": 75, "\u043a\u0430\u0440\u0433": [75, 92], "\u043a\u0443\u043b\u044c\u0442": [75, 92], "\u0438\u0441\u043a\u0430\u0437": 75, "\u043e\u0448\u0438\u0431": 75, "\u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430": 75, "\u043f\u0440\u0438\u0432\u043b\u0435\u043a": 75, "\u043a\u043e\u043b\u043b\u0435\u0433": 75, "\u043e\u0440\u0438\u0433\u0438\u043d\u0430": [75, 100], "\u0438\u0437\u043b\u043e\u0436\u0435\u043d": [75, 82], "gym": 75, "lift": 75, "interpretations": 75, "backward": 75, "compatibility": 75, "ripple": 75, "1970s": 75, "1980s": [75, 76], "fertile": 75, "rage": 75, "notions": 75, "amplified": 75, "\u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442": [75, 92], "\u0430\u0431\u0431\u0440\u0435\u0432\u0438\u0430\u0442\u0443\u0440": 75, "grasp": [75, 82, 95], "\u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [75, 82, 100], "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d": [75, 85], "\u0434\u043e\u0441\u0442\u0438\u0433": 75, "\u0441\u0435\u0440\u0435\u0431\u0440\u044f\u043d": 75, "\u043f\u0443\u043b": [75, 94], "\u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a": [75, 85], "\u043f\u044f\u0442": [75, 76, 82], "\u0431\u0443\u043a\u0432": [75, 82, 92], "\u0432\u043e\u043b\u0448\u0435\u0431\u043d": [75, 95], "\u0437\u0430\u0439\u0434": 75, "\u043c\u043d\u043e\u0433\u043e\u043e\u0431\u0440\u0430\u0437": 75, "\u0432\u0437\u0430\u0438\u043c\u043d": 75, "\u043f\u0440\u0435\u0442\u0435\u043d\u0434": 75, "\u044d\u0442\u0430\u043b\u043e\u043d": 75, "\u0434\u0440\u043e\u0432": [75, 90], "\u043f\u0430\u0440\u043d": [75, 88, 94], "\u043a\u0440\u0443\u0433\u043e\u0437\u043e\u0440": 75, "\u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d": 75, "\u0431\u044d\u043a\u0433\u0440\u0430\u0443\u043d\u0434": 75, "kamil": [75, 82], "grzybek": [75, 82], "\u043f\u0440\u0435\u0442\u0435\u043d\u0434\u043e\u0432\u0430": [75, 102], "modular": [75, 76, 82], "\u0443\u0447\u0430\u0441\u0442": [75, 82], "\u0430\u0432\u0442\u043e\u0440\u0438\u0442\u0435\u0442": [75, 86, 88, 92], "injection": 75, "paint": 75, "teach": 75, "judgement": 75, "arbitrary": 75, "relevance": 75, "liskov": 75, "substitution": 75, "lsp": 75, "isp": 75, "inversion": 75, "dip": 75, "repeated": 76, "intentional": 76, "guided": [76, 82], "deliberate": 76, "conscious": [76, 89], "thrown": [76, 86], "finding": 76, "anticipation": 76, "highsmith": 76, "influence": 76, "redone": 76, "forgo": 76, "jump": 76, "positioned": 76, "medical": 76, "safety": 76, "website": 76, "kayak": 76, "racing": 76, "foretelling": 76, "speaker": 76, "expansion": 76, "capability": [76, 82], "bogged": 76, "materialize": 76, "breakfast": 76, "food": 76, "cooker": 76, "ridgecrest": 76, "do_while": 76, "toaster": 76, "htm": 76, "bogging": 76, "realizing": 76, "worrying": 76, "succeeding": [76, 82], "involves": 76, "in\ufb02uence": 76, "pendulum": 76, "swung": 76, "lduf": 76, "enuf": 76, "strawman": 76, "solely": 76, "emergence": 76, "argues": [76, 85, 86], "saves": 76, "waste": 76, "accelerates": 76, "emerging": [76, 82], "assumptions": [76, 86], "verified": [76, 86], "july": 76, "axiom": 76, "bias": [76, 89], "waterfalls": 76, "nest": 76, "consist": 76, "projecta": 76, "contrast": [76, 85], "middle": 76, "ground": 76, "classify": 76, "predominates": 76, "overlooked": 76, "wanting": 76, "unnecessary": 76, "excessive": 76, "punishment": 76, "ralf": 76, "2021": [76, 86], "\u043d\u0430\u0437\u0440\u0435\u0432\u0448": 76, "ages": 76, "laszczak": [76, 82], "\u0442\u0435\u043c\u043d": 76, "\u0432\u0435\u043a": 76, "\u043f\u0435\u0448\u043a\u043e\u0432": 76, "\u043a\u0430\u0447\u043d\u0443\u043b": 76, "\u043f\u0440\u0435\u043e\u0431\u043b\u0430\u0434\u0430": [76, 86], "ipu5hps1c4": 76, "camden": 76, "maine": 76, "war": 76, "von": 76, "clausewitz": 76, "military": 76, "swinging": 76, "forth": 76, "relative": 76, "armor": 76, "mobility": 76, "knights": 76, "shining": 76, "dominate": 76, "knight": 76, "nearly": [76, 82, 95], "naked": 76, "pony": 76, "warriors": 76, "swept": 76, "plains": 76, "genghis": 76, "kahn": 76, "mongols": 76, "cavalry": 76, "tanks": 76, "fleet": 76, "footed": 76, "palestinian": 76, "teenagers": 76, "sagger": 76, "missiles": 76, "maginot": 76, "french": 76, "gambling": 76, "hadn": 76, "germans": 76, "laudable": 76, "obsessed": 76, "tended": 76, "reacted": 76, "imperatives": 76, "thrust": 76, "foreword": 76, "\u0440\u0443\u0431\u0435\u0436": 76, "\u043e\u0442\u043a\u043b\u043e\u043d": 76, "\u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u0443": [76, 90], "pbr": [76, 80, 86], "spike": [76, 80, 86], "\u0440\u0430\u0434\u0438\u043a\u0430\u043b\u044c\u043d": 76, "\u043e\u0442\u043a\u0440": [76, 85], "\u0441\u043c\u0435\u0441\u0442": 76, "pretends": 76, "ah": 76, "thrive": 76, "mostly": 76, "lived": [76, 86], "addressing": 76, "angles": 76, "sustain": 76, "unexpected": 76, "attitude": [76, 85], "quote": 76, "msf": [76, 86], "rad": [76, 86], "fdd": [76, 86], "switch": [76, 85, 88], "\u0434\u0430\u0431": [76, 92], "\u0441\u0442\u0438\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430": 76, "\u043f\u0440\u043e\u0434\u0432\u0438\u0436\u0435\u043d": 76, "\u043f\u0440\u0438\u0437\u043d\u0430": [76, 85], "\u043f\u0440\u0438\u043d\u0435\u0431\u0440\u0435\u0433\u0430": 76, "arms": 76, "beliefs": 76, "\u043f\u043e\u0448\u0435\u043b": 76, "\u043a\u043e\u0434\u0438\u043d\u0433": 76, "\u0432\u044f\u043b": 76, "\u0432\u0441\u043a\u043e\u043b\u044c\u0437": 76, "\u0431\u0443\u043d\u0442": 76, "\u0437\u0430\u0432\u0435\u0442": 76, "c\u0440\u0435\u0434\u043d": 76, "\u043d\u0430\u0440\u0430\u0441\u0442\u0430": [76, 88], "\u043e\u043f\u0435\u0440\u0435\u0436\u0435\u043d": 76, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c": [76, 86], "\u0432\u043e\u0441\u043a\u0440\u0435\u0448\u0435\u043d": 76, "dad": [76, 88], "\u043d\u0435\u043c\u043d\u043e\u0433\u043e\u0447\u0438\u0441\u043b\u0435\u043d": 76, "\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0446": 76, "\u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b": 76, "\u0432\u0430": 76, "\u0441\u043e\u0432\u043f\u0430": 76, "\u0445\u0440\u043e\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 76, "\u0432\u0437\u0440\u044b\u0432\u043d": 76, "storytelling": 76, "\u0434\u0435\u0448\u0435\u0432\u043b": 76, "\u0440\u0435\u0438\u043d\u043a\u0430\u0440\u043d\u0438\u0440\u043e\u0432\u0430": 76, "nexus": 76, "\u0445\u0438\u0440\u0443\u0440\u0433": [76, 85, 86], "\u0445\u0430\u0440\u043b\u0430": 76, "\u043c\u0438\u043b\u043b\u0437": 76, "\u043c\u043b\u0430\u0434\u0448": 76, "\u043a\u043e\u043d\u0432\u0435": 76, "\u0432\u044b\u0434\u0432\u0438\u043d\u0443\u043b": 76, "despite": [76, 85], "amended": 76, "signers": 76, "living": [76, 82], "u": 76, "rewrite": 76, "talks": 76, "lessons": [76, 82], "individuals": 76, "\u043e\u0442\u0440\u0430\u0441\u043b": [76, 83, 92], "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d": [76, 102], "chaotic": 76, "secondary": [76, 85], "strips": 76, "determination": 76, "totally": 76, "un": 76, "strawberries": 76, "personally": [76, 85], "chose": 76, "introduces": [76, 86], "underlie": 76, "\u0430\u043d\u0434\u0440": 76, "\u0433\u0430\u043d\u0438\u0447": 76, "contributor": 76, "\u0431\u0440\u0430\u043d\u0434\u043e\u043b\u0438\u043d": 76, "collective": [76, 94], "\u043d\u0435\u0434\u043e\u043f\u0438\u0441\u0430": 76, "pretending": 76, "domains": [76, 86], "tuning": 76, "renaming": [76, 85], "iterating": 76, "reasonable": 76, "upfront": 76, "recalls": 76, "memories": 76, "infamous": 76, "banned": 76, "blasphemy": 76, "typing": 76, "firs": 76, "implicitly": 77, "executable": 77, "emerges": [77, 86], "numerous": 77, "shorterterm": 77, "elicit": 77, "architecturally": [77, 85], "peaks": 77, "cleland": 77, "huang": 77, "depaul": 77, "hanmer": 77, "alcatel": 77, "lucent": 77, "supakkul": 77, "sabre": [77, 86], "mehdi": [77, 82], "mirakhorli": 77, "progression": 77, "recursion": 77, "differing": [77, 86], "accomplishes": 77, "proceeds": 77, "purposeful": 77, "downstream": 77, "predicted": 77, "genuine": 77, "feasibility": 77, "arising": 77, "obsolescence": 77, "reverse": 77, "regulatory": 77, "nor": 77, "\u0444\u0435\u043d\u043e\u043c": 77, "\u043a\u043e\u0440\u043e\u0447": 77, "\u0432\u044b\u0439\u0434": 77, "\u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0432": 77, "\u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430": 77, "\u043f\u043e\u043c\u043e\u0436\u0435\u0442": 77, "\u043f\u043e\u043c\u043e\u0433\u0443\u0442": 77, "\u043f\u0440\u043e\u0447\u043d": 77, "\u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442": 77, "\u0441\u0432\u0435\u0440\u0445": [77, 88, 90], "wished": 77, "armed": 77, "gained": [77, 86], "shorter": 77, "whirl": 77, "tug": 77, "considerations": 77, "healthy": 77, "dynamic": [77, 82], "stressed": 77, "wholly": 77, "\u043d\u0438\u0441\u0445\u043e\u0434\u044f": 77, "\u0432\u043e\u0441\u0445\u043e\u0434\u044f": 77, "\u043a\u0430\u0437\u0430": 77, "\u043d\u0435\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a": 77, "\u0445\u043e\u0434": [77, 83, 88, 90, 92], "\u0434\u0435\u0442\u0430\u043b\u044c\u043d": 77, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d": [77, 82], "\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a": 77, "\u043e\u0431\u0449\u043d\u043e\u0441\u0442": 77, "\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446": 77, "\u0440\u0430\u0437\u0431\u0438\u0432": 77, "\u0441\u043e\u0441\u0442\u0430\u0432\u043b": 77, "\u043f\u0440\u043e\u0440\u044b\u0432\u0430": 77, "\u043f\u043e\u0442\u043e\u043f": 77, "\u044d\u0432\u0440\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": 77, "fashioned": 77, "nonspecific": 77, "derived": [77, 86], "collaborating": [77, 88], "specifics": 77, "generalities": 77, "generalizes": 77, "strategies": [77, 86, 88], "composition": [77, 85], "builds": [77, 85], "strengths": 77, "weaknesses": 77, "tends": [77, 85], "ripples": 77, "torpedo": 77, "trial": 77, "establish": [77, 86], "selecting": 77, "complained": 80, "\u043c\u0430\u043a\u0435\u0442": [80, 83], "ux": [80, 83, 86], "dor": [80, 86], "reveal": 80, "\u0431\u043b\u0438\u0437\u043e\u043a": 80, "\u0432\u044b\u0447\u0442": 80, "breakdown": 80, "logarithmically": 80, "yow": 80, "33": 80, "\u0443\u043f\u043e\u043c\u044f\u043d\u0443\u043b": 80, "\u043d\u0430\u0441\u0442\u0443\u043f\u0430": [80, 83, 88], "\u043f\u043e\u0441\u043e\u0432\u0435\u0442": 82, "\u0438\u0437\u043b\u043e\u0436": 82, "\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 82, "\u043d\u043e\u0432\u0438\u0447\u043a": 82, "\u0436\u0430\u0436\u0434": 82, "\u043d\u0435\u0442\u0435\u0440\u043f\u0435\u043b\u0438\u0432": 82, "\u043f\u043e\u0433\u043e\u043d": 82, "\u043d\u0430\u0434\u0440\u044b\u0432\u0430": 82, "\u0432\u043f\u0430\u0434\u0430": 82, "\u0434\u0435\u043f\u0440\u0435\u0441\u0441": [82, 95], "\u043c\u043e\u043b": 82, "\u0430\u043a\u0430\u0434\u0435\u043c\u0438\u0447\u043d": 82, "\u043d\u0435\u0443\u043c\u0435\u0441\u0442\u043d": 82, "\u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0430": 82, "\u043e\u0431\u0440\u0435\u0442\u0435\u043d": [82, 83, 92, 95], "\u043c\u0430\u0442": 82, "\u043f\u043e\u0431\u0435\u0434": [82, 83, 90], "\u0441\u0443\u0432\u043e\u0440": 82, "\u0433\u043d\u0430\u0442": 82, "advancement": [82, 95], "35": [82, 95], "authorities": [82, 95], "scientific": [82, 95], "spheres": [82, 95], "acts": [82, 95], "faithfully": [82, 95], "busy": [82, 95], "waking": [82, 95], "morning": [82, 95], "cited": 82, "\u0442\u0435\u043c\u0430\u0442\u0438\u043a": 82, "\u043b\u0435\u0433\u043b": 82, "\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b": 82, "\u043f\u043b\u0430\u043d\u043e\u0432": 82, "\u0448\u0442\u0430\u043c\u043f": 82, "\u043f\u0430\u0440\u0435\u0442": 82, "\u0434\u0438\u0441\u043a\u0443\u0441\u0441": [82, 83], "\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0437\u0438\u0440": 82, "\u043e\u0448\u0438\u0431\u0430": [82, 83, 88, 92], "\u043a\u0440\u0438\u0441\u0442\u0430\u043b\u0438\u0437\u0430\u0446": 82, "\u0441\u0434\u0435\u0440\u0436\u0430\u043d": 82, "\u0437\u0430\u0432\u0435\u0441\u0442": 82, "\u043a\u043e\u043c\u044c\u044e\u043d\u0438\u0442": 82, "\u0437\u0430\u043a\u0440\u0435\u043f\u043b\u0435\u043d": 82, "\u043f\u0440\u0435\u0434\u0448\u0435\u0441\u0442\u0432\u043e\u0432\u0430": 82, "\u043b\u0435\u0447": [82, 93, 94], "\u0440\u0438\u0441\u043a\u0443\u0435\u0448": [82, 93], "\u0443\u043c\u0435\u0440\u0435\u0442": [82, 93], "\u043e\u043f\u0435\u0447\u0430\u0442\u043a": [82, 93], "\u043c\u0430\u0440\u043a": [82, 83, 93], "\u0442\u0432\u0435\u043d": [82, 83, 93], "\u043d\u0430\u0437\u0440\u0435\u0442": 82, "\u043d\u0430\u043a\u043e\u043f\u043b": 82, "\u0441\u043e\u043b\u0438\u0434\u043d": 82, "\u0431\u0430\u0433\u0430\u0436": 82, "bridge": 82, "\u043f\u0440\u043e\u043c\u0435\u043b\u044c\u043a\u043d\u0443\u043b": 82, "smells": 82, "\u0432\u0441\u043f\u043e\u043c\u0438\u043d\u0430": [82, 83], "\u043d\u0430\u0432\u0435\u0447\u043d": 82, "\u0437\u0430\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043b": 82, "\u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d": [82, 100], "\u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446": [82, 85], "\u0444\u0430\u043d\u0430\u0442\u0438\u0437\u043c": 82, "\u0437\u0430\u0441\u0430\u0441\u044b\u0432\u0430": 82, "\u0443\u0440\u0430\u0432\u043d\u043e\u0432\u0435\u0448\u0438\u0432\u0430": 82, "\u0441\u043f\u043e\u0440\u0442": [82, 92, 93], "\u0444\u0438\u0437\u043a\u0443\u043b\u044c\u0442\u0443\u0440": 82, "\u0448\u0430\u0448\u043b\u044b\u043a": [82, 90], "\u043f\u0443\u0442\u0435\u0448\u0435\u0441\u0442\u0432": 82, "\u043d\u0435\u043f\u0440\u0435\u0434\u0432\u0437\u044f\u0442": 82, "\u0438\u0437\u043e\u0431\u0438\u043b": [82, 93], "\u0441\u0430\u043c\u043e\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446": 82, "\u0441\u0442\u0440\u0435\u0441\u0441": [82, 85, 92], "\u043e\u0446\u0435\u0432\u0430\u043d": 82, "\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043d": [82, 94], "\u043f\u0440\u0430\u0432\u0434\u0438\u0432": 82, "\u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430": 82, "\u043a\u043e\u0434\u0435\u0440": 82, "\u0438\u0437\u044b\u0441\u043a\u0430": [82, 92], "\u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a": 82, "5th": 82, "lutz": 82, "jyotiswarup": 82, "raiturkar": 82, "alan": 82, "donovan": 82, "inc": 82, "brian": 82, "kernighan": 82, "erlang": 82, "pragmatic": [82, 85], "joe": 82, "armstrong": 82, "frontend": 82, "angular": 82, "ng": 82, "book2": 82, "nate": 82, "murray": 82, "felipe": 82, "coury": 82, "ari": 82, "lerner": 82, "carlos": 82, "taborda": 82, "\u043f\u0440\u0438\u0432\u043e\u0436": 82, "\u0438\u0437\u043e\u043b\u044f\u0446": 82, "\u043e\u0441\u0442\u0430\u043d\u0435\u0442": 82, "\u043c\u0435\u0447\u0442\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432": 82, "\u043d\u0430\u0441\u0442\u0430\u0432\u043d\u0438\u043a": 82, "\u043f\u043e\u0441\u043e\u0432\u0435\u0442\u043e\u0432\u0430": 82, "\u0440\u0435\u0433\u0438\u0441\u0442\u0440": 82, "\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440": 82, "\u0443\u0441\u0442\u0430\u0440\u0435\u043b": 82, "kernel": 82, "primer": 82, "x86": 82, "powerpc": 82, "claudia": 82, "salzberg": 82, "rodriguez": 82, "gordon": 82, "smolski": 82, "computers": 82, "microprocessors": 82, "aliyev": 82, "\u0446\u0438\u0444\u0440\u043e\u0432": 82, "\u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d": 82, "\u043c\u0438\u043a\u0440\u043e\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440": 82, "\u0430\u043b": [82, 83], "administration": 82, "evi": 82, "nemeth": 82, "garth": 82, "snyder": 82, "hein": 82, "ben": [82, 89], "whaley": 82, "mackin": 82, "\u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d": [82, 85, 100], "\u0443\u0442\u0438\u043b\u0438\u0442": 82, "\u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446": 82, "\u0431\u0438\u0440\u0436\u0435\u0432": 82, "\u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440": 82, "\u0434\u0432\u0435\u0441\u0442": 82, "algorithms": [82, 90], "unlocked": [82, 90], "cormen": [82, 90], "\u0430\u043a\u0446\u0435\u043d\u0442\u0438\u0440": 82, "\u043d\u0435\u0432\u043e\u0441\u043f\u043e\u043b\u043d\u0435\u043d": 82, "levitin": 82, "appendix": [82, 85], "formulas": 82, "recurrence": 82, "\u0433\u0443\u0441\u0430\u043a": 82, "viii": 82, "background": 82, "leiserson": 82, "rivest": 82, "clifford": 82, "stein": 82, "\u043b\u0438\u043a\u0431\u0435\u0437": 82, "\u043f\u043e\u0434\u043e\u0439\u0442": 82, "wladston": 82, "ferreira": 82, "filho": 82, "\u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0442\u043e\u0440\u0438\u043a": 82, "\u0436\u0435\u043b\u0435\u0437": 82, "\u0444\u0430\u043c\u0438\u043b": 82, "\u0442\u043e\u0440\u043c\u043e\u0437": 82, "\u043e\u0441\u0432\u0435\u0436\u0430": 82, "volume": [82, 88], "\u0445\u043e\u0442\u0435\u043b": [82, 86, 95], "\u0441\u0442\u0443\u0434\u0435\u043d\u0447\u0435\u0441\u0442\u0432": 82, "\u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d": 82, "\u0441\u043b\u0435\u0433\u043a": 82, "\u0432\u043d\u0438\u043a\u0430": 82, "polyglot": 82, "pramod": 82, "sadalage": 82, "newman": [82, 86, 92], "russian": 82, "crdt": 82, "\u0436\u0434\u0430\u0442": 82, "\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432": 82, "microsoftarchive": 82, "sagas": 82, "garcia": 82, "molina": 82, "salem": 82, "\u043a\u043b\u0430\u0441\u0441\u0438\u043a": 82, "isolation": 82, "uniqueness": 82, "link": [82, 100], "smith": 82, "overselling": 82, "streams": 82, "savvas": 82, "kleanthous": 82, "dennis": 82, "doomen": 82, "conversion": 82, "michiel": 82, "overeem": 82, "marten": 82, "spoor": 82, "slinger": 82, "jansen": 82, "jimmy": 82, "bogard": 82, "ddddd": 82, "subdomain": [82, 100], "tl": 82, "macro": 82, "zhamak": 82, "dehghani": 82, "crew": 82, "sheet": [82, 89], "quiz": 82, "contextmapper": 82, "mapper": 82, "servicecutter": 82, "domoroboto": 82, "topo": 82, "visualizing": 82, "sociotechnical": 82, "maps": 82, "apis": 82, "odata": 82, "apigee": 82, "crafting": 82, "love": 82, "urls": 82, "w3c": 82, "graphql": 82, "openapis": 82, "asyncapi": 82, "rql": 82, "jsonpath": 82, "xpath": 82, "falcor": 82, "prakash": 82, "subramaniam": 82, "whoughtworks": 82, "crud": 82, "mullender": 82, "sergey": 82, "konstantinov": 82, "discovering": 82, "covid": 82, "acceleration": 82, "trader": 82, "kevin": 82, "webber": 82, "dana": 82, "harrington": 82, "shipment": 82, "refarch": 82, "kc": 82, "awesome": 82, "c4": 82, "starter": 82, "modernisation": 82, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d": [82, 85], "roadmap": 82, "scott": 82, "berkun": 82, "\u043e\u0440\u0433\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0447\u0435\u0441\u043a": 82, "\u0449\u0435\u0434\u0440\u043e\u0432\u0438\u0446\u043a": 82, "\u0433\u0435\u043e\u0440\u0433": 82, "\u043f\u0435\u0442\u0440\u043e\u0432\u0438\u0447": 82, "7th": [82, 88], "daft": [82, 88], "013": [82, 88], "journeyman": 82, "hunt": [82, 94], "20th": 82, "york": 82, "dorset": 82, "house": 82, "gerald": 82, "1992": [82, 88], "0932633226": 82, "harvard": [82, 88], "school": 82, "elevator": 82, "redefining": 82, "richards": 82, "neal": [82, 85, 92], "analyses": 82, "37": 82, "eaten": 82, "jungle": 82, "warfare": 82, "politician": 82, "phil": 82, "porter": 82, "presentations": 82, "mccullough": 82, "nathaniel": 82, "schutta": 82, "eben": 82, "donella": 82, "meadows": 82, "diana": 82, "wright": 82, "psychology": [82, 88], "13th": [82, 88], "myers": [82, 88], "\u043c\u0430\u0439\u0435\u0440\u0441": [82, 88], "\u0430\u043d\u0433\u043b": [82, 88], "\u0437": [82, 86, 88], "\u0437\u0430\u043c\u0447\u0443\u043a": [82, 88], "\u0437\u0430\u0432": [82, 88], "\u0440\u0435\u0434": [82, 88], "\u043a\u043e\u043b": [82, 88], "\u0432\u0438\u043d\u043e\u043a\u0443\u0440": [82, 88], "2006": [82, 88], "depended": 82, "voss": 82, "\u0434\u043e\u0433\u043e\u0432\u043e\u0440": 82, "\u0443\u0441\u0442\u0443\u043f\u043e\u043a": 82, "\u043a\u0440\u0438\u0441": 82, "\u0432\u043e\u0441\u0441": 82, "\u0441\u043f\u043e\u0440": 82, "\u044d\u0440\u0438\u0441\u0442\u0438\u043a": 82, "\u043f\u043e\u0431\u0435\u0436\u0434\u0430": [82, 88], "\u0448\u043e\u043f\u0435\u043d\u0433\u0430\u0443\u044d\u0440": 82, "\u0430\u0440\u0442\u0443\u0440": 82, "win": [82, 86], "schopenhauer": 82, "\u043e\u0431\u0443\u0447\u0430": 82, "\u0440\u0438\u0442\u043e\u0440\u0438\u043a": 82, "\u0434\u043e\u0445\u043e\u0434\u0447\u0438\u0432": [82, 89], "\u0432\u0438\u0434\u0435\u043e\u043a\u0443\u0440\u0441": [82, 89], "softskills": [82, 89], "pro": [82, 89], "mastering": 82, "dimitri": 82, "fontaine": 82, "antipatterns": 82, "pitfalls": 82, "karwin": 82, "ambler": 82, "ibrar": 82, "ahmed": 82, "gregory": 82, "enrico": 82, "pirozzi": 82, "\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d": 82, "\u043d\u0435\u043e\u0441\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d": 82, "\u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d": 82, "\u043b\u0443\u0437\u0430\u043d": 82, "\u0440\u043e\u0433": 82, "\u043b\u0435\u0432\u0448\u0438\u043d": 82, "\u0438\u0437\u043d\u0443\u0442\u0440": [82, 92], "\u0434\u043c\u043a": 82, "\u043f\u0440\u0435\u0441\u0441": 82, "2022": 82, "660": 82, "\u0443\u0447\u0435\u0431": [82, 88], "\u043f\u043e\u0441\u043e\u0431": [82, 88], "\u043c\u043e\u0440\u0433\u0443\u043d": 82, "\u0440\u043e\u0433\u043e\u0432": 82, "\u043b\u0443\u0437\u0430\u043d\u043e\u0432": 82, "\u043d\u043e\u0432\u0438\u043a": 82, "\u0433\u043e\u0440\u0448\u043a\u043e\u0432": 82, "\u0433\u0440\u0430\u0444\u0435\u0435\u0432": 82, "\u0441\u043b\u0430\u0439\u0434": 82, "\u0430\u0440\u0445\u0438\u0432": 82, "\u0432\u0438\u0434\u0435\u043e\u0437\u0430\u043f\u0438\u0441": 82, "mvcc": 82, "wal": 82, "\u0431\u0443\u0444\u0435\u0440\u043d": 82, "\u043a\u0435\u0448": 82, "dozen": 82, "replica": 82, "divergence": 82, "reads": 82, "skew": 82, "tagged": 82, "\u0440\u0435\u0439\u0442\u0438\u043d\u0433": 82, "ranking": 82, "soap": 82, "wsdl": 82, "restful": 82, "daigneau": 82, "architecting": 82, "dino": 82, "esposito": 82, "andrea": 82, "saltarello": 82, "nygard": [82, 86], "edited": 82, "betsy": 82, "beyer": 82, "jennifer": 82, "petoff": 82, "niall": 82, "murphy": 82, "workbook": 82, "sre": 82, "rensin": 82, "kawahara": 82, "stephen": [82, 88], "thorne": 82, "maintaining": [82, 86], "heather": 82, "adkins": 82, "blankinship": 82, "ana": 82, "oprea": 82, "piotr": 82, "lewandowski": 82, "stubblefield": 82, "erl": 82, "definitive": 82, "aalst": 82, "wil": 82, "der": 82, "russell": 82, "ter": 82, "hofstede": 82, "bpmn": 82, "dmn": 82, "jakob": 82, "freund": 82, "bernd": 82, "r\u00fccker": 82, "ruecker": 82, "hypermedia": 82, "savas": 82, "parastatidis": 82, "robinson": 82, "leonard": 82, "amundsen": 82, "mulloy": 82, "rulebook": 82, "mass\u00e9": 82, "higginbotham": 82, "medjaoui": 82, "erik": 82, "wilde": 82, "ronnie": 82, "mitra": 82, "psaltis": 82, "realtime": 82, "nathan": 82, "marz": 82, "warren": [82, 88], "bejeck": 82, "lake": 82, "promise": 82, "gorelik": 82, "millett": 82, "signature": 82, "rebecca": [82, 85], "parsons": [82, 85], "hatching": 82, "meier": 82, "hill": 82, "jason": [82, 85, 88], "taylor": 82, "prashant": 82, "bansode": 82, "lonnie": 82, "rob": 82, "boucher": 82, "akshay": 82, "bogawat": 82, "joshua": [82, 85], "kerievsky": [82, 85], "interpretation": [82, 85, 100], "sicp": 82, "harold": 82, "abelson": 82, "jay": 82, "sussman": 82, "julie": 82, "matthias": 82, "felleisen": 82, "findler": 82, "flatt": 82, "shriram": 82, "krishnamurthi": 82, "ivar": 82, "jacobson": 82, "frank": 82, "buschmann": 82, "regine": 82, "meunier": 82, "hans": 82, "rohnert": 82, "sommerlad": 82, "stal": 82, "networked": 82, "douglas": 82, "kircher": 82, "jain": 82, "henney": 82, "oberon": [82, 93], "wirth": 82, "fascicle": 82, "mmix": 82, "risc": 82, "millennium": 82, "seminumerical": 82, "sorting": 82, "searching": 82, "combinatorial": 82, "boolean": [82, 85], "bitwise": 82, "tricks": [82, 85, 94], "tuples": 82, "permutations": 82, "combinations": 82, "partitions": 82, "paperback": 82, "trees": 82, "preliminaries": 82, "backtracking": 82, "dancing": 82, "links": 82, "satisfiability": 82, "4a": 82, "maxx": 82, "bookz": 82, "gerard": [82, 85], "meszaros": [82, 85], "mocking": [82, 85], "growing": 82, "freeman": 82, "nat": 82, "pryce": 82, "lisa": 82, "crispin": 82, "janet": 82, "journeys": 82, "atdd": 82, "g\u00e4rtner": 82, "jez": 82, "farley": 82, "duvall": 82, "matyas": 82, "glover": 82, "istqb": 82, "referenced": 82, "syllabi": 82, "interpreters": 82, "craftinginterpreters": 82, "nystrom": 82, "compiler": [82, 85], "compilers": 82, "alfred": 82, "aho": 82, "monica": 82, "lam": 82, "ravi": 82, "sethi": 82, "ullman": 82, "documenting": 82, "felix": 82, "bachmann": 82, "garlan": 82, "ivers": 82, "reed": 82, "paulo": 82, "merson": 82, "judith": 82, "viewpoints": 82, "rozanski": 82, "e\u00f3in": 82, "woods": 82, "sei": 82, "humberto": [82, 86], "cervantes": [82, 86], "mcsweeney": 82, "haley": 82, "wixom": 82, "roberta": 82, "roth": [82, 88], "scientist": [82, 92], "sharing": 82, "cyrille": 82, "martraire": 82, "george": [82, 88], "fairbanks": 82, "migration": 82, "michele": 82, "danieli": 82, "francois": 82, "landreau": 82, "tahir": 82, "hashmi": 82, "lee": 82, "atchison": 82, "skelton": [82, 86], "manuel": [82, 86], "pais": [82, 86], "patrick": 82, "kua": 82, "muhammad": 82, "babar": 82, "kai": 82, "koskimies": 82, "mistr\u00edk": 82, "centric": 82, "murat": 82, "erder": 82, "pierre": 82, "pureur": 82, "architected": [82, 86], "reliant": 82, "jo": 82, "lane": 82, "quantitative": 82, "ricardo": 82, "valerdi": 82, "42010": 82, "42020": 82, "25010": 82, "square": [82, 86], "57100": 82, "\u0443\u043f\u0440\u0430\u043b\u0435\u043d": 82, "gartner": 82, "markets": 82, "unified": 82, "widrig": 82, "exam": 82, "compliant": 82, "klaus": 82, "pohl": 82, "rupp": 82, "\u0442\u0430\u0440\u0430\u0441\u0435\u043d\u043a": 82, "cpre": 82, "qualification": 82, "caution": 82, "syllabus": 82, "whitepaper": 82, "volere": 82, "estimating": [82, 83, 86], "demystifying": 82, "pert": 82, "bartosz": 82, "milewski": 82, "latex": 82, "wlaschin": 82, "marick": 82, "haskell": 82, "sergei": 82, "winitzki": 82, "monitoring": 82, "anuj": 82, "kumar": 82, "lex": 82, "sheehan": 82, "tucker": 82, "teofilo": 82, "gonzalez": 82, "jorge": 82, "diaz": 82, "herrera": 82, "eabok": 82, "mitre": 82, "bizbok": 82, "dama": 82, "dmbok": 82, "\u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043d": 82, "4cdto": 82, "\u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446": [82, 92], "competency": [82, 86], "sfia": 82, "bodies": 82, "allgosts": 82, "\u043a\u043e\u043d\u0442\u043e\u0440\u0441\u043a": 82, "standartgost": 82, "\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d": 82, "\u043c\u0430\u0433\u0430\u0437\u0438\u043d": 82, "catalog": 82, "dsl": 82, "overview": 82, "soapatterns": 82, "cloudpatterns": 82, "bigdatapatterns": 82, "clickable": 82, "subway": 82, "arcitura": 82, "playbook": 82, "selection": 82, "supporting": [82, 86], "chapters": [82, 86], "prep": 82, "interview": 82, "courses": 82, "maximal": 82, "luxoft": 82, "pratices": 82, "toolkits": 82, "decade": 82, "anemic": 82, "xoom": 82, "vlingo": 82, "demonstrating": 82, "goa": 82, "holistic": 82, "j\u00e9r\u00e9mie": 82, "chassaing": 82, "contributors": 82, "serverless": 82, "shop": 82, "showcase": 82, "zhang": 82, "xiaolong": 82, "dci": 82, "sys": [82, 86], "grpc": 82, "cockroachdb": 82, "shiju": 82, "varghese": 82, "displays": 82, "positions": 82, "transport": 82, "vehicles": 82, "helsinki": 82, "proto": 82, "ultra": 82, "kotlin": 82, "realtimemap": 82, "demo": 82, "taxi": 82, "bank": 82, "cargo": 82, "shipping": 82, "ftgo": 82, "eventuate": 82, "tram": 82, "packt": 82, "eventuous": 82, "extended": 82, "idris": 82, "redelastic": 82, "contosouniversitydotnetcore": 82, "lagom": 82, "lightbend": 82, "native": 82, "witn": 82, "hybrid": 82, "mission": 83, "geeks": 83, "linkedin": 83, "profile": 83, "\u043e\u0448\u0438\u0431\u043e\u0447\u043d": [83, 93, 100], "\u0431\u0435\u0441\u043f\u043e\u043a\u043e": [83, 85], "\u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b": 83, "\u043d\u0435\u0434\u043e\u043e\u0446\u0435\u043d\u043a": [83, 92], "\u043f\u0440\u043e\u0432\u043e\u0446\u0438\u0440": 83, "\u0445\u0440\u043e\u043d\u0438\u0447\u0435\u0441\u043a": 83, "\u043d\u0435\u0443\u0441\u043f\u0435\u0432\u0430\u0435\u043c": 83, "\u043f\u043e\u0439\u0434\u0435\u0442": 83, "\u0434\u043e\u043b\u0438\u043d": 83, "\u043e\u0442\u0447\u0430\u044f\u043d": 83, "\u0434\u0430\u043d\u043d\u0438\u043d\u0433": [83, 88, 89], "\u043a\u0440\u044e\u0433\u0435\u0440": [83, 88, 89], "\u0438\u0441\u043a\u0430\u0436\u0430": 83, "\u043b\u0435\u0433\u0435\u043d\u0434\u0430\u0440\u043d": 83, "\u043b\u0435\u0442\u0447\u0438\u043a": 83, "\u0430\u0441": 83, "\u0438\u0432\u0430": [83, 96], "\u043a\u043e\u0436\u0435\u0434\u0443\u0431": 83, "\u043d\u0438\u043a\u0438\u0442\u043e\u0432\u0438\u0447": 83, "\u043f\u0440\u0435\u0441\u043b\u0435\u0434\u043e\u0432\u0430": 83, "\u043f\u0435\u0440\u0435\u0432\u0435\u043b": 83, "\u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d": 83, "\u0437\u0430\u0441\u0442\u0443\u043f\u043d\u0438\u0447\u0435\u0441\u0442\u0432": 83, "\u043a\u043e\u043c\u0430\u043d\u0434\u0438\u0440": 83, "\u043f\u043e\u043b\u043a": 83, "\u043c\u0430\u0439\u043e\u0440": 83, "\u0441\u043e\u043b\u0434\u0430\u0442\u0435\u043d\u043a": 83, "\u043f\u043e\u043c\u043e\u0433\u043b": 83, "\u043e\u0434\u0435\u0440\u0436\u0430": [83, 90], "\u0432\u044b\u043b\u0435\u0442": 83, "\u0441\u0431\u0438\u0432": 83, "\u043f\u0438\u043a\u0438\u0440\u043e\u0432\u0449\u0438\u043a": 83, "\u043a\u0438\u0441\u0435\u043b": 83, "\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440": [83, 94], "\u043d\u0435\u0432\u0430\u0436\u043d": 83, "\u043d\u0430\u0437\u0438\u0434\u0430\u0442\u0435\u043b\u044c\u043d": 83, "\u043a\u0443\u0431\u0438\u043d\u0435\u0446": 83, "\u043b\u043e\u043f\u0435\u0441": 83, "\u0447\u0435\u0442\u044b\u0440\u0435\u0445\u043a\u0440\u0430\u0442\u043d": 83, "\u043e\u043b\u0438\u043c\u043f\u0438\u0439\u0441\u043a": 83, "\u0447\u0435\u043c\u043f\u0438\u043e\u043d": 83, "\u0433\u0440\u0435\u043a": 83, "\u0440\u0438\u043c\u0441\u043a": 83, "\u043f\u0440\u0435\u0432\u0437\u043e\u0439\u0434": 83, "\u0430\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440": [83, 88], "\u043a\u0430\u0440\u0435\u043b\u0438\u043d": 83, "\u0434\u043e\u0441\u0440\u043e\u0447\u043d": 83, "\u043f\u0435\u0440\u0435\u043b": 83, "\u043d\u043e\u0433": [83, 90], "\u043f\u043e\u043f\u0430": 83, "\u0441\u0431\u043e\u0440\u043d": 83, "\u043a\u0443\u0431": 83, "\u0448\u043b\u043e": 83, "\u0441\u043e\u0440\u0435\u0432\u043d\u043e\u0432\u0430\u043d": 83, "\u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442": 83, "\u0442\u0440\u0435\u0441\u043a": 83, "\u043f\u0440\u043e\u0432\u0430\u043b": [83, 85], "\u0444\u0438\u043d\u0438\u0448\u0438\u0440\u043e\u0432\u0430": 83, "\u0432\u0435\u0441\u043e\u0432": 83, "\u0432\u044b\u0441\u0442\u0443\u043f": [83, 88], "\u0437\u0430\u043b\u0430\u0434": 83, "\u043e\u043b\u0438\u043c\u043f\u0438\u0430\u0434": 83, "\u0430\u0444\u0438\u043d": 83, "\u0447\u0435\u0442\u0432\u0435\u0440\u0442\u044c\u0444\u0438\u043d\u0430\u043b": 83, "\u043a\u0443\u0431\u0438\u043d\u0446": 83, "\u0440\u043e\u0441\u0441\u0438\u044f\u043d\u0438\u043d": 83, "\u0445\u0430\u0441\u0430": 83, "\u0431\u0430\u0440\u043e": 83, "\u0432\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432": 83, "\u043b\u0438\u0448\u0435\u043d": [83, 102], "\u043c\u0435\u0434\u0430": 83, "\u0437\u0430\u0440\u044f\u0436": 83, "\u0448\u043b\u0438": 83, "\u043d\u0430\u0447\u0438\u043d": 83, "\u0443\u043f\u043e\u0440\u043d": [83, 94], "\u0443\u043f\u0440\u044f\u043c": 83, "\u043f\u043e\u0448\u043b": 83, "2007": 83, "\u043a\u0443\u0431\u0438\u043d\u0441\u043a": 83, "\u0433\u0438\u0433\u0430\u043d\u0442": 83, "\u043f\u043e\u0431": 83, "\u0440\u0435\u043a\u043e\u0440\u0434": 83, "\u043b\u0430\u0437\u043e\u0440\u0438\u043d": 83, "\u0438\u0433\u043e\u0440": 83, "\u0442\u0430\u0441\u0441": 83, "\u0442\u0440\u0443\u0434\u043e\u043b\u044e\u0431": 83, "\u0437\u0430\u0445\u043e\u0442\u0435\u0442": 83, "\u0431\u043e\u044f": 83, "\u043f\u0440\u0435\u043e\u0434\u043e\u043b\u0435\u0432\u0430": 83, "\u043b\u0435\u043d\u043e\u0441\u0442": 83, "\u0442\u0440\u0443\u0441\u043e\u0441\u0442": 83, "\u0441\u0430\u043c\u043e\u0432\u043e\u0441\u043f\u0440\u0438\u044f\u0442": 83, "\u0432\u0441\u0442\u0430\u0442": 83, "\u0434\u0438\u0432\u0430": 83, "\u043f\u043e\u0434\u043d\u044f": 83, "\u0442\u0443\u0448": 83, "\u0441\u043e\u043f\u0435\u0440\u043d\u0438\u043a": 83, "\u043a\u043e\u0432\u0440": 83, "\u0438\u043c\u043f\u0443\u043b\u044c\u0441": 83, "\u0432\u043e\u043b\u0435\u0432": [83, 95], "\u043f\u043e\u043c\u043e\u0433": 83, "\u0432\u044b\u0441\u043e\u043a\u043e\u043a\u043b\u0430\u0441\u0441\u043d": 83, "\u043d\u0435\u043c\u0430": [83, 85], "\u044e\u0440": 83, "\u043d\u0438\u043a\u0443\u043b\u0438\u043d": 83, "\u0432\u0433\u0438\u043a": 83, "\u0430\u043a\u0442\u0435\u0440\u0441\u043a": 83, "\u0433\u0438\u0442\u0438\u0441": 83, "\u0448\u043a\u043e\u043b": [83, 95], "\u0441\u0442\u0443\u0434": 83, "\u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440\u043d": [83, 100], "\u0436\u0430\u043d\u0440": 83, "\u043c\u043e\u0441\u043a\u043e\u0432\u0441\u043a": 83, "\u0446\u0438\u0440\u043a": 83, "\u0446\u0432\u0435\u0442\u043d": 83, "\u0431\u0443\u043b\u044c\u0432\u0430\u0440": 83, "\u0442\u0430\u043b\u0430\u043d\u0442\u043b\u0438\u0432": 83, "sylvester": 83, "stallone": 83, "\u0443\u0441\u043f\u0435\u0432\u0430\u0435\u043c": [83, 95], "\u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d": [83, 85], "\u0432\u043b\u0430\u0434\u0435\u043d": [83, 86, 89], "\u0441\u0442\u0440\u0443": 83, "\u043a\u043e\u043c\u0430\u043d\u0434\u043d": 83, "\u0444\u0430\u043d\u0442\u0430\u0441\u0442\u0438\u0447\u0435\u0441\u043a": 83, "\u043e\u0431\u043b\u0430\u0434\u0430\u043d": 83, "\u0443\u043c\u0435\u043b": [83, 90, 94], "\u0434\u0435\u043c\u043e\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430": 83, "\u0440\u0430\u0437\u043d\u043e\u0433\u043b\u0430\u0441": 83, "\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u043d\u0442": 83, "\u043f\u0440\u043e\u0434\u0430\u043a\u0442": 83, "\u043e\u0446\u0435\u043d\u0438\u0432\u0430\u043d": [83, 86], "\u043e\u0446\u0435\u043d\u043a": 83, "\u043d\u0430\u043f\u0440\u043e\u0447": 83, "\u0443\u0431": 83, "\u0432\u0437\u0430\u0438\u043c\u043e\u043f\u043e\u043c\u043e\u0449": 83, "\u0440\u0430\u0437\u043e\u0433\u043d\u0430": 83, "\u043d\u0435\u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d": 83, "\u043f\u0443\u0442\u0430": 83, "\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432": 83, "\u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440": 83, "\u043f\u043e\u0442\u043e\u043f\u0430": 83, "\u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d": [83, 86, 88], "\u0443\u0432\u043e\u043b\u044c\u043d\u0435\u043d": 83, "\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430": 83, "\u043f\u043e\u0441\u0442\u0430\u0432\u043b": 83, "\u043f\u043e\u043b\u0443\u0447\u0448": 83, "\u0432\u043b\u0438": [83, 85], "\u043a\u0430\u0440\u044c\u0435\u0440\u043d": 83, "\u0436\u0438\u0442": 83, "\u0447\u0435\u0441\u0442\u043d": 83, "\u0440\u0432\u0430\u0442": 83, "\u0431\u0440\u043e\u0441\u0430": 83, "\u0431\u043e\u0440\u043e\u0442": 83, "\u0441\u043f\u043e\u043a\u043e\u0439\u0441\u0442\u0432": [83, 95], "\u0434\u0443\u0448\u0435\u0432\u043d": 83, "\u043f\u043e\u0434\u043b\u043e\u0441\u0442": 83, "\u043b\u0435\u0432": 83, "\u043d\u0438\u043a\u043e\u043b\u0430\u0435\u0432\u0438\u0447": 83, "\u0442\u043e\u043b\u0441\u0442": 83, "\u043e\u0441\u043c\u0435\u043b\u0438\u0432\u0430": 83, "\u043c\u043e\u0433\u0443\u0447": 83, "\u0441\u043b\u0430\u0432\u043d": 83, "\u0442\u0440\u0438\u0443\u043c\u0444": 83, "\u043f\u0435\u0440\u0435\u043c\u0435\u0436\u0430": 83, "\u0441\u043b\u0430\u0431": [83, 90], "\u0434\u0443\u0445": 83, "\u043d\u0430\u0441\u043b\u0430\u0436\u0434\u0430": 83, "\u0434\u0443\u0448": 83, "\u0436\u0438\u0432\u0443\u0442": 83, "\u0441\u0443\u043c\u0435\u0440\u043a": 83, "\u043f\u043e\u0440\u0430\u0436\u0435\u043d": 83, "\u043c\u0443\u0436\u0435\u0441\u0442\u0432": 83, "\u0441\u043f\u043e\u0442\u043a\u043d\u0443\u043b": 83, "\u0434\u043e\u0441\u0442\u043e\u0438\u043d": 83, "\u0430\u0440\u0435\u043d": 83, "\u043f\u043e\u043a\u0440\u044b\u0442": [83, 85], "\u043a\u0440\u043e\u0432": 83, "\u0433\u0440\u044f\u0437": 83, "\u043e\u0442\u0432\u0430\u0436\u043d": 83, "\u0431\u043e\u0440\u0435\u0442": 83, "\u0441\u043e\u0432\u0435\u0440\u0448\u0430": 83, "\u043f\u0440\u043e\u043c\u0430\u0445": 83, "\u043f\u043e\u0437\u043d\u0430": 83, "\u043f\u0440\u0435\u0434\u0430\u043d": 83, "\u0432\u044b\u0441\u043e\u0447\u0430\u0439\u0448": 83, "\u043f\u043e\u0441\u0442\u0438\u0433\u0430": 83, "\u0434\u0435\u0440\u0437\u043d\u043e\u0432\u0435\u043d": 83, "\u0445\u043e\u043b\u043e\u0434\u043d": 83, "\u0440\u043e\u0431\u043a": 83, "\u043f\u0430\u0440\u0438\u0436": 83, "\u0441\u043e\u0440\u0431\u043e\u043d": 83, "1910": 83, "\u0442\u0435\u043e\u0434\u043e\u0440": [83, 89], "\u0440\u0443\u0437\u0432\u0435\u043b\u044c\u0442": [83, 89], "\u043b\u0435\u0442\u0430": 83, "\u0443\u043c\u0435\u0435\u0448": 83, "\u043a\u043e\u0432\u0447\u0435\u0433": 83, "\u043b\u044e\u0431\u0438\u0442\u0435\u043b": 83, "\u0442\u0438\u0442\u0430\u043d\u0438\u043a": 83, "\u0441\u043f\u043e\u0442\u044b\u043a\u0430": 83, "\u043c\u0443\u0434\u0440\u043e\u0441\u0442": 83, "\u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442": [83, 92, 100], "\u0437\u0430\u0436\u0435\u0447": 83, "\u0441\u0432\u0435\u0447": 83, "\u043f\u0440\u043e\u043a\u043b\u0438\u043d\u0430": 83, "\u043c\u0430\u0445\u0430\u0442\u043c": 83, "\u0433\u0430\u043d\u0434": 83, "\u0441\u043e\u043b\u043d\u0446": 83, "\u0431\u0435\u0437\u0440\u0430\u0437\u043b\u0438\u0447\u043d": 83, "\u043f\u043e\u0447\u0438\u0442\u0430": [83, 93], "\u0441\u0432\u0435\u0442\u043b\u044f\u0447\u043e\u043a": 83, "\u043f\u043e\u0434\u043e\u0440\u0432\u0430": 83, "\u0432\u043d\u0443\u0448\u0430": 83, "\u0441\u043c\u0435\u043b\u043e\u0441\u0442": [83, 88], "\u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d": [83, 88, 89, 90], "\u0433\u043e\u0441\u043f\u043e\u0434\u0441\u0442\u0432": [83, 90], "\u043c\u043e\u0436\u0435\u0448": 83, "\u0442\u043e\u0431": 83, "\u0432\u043e\u043a\u0440\u0443\u0433": [85, 86], "\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0435\u043b\u044c\u043d": 85, "\u0440\u043e\u043d": 85, "\u0434\u0436\u0435\u0444\u0444\u0440\u0438\u0437": 85, "seeming": 85, "contradiction": 85, "replies": 85, "paradox": 85, "\u0438\u0440\u043e\u043d": 85, "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 85, "ironies": 85, "koan": 85, "structuring": 85, "\u0434\u0435\u0444\u0435\u043a\u0442": 85, "\u0438\u0437\u044f\u0449\u0435\u0441\u0442\u0432": 85, "cleaner": 85, "souls": 85, "healed": 85, "balm": 85, "\u0431\u0430\u0437\u0438\u0440": 85, "\u043e\u0447\u0430\u0440\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d": 85, "\u043d\u0430\u0438\u0432\u043d": 85, "\u043f\u043e\u0434\u0445\u043e\u0434\u044f": 85, "\u0447\u0438\u0449": 85, "\u0432\u0441\u0442\u0430\u044e\u0442": 85, "rests": 85, "charmingly": 85, "geekoid": 85, "\u0437\u0430\u043a\u043e\u043d\u043e\u043c\u0435\u0440\u043d": [85, 92], "\u043c\u0438\u043d\u0443\u0441": 85, "\u0430\u043c\u0435\u0440\u0438\u043a\u0430\u043d\u0441\u043a": 85, "\u0434\u0436\u043e\u0440\u0434\u0436": 85, "\u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d": 85, "\u043f\u0440\u0435\u043e\u0434\u043e\u043b\u0435\u0442": [85, 90], "\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0430\u0446": [85, 86, 90, 100], "\u0432\u0435\u043d\u0438\u043a": 85, "\u043f\u043e\u043b\u043e\u043c\u0430": 85, "\u0440\u0430\u0437\u0432\u044f\u0437\u0430": 85, "\u043f\u0440\u0443\u0442\u0438\u043a": 85, "\u043f\u0435\u0440\u0435\u043b\u043e\u043c\u0430": 85, "\u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0440": 85, "\u043f\u0435\u0440\u0435\u043c\u0430\u043b\u044b\u0432\u0430": 85, "\u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d\u0438\u0440\u043e\u0432\u0430": 85, "\u043f\u043e\u044d\u0442\u0430\u043f\u043d": 85, "\u0432\u044b\u0441\u043e\u0442": [85, 90], "\u0444\u0443\u0442": 85, "feet": 85, "\u043d\u0435\u043e\u0431\u044a\u0435\u043c\u043b\u0435\u043c": 85, "\u0437\u0435\u043b\u0435\u043d": 85, "\u043c\u0430\u043d\u0442\u0440": 85, "mantra": 85, "factoring": 85, "\u0434\u043e\u0441\u043b\u043e\u0432\u043d": 85, "\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u0437\u0430\u0446": 85, "5x": 85, "broken": 85, "chunks": 85, "etymology": 85, "reorganization": 85, "equivalence": 85, "functionally": 85, "whatisreworking": 85, "practically": 85, "rewriting": 85, "grokable": 85, "operators": 85, "arguably": 85, "\u043d\u0430\u0441\u0442\u0430\u0432\u043d\u0438\u0447\u0435\u0441\u0442\u0432": 85, "\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0435\u0441\u0442\u0432": 85, "\u0443\u043e\u0440\u0434": 85, "\u043a\u0430\u043d\u043d\u0438\u043d\u0433\u044d\u043c": 85, "\u0434\u0440\u0443\u0436\u0431": 85, "\u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d": 85, "patient": 85, "mentoring": 85, "comfort": 85, "intimacy": 85, "factorization": 85, "decompositions": 85, "surjective": 85, "injective": 85, "conceive": 85, "\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u0437": 85, "\u0446\u0438": 85, "\u0444\u0430": 85, "\u043a\u0442\u043e\u0440\u0438\u043d\u0433": 85, "\u043f\u043e\u043b\u0438\u043d\u043e\u043c": 85, "\u043c\u0430\u0442\u0440\u0438\u0446": 85, "\u0431\u0443\u0434\u0443\u0447": 85, "\u043f\u0435\u0440\u0435\u043c\u043d\u043e\u0436\u0435\u043d": 85, "\u043f\u043e\u043b\u0438\u043d": 85, "x2": 85, "\u043f\u043e\u0434\u043e\u0431": [85, 92, 94], "\u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d": [85, 102], "\u0440\u0430\u0441\u0449\u0435\u043f\u043b\u044f": 85, "\u043f\u0435\u0441\u043e\u0447\u043d": [85, 95], "\u043f\u0435\u0441\u0447\u0438\u043d\u043a": [85, 95], "\u0438\u0437\u043e\u043b\u0438\u0440": 85, "\u0445\u0438\u0440\u0443\u0440\u0433\u0438\u0447\u0435\u0441\u043a": 85, "\u043e\u043f\u0435\u0440\u0438\u0440\u0443\u0435\u043c": 85, "\u043f\u0430\u0446\u0438\u0435\u043d\u0442": 85, "\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d": [85, 93, 100], "\u043f\u0440\u043e\u0441\u0442\u044b\u043d": 85, "\u0432\u0440\u0430\u0447": 85, "\u0441\u043a\u043e\u043b": 85, "\u043e\u0431\u0441\u0443\u0436\u0434\u0430": 85, "\u043e\u0440\u0433\u0430": 85, "isolate": 85, "operated": 85, "draped": 85, "draping": 85, "surgeon": 85, "abdomen": 85, "health": 85, "glad": 85, "\u0448\u043e\u0440": 85, "\u043e\u0449\u0443\u0449\u0430": 85, "\u0436\u043e\u043d\u0433\u043b\u0438\u0440": 85, "\u0448\u0430\u0440\u0438\u043a": 85, "\u0441\u044b\u043f\u0435\u0442": 85, "\u0434\u043e\u0431": 85, "\u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d": 85, "\u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430": 85, "\u0440\u0435\u0436": [85, 92], "\u0431\u0435\u0441\u043f\u043e\u043a": 85, "\u0440\u0430\u0441\u043f\u044b\u043b\u044f": 85, "lapse": 85, "concentration": 85, "tumbling": 85, "unhurriedness": 85, "ball": 85, "concentrate": 85, "worried": 85, "afterword": 85, "\u0432\u0442\u043e\u0440\u0438\u0447\u043d": 85, "\u043d\u0435\u0440\u0432\u043d": 85, "\u0437\u0430\u0441\u0442\u0430\u0432": 85, "pa\u0431\u043e\u0442\u0430": 85, "\u043f\u0430\u0440\u0442\u043d\u0435\u0440": 85, "\u0441\u0431\u043e": 85, "\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d": 85, "\u0432\u044b\u043f\u0443\u0441\u043a": 85, "mars": 85, "lander": 85, "teammates": 85, "andpeople": 85, "host": 85, "\u0443\u0434\u0435\u0440\u0436\u0430": 85, "\u0431\u0435\u0440\u0435\u0442": [85, 89], "\u043b\u0438\u0441\u0442\u043e\u0447\u0435\u043a": 85, "\u0440\u0443\u0447\u043a": 85, "\u043b\u0438\u0441\u0442\u043e\u0447\u043a": 85, "\u043f\u0435\u0440\u0435\u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [85, 92], "\u043f\u0440\u0430\u043a\u0442\u0438\u043a\u043e\u0432\u0430\u043d": 85, "\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c": [85, 90, 94], "\u0442\u0440\u0438\u0430\u043d\u0433\u0443\u043b\u044f\u0446": [85, 93], "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u044f": [85, 86], "\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430": 85, "\u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d": 85, "\u0432\u044b\u0432\u0435\u0434\u0435\u043d": [85, 92], "\u0444\u0438\u0431\u043e\u043d\u0430\u0447": 85, "fibonacci": 85, "\u043e\u0431\u043e\u0431\u0449": [85, 92], "\u0437\u0430\u043c\u0435\u043d\u044f": [85, 100], "\u0443\u043c\u043e\u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d": 85, "generalize": [85, 93], "replacing": [85, 93], "constants": [85, 93], "hardwired": [85, 93], "reasoning": [85, 93], "\u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d": 85, "\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440\u0443\u0435\u0442": 85, "imagining": 85, "sorts": 85, "generalizing": 85, "prevents": 85, "prematurely": 85, "confusing": 85, "extraneous": [85, 100], "recurrent": 85, "tower": [85, 86], "hanoi": 85, "\u043d\u0438\u0442\u043e\u0447\u043a": 85, "\u0440\u0430\u0441\u043f\u0443\u0442\u0430": 85, "\u043a\u043b\u0443\u0431\u043e\u043a": 85, "\u043f\u043e\u0434\u0441\u0442\u0443\u043f": 85, "\u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430": 85, "\u0432\u0434\u0432\u043e": 85, "83": 85, "\u0441\u0432\u0435\u0445": 85, "\u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442": 85, "\u0437\u0430\u0432\u044b\u0448": 85, "gorman": 85, "\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430": 85, "\u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d": 85, "\u043a\u0430\u0442": 85, "\u043f\u0435\u0440\u0435\u043f\u0440\u043e\u0432\u0435\u0440\u044f": 85, "\u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0438\u0440\u043e\u0432\u0430": 85, "decouple": 85, "untestable": 85, "mass": 85, "outputs": 85, "\u043f\u0440\u0435\u0443\u0432\u0435\u043b\u0438\u0447": [85, 88], "\u0431\u0435\u0437\u0443\u0441\u043b\u043e\u0432\u043d": 85, "overstating": 85, "sink": 85, "\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f": 85, "\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d": 85, "\u043d\u0435\u043f\u043e\u043b\u043d": 85, "shore": 85, "\u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f": [85, 88, 92], "opportunities": 85, "\u0442\u0435\u0441\u0442\u0438\u0440\u0443": 85, "\u043f\u043e\u0434\u043c\u0435\u043d\u044f": 85, "\u0433\u043b\u0443\u0431": 85, "\u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d": [85, 86, 88], "\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430": 85, "\u043e\u043a\u043e\u0432": 85, "\u043a\u0440\u0435\u0441\u0442": 85, "personal": 85, "mock": 85, "mocks": 85, "couldn": 85, "streets": 85, "piecemeal": 85, "assertequals": 85, "\u0431\u0443\u043b\u0435\u0432\u0441\u043a": 85, "\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442": 85, "startdate": 85, "\u0440\u0430\u0432": 85, "\u043f\u043b\u044b\u0442": 85, "\u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b": 85, "jxunit": 85, "junit": 85, "\u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d": 85, "\u043f\u043e\u0434\u0435\u043b\u0430": 85, "\u0441\u043c\u0430\u0445\u0438\u0432\u0430": 85, "\u043d\u0435\u043f\u0440\u043e\u0448\u0435\u043d": 85, "\u0441\u043b\u0435\u0437": 85, "\u0432\u043d\u043e\u0448": 85, "\u043d\u0430\u0434\u0435": 85, "\u043d\u0430\u0441\u0442\u0443\u043f": 85, "boxes": 85, "throws": 85, "swimming": 85, "tide": 85, "extends": 85, "wishing": 85, "anytime": 85, "checking": 85, "ran": 85, "shed": 85, "\u043f\u0440\u0430\u0433\u043c\u0430\u0442\u0438\u0447": 85, "\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443": [85, 92], "heavy": 85, "parse": 85, "pollute": 85, "speculation": 85, "providing": 85, "rip": 85, "\u043a\u043e\u0432\u0430\u0440\u043d": 85, "\u043f\u043e\u0432\u043b\u0435\u0447": 85, "\u0445\u0440\u0443\u043f\u043a": 85, "\u043d\u0430\u043f\u0440\u043e\u0442": 85, "strongest": 85, "insidious": 85, "fragile": 85, "rigid": 85, "increasingly": 85, "impedes": 85, "\u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430": 85, "\u0434\u0443\u0431\u043b\u0435\u0440": 85, "criticized": 85, "mockist": 85, "mockists": 85, "insist": 85, "classicists": 85, "stayed": 85, "pyramid": 85, "ham": 85, "vocke": 85, "testdrivendevelopment": 85, "implicates": 85, "recent": 85, "reverting": 85, "stubs": 85, "\u043c\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d": 85, "\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0438\u0440": 85, "monkey": 85, "patch": 85, "\u043d\u0438\u0437\u043a\u043e\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d": 85, "\u043c\u043e\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 85, "\u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d": 85, "\u043e\u0431\u043e\u043b\u043e\u0447\u043a": 85, "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430": 85, "\u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430": 85, "\u043f\u043e\u043b\u0443\u0444\u0430\u0431\u0440\u0438\u043a\u0430\u0442": 85, "\u0437\u0430\u0434\u0443\u043c\u044b\u0432": 85, "\u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430": 85, "\u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": 85, "\u0441\u043c\u0435\u0441": 85, "\u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d": [85, 94], "\u043f\u0440\u0438\u0432\u0435\u0440\u0436\u0435\u043d\u0446": 85, "\u043b\u0438\u0434\u0435\u0440": [85, 88], "\u043e\u043f\u0430\u0441\u043d": [85, 86], "\u043c\u043e\u0449": 85, "monological": 85, "flavors": 85, "stint": 85, "keyboard": 85, "pulled": 85, "programmed": 85, "fair": 85, "manipulating": 85, "baked": 85, "oven": 85, "blindly": 85, "struggled": 85, "intersection": 85, "advocates": 85, "dangerous": [85, 86], "concert": 85, "inevitably": 85, "emphasized": 85, "eloquently": 85, "repeat": 85, "bearing": [85, 86], "fresh": [85, 86, 94], "sixteen": [85, 94], "evening": [85, 94], "fueled": [85, 94], "malt": [85, 94], "joke": [85, 94], "overused": [85, 94], "invent": 85, "gradually": 85, "treats": 85, "mailing": 85, "discouraging": 85, "irony": 85, "vitally": 85, "backbone": 85, "evolving": 85, "xpers": 85, "pulling": 85, "emphasize": 85, "objectclub": 85, "jp": 85, "xp_relate": 85, "xp_patterns": 85, "industriallogic": 85, "patternsandxp": 85, "\u0443\u0431\u0435\u0436\u0434\u0435\u043d": 85, "\u043d\u0430\u0448\u0435\u043b": 85, "\u0443\u043c\u0430\u043b\u0447\u0438\u0432\u0430": 85, "contentious": 85, "insistence": 85, "testcase": 85, "fixture": 85, "verifying": 85, "awaitingapprovalflight": 85, "validapproverrequestshouldbeapproved": 85, "elds": 85, "comply": 85, "extracting": 85, "474": 85, "readable": 85, "dogmatic": 85, "\u043b\u0438\u0441\u0442\u0438\u043d\u0433": 85, "\u0434\u0438\u0440\u0435\u043a\u0442": 85, "\u0441\u0432\u0435\u0434": 85, "\u043c\u0438\u043d\u0438\u043c\u0443\u043c": 85, "domainspeci\ufb01c": 85, "supports": 85, "ought": 85, "minimized": 85, "astels": 85, "\u0443\u043a\u043b\u0430\u0434\u044b\u0432\u0430": 86, "\u0437\u0430\u0434\u0435\u0440\u0436": 86, "manpower": 86, "communications": 86, "cotton": 86, "partitionable": 86, "nine": 86, "women": 86, "baby": 86, "woman": 86, "picking": 86, "staff": 86, "brought": 86, "train": 86, "lost": 86, "repealed": 86, "\u0432\u0437\u0430\u0438\u043c\u043e\u0437\u0430\u043c\u0435\u043d\u044f": 86, "\u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b": [86, 95], "interchangeable": 86, "commodities": 86, "workers": 86, "fig": 86, "stefan": 86, "tilkov": 86, "consultant": 86, "innoq": 86, "\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u044b\u0432\u0430": 86, "\u0438\u0437\u0434\u0435\u0440\u0436\u0435\u043a": 86, "\u043e\u0431\u0449\u0435\u043d": [86, 92, 102], "\u0440\u0430\u0437\u043e\u0431\u0449\u0435\u043d": 86, "\u0432\u043b\u0435\u0447\u0435\u0442": 86, "\u0443\u0434\u043e\u0440\u043e\u0436\u0430\u043d": 86, "\u0437\u0430\u043c\u0435\u0434\u043b\u0435\u043d": 86, "\u043d\u0435\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d": 86, "\u0446\u0435\u043b\u043e\u0441\u0442\u043d": [86, 93], "\u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0438\u0440": 86, "\u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447": 86, "os": 86, "exec": 86, "scop": 86, "6600": 86, "multics": 86, "tss": 86, "sage": 86, "argued": 86, "sheer": 86, "minds": 86, "coordinated": 86, "affects": 86, "miscommunication": 86, "brute": 86, "costly": 86, "inefficient": 86, "codebases": 86, "\u043f\u043e\u043b\u043e\u0436": 86, "\u043c\u0430\u043b\u043e\u0447\u0438\u0441\u043b\u0435\u043d": 86, "\u043f\u0440\u043e\u0442\u044f\u0436\u0435\u043d": [86, 88], "5000": 86, "\u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442": 86, "tackled": 86, "postulate": 86, "\u0434\u0438\u043b\u0435\u043c\u043c": 86, "\u0436\u0435\u0441\u0442\u043e\u043a": 86, "\u0441\u0432\u0435\u0442\u043b": 86, "\u0433\u043e\u043b": 86, "\u0440\u0443\u0436": 86, "\u043a\u043e\u043d\u0442\u0438\u043d\u0433\u0435\u043d\u0442": 86, "\u0432\u043e\u0432\u0440\u0435\u043c": 86, "\u043f\u0440\u0438\u043c\u0438\u0440": 86, "dilemma": 86, "cruel": 86, "prefers": 86, "bear": 86, "appearance": 86, "reconciled": 86, "\u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0435\u043d": [86, 102], "\u0437\u0430\u043a\u043b\u044e\u0447": 86, "\u0438\u0437\u043c\u0435\u0440\u044f": 86, "\u0437\u0430\u0442\u0440\u0430\u0447\u0435\u043d": 86, "\u0436\u043d\u0443\u0442": 86, "\u043f\u0448\u0435\u043d\u0438\u0446": 86, "\u0445\u043b\u043e\u043f\u043e\u043a": 86, "\u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c": 86, "\u0440\u0430\u0437\u0431": 86, "\u0440\u0435\u0431\u0435\u043d\u043a": 86, "\u0434\u0435\u0432\u044f": 86, "\u0436\u0435\u043d\u0449\u0438\u043d": 86, "\u043f\u0440\u0438\u0432\u043b\u0435\u0447": 86, "\u043d\u043e\u0441": [86, 100, 102], "\u043d\u0435\u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c": 86, "unpartitionable": 86, "\u0440\u0430\u0437\u0431\u0438\u0442": [86, 89, 94], "\u043f\u043e\u0434\u0437\u0430\u0434\u0430\u0447": 86, "\u0434\u043e\u0431\u0430\u0432\u043b": 86, "\u0434\u043e\u0441\u0442\u0438\u0436\u0438\u043c": 86, "\u043e\u0431\u0443\u0447": 86, "\u043e\u0431\u043c\u0435\u043d": 86, "\u0441\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u043e\u0432\u0430": 86, "\u0432\u0442\u0440\u043e": 86, "\u043f\u043e\u043f\u0430\u0440\u043d": 86, "\u0432\u0448\u0435\u0441\u0442\u0435\u0440": 86, "\u0441\u043e\u0432\u0435\u0449\u0430\u043d": [86, 92], "\u043e\u0431\u0435\u0441\u0446\u0435\u043d": 86, "\u0434\u0440\u043e\u0431\u043b\u0435\u043d": 86, "\u0440\u0438\u0441\u0443\u043d\u043a": [86, 100], "interrelationships": [86, 100], "\u043f\u0440\u0438\u0432\u043b\u0435\u0447\u0435\u043d": [86, 102], "\u0441\u043e\u043a\u0440\u0430\u0449\u0430": [86, 93], "\u0443\u0434\u043b\u0438\u043d\u044f": 86, "fallacious": 86, "deceptive": 86, "reaping": 86, "wheat": 86, "child": 86, "subtasks": 86, "poorer": 86, "intercommunication": 86, "worker": 86, "linearly": 86, "increases": 86, "pairwise": 86, "moreover": 86, "conferences": 86, "jointly": 86, "communicating": 86, "counteract": 86, "division": 86, "inherently": 86, "dominates": 86, "lengthens": 86, "shortens": 86, "\u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430": 86, "\u0432\u044b\u0439\u0442": 86, "\u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443": 86, "\u0441\u043f\u0440\u0430\u0432\u043b\u044f": 86, "\u0431\u043b\u0430": 86, "blaauw": 86, "\u0446\u0438\u0444\u0435\u0440\u0431\u043b\u0430\u0442": 86, "\u0441\u0442\u0440\u0435\u043b\u043e\u043a": 86, "\u0437\u0430\u0432\u043e\u0434\u043d": 86, "\u0433\u043e\u043b\u043e\u0432\u043a": 86, "\u0440\u0435\u0431\u0435\u043d\u043e\u043a": 86, "\u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432": 86, "\u0440\u0443\u0447\u043d": 86, "\u043a\u043e\u043b\u043e\u043a\u043e\u043b\u044c\u043d": 86, "distinguished": 86, "winding": 86, "knob": 86, "wristwatch": 86, "church": 86, "realization": 86, "powering": 86, "accuracy": 86, "harlan": 86, "proposal": 86, "federal": 86, "fsc": 86, "71": 86, "5108": 86, "gaithersburg": 86, "1971": 86, "baker": 86, "\u0441\u0432\u0435\u0436": 86, "\u0443\u0447\u0430\u0441\u0442\u043a": [86, 90], "\u043d\u0430\u043f\u043e\u0434\u043e\u0431": 86, "\u0431\u0440\u0438\u0433\u0430\u0434": 86, "\u043c\u044f\u0441\u043d\u0438\u043a": 86, "\u0432\u0440\u0435\u0437\u0430": 86, "\u0440\u0435\u0437\u0430": 86, "\u0432\u0441\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d": 86, "\u043f\u043e\u0432\u044b\u0448": 86, "\u043f\u043b\u043e\u0434\u043e\u0442\u0432\u043e\u0440\u043d": 86, "\u043f\u043e\u0434\u0445\u0432\u0430\u0442": 86, "\u0430\u043d\u0435\u0441\u0442\u0435\u0437\u0438\u043e\u043b\u043e\u0433": 86, "\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d": 86, "\u0441\u0435\u0441\u0442\u0435\u0440": 86, "\u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430": [86, 92], "\u043c\u044b\u0441\u043b\u0438\u043c": 86, "\u0432\u043e\u043b\u044c\u043d": 86, "surgical": 86, "hog": 86, "butchering": 86, "enhance": 86, "desiderata": 86, "anesthesiologists": 86, "nurses": 86, "freely": 86, "metaphors": 86, "enlarged": 86, "conceivable": 86, "aim": 86, "pace": 86, "premium": 86, "rescued": 86, "helpful": 86, "influx": 86, "accelerated": 86, "ramp": 86, "netflix": 86, "\u043f\u0440\u043e\u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430": 86, "\u0432\u0441\u0435\u0446\u0435\u043b": 86, "\u0440\u0430\u0441\u043f\u043e\u0440\u044f\u0436\u0430": 86, "\u0443\u043f\u0440\u0430\u0432\u043b": 86, "\u0437\u043d\u0430\u043b": [86, 95], "\u043d\u0430\u043a\u043e\u0440\u043c": 86, "\u043f\u0438\u0446\u0446": 86, "\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440": 86, "\u0432\u043e\u043e\u0440\u0443\u0436\u0435\u043d": 86, "\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c": 86, "\u043f\u0440\u0438\u0446\u0435\u043b": 86, "poster": 86, "children": 86, "owning": 86, "famously": 86, "pizza": 86, "fed": 86, "pizzas": 86, "ensured": 86, "optimized": 86, "kit": 86, "\u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d": 86, "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b": 86, "\u0430\u0432\u0442\u043e\u043d\u043e\u043c": 86, "contemporary": 86, "singular": 86, "elegantly": 86, "friction": 86, "ship": 86, "toolkit": 86, "\u0430\u0440\u043c\u0435\u0439\u0441\u043a": 86, "\u0443\u043a\u0440\u0435\u043f\u043b\u044f": 86, "\u043c\u0438\u043a\u043e\u0440\u0441\u0435\u0440\u0432\u0438\u0441": 86, "\u0430\u043c": 86, "monolithic": 86, "creeping": 86, "leak": 86, "\u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u043d": 86, "\u0443\u043f\u0440\u043e\u0447": 86, "\u043e\u0431\u043e\u0441\u043e\u0431\u043b\u0435\u043d": 86, "\u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d": [86, 100], "perils": 86, "\u0447\u0435\u0440\u0432\u044f\u043a": 86, "\u0431\u0435\u0441\u043f\u043e\u0437\u0432\u043e\u043d\u043e\u0447\u043d": 86, "\u0436\u0438\u0432\u043e\u0442\u043d": 86, "\u0442\u044f\u0436\u0435\u0441\u0442": [86, 90, 95], "\u043f\u0440\u043e\u0447\u043d\u043e\u0441\u0442": [86, 90], "\u043e\u043f\u0435\u0440\u0435\u0436\u0430": 86, "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043c": 86, "\u043e\u043f\u043e\u0440\u043d": 86, "\u043a\u043e\u0440\u0430\u0431\u043b\u0438\u043a": 86, "\u0434\u0435\u0440\u0436": [86, 90], "\u043f\u0440\u043e\u043f\u043e\u0440\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [86, 93], "\u0440\u0443\u0445\u043d\u0435\u0442": 86, "\u0444\u0435\u0440\u043c": 86, "\u0436\u0435\u0441\u0442\u043a\u043e\u0441\u0442": 86, "\u0441\u0435\u043b": 86, "\u0433\u043e\u0440\u043e\u0434": [86, 89], "\u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d": 86, "\u043c\u0430\u0433\u0438\u0441\u0442\u0440\u0430": 86, "galileo": 86, "galilei": 86, "beam": 86, "bending": 86, "discorsi": 86, "dimostrazioni": 86, "matematiche": 86, "intorno": 86, "\u00e0": 86, "nuoue": 86, "scienze": 86, "leiden": 86, "appresso": 86, "gli": 86, "elsevirii": 86, "1638": 86, "mathematicians": 86, "statics": 86, "strength": 86, "transmit": 86, "length": 86, "decreases": 86, "thickness": 86, "breadth": 86, "triple": 86, "dimensions": 86, "animal": 86, "branches": 86, "limbs": 86, "illustration": 86, "cantilever": 86, "\u0431\u0430\u043b\u043a": 86, "\u043a\u0443\u0431\u0430\u0442\u0443\u0440": 86, "\u0441\u0435\u0447\u0435\u043d": 86, "\u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0443\u0440": 86, "\u0440\u0430\u0432\u043d\u043e\u0441\u0438\u043b\u044c\u043d": 86, "\u0434\u0438\u043d\u043e\u0437\u0430\u0432\u0440": 86, "\u0440\u0443\u0448": 86, "\u043d\u0435\u0443\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044c\u043d": 86, "\u0434\u0432\u0438\u0436\u0435\u043d": 86, "\u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440": 86, "\u044d\u043a\u0438\u043f\u0430\u0436": 86, "\u0440\u0430\u0441\u0445\u043e\u0434": 86, "\u044d\u0448\u0435\u043b\u043e\u043d": 86, "\u043f\u043e\u0441\u0430\u0434\u043a": 86, "\u0432\u0437\u043b\u0435\u0442": 86, "\u0433\u0438\u043f\u043e\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a": 86, "\u0440\u0430\u0439\u043e\u043d": 86, "\u043c\u0430\u043b\u043e\u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d": 86, "\u0430\u044d\u0440\u043e\u043f\u043e\u0440\u0442": 86, "\u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0435\u0442": [86, 100], "\u0441\u0443\u0434\u043d": [86, 90, 92, 100], "\u0448\u0435\u0440\u0435\u043c\u0435\u0442\u044c\u0435\u0432": 86, "\u0442\u0435\u0440\u043f": 86, "\u0431\u0435\u0434\u0441\u0442\u0432": 86, "squads": 86, "road": 86, "coordinates": 86, "input": 86, "squad": 86, "tribes": 86, "guilds": 86, "anders": 86, "ivarsson": 86, "oct": 86, "2012": [86, 88], "\u043e\u0442\u0447\u0435\u0442\u043b\u0438\u0432": 86, "\u0440\u0435\u0433\u043b\u0430\u043c\u0435\u043d\u0442\u0438\u0440": 86, "\u043e\u0431\u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430": 86, "titles": 86, "analysts": 86, "personnel": 86, "assure": 86, "conformance": 86, "specialists": 86, "designers": 86, "administrators": 86, "whomever": 86, "\u043d\u0435\u0441\u0438\u043d\u0445\u0440\u043e\u043d": 86, "\u043e\u043f\u0435\u0440\u0435\u0436": 86, "\u0434\u043e\u0432\u0435\u0434\u0435\u043d": 86, "\u043e\u0442\u0432\u043b\u0435\u043a\u0430": 86, "\u043d\u0430\u043b\u0438\u0446": 86, "\u043d\u0430\u043a\u043b\u0430\u0434\u043d": 86, "\u043f\u043e\u0433\u0440\u0443\u0436\u0430": 86, "\u0434\u0443\u0431\u043b\u0438\u0440\u0443": 86, "\u0441\u043c\u0435\u0449\u0435\u043d": 86, "pridiction": 86, "backlogs": 86, "\u043c\u044f": 86, "runway": 86, "dimension": 86, "assist": 86, "devops": [86, 88], "staging": 86, "readily": 86, "dbas": 86, "\u043e\u0440\u0443\u0436": 86, "\u043d\u0435\u043e\u0441\u043f\u043e\u0440\u0438\u043c": 86, "\u043e\u0441\u0442\u0440": 86, "\u0443\u0441\u043b\u044b\u0448": 86, "\u0432\u043e\u0437\u0440\u0430\u0436\u0435\u043d": 86, "analogous": 86, "similarities": 86, "synergies": 86, "yuval": 86, "yeret": 86, "\u0443\u0437\u043a": [86, 93], "\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440": 86, "\u043f\u0440\u0435\u0434\u043b\u0430\u0433": 86, "\u0434\u0435\u043b\u0435\u0433\u0430\u0446": [86, 88], "\u0433\u043e\u0440\u043b\u044b\u0448\u043a": 86, "delegate": 86, "subordinate": 86, "kanbans": 86, "enablers": 86, "epics": 86, "\u043f\u0440\u043e\u0447": 86, "\u043b\u0435\u0441\u0442\u043d": 86, "\u043e\u0442\u0437\u044b\u0432": 86, "complementary": 86, "ranging": 86, "\u0432\u044b\u0441\u0442\u0440\u043e": 86, "\u0434\u0435\u043b\u0438\u043a\u0430\u0442\u043d": [86, 88, 92], "\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0435\u043b": 86, "sized": 86, "director": 86, "qentinel": 86, "awareness": 86, "adaptations": 86, "augmented": 86, "scales": 86, "hundred": 86, "solvable": 86, "fracture": 86, "reconcile": 86, "airline": 86, "profiled": 86, "extensively": 86, "occasional": 86, "exceptions": 86, "norm": 86, "coordinating": 86, "fails": 86, "faced": 86, "senior": 86, "commitment": [86, 88], "remediation": 86, "branding": 86, "sos": 86, "factory": 86, "amogh": 86, "upstream": 86, "achievement": 86, "\u0432\u044b\u0437\u044b\u0432\u0430\u0442": 86, "selected": 86, "vetted": 86, "workable": 86, "continues": 86, "\u0437\u0430\u0432\u043e\u0434": 86, "\u0444\u0430\u0437": [86, 89, 91, 92, 138], "powerhouse": 86, "kyle": 86, "foreman": 86, "\u0445\u0440\u0435\u0431\u0442": 86, "\u0441\u0432\u043e\u0435\u0432\u0440\u0435\u043c\u0435\u043d": 86, "\u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u0430\u0446": 86, "\u043a\u0430\u0440\u0442": [86, 92, 94, 100], "\u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u043e\u043d": [86, 100], "supplier": 86, "\u043a\u043e\u043d\u0442\u0440\u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0438\u0432\u043d": 86, "cdc": 86, "obstacles": 86, "118": 86, "jyri": 86, "lehv\u00e4": 86, "niko": 86, "m\u00e4kitalo": 86, "tommi": 86, "mikkonen": 86, "pact": 86, "provider": 86, "pathways": 86, "bullet": 86, "caves": 86, "toss": 86, "invested": 86, "organisation": 86, "cd": 86, "setup": 86, "\u043c\u0438\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430": 86, "maccormack": 86, "colleagues": 86, "participation": 86, "contribution": 86, "exploring": 86, "remit": 86, "kelly": 86, "conway": 86, "modernization": [86, 88], "weak": 86, "evan": 86, "bottcher": 86, "audit": 86, "\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a": 88, "\u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 88, "\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d": 88, "\u0440\u0430\u0437\u0440": 88, "\u0441\u043c\u0438\u0440\u044f": 88, "\u043f\u0440\u043e\u044f\u0432": 88, "\u043e\u043f\u0430\u0441": 88, "\u043f\u043e\u0434\u0430\u0432": 88, "\u0434\u0438\u0441\u0441\u043e\u043d\u0430\u043d\u0441": [88, 89], "\u043f\u0440\u0438\u0443\u043c\u0435\u043d\u044c\u0448": 88, "\u043e\u0442\u0432\u0435\u0440\u0433\u043d\u0443\u0442": 88, "\u0432\u0441\u043b\u0435\u0434\u0441\u0442\u0432": 88, "\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043a": 88, "\u0440\u0435\u0430\u043a\u0446\u0438\u043e\u043d\u0438\u0441\u0442": 88, "\u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a": [88, 94], "\u044e\u043d\u043e\u0448\u0435\u0441\u043a": 88, "\u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u0438\u0437\u043c": 88, "\u043a\u0435\u043c": 88, "\u0444\u0430\u0442\u0430\u043b\u0438\u0437\u043c": 88, "\u0442\u0440\u0443\u0441": 88, "\u0443\u0447": [88, 92], "\u0441\u043e\u043a\u0440\u0443\u0448\u0430": 88, "\u0434\u043e\u0440\u043e\u0433": 88, "\u0448\u0430\u0440\u043b": 88, "\u0434\u0435": 88, "\u0433\u043e\u043b\u043b": 88, "\u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d": 88, "\u0440\u0430\u0437\u0440\u044b\u0432": 88, "\u0440\u0438\u0433\u0438\u0434\u043d": 88, "\u043e\u0431\u0443\u0447\u0430\u0435\u043c": [88, 89], "\u0432\u043e\u0437\u0432\u0435\u0441\u0442": 88, "\u043f\u0440\u0435\u0441\u0442\u0438\u0436": [88, 94], "\u0448\u0435": 88, "\u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a": 88, "\u043d\u0435\u043f\u0440\u0430\u0432\u043e\u0442": 88, "\u0441\u0435\u043b\u0435\u043a\u0442\u0438\u0432\u043d": [88, 89], "\u0441\u043a\u043b\u043e\u043d\u043d\u043e\u0441\u0442": [88, 89, 94], "\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430": 88, "\u0442\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a": 88, "\u0440\u0430\u0441\u0441\u0435\u044f": 88, "\u0432\u043e\u0434": [88, 90], "\u043a\u0430\u043c\u0435\u043d": [88, 90], "\u0442\u043e\u0447": [88, 90], "\u043c\u043e\u0440": [88, 90], "\u0440\u0435\u0436\u0435\u0442": [88, 90], "\u0441\u043a\u0430\u043b": [88, 90], "\u0432\u0434\u043e\u0445\u043d\u043e\u0432\u043b\u044f": [88, 90], "\u0441\u0442\u0435\u043a\u0430": [88, 90], "\u043a\u0430\u043f\u0435\u043b\u044c\u043a": [88, 90], "\u043f\u0440\u043e\u0440\u0435\u0437\u0430": [88, 90], "\u043a\u0430\u043c\u043d": [88, 90], "\u0431\u043e\u0440\u043e\u0437\u0434\u043a": [88, 90], "\u0443\u0433\u043b\u0443\u0431\u043b\u044f": [88, 90], "\u0433\u043b\u044b\u0431": [88, 90, 93], "\u043e\u0431\u0440\u0443\u0448": [88, 90], "\u043a\u0430\u043f\u043b": [88, 90], "\u0442\u0435\u0440\u043f\u0435\u043d": 88, "\u0433\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d": 88, "\u0441\u0438\u043b\u043e\u0432": [88, 90], "\u0443\u0434\u0435\u043b\u044c\u043d": [88, 90], "\u043f\u043b\u043e\u0449\u0430\u0434": [88, 90, 100], "\u0441\u0440\u0430\u0431\u043e\u0442\u0430": 88, "\u043a\u0430\u0441\u043a\u0430\u0434": [88, 89], "\u0433\u0435\u043d\u0440": 88, "\u0444\u043e\u0440\u0434": 88, "\u043f\u0440\u043e\u043b\u0438\u0432\u0430\u043d": 88, "\u043d\u0435\u0434\u043e\u0441\u0442\u0430": [88, 92, 95], "\u0441\u043f\u0443\u0441\u043a\u0430": 88, "\u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u043d": 88, "\u0432\u043d\u0435\u0434\u0440": 88, "\u043f\u043e\u0434\u043f\u0438\u0442\u044b\u0432\u0430": 88, "\u0441\u043b\u0443\u0448\u0430": 88, "\u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430": [88, 92, 93], "\u0442\u0430\u043a\u0442\u0438\u043a": 88, "\u043a\u043e\u043d\u043a\u0440\u0435\u0442\u0438\u0437\u0438\u0440": 88, "\u0437\u0430\u0434\u0430\u0432\u0430": 88, "\u043d\u0430\u0448\u0443\u043c\u0435\u0432\u0448": 88, "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d": 88, "\u0441\u0438\u043d\u044c\u043e\u0440": 88, "\u0434\u0435\u0440\u0436\u0430": 88, "\u043f\u0440\u0438\u0448\u0435\u043b": 88, "\u0441\u0430\u0431\u043e\u0442\u0438\u0440\u043e\u0432\u0430": 88, "\u0440\u0430\u0441\u043a\u043e\u043b": [88, 92], "\u043c\u043d\u043e\u0433\u043e\u043b\u0435\u0442\u043d": 88, "\u0432\u043a\u043b\u0430\u0434": 88, "\u043d\u0435\u0434\u043e\u0432\u0435\u0440": 88, "\u043d\u0430\u043d\u044f\u0442": 88, "\u043f\u043e\u0434\u0447\u0438\u043d\u044f": 88, "\u043a\u0430\u0442\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440": 88, "forming": 88, "\u043f\u0440\u0438\u043d\u0443\u0436\u0434\u0435\u043d": [88, 92], "\u043a\u043e\u043d\u0441\u043e\u043b\u0438\u0434\u0430\u0446": [88, 92], "\u0440\u0430\u0441\u043f\u0430": 88, "\u043f\u0440\u0438\u043d\u0443\u0436\u0434\u0430": 88, "\u043d\u0435\u0434\u043e\u043e\u0446\u0435\u043d\u0435\u043d": 88, "\u043d\u0435\u0434\u043e\u043e\u0446\u0435\u043d\u043d\u0435\u043d": 88, "\u043f\u043e\u0447\u0443\u0432\u0441\u0442\u0432\u043e\u0432\u0430": 88, "\u043e\u043a\u0430\u0437\u0430\u043d": 88, "\u0434\u043e\u0432\u0435\u0440": 88, "\u0432\u044b\u0431": 88, "\u0432\u043e\u0437\u0432\u0435\u0434\u0435\u043d": 88, "\u043f\u0430\u0440\u0435\u043d": 88, "\u0437\u0430\u043c\u043a\u043d\u0443\u0442": 88, "\u043f\u043e\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a": 88, "\u0443\u0432\u043e\u043b": 88, "\u043e\u0431\u043b\u0430\u0434": 88, "\u043e\u0447\u0430\u0433": 88, "\u0448\u043b\u0430": 88, "\u0444\u0440\u043e\u043d\u0442": [88, 90, 95], "\u043e\u0441\u043b\u0430\u0431": 88, "\u0432\u044b\u043d\u0443\u0436\u0434\u0435\u043d": 88, "speak": 88, "\u0432\u043d\u0435\u0434\u0440\u044f": 88, "\u043f\u043b\u0430\u0446\u0434\u0430\u0440\u043c": [88, 90], "\u0440\u0430\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043a": 88, "\u0438\u0437\u0433\u043e": 88, "\u0432\u043e\u0437\u0434\u0435\u0440\u0436\u0430": 88, "\u0441\u0430\u0431\u043e\u0442\u0430\u0436": 88, "\u0432\u044b\u043d\u043e\u0441": 88, "\u043e\u043f\u0440\u043e\u043c\u0435\u0442\u0447\u0438\u0432": 88, "\u043e\u0442\u043e\u0436\u0434\u0435\u0441\u0442\u0432\u043b\u0435\u043d": [88, 92], "\u0443\u0433\u0440\u043e\u0437": [88, 92, 94], "reversing": 88, "disablement": 88, "reinforcing": 88, "preface": 88, "kotter": 88, "dance": 88, "sustaining": 88, "momentum": 88, "senge": 88, "march": 88, "1999": 88, "innovative": 88, "\u043a\u0430\u0440\u043b\u043e\u0444": 88, "\u0441\u0435\u0434\u0435\u0440\u0431\u0435\u0440\u0433": 88, "huse": 88, "1975": 88, "masters": 88, "kanter": 88, "schlesinger": 88, "transformational": 88, "initiatives": 88, "mayner": 88, "proquest": 88, "employees": 88, "herold": 88, "fedor": 88, "caldwell": 88, "yi": 88, "liu": 88, "93": 88, "heath": 88, "crown": 88, "inquiry": 88, "spark": 88, "breakthrough": 88, "berger": 88, "goulston": 88, "\u0431\u0440\u0430\u0436\u043d\u0438\u043a": 88, "\u0445\u043e\u0440\u0438\u043d": 88, "\u0441\u0430\u043c\u0430\u0440": 88, "\u0433\u043e\u0441": 88, "\u0442\u0435\u0445\u043d": 88, "\u0443\u043d": 88, "238": 88, "\u0434\u0430\u043d\u0438\u043b\u044e\u043a": 88, "\u0442\u044e\u043c\u0435\u043d": 88, "\u0442\u044e\u043c\u0435\u043d\u0441\u043a": 88, "\u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432\u0435\u043d": 88, "\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442": 88, "288": 88, "\u0438\u0432\u0430\u043d\u043e\u0432": [88, 96], "\u043c\u0433\u0443\u043f\u0441": 88, "\u043c\u0438": 88, "167": 88, "\u043a\u0443\u0436\u0435\u0432": 88, "\u043e\u043c\u0441\u043a": 88, "\u043e\u043c": 88, "140": 88, "\u043c\u0435\u0434\u0432\u0435\u0434\u0435\u0432": 88, "\u0441\u0430\u0440\u0430\u0442": 88, "\u0441\u0433\u0443": 88, "119": 88, "\u043a\u043e\u043b\u0435\u043c\u0430": 88, "\u0444\u0430\u0440\u043c\u0435\u0440": 88, "\u0436\u0443\u043a\u043e\u0432\u0441\u043a": 88, "\u0442\u0438\u0447": 88, "\u0434\u0435\u0432\u0430\u043d": 88, "\u0440\u0435\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446": 88, "\u0440\u043e\u0441\u0441": 88, "\u0434\u0435\u043c\u044c\u044f\u043d\u0435\u043d\u043a": 88, "\u0432\u0430\u0441\u0438\u043b": 88, "scarf": 88, "influencing": 88, "vol": 88, "rock": 88, "\u0434\u044d\u0432\u0438\u0434": 88, "\u0440\u043e\u043a": 88, "\u043a\u043d\u0443\u0442": 88, "\u043f\u0440\u044f\u043d\u0438\u043a": 88, "\u0441\u043c\u0430\u0440\u0430\u043a\u043e\u0432": 88, "\u043b\u044e\u0434\u044c\u043c": 89, "\u0432\u0435\u0436\u043b\u0438\u0432": 89, "\u0441\u0438\u043d\u0434\u0440": 89, "\u043d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d": [89, 91, 138], "\u0441\u043f\u0438\u0440\u0430\u043b": [89, 91, 138], "\u043f\u0440\u0438\u0432\u044f\u0437\u043a": 89, "\u044f\u043a\u043e\u0440": 89, "\u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d": 89, "\u043d\u0443\u043b\u0435\u0432": 89, "sunk": 89, "\u043a\u043e\u043d\u0444\u043e\u0440\u043c\u043d": 89, "\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 89, "\u0432\u044b\u0436": 89, "\u043e\u043a\u043e\u043d": [89, 94], "\u0430\u043f\u0435\u043b\u043b\u044f\u0446": 89, "\u043b\u0438\u0447\u043d\u043e\u0441\u0442": 89, "\u0445\u043e\u0442\u043e\u0440\u043d\u0441\u043a": 89, "\u043d\u043e\u0432\u0438\u0437\u043d": 89, "\u0434\u0435\u0444\u043e\u0440\u043c\u0430\u0446": 89, "\u043f\u0440\u043e\u0436\u0435\u043a\u0442\u043e\u0440": 89, "\u043f\u0440\u043e\u043a\u0440\u0430\u0441\u0442\u0438\u043d\u0430\u0446": 89, "\u044d\u043c\u043e\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 89, "\u0432\u044b\u0433\u043e\u0440\u0430\u043d": 89, "\u0442\u0435\u043b\u0435\u0441\u043a\u043e\u043f": 89, "\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d": 89, "\u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u043d": 89, "\u0441\u0430\u0440": 89, "\u043f\u0430\u0440\u043a\u0438\u043d\u0441\u043e\u043d": 89, "\u0437\u0430\u043f\u043e\u043b\u043d\u044f": 89, "\u043e\u0442\u043f\u0443\u0449\u0435\u043d": 89, "\u043d\u0435\u043f\u0440\u0438\u044f\u0442": 89, "\u0433\u0440\u0443\u043f\u043f\u043e\u0432": [89, 100], "\u0437\u0430\u0431\u044b\u0432\u0430\u043d": 89, "\u043a\u0440\u0430": 89, "\u0430\u0433\u0440\u0435\u0433\u0438\u0440\u043e\u0432\u0430": 89, "cognitive": 89, "crothers": 89, "\u0431\u0438\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 89, "crunching": 89, "\u043d\u0435\u0438\u0437\u0431\u0435\u0436": 89, "\u0432\u044b\u0437\u0440\u0435\u0432\u0430\u043d": 89, "plastic": 89, "temporal": 89, "\u0445\u0430\u0431\u0440": 89, "\u043c\u043e\u0431\u0438\u043b\u044c\u043d": 89, "dropbox": 89, "8l49rx8ig9i4za3": 89, "ezh": 89, "li": 89, "cbcs": 89, "busterbenson": 89, "blob": 89, "benson": 89, "\u043f\u0430\u043c\u044f\u0442\u043a": 89, "ezhikov": 89, "\u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434": [90, 95], "\u043b\u0435\u0434": 90, "\u043a\u043e\u0440\u0430\u0431\u043b": 90, "\u0430\u0442\u0430\u043a": 90, "\u043b\u044c\u0434\u0430": 90, "\u0442\u043e\u0440\u0446": 90, "\u043b\u044c\u0434\u043e\u043c": 90, "\u0442\u043e\u043b\u0449": 90, "\u043f\u0440\u043e\u0441\u0442\u0438\u0440\u0430": 90, "\u0441\u043e\u0442\u043d": [90, 100], "\u043a\u0438\u043b\u043e\u043c\u0435\u0442\u0440": 90, "\u043f\u0440\u043e\u043b\u043e\u0436": 90, "\u043a\u043e\u043b\u0435\u0442": 90, "\u0437\u0438\u043c\u043d": 90, "\u043f\u0440\u043e\u0435\u0446\u0438\u0440\u0443": 90, "\u0432\u043e\u0438\u043d\u0441\u043a": 90, "\u043c\u043d\u043e\u0433\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432": 90, "taming": 90, "\u0432\u0438\u0441\u044f\u0447\u043a": 90, "\u0441\u0430\u043c\u0431": [90, 92], "\u043e\u0434\u0435\u0440\u0436\u0430\u043d": 90, "\u043f\u0440\u043e\u0442\u0438\u0432\u043d\u0438\u043a": 90, "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u0441\u0442\u0430\u0432": 90, "\u043c\u044b\u0448\u0446": [90, 95], "\u0444\u043e\u0442": 90, "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b": 90, "\u0441\u043f\u0438\u043d": 90, "\u0431\u0438\u0446\u0435\u043f\u0441": 90, "\u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434\u044f": 90, "\u0431\u043e\u043b\u0435\u0432": 90, "\u043f\u0440\u0438\u0435\u043c": [90, 93], "\u0432\u0435\u0434\u043e\u043c\u0441\u0442\u0432": 90, "\u0444\u0438\u043b\u044c\u043c": 90, "\u0432\u043e\u0435\u0432\u0430": 90, "\u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d": 90, "\u0442\u044f\u0433\u043e\u0442\u0435\u043d": 90, "\u0437\u0435\u043c\u043b": [90, 92, 100], "\u043f\u043e\u0432\u0430\u043b": 90, "\u043e\u043a\u0440\u0443\u0436\u0435\u043d": 90, "\u0436\u0443\u043a": 90, "\u0441\u0443\u0445": 90, "\u043f\u0435\u0440\u0435\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a": [90, 95], "\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a": 90, "\u043a\u043b\u0435\u0449": 90, "\u043e\u0441\u043b\u0430\u0431\u043b\u0435\u043d": 90, "\u0442\u044b\u043b\u043e\u0432": 90, "\u0444\u043e\u0440\u0441\u0438\u0440\u043e\u0432\u0430\u043d": 90, "\u0432\u043e\u0434\u043d": 90, "\u043f\u0440\u0435\u0433\u0440\u0430\u0434": 90, "\u043d\u0430\u0441\u0442\u0443\u043f\u043b\u0435\u043d": 90, "\u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430": 90, "\u043f\u0440\u0438\u0441\u0435\u0434": 90, "\u043f\u043b\u0435\u0447": 90, "\u043f\u043e\u0437\u0432\u043e\u043d\u043e\u0447\u043d\u0438\u043a": 90, "\u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d": 90, "\u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f": 90, "\u043a\u043e\u043d\u0442\u0430\u043a\u0442\u043d": 90, "\u043f\u043e\u0432\u0435\u0440\u0445\u043d": [90, 100], "\u043f\u043e\u0437\u0432\u043e\u043d\u043a": 90, "\u0438\u043d\u0432\u0435\u0441\u0442\u043e\u0440": 90, "\u0434\u0438\u0432\u0435\u0440\u0441\u0438\u0444\u0438\u043a\u0430\u0446": 90, "\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c": [90, 92], "\u0440\u0430\u0432\u043d\u043e\u0432\u0435\u0441": 90, "\u043f\u043b\u0430\u0432\u0443\u0447\u0435\u0441\u0442": 90, "\u0432\u043e\u0434\u043e\u043d\u0435\u043f\u0440\u043e\u043d\u0438\u0446\u0430": 90, "\u043f\u0435\u0440\u0435\u0433\u043e\u0440\u043e\u0434\u043a": 90, "\u0433\u0438\u0434\u0440\u043e\u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 90, "\u043f\u043e\u0434\u044a\u0435\u043c\u043d": 90, "\u043f\u0440\u043e\u0431\u043e\u0438\u043d": 90, "\u0434\u0435\u0439\u043b": [90, 92, 95], "\u043a\u0430\u0440\u043d\u0435\u0433": [90, 92, 95], "\u043e\u0442\u0441\u0435\u043a": 90, "\u0431\u0438\u0442\u0432": 90, "\u0440\u0430\u0437\u0436\u0438\u0433": 90, "\u043c\u0430\u043d\u0433\u0430\u043b": 90, "\u0448\u0435\u043f\u043a": 90, "\u0432\u0435\u0442\u043a": 90, "\u0431\u0443\u043c\u0430\u0433": 90, "\u0433\u043e\u0440\u044e\u0447": 90, "\u0436\u0438\u0434\u043a\u043e\u0441\u0442": 90, "\u043f\u043b\u0430\u043c\u0435\u043d": 90, "\u0441\u043f\u0438\u0447\u043a": 90, "\u0442\u0435\u043f\u043b\u043e\u0435\u043c\u043a": 90, "\u0432\u043e\u0441\u043f\u043b\u0430\u043c\u0435\u043d\u044f": 90, "\u0432\u043e\u0441\u043f\u043b\u0430\u043c\u0435\u043d": 90, "\u043d\u0430\u043f\u0440\u044f\u043c": 90, "\u0448\u0438\u0440\u043e\u0442": [92, 102], "\u043f\u0440\u0438\u0440\u043e\u0434\u043d": 92, "\u043c\u043b\u043d": 92, "\u043c\u0430\u0441\u0442\u0435\u0440\u0441\u0442\u0432": 92, "\u043f\u043e\u043b\u0438\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a": 92, "\u044d\u043d\u0446\u0438\u043a\u043b\u043e\u043f\u0435\u0434": [92, 102], "\u0440\u044f\u0437\u0430\u043d\u0446": 92, "lucky": 92, "\u044d\u043b\u0435\u0430\u0442": 92, "\u0430\u0442\u043e\u043c\u0438\u0441\u0442": 92, "\u043f\u043b\u0430\u0442\u043e\u043d": 92, "\u0444\u0438\u043b\u043e\u0441\u043e\u0444\u0441\u043a": [92, 100, 102], "\u0442\u0442": 92, "\u0441\u0442\u0435\u043f\u0438\u043d": 92, "\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c": 92, "\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u0435\u043b\u044c\u043d": 92, "\u043d\u0435\u043f\u0440\u0435\u0445\u043e\u0434\u044f": 92, "3\u043d\u0430\u043d": 92, "\u044f\u0432\u043b": [92, 100], "\u0441\u043e\u0432\u0435\u0442\u0441\u043a": 92, "\u0433\u043b": 92, "\u0438\u043b\u044c\u0438\u0447": 92, "\u0444\u0435\u0434\u043e\u0441\u0435": 92, "\u043a\u043e\u0432\u0430\u043b": 92, "\u043f\u0430\u043d": 92, "\u0441\u043e\u0437\u043d\u0430\u043d": [92, 102], "\u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d": 92, "\u0437\u043d\u0430\u043a\u043e\u0432": 92, "\u043f\u0440\u0438\u0434\u0430\u043d": 92, "\u0441\u043e\u0432\u0440": 92, "\u043e\u0441\u043d": [92, 100], "\u044d\u043c\u043f\u0438\u0440\u0438\u0447": 92, "\u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447": 92, "\u043f\u043e\u0441\u0442\u0443\u043b\u0430\u0442": 92, "\u0430\u043a\u0441": 92, "\u0438\u0434\u0435\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430": 92, "\u043b\u043e": 92, "\u0433\u0438\u0447": 92, "\u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d": 92, "\u043f\u0440\u0438\u0437\u0432\u0435\u0434": 92, "\u043d\u0435\u0441\u043e\u0433\u043b\u0430\u0441": 92, "\u0443\u0449\u0435\u043c\u043b\u0435\u043d": 92, "\u043a\u043e\u0433\u043d\u0438\u0442\u0438\u0432": 92, "\u0442\u043e\u043a\u0441\u0438\u0447\u043d": 92, "\u043e\u0442\u043e\u0436\u0434\u0435\u0441\u0442\u0432\u043b\u044f": 92, "\u043c\u043e\u043f\u0435\u0434": 92, "issac": 92, "newton": 92, "standing": 92, "shoulders": 92, "giants": 92, "isaac": 92, "1675": 92, "letter": 92, "fellow": 92, "hooke": 92, "\u0432\u043e\u0441\u043f\u043e\u043b\u043d": 92, "\u0432\u0430\u043a\u0443\u0443\u043c": 92, "\u0432\u043e\u0437\u043d\u0438\u043a\u0448": 92, "\u0437\u0430\u0432\u0435\u0434\u043e\u043c": 92, "\u043e\u0442\u0442\u043e\u0440\u0433\u043d\u0443\u0442": 92, "\u043f\u0440\u043e\u043b": 92, "\u0440\u0430\u0437\u0434\u0432\u0438\u0433\u0430": 92, "\u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430": [92, 93], "\u043f\u0435\u0440\u0435\u043e\u0441\u043c\u044b\u0441\u043b": 92, "\u043d\u0435\u043f\u0440\u0438\u0441\u0442\u0443\u043f\u043d": 92, "\u043a\u0440\u0435\u043f\u043e\u0441\u0442": 92, "\u0431\u0435\u0440\u0443\u0442": 92, "\u043e\u0431\u0449\u0435\u043f\u0440\u0438\u0437\u043d\u0430": 92, "\u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0446": 92, "\u043e\u0442\u0441": 92, "\u0434\u043e\u0431\u044b\u0432\u0430\u043d": [92, 100], "\u0441\u043e\u0438\u0437\u043c\u0435\u0440\u0438\u043c": 92, "\u0434\u0438\u0432\u0435\u0440\u0433\u0435\u043d\u0442\u043d": 92, "\u0433\u043b\u0443\u0431\u0438\u043d": 92, "\u043a\u043e\u043d\u0432\u0435\u0440\u0433\u0435\u043d\u0442\u043d": 92, "\u043e\u0442\u043c\u0435\u043d\u044f": 92, "ch": 92, "\u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0430": 92, "\u043f\u0435\u0440\u0435\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430": 92, "\u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440": 92, "\u0432\u043e\u0437\u043e\u0431\u043b\u0430\u0434\u0430": 92, "\u043f\u043e\u0439\u043c\u0443\u0442": 92, "\u044d": 92, "\u0431\u043e\u043b\u043e\u0442": 92, "\u043f\u0440\u043e\u0439\u0442": 92, "\u0441\u043e\u0432\u0435\u0440\u0448": 92, "\u043f\u043e\u0445\u043e\u0434": 92, "\u0432\u043b\u044f\u043f\u0430": 92, "\u0441\u0430\u043c\u043e\u043b\u0438\u0447\u043d": 92, "\u043a\u043e\u0440\u043c\u0447": 92, "\u0432\u0441\u0442\u0443\u043f\u0430": 92, "\u043a\u043e\u043c\u043f\u0430\u0441": [92, 100], "\u043f\u043b\u044b\u0432\u0435\u0442": 92, "\u043e\u043f\u0438\u0440\u0430": 92, "\u0442\u0432\u0435\u0440\u0434": 92, "\u043e\u0441\u043d\u043e\u0432\u0430\u043d": 92, "\u043b\u0435\u043e\u043d\u0430\u0440\u0434": 92, "\u0432\u0438\u043d\u0447": 92, "\u0440\u0435\u0431": 92, "\u0441\u0440\u0435\u0434\u043d\u0435\u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": 92, "\u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a": 92, "\u0441\u043b\u0443\u0436": [92, 100], "\u0441\u0430\u043c\u043e\u043d\u0430\u0434\u0435\u044f": 92, "\u0438\u0437\u043e\u0431\u0440\u0435\u0441\u0442": 92, "\u043a\u043e\u043b\u0435\u0441": 92, "\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430": 92, "\u044d\u0440\u0438\u0445": 92, "\u0433\u0430\u043c\u043c": 92, "\u0444\u0430\u0443\u043b\u0435\u0440": 92, "\u0437\u0430\u043c\u043a\u043d\u0443\u043b": 92, "\u0441\u043c\u043e\u0442\u0440\u0435\u043b": 92, "\u043f\u043e\u0434\u043d\u043e\u0436\u043a": 92, "\u0443\u044f\u0437\u0432\u0438\u043c": 92, "\u043a\u043e\u043d\u0442\u0440\u0430\u0442\u0430\u043a\u043e\u0432\u0430": 92, "\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a": 92, "\u0441\u043d\u0430\u0440\u0443\u0436": 92, "\u043f\u0440\u043e\u0436\u0438\u0432\u0430": 92, "\u043f\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442": 92, "\u044d\u043f\u0438\u0437\u043e\u0434": 92, "\u043f\u0435\u0440\u043f\u0435\u043d\u0434\u0438\u043a\u0443\u043b\u044f\u0440\u043d": [92, 102], "\u0433\u0435\u043e\u043c\u0435\u0442\u0440": 92, "\u043a\u043e\u0440\u043e\u0442\u043a\u043e\u043c\u0435\u0442\u0440\u0430\u0436\u043a": 92, "\u0430\u043b\u0435\u043a\u0441": 92, "\u0431\u0435\u0440\u0435\u0437\u0438\u043d": 92, "\u0431\u043b\u0430\u0433": 92, "\u0437\u043b\u043e": 92, "\u043d\u0435\u0432\u0435\u0436\u0435\u0441\u0442\u0432": 92, "\u043a\u0430\u043f\u0438\u0442\u0430": 92, "\u0443\u043c\u0440\u0443\u0442": 92, "\u043f\u043e\u0433\u0443\u0431": 92, "\u043b\u0430\u0440\u0440": 92, "\u043f\u0440\u0443\u0441\u0430\u043a": 92, "\u0433\u043b\u0443\u043f\u043e\u0441\u0442": 92, "\u0434\u0430\u0440": 92, "\u0431\u043e\u0436": 92, "\u043e\u0442\u0442": 92, "\u0431\u0438\u0441\u043c\u0430\u0440\u043a": 92, "shakespeare": 92, "lear": 92, "\u0438\u0449\u0443\u0442": 92, "\u0441\u0430\u043c\u043e\u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d": 92, "\u0441\u0445\u043e\u0434": [92, 94], "\u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c": 92, "\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442": [92, 100], "\u0432\u044b\u0432\u0435\u0441\u0442": 92, "\u043f\u0440\u0438\u043b\u0430\u0433\u0430": 92, "\u043f\u0440\u0438\u0441\u0430\u0434": 92, "\u043e\u043f\u043f\u043e\u043d\u0435\u043d\u0442": 92, "\u043f\u043e\u0441\u0442\u0438\u0436\u0435\u043d": 92, "\u043c\u0430\u043b\u043e\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d": 92, "113": 92, "\u043e\u0442\u0441\u0435\u0447\u0435\u043d": 93, "\u0441\u043a\u0443\u043b\u044c\u043f\u0442\u043e\u0440": 93, "\u0431\u0435\u0441\u0444\u043e\u0440\u043c\u0435\u043d": 93, "\u0432\u044b\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430": 93, "\u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b": 93, "\u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437": 93, "\u0434\u0435\u0442\u0441\u0442\u0432": 93, "\u043e\u0444\u0438\u0446\u0435\u0440": 93, "\u0441\u043f\u0435\u0446\u0441\u043b\u0443\u0436\u0431": 93, "\u0441\u043e\u0441\u043b\u0443\u0436\u0438\u0432\u0446": 93, "\u043e\u0442\u0446": 93, "\u0440\u0443\u043a\u043e\u043f\u0430\u0448\u043d": 93, "\u0432\u0440\u0435\u0434\u043d": 93, "\u043d\u0440\u0430\u0432": 93, "\u043d\u0438\u043a\u043b\u0430\u0443\u0441": 93, "\u0432\u0438\u0440\u0442": 93, "\u0431\u043e\u0433\u0430\u0442\u0441\u0442\u0432": 93, "\u043a\u043e\u043b\u043e\u043a\u043e\u043b\u044c\u0447\u0438\u043a": 93, "\u0441\u0432\u0438\u0441\u0442\u043a": 93, "\u0431\u0430\u0437\u0438\u0441\u043d": 93, "\u043d\u0435\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d": 93, "\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0430\u043d": 93, "pascal": 93, "modula": 93, "\u043f\u0440\u0430\u043a\u0442\u0438\u0447\u043d": 93, "\u0437\u0430\u043c\u0435\u0449\u0430": 93, "\u0431\u0438\u0442": 93, "\u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c": 93, "\u0430\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u0447\u0435\u0441\u043a": 93, "\u0431\u0438\u0442\u043e\u0432": 93, "\u0431\u0435\u0441\u043f\u043e\u0434\u043e\u0431\u043d": 93, "\u0432\u0435\u0447\u0435\u0440": 93, "\u0441\u043f\u0438\u0440\u0430": 94, "\u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d": [94, 100], "\u0443\u0432\u043b\u0435\u0447\u0435\u043d": 94, "\u0437\u0430\u043d\u043e\u0441": 94, "\u044d\u0439\u0444\u043e\u0440": 94, "\u0440\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 94, "\u0432\u0437\u0430\u0438\u043c\u043e\u043f\u043e\u043d\u0438\u043c\u0430\u043d": 94, "\u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430": 94, "\u0434\u0435\u0432\u0438\u0430\u0446": 94, "\u0438\u043d\u0442\u0435\u0440\u0432\u044c\u044e\u0435\u0440": 94, "\u043f\u043e\u0433\u043e\u0432\u043e\u0440": 94, "\u0432\u043e\u0437\u0432\u0435\u0434": 94, "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0441\u0442\u043e\u044f\u043d": 94, "\u0430\u0441\u0441\u043e\u0446\u0438\u0438\u0440\u043e\u0432\u0430": 94, "\u0433\u0435\u043d\u0438\u0430\u043b\u044c\u043d": 94, "\u0438\u043c\u0438\u0434\u0436": 94, "\u043e\u0431\u0438\u0436\u0430": 94, "\u043e\u0442\u0432\u0435\u0440\u0433\u0430\u043d": 94, "\u043d\u044c\u044e\u0442\u043e\u043d": 94, "\u0441\u0435\u0440\u0435\u0431\u0440\u044f": 94, "\u0432\u043f\u0440\u0438\u043d\u0446\u0438\u043f": 94, "\u043d\u0430\u043e\u0449\u0443\u043f": 94, "\u0432\u044b\u044f\u0432\u043b": 94, "frederic": 94, "\u0441\u0430\u0434\u043e\u0432\u043d\u0438\u043a": 94, "\u0432\u044b\u0440\u0430\u0449\u0438\u0432\u0430": 94, "\u0441\u0442\u0440\u043e": 94, "\u043d\u0435\u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043d": 94, "\u043d\u0430\u0447\u0430\u043b\u044c\u043d": 94, "\u043c\u0435\u043d\u0442\u043e\u0440\u0438\u043d\u0433": 94, "matias": 94, "pre": 94, "intention": 94, "\u0431\u0435\u0441\u043f\u043e\u043a\u043e\u0439\u0441\u0442\u0432": 95, "\u043e\u0442\u0440\u0435\u0437\u043a": 95, "\u0441\u043f\u0435\u0448\u043a": 95, "remaining": 95, "\u043f\u0430\u043d\u0438\u043a": 95, "\u043d\u0430\u0443\u043a\u043e\u0435\u043c\u043a": 95, "\u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0436\u0430": 95, "\u043f\u0441\u0438\u0445\u0438\u043a": 95, "\u043e\u0431\u043e\u0441\u0442\u0440": 95, "\u0433\u0440\u0443\u0437": [95, 100], "\u0443\u0441\u043f\u0435\u0432\u0430": 95, "\u0444\u043e\u043a\u0443\u0441\u0438\u0440": 95, "\u043e\u0441\u0432\u0430\u0438\u0432\u0430": 95, "\u0441\u043b\u043e\u043c\u0430": 95, "\u0441\u043f\u0430\u0437\u043c": 95, "\u043d\u0435\u0437\u0430\u0449\u0438\u0449\u0435\u043d": 95, "\u0445\u0440\u0443\u0441\u0442\u0430\u043b\u0438\u043a": 95, "\u0430\u043a\u043a\u043e\u043c\u043e\u0434\u0430\u0446": 95, "\u043c\u0438\u043e\u043f": 95, "\u043d\u0435\u0441\u043b\u0443\u0447\u0430\u0439\u043d": 95, "\u043f\u0438\u043b\u044e\u043b": 95, "\u0440\u0438\u0441\u043e\u0432\u0430": 95, "\u0442\u0430\u0431\u043b\u0438\u0447\u043a": 95, "timelines": 95, "trello": 95, "\u043e\u0432\u043b\u0430\u0434\u0435\u0442": 95, "\u043e\u0441\u043e\u0437\u043d\u0430\u043d": 95, "\u043f\u0430\u0431\u043b\u0438\u043a": 95, "\u0434\u043d\u044f\u0445": 95, "\u0441\u0442\u0430\u043d\u0438\u0441\u043b\u0430\u0432": 96, "\u0431\u043e\u043b\u0441\u0443\u043d": 96, "rss": 96, "\u0432\u044b\u043c\u044b\u0448\u043b\u0435\u043d": 97, "bolsun": [100, 102], "simplification": 100, "abstracts": 100, "ignores": 100, "\u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446": 100, "\u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442": 100, "\u0438\u0433\u043d\u043e\u0440\u0438\u0440": 100, "\u0441\u043c\u043e\u0436": 100, "\u0441\u043b\u0443\u0436\u0430": 100, "\u0437\u0438\u043c\u0430\u0440": 100, "narrow": 100, "rough": 100, "stage": 100, "intend": 100, "replicate": 100, "literal": 100, "subsystem": 100, "practicing": 100, "smallish": 100, "phew": 100, "\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430": 100, "head": 100, "rigorously": 100, "selective": 100, "sentence": 100, "intimate": 100, "binding": 100, "inclusive": 100, "opposite": 100, "moderately": 100, "encompassing": 100, "vigorously": 100, "brussels": 100, "\u043c\u043e\u0440\u0441\u043a": 100, "\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 100, "\u0446\u0438\u043b\u0438\u043d\u0434\u0440\u0438\u0447\u0435\u0441\u043a": 100, "\u043c\u0435\u0440\u043a\u0430\u0442\u043e\u0440": 100, "\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f": 100, "\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u0442": 100, "\u0441\u0442\u0440\u0435\u043b\u043a": 100, "\u0430\u0444\u0440\u0438\u043a": 100, "\u0433\u0440\u0435\u043d\u043b\u0430\u043d\u0434": 100, "\u043a\u0430\u0440\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a": 100, "\u0437\u0435\u043c\u043d": 100, "\u043c\u043d\u043e\u0433\u043e\u0433\u0440\u0430\u043d\u043d\u0438\u043a": 100, "\u0434\u0438\u043c\u0430\u043a\u0441\u0438\u043e\u043d": 100, "\u0444\u0443\u043b\u043b\u0435\u0440": 100, "painful": 100, "\u0432\u0441\u0435\u043e\u0431\u044a\u0435\u043c\u043b\u044e\u0449": 100, "\u0434\u043e\u043f\u043e\u043b\u043d": 100, "\u043e\u0431\u0449\u0435\u0441\u0438\u0441\u0442\u0435\u043c\u043d": 100, "\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u0443\u0435\u043c": 100, "\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b": 100, "\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d": 100, "\u043a\u043e\u043d\u043a\u0440\u0435\u0442\u0438\u0437\u0430\u0446": 100, "\u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0430": 100, "\u0441\u043e\u0447\u0442\u0435\u043d": 100, "\u043d\u0435\u0432\u043a\u043b\u044e\u0447\u0435\u043d": 100, "\u043d\u0435\u0447\u0442": [100, 102], "\u043d\u0435\u043f\u043e\u0437\u043d\u0430": 100, "\u043c\u043e\u0433\u0443\u0449": 100, "\u0437\u0430\u043c\u0435\u043d\u0438\u0442\u0435\u043b": 100, "\u0440\u0430\u043a\u0443\u0440\u0441": 100, "\u043e\u0433\u0443\u0440\u0446": 100, "\u043b\u0435\u043a\u0441\u0438\u043a\u043e\u043d": 100, "6000": 100, "\u043a\u043e\u043b\u0438\u0447\u0441\u0442\u0432": 100, "\u0431\u0435\u0437\u0433\u0440\u0430\u043d\u0438\u0447\u043d": 100, "\u043b\u0438\u043d\u0433\u0432\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": [100, 102], "\u0441\u043b\u043e\u0432\u0430\u0440\u043d": 100, "\u0437\u0430\u043f\u0430\u0441": 100, "\u043c\u0430\u0440\u043a\u0435\u0440": 100, "\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d": 100, "\u044f\u0437\u044b\u043a\u043e\u0432": 100, "\u0441\u0438\u0433\u043d\u0430": 100, "\u0443\u0434\u043e\u0440\u043e\u0436\u0430": 100, "semantics": 100, "tailored": 100, "precise": 100, "cord": 100, "weaves": 100, "\u043e\u0431\u044b\u043a\u043d\u043e\u0432\u0435\u043d": 100, "\u043e\u0433\u0443\u0440\u0435\u0446": 100, "\u0442\u043e\u043b\u043a\u043e\u0432\u0430\u043d": 100, "\u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442": 100, "\u0440\u0430\u0441\u043f\u043b\u044b\u0432\u0447\u0430\u0442": 100, "\u0441\u043b\u043e\u0432\u0435\u0441\u043d": [100, 102], "\u0432\u043e\u0448\u0435\u043b": 100, "\u0441\u0432\u0435\u0440\u0442\u043e\u043a": 100, "\u043e\u0431\u043b\u0430\u043a": 100, "\u043e\u043f\u0438\u0441\u044b\u0432": 100, "\u043e\u0431\u0432\u043e\u043b\u0430\u043a\u0438\u0432\u0430": 100, "\u0433\u0434\u0435\u0442": 100, "\u0441\u0435\u0440\u0435\u0434\u0438\u043d": 100, "\u0441\u043a\u043e\u043f\u043b\u0435\u043d": 100, "\u043f\u043e\u044d\u0437": 100, "\u044e\u043c\u043e\u0440": 100, "\u0434\u0438\u043f\u043b\u043e\u043c\u0430\u0442": 100, "\u043c\u043e\u0448\u0435\u043d\u043d\u0438\u0447\u0435\u0441\u0442\u0432": 100, "\u0431\u044b\u0442\u043e\u0432": 100, "\u0438\u0437\u0436\u0438\u0432\u0430": 100, "\u0432\u044b\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": 100, "\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a": 100, "\u0441\u043a\u043e\u0442\u043e\u0432\u043e\u0434\u0447\u0435\u0441\u043a": 100, "\u0430\u0444\u0440\u0438\u043a\u0430\u043d\u0441\u043a": 100, "\u043f\u043b\u0435\u043c\u0435\u043d": 100, "\u043c\u0430\u0441\u0430": 100, "\u043a\u043e\u0440": 100, "\u0441\u0435\u0432\u0435\u0440\u043d": 100, "\u043d\u0430\u0440\u043e\u0434": 100, "\u0441\u043d\u0435\u0433": 100, "\u0440\u0430\u0437\u0433\u043e\u0432\u0430\u0440\u0438\u0432\u0430": 100, "\u0444\u0438\u0437\u0438\u043a": 100, "\u043c\u0435\u0434\u0438\u043a": 100, "\u044e\u0440\u0438\u0441\u0442": 100, "\u0443\u0433\u043e\u043b\u043e\u0432\u043d\u0438\u043a": 100, "\u0431\u043e\u0442\u0430": 100, "\u0444\u0435\u043d": 100, "\u043c\u043e\u043b\u043e\u0434\u0435\u0436": 100, "\u0441\u043b\u044d\u043d\u0433": 100, "\u0432\u0437\u0440\u043e\u0441\u043b": 100, "\u043b\u043e\u043d\u0434\u043e\u043d\u0441\u043a": 100, "\u043d\u0438\u0437": 100, "\u043a\u043e\u043a\u043d": 100, "\u043d\u0430\u0437\u043e\u0432": 100, "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b": 100, "\u0438\u0437\u0436": 100, "\u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d": 100, "\u043d\u0430\u0431\u043e\u043b\u044c\u0448": 100, "\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430": 100, "\u0441\u0432\u044f\u0437\u0430\u043d": 100, "\u0440\u0430\u0437\u0440\u0435\u0437\u0430": 100, "\u0441\u0432\u0430\u043b": 100, "\u043d\u0435\u0440\u0435\u043b\u0435\u0432\u0430\u0442\u043d": 100, "\u043e\u0442\u043d\u0438\u043c": 100, "\u0437\u0430\u043f\u0438\u0445\u043d\u0443\u0442": 100, "\u043a\u0440\u043e\u0439\u043a": 100, "\u0431\u043b\u044e\u0434": 100, "\u0434\u043e\u0434\u0435\u043a": 100, "\u044d\u0434\u0440": 100, "\u043f\u0430\u0437\u043b": 100, "\u043f\u043e\u043b\u043e\u0442\u043d": 100, "\u043f\u043e\u0441\u0435\u0442\u0438\u0442\u0435\u043b": 100, "\u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b": 100, "\u043f\u043b\u0430\u0442\u0435\u043b\u044c\u0449\u0438\u043a": 100, "\u0430\u0434\u0440\u0435\u0441\u0430\u0442": 100, "\u0432\u043b\u0430\u0434\u0438\u043a": 100, "divergent": 100, "cope": 100, "ambiguity": 100, "optimizing": 100, "advertising": 100, "campaigns": 100, "simplify": 100, "simplistic": 100, "overengineered": 100, "engineered": 100, "zakrevskii": 100, "\u0442\u0433": 100, "ru_arc": 100, "chat": 100, "tg": 100, "idddqd": 100, "topology": 100, "\u0438\u0437\u0431\u0440\u0430": 102, "\u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d": 102, "\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c": 102, "\u044d\u043b\u0438\u043c\u0438\u043d\u0438\u0440": 102, "\u043c\u043d\u043e\u0433\u043e\u0437\u043d\u0430\u0447\u043d": 102, "\u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0438\u0440": 102, "\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0443\u0430\u043b\u044c\u043d": 102, "\u043d\u0430\u043f\u0440": 102, "\u0441\u0438\u043d\u043e\u043d\u0438\u043c": 102, "\u0430\u043d\u0442\u043e\u043d\u0438\u043c": 102, "\u0440\u0430\u0437\u043b\u0438\u0447\u0435\u043d": 102, "\u044d\u043a\u0441\u0442\u0435\u043d\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 102, "\u0438\u043d\u0442\u0435\u043d\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 102, "\u0441\u0438\u043d\u043e\u043d\u0438\u043c\u0438\u0447\u043d": 102, "\u044d\u043a\u0441\u0442\u0435\u043d\u0441\u0438\u043e\u043d\u0430\u043b": 102, "\u0434\u0438\u0430\u0433\u043e\u043d\u0430": 102, "\u0440\u043e\u043c\u0431": 102, "\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u043e\u0433\u0440\u0430\u043c\u043c": 102, "\u0441\u043c\u0435\u0436\u043d": 102, "\u044d\u043f\u0438\u0441\u0442\u0435\u043c\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 102, "\u0432\u0437\u0430\u0438\u043c\u043e\u0437\u0430\u043c\u0435\u043d\u0438\u043c": 102, "\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d": 102, "\u0437\u0430\u043c\u0435\u043d\u0438\u043c": 102, "\u0432\u044b\u0442\u0435\u043a\u0430": 102, "\u0442\u043e\u0436\u0434\u0435\u0441\u0442\u0432": 102, "\u0438\u043d\u0442\u0435\u043d\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 102, "\u043d\u043e\u044d\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 102, "\u0444\u0440\u0435\u0433": 102, "\u043f\u0440\u043e\u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 102, "\u0430\u043a\u0442": 102, "\u0444\u0438\u0433\u0443\u0440\u0438\u0440": 102, "\u043e\u0431\u044b\u0434\u0435\u043d": 102, "\u0435\u0441\u0442\u0435\u0441\u0442\u0432\u043e\u0437\u043d\u0430\u043d": 102, "\u0444\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446": 102, "\u0444\u043e\u0440\u043c\u0430\u043b\u044c\u043d": 102, "\u0433\u0443\u043c\u0430\u043d\u0438\u0442\u0430\u0440\u043d": 102, "\u043c\u0430\u0442\u0435\u0440": 102, "\u0430\u0440\u0438\u0441\u0442\u043e\u0442\u0435\u043b": 102, "\u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d": 102, "\u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 102, "\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u043a": 102, "\u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c": 102, "\u0440\u0430\u0441\u043a\u0440\u044b\u0442": 102, "\u0434\u043b\u0438\u043d": 102, "\u043b\u0438\u043d\u0433\u0432\u0438\u0441\u0442\u0438\u043a": 102, "\u044d\u043a\u0441\u0442\u0440\u0430\u043b\u0438\u043d\u0433\u0432\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": 102, "\u0438\u043c\u043f\u043b\u0438\u0446\u0438\u0442\u043d": 102, "\u043d\u0435\u044f\u0437\u044b\u043a\u043e\u0432": 102, "\u043e\u0431\u0441\u0442\u0430\u043d\u043e\u0432\u043a": 102, "\u043f\u0441\u0438\u0445\u0438\u0447\u0435\u0441\u043a": 102, "\u0441\u0442\u0430\u0442\u0443\u0441": 102, "\u044d\u043a\u0441\u043f\u043b\u0438\u0446\u0438\u0442\u043d": 102, "\u043f\u0440\u0435\u0441\u0443\u043f\u043f\u043e\u0437\u0438\u0446": 102, "\u0434\u0438\u0441\u043a\u0443\u0440\u0441": 102, "\u0433\u0443\u0442\u043d\u0435\u0440": 102, "\u044d\u043f\u0438\u0441\u0442\u0435\u043c\u043e\u043b\u043e\u0433": 102, "\u043a\u0430\u043d\u043e\u043d": 102, "\u0440\u043e\u043e": 102, "\u0440\u0435\u0430\u0431\u0438\u043b\u0438\u0442\u0430\u0446": 102, "\u043a\u0430\u0441\u0430\u0432\u0438\u043d": 102}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"\u043a\u0430\u043a": [0, 9, 40, 70, 83, 88, 93], "\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": 0, "\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d": [0, 5, 8, 9, 10, 11, 21, 23, 30, 34, 37, 38, 39, 40, 41, 46, 52, 56, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 94, 95, 100], "\u043f\u043e\u0447": [0, 11, 23, 52, 85], "\u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432\u043d": [0, 72], "\u0441\u0443\u0431\u044a\u0435\u043a\u0442\u043d": 0, "\u043f\u0441\u0438\u0445\u043e\u043b\u043e\u0433": [0, 90], "\u044d\u043a\u043e\u043d\u043e\u043c": 0, "\u0432\u0440\u0435\u043c\u0435\u043d": [0, 40], "\u043d\u0430\u0432\u0438\u0433\u0430\u0446": 0, "\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446": [0, 5], "\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446": [0, 8, 70], "\u0432\u043b\u0438\u044f\u043d": [0, 77, 85, 95], "\u043d\u0430": [0, 30, 38, 46, 77, 82, 85, 90, 92, 95], "\u043a\u0430\u0447\u0435\u0441\u0442\u0432": [0, 40, 53, 74, 82], "\u043e\u0431\u0443\u0447\u0435\u043d": [0, 82, 94, 95], "\u043b\u0435\u0433\u043a\u043e\u0441\u0442": 0, "\u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d": 0, "\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442": [0, 30, 100, 102], "\u043f\u043e\u0440\u044f\u0434\u043e\u043a": 0, "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d": 0, "\u0441\u043e\u0431\u0440\u0430": 0, "html": 0, "\u043e": [0, 21, 34, 37, 70, 85, 92], "zettelkasten": 0, "\u0444\u0438\u043b\u043e\u0441\u043e\u0444": 0, "\u0431\u043b\u0438\u0437\u043a": 0, "\u043f\u043e": [0, 40, 66, 82, 86, 88, 100], "\u0434\u0443\u0445": 0, "\u0441\u0438\u0441\u0442\u0435\u043c": [0, 82], "obsidian": 0, "neuron": 0, "antora": 0, "gitjournal": 0, "\u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 0, "\u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440": 0, "\u0441\u0430\u0439\u0442": 0, "\u0434\u0440\u0443\u0433": [0, 73, 82, 86], "\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d": 0, "\u043f\u0440\u043e\u0435\u043a\u0442": [0, 15], "markdown": 0, "\u0440\u0430\u0431\u043e\u0442\u0430": 0, "\u043c\u043e\u0431\u0438\u043b\u044c\u043d": 0, "\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432": 0, "android": 0, "iphone": 0, "\u0441": [0, 21], "notion": 0, "evernote": 0, "rss": 0, "\u0438\u043d\u0442\u0435\u0433\u0430\u0446": 0, "mattermost": 0, "telegram": 0, "sitemap": 0, "\u043f\u043e\u043b\u0435\u0437\u043d": 0, "\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d": 0, "\u043f\u043e\u0441\u043b\u0435\u0441\u043b\u043e\u0432": [0, 23], "\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432": [1, 96, 97, 98, 99, 105], "emacsway": 1, "\u043e\u0433\u043b\u0430\u0432\u043b\u0435\u043d": [1, 2, 6, 7, 12, 16, 17, 19, 22, 24, 25, 27, 28, 31, 32, 33, 35, 36, 43, 44, 45, 48, 50, 54, 57, 58, 61, 67, 69, 71, 78, 79, 81, 84, 87, 91, 99, 101, 103, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138], "concurrency": [2, 106], "saga": 3, "transaction": 4, "event": [5, 6, 10, 16, 23, 82, 107], "storming": [5, 6, 82, 107], "with": 5, "archi": 5, "\u043e\u0431\u0437\u043e\u0440": 5, "\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442": 5, "\u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432": 5, "\u0434\u043b\u044f": [5, 11, 21, 82], "\u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a": [5, 92], "\u0441\u0440\u0435\u0434\u0441\u0442\u0432": 5, "git": 5, "\u0448\u0442\u0430\u0442\u043d": 5, "\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c": 5, "\u0441\u043b\u0438\u044f\u043d": 5, "\u043c\u043e\u0434\u0435\u043b": [5, 8, 11, 100], "\u0438\u0437\u0431\u0435\u0433\u0430\u043d": 5, "\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442": [5, 92], "\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a": 5, "\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [5, 37, 75, 102], "\u0433\u0440\u0430\u043d\u0438\u0446": [5, 8], "\u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441": [5, 86], "\u0433\u0435\u043d\u0435\u0440\u0430\u0446": 5, "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446": 5, "\u0441\u0442\u0438\u043a\u0435\u0440": 5, "c4": 5, "model": [5, 25, 100, 101, 113], "archimatetool": 5, "troubleshooting": 5, "ddd": [7, 16, 19, 23, 82, 86, 103, 108, 109], "in": [7, 14, 18, 23, 38, 44, 48, 50, 72, 73, 74, 75, 108, 122, 124, 125], "practice": [7, 86, 108], "\u043f\u043e\u0438\u0441\u043a": [8, 38], "\u0430\u0433\u0440\u0435\u0433\u0430\u0442": [8, 9, 11], "\u0431\u0438\u0437\u043d\u0435\u0441": [8, 23, 38, 43, 46, 121], "\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d": [8, 52, 77], "strong": [8, 23], "consistency": [8, 23, 30], "rdbms": 8, "eventual": [8, 23], "\u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d": 8, "\u0443\u043f\u0440\u043e\u0449\u0435\u043d": 8, "\u043f\u0440\u043e\u0431\u043b\u0435\u043c": [8, 23], "\u0434\u0430\u043d": [8, 82], "\u0432\u0435\u0440\u043e\u044f\u0442\u043d": 8, "\u0443\u0442\u0440\u0430\u0442": 8, "\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d": 8, "\u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d": 8, "\u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442": 8, "\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d": 8, "endorsement": 8, "\u0432": [8, 9, 11, 15, 21, 34, 40, 46, 47, 70, 76, 86, 88, 90, 92, 93, 95], "\u0441\u0443\u0449\u043d\u043e\u0441\u0442": [8, 11], "\u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d": 8, "data": 8, "context": [8, 11, 30, 82, 102], "and": [8, 23, 29, 30, 75, 82, 86, 96], "interaction": 8, "dci": 8, "process": [8, 23], "manager": 8, "pattern": [8, 9, 15], "pessimistic": 8, "offline": 8, "lock": 8, "\u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u043d": 8, "\u0438\u0442\u043e\u0433\u043e\u0432": 8, "missing": 8, "chapter": 8, "\u0441\u043e\u0445\u0440\u0430\u043d": 9, "\u0431\u0434": 9, "\u043d\u0435": [9, 21, 23, 26, 46, 52, 70, 93], "\u0440\u0430\u0437\u0440\u0443\u0448": 9, "\u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u044f\u0446": 9, "memento": 9, "walker": 9, "valuer": 9, "scanner": 9, "reflection": 9, "exporter": 9, "1": [9, 83], "accepting": 9, "interface": 9, "mediator": 9, "2": [9, 83], "returning": 9, "structure": 9, "sourcing": [10, 16, 82], "\u0444\u0430\u0439\u043b\u043e\u0432": 11, "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440": [11, 82, 86], "\u0434\u043e\u043c\u0435\u043d": [11, 100], "\u0437\u0430\u0447": 11, "\u043a\u0430\u0436\u0434": 11, "bounded": [11, 30, 82], "\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440": 11, "internal": [11, 23], "\u0440\u0435\u0437\u043c\u0435\u0449": 11, "\u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d": 11, "\u0432\u044b\u0434\u0435\u043b": 11, "\u043e\u0442\u0434\u0435\u043b\u044c\u043d": [11, 30], "\u043d\u0435\u0442": 11, "\u0435\u0433": 11, "\u043e\u0431\u044a\u0435\u043a\u0442": [11, 23], "\u0437\u043d\u0430\u0447\u0435\u043d": [11, 21, 95], "\u0441\u043e\u0431\u044b\u0442": [11, 23, 30, 34], "\u0440\u0430\u0437\u043c\u0435\u0449": 11, "\u0438": [11, 21, 23, 41, 52, 75, 82, 85, 86, 93, 100], "domain": [12, 23, 24, 25, 82, 100, 101, 112, 113], "layer": [12, 29], "shotgun": 13, "surgery": 13, "specification": 14, "golang": [14, 16, 18], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": 15, "\u043b\u0438": [15, 21, 23, 74, 92], "canexecute": 15, "cqrs": [16, 21, 22, 23, 82, 111], "reference": [16, 21, 64], "application": 16, "grade": 16, "infrastructure": 17, "repository": [18, 29, 30, 31, 116], "strategic": [20, 110], "design": [20, 28, 71, 72, 74, 77, 82, 85, 110, 115, 132], "\u043c\u043e\u0436\u0435\u0442": [21, 23], "\u043a\u043e\u043c\u0430\u043d\u0434": [21, 23, 82, 83, 86, 100], "\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430": [21, 23], "\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442": [21, 23, 56], "transparency": 21, "\u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [21, 82], "\u0441\u0440\u0435\u0434": 21, "\u0447\u0435\u043c": 21, "\u043e\u0442\u043b\u0438\u0447\u0430": 21, "\u043e\u0442": [21, 23, 70, 75], "cqs": 21, "\u0430": [21, 23, 52, 100], "\u0435\u0441\u0442": 21, "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447": [21, 86], "\u0430\u0432\u0442\u043e\u0440\u0438\u0442\u0435\u0442\u043d": 21, "\u0442\u043e\u0447\u043a": 21, "\u0437\u0440\u0435\u043d": 21, "\u044d\u0442": [21, 23, 85, 92], "\u0431\u043e\u043b\u044c\u0448": 21, "referential": 21, "query": 21, "command": 21, "\u0441\u043b\u0443\u0436\u0435\u0431\u043d": 21, "\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446": [21, 82, 93, 100], "\u043a\u043e\u0434": [21, 40, 46, 73, 74, 83], "\u043e\u0448\u0438\u0431\u043a": [21, 40, 100], "\u0438\u043b": 21, "\u0443\u0441\u043f\u0435\u0448\u043d": [21, 83], "\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d": 21, "\u043a\u0440\u043e\u043c": 21, "\u0441\u0443\u0449\u0435\u0441\u0442\u0432": 21, "\u0435\u0449": 21, "\u0444\u0443\u043d\u043a\u0446": 21, "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440": 21, "\u0434\u043e\u043b\u0436": 21, "\u0438\u043c\u0435\u0442": 21, "abstract": 21, "side": 21, "effect": 21, "\u043d\u043e": 21, "concrete": 21, "\u0447\u0442\u043e": [21, 26, 37, 40, 46, 52, 65, 80, 85, 100], "\u0434\u0435\u043b\u0430": [21, 26, 46, 82], "\u0430\u0442\u043e\u043c\u0430\u0440\u043d": 21, "\u043e\u043f\u0435\u0440\u0430\u0446": 21, "\u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440": 21, "\u0438\u0437\u043c\u0435\u043d": 21, "\u0441\u0441\u044b\u043b\u043e\u0447\u043d": 21, "\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442": 21, "\u043a\u043e\u043d\u0446\u0435\u043f\u0446": 21, "\u0431\u0443\u0444\u0435\u0440": 21, "\u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d": 21, "\u0435\u0441\u043b": [21, 26, 46, 83, 100], "\u0434\u043e\u043b\u0436\u043d": 21, "\u0432\u0435\u0440\u043d\u0443\u0442": 21, "\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440": 21, "\u0441\u043e\u0437\u0434\u0430": 21, "\u0440\u0435\u0441\u0443\u0440\u0441": [21, 46], "\u043e\u0434\u043d\u043e\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d": 21, "\u043f\u043e\u0442\u043e\u043a": 21, "\u0438\u0437\u043c\u0435\u043d\u0435\u043d": [21, 88], "jimmy": [21, 23], "bogard": [21, 23], "\u0432\u044b\u0432\u043e\u0434": [21, 30, 95], "events": [23, 24, 82, 112], "\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d": [23, 65], "vs": [23, 56], "transactional": 23, "\u0441\u043b\u0435\u0434\u0441\u0442\u0432": 23, "\u043f\u0440\u0438\u0447\u0438\u043d": [23, 34], "\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d": 23, "\u0432\u0441\u0435": [23, 83], "\u0440\u0435\u0448\u0430": 23, "\u043f\u0440\u0430\u0432": 23, "\u043f\u0440\u0438\u043d\u0446\u0438\u043f": [23, 90], "ask": 23, "whose": 23, "job": 23, "it": [23, 32, 104, 117], "is": [23, 75], "\u043d\u043e\u0432\u0438\u0447\u043a": 23, "\u0438\u043d\u0442\u0435\u0440\u0435\u0441": [23, 38, 43, 45, 75, 121, 123], "performance": 23, "\u043e\u0431\u0440\u0430\u0442\u043d": 23, "\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c": 23, "\u0444\u043e\u0440\u043c\u0430\u0442": 23, "\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446": 23, "net": 23, "microservices": [23, 82], "\u043c\u043d\u0435\u043d": [23, 92], "scott": 23, "millett": 23, "nick": 23, "tune": 23, "kamil": 23, "grzybek": 23, "udi": 23, "dahan": 23, "cesar": 23, "de": 23, "la": 23, "torre": 23, "out": 23, "of": [23, 72, 73, 74, 75, 82, 86], "external": 23, "one": [23, 75, 85], "phase": 23, "two": 23, "\u043a\u0442\u043e": [23, 74], "\u0438\u0437\u0434\u0430\u0432\u0430": 23, "\u043e\u0442\u043c\u0435\u043d": 23, "\u0441\u0432\u043e": 23, "\u0440\u0435\u0448\u0435\u043d": [23, 30, 38, 70, 92], "\u0431\u0430\u043b\u0430\u043d\u0441": [23, 38, 75, 76], "\u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442": [23, 40, 76], "\u043e\u0431\u0440\u0435\u0442\u0430": 23, "\u0432\u044b\u0433\u043e\u0434": 23, "atomicity": 23, "resiliency": 23, "integration": [23, 35, 119], "\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d": 23, "\u043e\u0447\u0435\u0440\u0435\u0434\u043d": [23, 34], "\u0433\u0434\u0435": 23, "\u0441\u043e\u0437\u0434\u0430\u0432\u0430": 23, "\u043e\u0431": 23, "\u0443\u0434\u0430\u043b\u0435\u043d": 23, "\u0432\u0430\u0436\u043d": [23, 100], "\u0447\u0438\u0442\u0430": [23, 74, 93], "\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b": 23, "\u0432\u043c\u0435\u0441\u0442": 23, "\u043f\u0435\u0440\u0435\u0432\u043e\u0434": 23, "immutability": 26, "\u044f\u043f": 26, "\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430": 26, "\u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c": 26, "value": [27, 114], "objects": [27, 114], "tactical": [28, 115], "anticorruption": 29, "causal": 30, "\u0432\u0430\u0440\u0438\u0430\u043d\u0442": 30, "\u0432\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d": 30, "\u0441\u043e\u0441\u0442\u043e\u044f\u043d": 30, "\u0432\u0435\u0440\u0441": [30, 38], "asynchronous": [33, 118], "communication": [33, 118], "\u0433\u043e\u043d\u043a": 34, "\u0441\u043e\u043e\u0431\u0449\u0435\u043d": 34, "\u0443\u0441\u043b\u043e\u0432": 34, "\u043a\u043e\u043d\u043a\u0443\u0440\u0438\u0440": 34, "\u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a": 34, "\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a": 34, "\u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0442\u0438\u0432\u043d": [34, 40], "\u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d": 34, "\u043d\u0430\u0440\u0443\u0448\u0435\u043d": 34, "\u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d": 34, "\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a": 34, "sdlc": [36, 61, 64, 82, 120, 129], "\u0442\u0430\u043a": [37, 52, 65, 80, 85], "agile": [37, 38, 44, 48, 49, 50, 51, 52, 53, 54, 55, 58, 72, 73, 74, 75, 76, 82, 86, 122, 124, 125, 126, 128], "development": [37, 57, 59, 60, 62, 63, 64, 127], "\u0438\u0441\u0442\u043e\u0440": 37, "\u0441\u0443\u0442": [37, 38, 65, 90], "\u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442": [37, 85], "\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u043d": 38, "\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a": [38, 40, 45, 123], "\u043f\u0440\u0435\u043e\u0431\u043b\u0430\u0434\u0430\u043d": 38, "extreme": [38, 86], "programming": [38, 86], "\u043f\u0435\u0440\u0432": 38, "xp": 38, "\u0432\u0442\u043e\u0440": [38, 82], "scrum": [38, 86], "the": [38, 76, 86], "guide": [38, 86], "\u043a": [38, 76], "\u043f\u0435\u0440\u0432\u043e\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a": [38, 75], "\u0437\u0430": 38, "atam": 38, "\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430": 38, "\u0447\u0430\u0441\u0442": [38, 40, 82], "\u0438\u0442\u0435\u0440\u0430\u0446": 38, "\u0437\u0430\u0434\u0430\u0447": [38, 40, 82], "open": [38, 76], "architecture": [38, 39, 76, 96], "\u0441\u0438\u0441\u0442\u0435\u043c\u043d": 38, "\u043c\u044b\u0448\u043b\u0435\u043d": 38, "\u043f\u0441\u0438\u0445\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": [38, 89, 95], "\u0441\u0442\u043e\u0440\u043e\u043d": [38, 76], "\u0432\u043e\u043f\u0440\u043e\u0441": [38, 82], "\u043f\u043b\u0430\u043d": [38, 92], "selling": 39, "options": 39, "\u043d\u0430\u0438\u0431\u043e\u043b": 40, "\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d": [40, 95], "\u0441\u043f\u0438\u0441\u043e\u043a": [40, 82, 89], "\u043e\u0448\u0438\u0431\u043e\u043a": 40, "\u043b\u043e\u0436\u043d": 40, "\u0432\u0435\u0440": 40, "\u0442\u043e": 40, "\u0442\u0435\u0445\u0434\u043e\u043b\u0433": 40, "\u044f\u0432\u043b\u044f": 40, "\u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u043d": 40, "\u0432\u0435\u043b\u0438\u0447\u0438\u043d": 40, "\u043e\u0442\u043d\u043e\u0448\u0435\u043d": 40, "\u043a\u043e": 40, "\u043d\u0430\u043a\u043e\u043f\u043b\u0435\u043d": 40, "\u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430": 40, "\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a": [40, 66, 85, 100], "\u043b\u0438\u043d\u0435\u0439\u043d": 40, "\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a": [40, 42, 82, 83], "\u0431\u0435\u0437\u0440\u0430\u0437\u043b\u0438\u0447\u043d": 40, "\u0432\u0437\u044f\u0442": 40, "\u0440\u0435\u043b\u0438\u0437": 40, "technical": [41, 74], "debt": 41, "\u0441\u043b\u043e\u0436\u043d": 41, "\u043f\u0440\u043e\u0446\u0435\u043d\u0442": 41, "\u043c\u043e\u0442\u0438\u0432\u0430\u0446": 42, "\u0441oncerns": [44, 122], "\u043a\u043e\u0433\u0434": [46, 47, 70], "refactoring": 46, "legacy": [46, 47], "\u0432\u044b\u0434\u0435\u043b\u044f": 46, "\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433": 46, "\u043f\u0438\u0441\u0430": [47, 83], "unit": 47, "tests": 47, "analysis": [48, 124], "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 49, "requirements": [49, 50, 51, 52, 53, 86, 125], "nonfunctional": 51, "product": 52, "backlog": 52, "item": 52, "user": 52, "story": 52, "\u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440": [52, 70, 82, 86, 88], "\u043f\u0440\u043e": 52, "\u043a\u0440\u0438\u0442\u0435\u0440": 53, "particular": 55, "models": [55, 61, 129], "code": [56, 82, 85, 94], "review": [56, 94], "\u0432\u043e\u0437\u043c\u043e\u0436\u043d": 56, "apaptation": 56, "prediction": [56, 76, 79, 80, 134], "continuous": 56, "collaborative": [57, 127], "practices": [58, 86, 128], "evolutionary": 59, "incremental": 60, "iterative": 62, "spiral": 63, "systems": 64, "life": 64, "cycle": 64, "adaptation": [65, 67, 76, 130], "\u0430\u0434\u0430\u043f\u0442\u0430\u0446": 65, "\u043a\u0440\u0430\u0442\u043a": 66, "\u043a\u0443\u0440\u0441": 66, "\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u043a": 66, "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d": [66, 82], "\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d": [66, 82], "borrowing": 68, "trouble": 68, "software": [69, 71, 74, 85, 86, 131, 132], "construction": [69, 131], "yagni": 70, "\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430": 70, "\u043f\u0440\u043e\u0435\u043a\u0442\u043d": 70, "\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0447\u0435\u0441\u043a": [70, 72, 83], "\u0443\u0449\u0435\u0440\u0431": 70, "\u043f\u0440\u0435\u0436\u0434\u0435\u0432\u0440\u0435\u043c\u0435\u043d": 70, "\u0441\u043b\u0443\u0447\u0430": 70, "\u043c\u043e\u043c\u0435\u043d\u0442": 70, "\u0441\u0442\u043e": 70, "\u043e\u0442\u043a\u043b\u0430\u0434\u044b\u0432\u0430": 70, "role": [72, 73, 74, 75], "patterns": [72, 85], "\u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f": 72, "\u044d\u0444\u0444\u0435\u043a\u0442": [72, 89], "\u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d": 72, "\u043f\u0430\u0442\u0442\u0435\u0440\u043d": 72, "\u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d": 72, "simplicity": 73, "\u0435\u0434\u0438\u043d\u0438\u0446": 73, "\u0438\u0437\u043c\u0435\u0440\u0435\u043d": 73, "\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d": 73, "\u0432\u0441\u0435\u0433\u0434": 73, "\u043f\u0440\u043e\u0441\u0442": 73, "eric": 73, "evans": 73, "edsger": 73, "w": 73, "dijkstra": 73, "steve": [73, 74], "mcconnell": [73, 74], "kent": [73, 74], "beck": [73, 74], "martin": [73, 74], "fowler": [73, 74], "robert": [73, 74], "c": 73, "bjarne": 73, "stroustrup": 73, "primary": 74, "imperative": 74, "\u043e\u043f\u0440\u0430\u0432\u0434\u0430": 74, "manifesto": 74, "ralph": 74, "johnson": 74, "\u0441\u0435\u0440\u0433": 74, "\u0442\u0435\u043f\u043b\u044f\u043a": 74, "\u043d\u0430\u0440\u043e\u0434\u043d": 74, "\u0442\u0432\u043e\u0440\u0447\u0435\u0441\u0442\u0432": 74, "randy": 74, "shoup": 74, "solid": 75, "principles": 75, "\u043e\u0448\u0438\u0431\u043e\u0447\u043d": 75, "\u0442\u0440\u0430\u043a\u0442\u043e\u0432\u043a": 75, "srp": 75, "not": 75, "to": 75, "do": 75, "just": 75, "thing": 75, "about": [75, 76], "cohesion": 75, "conway": 75, "s": 75, "law": 75, "common": 75, "closure": 75, "principle": 75, "ccp": 75, "complexity": 75, "ad": 75, "hominem": 75, "\u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0440\u043e\u0447\u043d": 75, "\u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d": 75, "ocp": 75, "no": 75, "silver": 75, "bullet": 75, "\u043f\u043e\u0441\u043b\u0435\u0434\u043d": 75, "2022": 75, "07": 75, "06": 75, "balancing": [76, 77], "\u0433\u0438\u0431\u043a\u043e\u0441\u0442": 76, "standard": 76, "by": [76, 86], "group": 76, "\u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d": 76, "\u043c\u0430\u044f\u0442\u043d\u0438\u043a": 76, "\u0437\u0430\u043d\u043e\u0441": 76, "\u043e\u0442\u0441\u043a\u043e\u043a": 76, "\u043d\u0430\u0437\u0430\u0434": 76, "alberto": 76, "brandolini": 76, "top": 77, "down": 77, "bottom": 77, "up": 77, "approaches": 77, "\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440": [77, 82, 86], "\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d": [78, 85, 95, 133], "\u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [78, 133], "\u0441\u0430\u043c\u043e\u043e\u0431\u0443\u0447\u0435\u043d": [81, 82, 135], "\u043f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432": 82, "\u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u0441\u043a": 82, "\u043c\u0438\u043d\u0438\u043c\u0443\u043c": 82, "\u0443\u0447": [82, 83], "\u0438\u0437\u0443\u0447\u0430": 82, "\u043e\u0441\u043d\u043e\u0432\u043d": [82, 85], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c": 82, "\u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433": 82, "\u0430\u0437\u0431\u0443\u043a": 82, "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d": [82, 90], "\u0431\u044b\u0442": [82, 90], "\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d": [82, 83, 86], "\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d": 82, "\u0441\u0438\u0441\u0442": 82, "\u043e\u0441\u043d\u043e\u0432": 82, "\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c": 82, "\u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a": 82, "\u0443\u0433\u043b\u0443\u0431\u043b\u044f": 82, "\u043d\u0430\u0432\u044b\u043a": 82, "\u0441\u0442\u0430\u0442": [82, 83], "aggregate": 82, "modeling": 82, "api": 82, "modelling": 82, "\u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d": 82, "\u0432\u044b\u0431\u043e\u0440": 82, "single": 82, "team": [82, 87, 137], "scaled": [82, 86], "\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442": 82, "\u043c\u0435\u043d\u0435\u0434\u0436\u043c\u0435\u043d\u0442": 82, "\u0440\u0430\u0437\u0432\u0438\u0442": 82, "\u043b\u0438\u0447\u043d\u043e\u0441\u0442\u043d": 82, "\u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 82, "\u0431\u0430\u0437": 82, "\u0442\u0440\u0435\u0442": 82, "\u0437\u0430\u0445\u043e\u0434": 82, "streaming": 82, "processing": 82, "\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 82, "posa": 82, "\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [82, 85], "\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440": 82, "\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a": 82, "\u043e\u0446\u0435\u043d\u0438\u0432\u0430\u043d": 82, "\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 82, "\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a": 82, "\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d": 82, "body": 82, "knowledge": 82, "\u0433\u043e\u0441\u0442": 82, "online": 82, "\u043a\u0430\u0442\u0430\u043b\u043e\u0433": 82, "smell": 82, "catalogs": 82, "\u043f\u043e\u0434\u0431\u043e\u0440\u043a": 82, "\u043f\u043e\u0447\u0442\u043e\u0432": 82, "\u0440\u0430\u0441\u0441\u044b\u043b\u043a": 82, "\u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432": 82, "\u044d\u0442\u0430\u043b\u043e\u043d": 82, "\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d": 82, "\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d": 82, "\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a": 83, "\u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a": 83, "\u043f\u0440\u0438\u043c\u0435\u0440": [83, 88], "\u0434\u043e\u0440\u043e\u0436\u043d": 83, "\u043a\u0430\u0440\u0442": 83, "\u043e\u0431\u0443\u0447\u0430": 83, "3": 83, "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430": 83, "\u043f\u0440\u043e\u0446\u0435\u0441\u0441": 83, "4": 83, "\u0438\u0437\u043c\u0435\u043d\u044f": 83, "\u043a\u043e\u043b\u043b\u0435\u043a\u0442": 83, "\u0445\u043e\u0447\u0435\u0442": 83, "\u0431\u0440\u043e\u0441": 83, "tdd": [84, 85, 136], "\u0447\u0435\u0440\u0435\u0437": 85, "\u0441\u043f\u043e\u0441\u043e\u0431": 85, "\u0431\u044b\u0441\u0442\u0440": 85, "\u043a\u0430\u0442\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440": 85, "clean": 85, "\u0442\u0435\u043c\u043f": 85, "black": 85, "box": 85, "or": 85, "white": 85, "sociable": 85, "solitary": 85, "assertion": 85, "per": 85, "test": 85, "\u0440\u043e\u043b": [86, 92], "\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d": 86, "\u0437\u0430\u043a\u043e\u043d": 86, "\u0431\u0440\u0443\u043a\u0441": 86, "\u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d": 86, "\u043c\u0435\u0436\u0434": 86, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d": 86, "\u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d": 86, "\u0445\u0430\u0440\u043b\u0430": 86, "\u043c\u0438\u043b\u043b\u0437": 86, "program": 86, "management": 86, "spotify": 86, "lean": 86, "for": 86, "teams": 86, "programs": 86, "enterprise": 86, "framework": 86, "safe": 86, "pmi": 86, "disciplined": 86, "delivery": 86, "dad": 86, "iso": 86, "iec": 86, "ieee": 86, "12207": 86, "2017": 86, "nexus": 86, "scrums": 86, "\u0444\u0440\u0430\u043a\u0442\u0430\u043b\u044c\u043d": 86, "\u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d": 86, "\u0441\u0441\u044b\u043b\u043a": 86, "\u0442\u0435\u043c": [86, 88], "topologies": [87, 137], "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f": 88, "\u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432": 88, "\u043e\u0434\u0438\u043d": 88, "\u0438\u0437": 88, "\u0440\u0435\u0430\u043b\u044c\u043d": 88, "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u0435\u043d": 88, "\u043b\u0435\u0434\u043e\u043a\u043e\u043b": 90, "\u0431\u043e\u0440\u044c\u0431": 90, "\u0432\u043e\u0435\u043d": 90, "\u0434\u0435\u043b": 90, "\u0441\u043f\u043e\u0440\u0442": 90, "\u0442\u043e\u0440\u0433\u043e\u0432\u043b": 90, "\u0444\u043e\u043d\u0434\u043e\u0432": 90, "\u0440\u044b\u043d\u043a": 90, "\u0442\u0435\u0445\u043d\u0438\u043a": 90, "\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0447\u0435\u0441\u043a": 90, "\u043f\u0440\u0438\u0440\u043e\u0434": 90, "soft": [91, 138], "skills": [91, 138], "\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d": 92, "\u043f\u043e\u0447\u0432": 92, "\u0437\u043d\u0430\u043d": [92, 93], "\u0442\u0435\u043e\u0440": 92, "\u043e\u0431\u043e\u0431\u0449\u0435\u043d": 92, "\u043f\u0440\u0430\u043a\u0442\u0438\u043a": 92, "\u0440\u043e\u0436\u0434\u0430": 92, "\u0441\u043f\u043e\u0440": 92, "\u0438\u0441\u0442\u0438\u043d": 92, "\u043a\u0440\u0438\u0441\u0442\u0430\u043b\u043b\u0438\u0437\u0430\u0446": 93, "\u043f\u0440\u0435\u0432\u0440\u0430\u0442": 93, "\u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u043e\u043d\u0435\u0440": 93, "\u043d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d": 94, "\u0444\u0430\u0437": 94, "\u0441\u043f\u0438\u0440\u0430\u043b": 94, "\u043d\u0430\u043f\u0440\u044f\u0436\u0435\u043d": 95, "\u0437\u0434\u043e\u0440\u043e\u0432": 95, "system": 96, "\u043e\u0431\u0449": [96, 105], "\u0430\u0432\u0442\u043e\u0440\u0441\u043a": 96, "\u043f\u0440\u0438\u0432\u0430\u0442\u043d": [96, 98], "\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432o": 96, "\u043f\u0440\u043e\u0447": 96, "indices": 96, "tables": 96, "\u0438\u0432\u0430": 97, "\u0438\u0432\u0430\u043d\u043e\u0432": 97, "\u0441\u0442\u0430\u043d\u0438\u0441\u043b\u0430\u0432": 99, "\u0431\u043e\u043b\u0441\u0443\u043d": 99, "definition": [100, 102], "\u043f\u043e\u043f\u044b\u0442\u0430": 100, "\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430": 100, "\u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d": 100, "\u0432\u0441\u0435\u043e\u0431\u044a\u0435\u043c\u043b\u0438\u0432\u0430": 100, "\u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d": 100, "\u043e\u0431\u043b\u0430\u0441\u0442": 100, "\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d": 100, "\u0442\u0430\u0440\u0430\u0441\u0435\u043d\u043a": 100, "\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d": 100, "\u0435\u0434\u0438\u043d": 100, "\u044f\u0437\u044b\u043a": 100, "\u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a": 100, "\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d": 100, "\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a": 100, "language": 102, "\u044f\u0437\u044b\u043a\u043e\u0432": 102}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.todo": 2, "sphinx": 56}}) \ No newline at end of file +Search.setIndex({"docnames": ["README", "emacsway/index", "emacsway/it/concurrency/index", "emacsway/it/concurrency/saga", "emacsway/it/concurrency/transaction", "emacsway/it/ddd/ddd-in-practice/event-storming/archi", "emacsway/it/ddd/ddd-in-practice/event-storming/index", "emacsway/it/ddd/ddd-in-practice/index", "emacsway/it/ddd/grade/domain/aggregate-boundaries", "emacsway/it/ddd/grade/domain/aggregate-encapsulation", "emacsway/it/ddd/grade/domain/event-sourcing", "emacsway/it/ddd/grade/domain/file-structure", "emacsway/it/ddd/grade/domain/index", "emacsway/it/ddd/grade/domain/shotgun-surgery", "emacsway/it/ddd/grade/domain/specification", "emacsway/it/ddd/grade/domain/why-no-can-execute", "emacsway/it/ddd/grade/index", "emacsway/it/ddd/grade/infrastructure/index", "emacsway/it/ddd/grade/infrastructure/repository", "emacsway/it/ddd/index", "emacsway/it/ddd/strategic-design/index", "emacsway/it/ddd/tactical-design/cqrs/cqrs-command-and-result", "emacsway/it/ddd/tactical-design/cqrs/index", "emacsway/it/ddd/tactical-design/domain-model/domain-events/domain-events-in-ddd", "emacsway/it/ddd/tactical-design/domain-model/domain-events/index", "emacsway/it/ddd/tactical-design/domain-model/index", "emacsway/it/ddd/tactical-design/domain-model/value-objects/immutability", "emacsway/it/ddd/tactical-design/domain-model/value-objects/index", "emacsway/it/ddd/tactical-design/index", "emacsway/it/ddd/tactical-design/repository/anticorruption-layer", "emacsway/it/ddd/tactical-design/repository/causal-consistency", "emacsway/it/ddd/tactical-design/repository/index", "emacsway/it/index", "emacsway/it/integration/asynchronous/index", "emacsway/it/integration/asynchronous/message-ordering-in-competing-consumers", "emacsway/it/integration/index", "emacsway/it/sdlc/index", "emacsway/it/sdlc/models/agile/agile", "emacsway/it/sdlc/models/agile/analysis/concerns/balancing-business-technical-concerns", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/architecture-options", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/common-planning-errors", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/compound-interest", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/developer-motivation", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/index", "emacsway/it/sdlc/models/agile/analysis/concerns/index", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/index", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/when-to-refactor", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/when-to-write-unit-tests", "emacsway/it/sdlc/models/agile/analysis/index", "emacsway/it/sdlc/models/agile/analysis/requirements/documenting", "emacsway/it/sdlc/models/agile/analysis/requirements/index", "emacsway/it/sdlc/models/agile/analysis/requirements/nonfunctional-requirements", "emacsway/it/sdlc/models/agile/analysis/requirements/requirements", "emacsway/it/sdlc/models/agile/analysis/requirements/requirements-criteria", "emacsway/it/sdlc/models/agile/index", "emacsway/it/sdlc/models/agile/particular/index", "emacsway/it/sdlc/models/agile/practices/collaborative-development/code-review", "emacsway/it/sdlc/models/agile/practices/collaborative-development/index", "emacsway/it/sdlc/models/agile/practices/index", "emacsway/it/sdlc/models/evolutionary", "emacsway/it/sdlc/models/incremental", "emacsway/it/sdlc/models/index", "emacsway/it/sdlc/models/iterative", "emacsway/it/sdlc/models/spiral", "emacsway/it/sdlc/sdlc-reference", "emacsway/it/sdlc/uncertainty-management/adaptation/adaptation", "emacsway/it/sdlc/uncertainty-management/adaptation/crash-course-in-software-development-economics", "emacsway/it/sdlc/uncertainty-management/adaptation/index", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/borrowing-trouble", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/index", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/index", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/patterns", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/software-design", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/solid", "emacsway/it/sdlc/uncertainty-management/balancing-prediction-adaptation", "emacsway/it/sdlc/uncertainty-management/balancing-top-down-bottom-up-design-approaches", "emacsway/it/sdlc/uncertainty-management/index", "emacsway/it/sdlc/uncertainty-management/prediction/index", "emacsway/it/sdlc/uncertainty-management/prediction/prediction", "emacsway/it/self-education/index", "emacsway/it/self-education/self-education-for-software-engineer", "emacsway/it/self-education/success-roadmap", "emacsway/it/tdd/index", "emacsway/it/tdd/tdd", "emacsway/it/team-topologies/harlan-mills'-proposal", "emacsway/it/team-topologies/index", "emacsway/soft-skills/change-making", "emacsway/soft-skills/cognitive-biases", "emacsway/soft-skills/icebreaker-principle", "emacsway/soft-skills/index", "emacsway/soft-skills/knowledge-vs-opinion", "emacsway/soft-skills/learning", "emacsway/soft-skills/learning-spiral-phase-mismatch", "emacsway/soft-skills/planning-in-psychology", "index", "ivan.ivanov/index", "private/index", "stanislav.bolsun/index", "stanislav.bolsun/it/ddd/domain-model/domain-model-definition", "stanislav.bolsun/it/ddd/domain-model/index", "stanislav.bolsun/it/ddd/domain-model/language-context", "stanislav.bolsun/it/ddd/index", "stanislav.bolsun/it/index", "trunk/index", "trunk/it/concurrency/index", "trunk/it/ddd/ddd-in-practice/event-storming/index", "trunk/it/ddd/ddd-in-practice/index", "trunk/it/ddd/index", "trunk/it/ddd/strategic-design/index", "trunk/it/ddd/tactical-design/cqrs/index", "trunk/it/ddd/tactical-design/domain-model/domain-events/index", "trunk/it/ddd/tactical-design/domain-model/index", "trunk/it/ddd/tactical-design/domain-model/value-objects/index", "trunk/it/ddd/tactical-design/index", "trunk/it/ddd/tactical-design/repository/index", "trunk/it/index", "trunk/it/integration/asynchronous/index", "trunk/it/integration/index", "trunk/it/sdlc/index", "trunk/it/sdlc/models/agile/analysis/concerns/business-concerns/index", "trunk/it/sdlc/models/agile/analysis/concerns/index", "trunk/it/sdlc/models/agile/analysis/concerns/technical-concerns/index", "trunk/it/sdlc/models/agile/analysis/index", "trunk/it/sdlc/models/agile/analysis/requirements/index", "trunk/it/sdlc/models/agile/index", "trunk/it/sdlc/models/agile/practices/collaborative-development/index", "trunk/it/sdlc/models/agile/practices/index", "trunk/it/sdlc/models/index", "trunk/it/sdlc/uncertainty-management/adaptation/index", "trunk/it/sdlc/uncertainty-management/adaptation/software-construction/index", "trunk/it/sdlc/uncertainty-management/adaptation/software-design/index", "trunk/it/sdlc/uncertainty-management/index", "trunk/it/sdlc/uncertainty-management/prediction/index", "trunk/it/self-education/index", "trunk/it/tdd/index", "trunk/it/team-topologies/index", "trunk/soft-skills/index"], "filenames": ["README.rst", "emacsway/index.rst", "emacsway/it/concurrency/index.rst", "emacsway/it/concurrency/saga.rst", "emacsway/it/concurrency/transaction.rst", "emacsway/it/ddd/ddd-in-practice/event-storming/archi.rst", "emacsway/it/ddd/ddd-in-practice/event-storming/index.rst", "emacsway/it/ddd/ddd-in-practice/index.rst", "emacsway/it/ddd/grade/domain/aggregate-boundaries.rst", "emacsway/it/ddd/grade/domain/aggregate-encapsulation.rst", "emacsway/it/ddd/grade/domain/event-sourcing.rst", "emacsway/it/ddd/grade/domain/file-structure.rst", "emacsway/it/ddd/grade/domain/index.rst", "emacsway/it/ddd/grade/domain/shotgun-surgery.rst", "emacsway/it/ddd/grade/domain/specification.rst", "emacsway/it/ddd/grade/domain/why-no-can-execute.rst", "emacsway/it/ddd/grade/index.rst", "emacsway/it/ddd/grade/infrastructure/index.rst", "emacsway/it/ddd/grade/infrastructure/repository.rst", "emacsway/it/ddd/index.rst", "emacsway/it/ddd/strategic-design/index.rst", "emacsway/it/ddd/tactical-design/cqrs/cqrs-command-and-result.rst", "emacsway/it/ddd/tactical-design/cqrs/index.rst", "emacsway/it/ddd/tactical-design/domain-model/domain-events/domain-events-in-ddd.rst", "emacsway/it/ddd/tactical-design/domain-model/domain-events/index.rst", "emacsway/it/ddd/tactical-design/domain-model/index.rst", "emacsway/it/ddd/tactical-design/domain-model/value-objects/immutability.rst", "emacsway/it/ddd/tactical-design/domain-model/value-objects/index.rst", "emacsway/it/ddd/tactical-design/index.rst", "emacsway/it/ddd/tactical-design/repository/anticorruption-layer.rst", "emacsway/it/ddd/tactical-design/repository/causal-consistency.rst", "emacsway/it/ddd/tactical-design/repository/index.rst", "emacsway/it/index.rst", "emacsway/it/integration/asynchronous/index.rst", "emacsway/it/integration/asynchronous/message-ordering-in-competing-consumers.rst", "emacsway/it/integration/index.rst", "emacsway/it/sdlc/index.rst", "emacsway/it/sdlc/models/agile/agile.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/balancing-business-technical-concerns.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/architecture-options.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/common-planning-errors.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/compound-interest.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/developer-motivation.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/business-concerns/index.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/index.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/index.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/when-to-refactor.rst", "emacsway/it/sdlc/models/agile/analysis/concerns/technical-concerns/when-to-write-unit-tests.rst", "emacsway/it/sdlc/models/agile/analysis/index.rst", "emacsway/it/sdlc/models/agile/analysis/requirements/documenting.rst", "emacsway/it/sdlc/models/agile/analysis/requirements/index.rst", "emacsway/it/sdlc/models/agile/analysis/requirements/nonfunctional-requirements.rst", "emacsway/it/sdlc/models/agile/analysis/requirements/requirements.rst", "emacsway/it/sdlc/models/agile/analysis/requirements/requirements-criteria.rst", "emacsway/it/sdlc/models/agile/index.rst", "emacsway/it/sdlc/models/agile/particular/index.rst", "emacsway/it/sdlc/models/agile/practices/collaborative-development/code-review.rst", "emacsway/it/sdlc/models/agile/practices/collaborative-development/index.rst", "emacsway/it/sdlc/models/agile/practices/index.rst", "emacsway/it/sdlc/models/evolutionary.rst", "emacsway/it/sdlc/models/incremental.rst", "emacsway/it/sdlc/models/index.rst", "emacsway/it/sdlc/models/iterative.rst", "emacsway/it/sdlc/models/spiral.rst", "emacsway/it/sdlc/sdlc-reference.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/adaptation.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/crash-course-in-software-development-economics.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/index.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/borrowing-trouble.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/index.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-construction/yagni.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/index.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/patterns.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/simplicity.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/software-design.rst", "emacsway/it/sdlc/uncertainty-management/adaptation/software-design/solid.rst", "emacsway/it/sdlc/uncertainty-management/balancing-prediction-adaptation.rst", "emacsway/it/sdlc/uncertainty-management/balancing-top-down-bottom-up-design-approaches.rst", "emacsway/it/sdlc/uncertainty-management/index.rst", "emacsway/it/sdlc/uncertainty-management/prediction/index.rst", "emacsway/it/sdlc/uncertainty-management/prediction/prediction.rst", "emacsway/it/self-education/index.rst", "emacsway/it/self-education/self-education-for-software-engineer.rst", "emacsway/it/self-education/success-roadmap.rst", "emacsway/it/tdd/index.rst", "emacsway/it/tdd/tdd.rst", "emacsway/it/team-topologies/harlan-mills'-proposal.rst", "emacsway/it/team-topologies/index.rst", "emacsway/soft-skills/change-making.rst", "emacsway/soft-skills/cognitive-biases.rst", "emacsway/soft-skills/icebreaker-principle.rst", "emacsway/soft-skills/index.rst", "emacsway/soft-skills/knowledge-vs-opinion.rst", "emacsway/soft-skills/learning.rst", "emacsway/soft-skills/learning-spiral-phase-mismatch.rst", "emacsway/soft-skills/planning-in-psychology.rst", "index.rst", "ivan.ivanov/index.rst", "private/index.rst", "stanislav.bolsun/index.rst", "stanislav.bolsun/it/ddd/domain-model/domain-model-definition.rst", "stanislav.bolsun/it/ddd/domain-model/index.rst", "stanislav.bolsun/it/ddd/domain-model/language-context.rst", "stanislav.bolsun/it/ddd/index.rst", "stanislav.bolsun/it/index.rst", "trunk/index.rst", "trunk/it/concurrency/index.rst", "trunk/it/ddd/ddd-in-practice/event-storming/index.rst", "trunk/it/ddd/ddd-in-practice/index.rst", "trunk/it/ddd/index.rst", "trunk/it/ddd/strategic-design/index.rst", "trunk/it/ddd/tactical-design/cqrs/index.rst", "trunk/it/ddd/tactical-design/domain-model/domain-events/index.rst", "trunk/it/ddd/tactical-design/domain-model/index.rst", "trunk/it/ddd/tactical-design/domain-model/value-objects/index.rst", "trunk/it/ddd/tactical-design/index.rst", "trunk/it/ddd/tactical-design/repository/index.rst", "trunk/it/index.rst", "trunk/it/integration/asynchronous/index.rst", "trunk/it/integration/index.rst", "trunk/it/sdlc/index.rst", "trunk/it/sdlc/models/agile/analysis/concerns/business-concerns/index.rst", "trunk/it/sdlc/models/agile/analysis/concerns/index.rst", "trunk/it/sdlc/models/agile/analysis/concerns/technical-concerns/index.rst", "trunk/it/sdlc/models/agile/analysis/index.rst", "trunk/it/sdlc/models/agile/analysis/requirements/index.rst", "trunk/it/sdlc/models/agile/index.rst", "trunk/it/sdlc/models/agile/practices/collaborative-development/index.rst", "trunk/it/sdlc/models/agile/practices/index.rst", "trunk/it/sdlc/models/index.rst", "trunk/it/sdlc/uncertainty-management/adaptation/index.rst", "trunk/it/sdlc/uncertainty-management/adaptation/software-construction/index.rst", "trunk/it/sdlc/uncertainty-management/adaptation/software-design/index.rst", "trunk/it/sdlc/uncertainty-management/index.rst", "trunk/it/sdlc/uncertainty-management/prediction/index.rst", "trunk/it/self-education/index.rst", "trunk/it/tdd/index.rst", "trunk/it/team-topologies/index.rst", "trunk/soft-skills/index.rst"], "titles": ["\u041a\u0430\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f", "\u041f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e Emacsway", "Concurrency", "SAGA", "Transaction", "Event Storming with Archi", "Event Storming", "DDD in practice", "\u041f\u043e\u0438\u0441\u043a \u0433\u0440\u0430\u043d\u0438\u0446 \u0410\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0432", "\u041a\u0430\u043a \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0410\u0433\u0440\u0435\u0433\u0430\u0442 \u0432 \u0411\u0414 \u043d\u0435 \u0440\u0430\u0437\u0440\u0443\u0448\u0430\u044f \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u044f\u0446\u0438\u0438?", "Event Sourcing", "\u0424\u0430\u0439\u043b\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0414\u043e\u043c\u0435\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438", "Domain Layer", "Shotgun Surgery", "Specification in Golang", "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u0438 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 CanExecute pattern?", "Golang DDD (CQRS / Event Sourcing) Reference Application "Grade"", "Infrastructure", "Repository in Golang", "DDD", "Strategic design", "\u041c\u043e\u0436\u0435\u0442 \u043b\u0438 CQRS-\u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442?", "CQRS", "Domain Events in DDD", "Domain Events", "Domain Model", "Immutability", "Value Objects", "Tactical design", "Repository and Anticorruption Layer", "Repository and Causal Consistency", "Repository", "IT", "Asynchronous communication", "\u041e \u0433\u043e\u043d\u043a\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 \u043a\u043e\u043d\u043a\u0443\u0440\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u0432", "Integration", "SDLC", "\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Agile Development", "\u0411\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0411\u0438\u0437\u043d\u0435\u0441/\u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432", "Architecture: Selling Options", "\u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0447\u0430\u0441\u0442\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f", "Technical Debt \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u043d\u0442", "\u041c\u043e\u0442\u0438\u0432\u0430\u0446\u0438\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432", "\u0411\u0438\u0437\u043d\u0435\u0441-\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u044b", "\u0421oncerns in Agile", "\u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u044b", "\u041a\u043e\u0433\u0434\u0430 \u0434\u0435\u043b\u0430\u0442\u044c refactoring \u0432 legacy", "\u041a\u043e\u0433\u0434\u0430 \u043f\u0438\u0441\u0430\u0442\u044c Unit Tests \u0432 legacy", "Analysis in Agile", "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 Agile Requirements", "Requirements in Agile", "Agile nonfunctional Requirements", "Agile Requirements", "\u041a\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 Agile Requirements", "Agile", "Particular Agile Models", "Code Review", "Collaborative Development", "Agile Practices", "Evolutionary Development", "Incremental Development", "SDLC-Models", "Iterative Development", "Spiral Development", "Systems Development Life Cycle (SDLC) Reference", "\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Adaptation", "\u041a\u0440\u0430\u0442\u043a\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u043a\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f", "Adaptation", "Borrowing trouble", "Software Construction", "YAGNI", "Software Design", "Role of Design Patterns in Agile", "Role of Simplicity in Agile", "Role of Software Design in Agile", "Role of SOLID principles in Agile", "Balancing Prediction/Adaptation", "Balancing Top-Down/Bottom-Up Design Approaches", "\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e", "Prediction", "\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Prediction", "\u0421\u0430\u043c\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435", "\u0421\u043f\u0438\u0441\u043e\u043a \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u0441\u0430\u043c\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f", "\u041a\u0430\u043a \u0441\u0442\u0430\u0442\u044c \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c", "TDD", "TDD - \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435", "\u0420\u043e\u043b\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0432 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434, DDD \u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445", "Team Topologies", "\u041a\u0430\u043a \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432\u0435", "\u0421\u043f\u0438\u0441\u043e\u043a \u043f\u0441\u0438\u0445\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432", "\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u043b\u0435\u0434\u043e\u043a\u043e\u043b\u0430", "Soft Skills", "\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u043d\u0430 \u043f\u043e\u0447\u0432\u0435 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0430 \u0437\u043d\u0430\u043d\u0438\u0439", "\u041a\u0440\u0438\u0441\u0442\u0430\u043b\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0437\u043d\u0430\u043d\u0438\u0439. \u041a\u0430\u043a \u0447\u0438\u0442\u0430\u0442\u044c \u0438 \u043d\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u0432 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u043e\u043d\u0435\u0440\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438.", "\u041d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u0444\u0430\u0437 \u0441\u043f\u0438\u0440\u0430\u043b\u0435\u0439 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f", "\u041f\u0441\u0438\u0445\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f", "System Architecture", "\u041f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0418\u0432\u0430\u043d\u0430 \u0418\u0432\u0430\u043d\u043e\u0432\u0430", "\u041f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e", "\u041f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0421\u0442\u0430\u043d\u0438\u0441\u043b\u0430\u0432\u0430 \u0411\u043e\u043b\u0441\u0443\u043d\u0430", "Domain Model Definition", "Domain Model", "Language Context Definition", "DDD", "IT", "\u041e\u0431\u0449\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e", "Concurrency", "Event Storming", "DDD in practice", "DDD", "Strategic design", "CQRS", "Domain Events", "Domain Model", "Value Objects", "Tactical design", "Repository", "IT", "Asynchronous communication", "Integration", "SDLC", "\u0411\u0438\u0437\u043d\u0435\u0441-\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u044b", "\u0421oncerns in Agile", "\u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u044b", "Analysis in Agile", "Requirements in Agile", "Agile", "Collaborative Development", "Agile Practices", "SDLC Models", "Adaptation", "Software Construction", "Software Design", "\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e", "Prediction", "\u0421\u0430\u043c\u043e\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435", "TDD", "Team Topologies", "Soft Skills"], "terms": {"distributed": [0, 5, 23, 34, 75, 82, 100], "collaborative": [0, 21, 58, 86, 94, 128], "knowledge": [0, 38, 51, 59, 64, 65, 66, 68, 72, 75, 77, 85, 89, 100], "management": [0, 23, 34, 37, 38, 49, 51, 52, 64, 74, 76, 82, 88], "system": [0, 8, 9, 15, 21, 23, 34, 37, 38, 39, 46, 47, 49, 51, 52, 62, 64, 65, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90], "\u043e\u0431\u044a": [0, 38, 74, 82, 85, 86, 95], "\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446": [0, 5, 9, 10, 11, 15, 23, 37, 38, 64, 74, 75, 77, 83, 85, 88, 89, 90, 91, 92, 95, 138], "\u0432": [0, 5, 10, 12, 13, 16, 23, 26, 29, 30, 33, 37, 38, 41, 42, 45, 49, 51, 52, 53, 56, 60, 62, 64, 65, 66, 68, 72, 73, 74, 75, 77, 80, 82, 83, 85, 87, 89, 91, 94, 100, 102, 118, 123, 137, 138], "\u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d": [0, 34, 37, 40, 72, 74, 76, 85, 86, 90, 93], "\u043c\u0438\u0440": [0, 8, 21, 34, 37, 75, 83, 92, 100], "\u0441\u0442\u0430\u043b": [0, 5, 37, 38, 72, 73, 76, 82, 83, 85, 86, 88], "\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d": [0, 5, 8, 11, 23, 34, 37, 38, 56, 70, 82, 85, 86, 88, 90, 95, 100, 102], "\u0431\u043e\u043b\u044c\u0448": [0, 5, 8, 9, 23, 37, 38, 40, 46, 47, 52, 65, 68, 70, 72, 73, 74, 75, 76, 77, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100], "\u0438": [0, 5, 8, 9, 10, 13, 15, 26, 29, 30, 34, 37, 38, 39, 40, 42, 43, 46, 47, 49, 51, 56, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 76, 77, 80, 83, 87, 88, 89, 90, 91, 92, 94, 95, 102, 121, 137, 138], "\u0432\u043e\u0437\u043d\u0438\u043a\u043b": [0, 23, 34, 37], "\u043f\u043e\u0442\u0440\u0435\u0431\u043d": [0, 8, 21, 23, 38, 74, 76, 82, 86, 90], "\u044d\u0442": [0, 5, 8, 9, 11, 13, 15, 16, 26, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 51, 52, 56, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 86, 88, 89, 90, 93, 94, 95, 100, 102], "\u043e\u0431\u044a\u0435\u043c": [0, 21, 73, 74, 85, 86, 90, 95], "\u0442\u043e": [0, 5, 8, 9, 11, 13, 15, 21, 23, 26, 29, 30, 34, 37, 38, 41, 42, 46, 51, 52, 56, 60, 64, 65, 70, 72, 73, 74, 75, 76, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u0443\u043f\u0440\u0430\u0432\u043b\u044f": [0, 5, 21, 38, 72, 73, 74, 75, 77, 82, 83, 86, 88, 90, 94], "\u043e\u043f": [0, 74, 83, 85, 86, 92], "\u043f\u043e\u043a\u0430\u0437\u0430": [0, 13, 21, 23, 82, 86, 92], "\u0447\u0442\u043e": [0, 5, 8, 9, 11, 13, 15, 23, 30, 34, 38, 41, 42, 47, 51, 53, 54, 56, 60, 62, 64, 66, 67, 68, 70, 72, 73, 74, 75, 76, 77, 79, 82, 83, 86, 88, 89, 90, 92, 93, 94, 95, 102, 126, 130, 134], "\u0432\u044b\u0441\u043e\u043a": [0, 8, 11, 37, 70, 72, 73, 74, 77, 83, 85, 86, 90, 92, 100], "\u043e\u0431\u044a\u0435\u043c\u043d": [0, 38], "\u043c\u0430\u0442\u0435\u0440\u0438\u0430": [0, 82, 90], "\u043b\u0435\u0433\u0447": [0, 5, 21, 38, 70, 73, 74, 90, 92, 93], "\u0434\u043e\u0441\u0442\u0438\u0433\u0430": [0, 23, 40, 73, 83, 86, 88], "\u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432": [0, 38, 76, 83, 86, 90, 91, 92, 94, 138], "\u0430\u0432\u0442\u043e\u0440": [0, 3, 4, 5, 8, 9, 10, 11, 14, 15, 18, 21, 23, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 56, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 97, 100, 102], "\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440": [0, 5, 8, 9, 11, 21, 23, 30, 34, 38, 40, 51, 74, 75, 76, 77, 82, 83, 85, 86, 88, 92, 94, 100], "net": [0, 34, 38, 70, 75, 82, 86, 100], "microservices": [0, 5, 34, 85, 86], "architecture": [0, 5, 8, 9, 11, 13, 21, 23, 34, 37, 40, 41, 43, 46, 49, 51, 59, 64, 65, 66, 72, 73, 74, 75, 77, 80, 82, 85, 86, 90, 100, 121], "for": [0, 5, 8, 9, 11, 13, 15, 21, 23, 26, 29, 30, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 59, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 88, 89, 90, 92, 94, 95, 100], "containerized": [0, 23, 82], "applications": [0, 21, 23, 30, 34, 51, 64, 74, 75, 82], "\u0431\u043e\u043b": [0, 8, 9, 21, 23, 30, 37, 38, 41, 42, 47, 68, 70, 73, 74, 75, 76, 77, 82, 85, 86, 88, 90, 92, 93, 94, 100, 102], "4": [0, 5, 8, 9, 16, 21, 23, 34, 37, 38, 41, 42, 64, 65, 66, 74, 76, 77, 82, 85, 86, 92, 94], "5": [0, 5, 8, 9, 23, 34, 37, 38, 46, 49, 51, 52, 64, 65, 70, 76, 77, 82, 83, 85, 86, 89, 94, 95], "\u0442\u044b\u0441": 0, "\u0444\u043e\u0440\u043a": 0, "azure": [0, 23, 34, 82], "center": [0, 38], "1": [0, 5, 8, 15, 21, 23, 29, 34, 37, 38, 41, 46, 51, 52, 64, 66, 73, 74, 75, 76, 82, 85, 86, 88, 92, 94, 100, 102], "microsoft": [0, 21, 23, 34, 38, 41, 82], "\u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430": [0, 15], "\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d": [0, 21, 38, 46, 56, 70, 72, 73, 85, 92, 94, 100], "\u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [0, 15, 23, 34, 38, 75, 83, 90], "\u0441\u0438\u0441\u0442": [0, 34, 37, 38, 40, 64, 72, 73, 74, 75, 77, 85, 86, 88, 90, 92, 100], "\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d": [0, 5, 36, 37, 38, 40, 41, 60, 64, 72, 73, 74, 75, 76, 82, 86, 88, 90, 120], "\u0437\u043d\u0430\u043d": [0, 8, 9, 37, 56, 65, 72, 77, 82, 83, 85, 88, 89, 91, 94, 95, 100, 102, 138], "\u043e\u0442\u043a\u0440\u044b\u0442": [0, 5, 34, 38, 74, 75, 86, 90, 92], "\u043d\u0435\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d": 0, "\u0430\u0432\u0442\u043e\u0440\u0441\u043a": 0, "\u043a\u0440\u0443\u0433": [0, 9, 38, 40, 75, 92], "\u043c\u043e\u0436\u043d": [0, 5, 8, 9, 11, 21, 23, 30, 34, 37, 38, 40, 46, 47, 53, 56, 60, 64, 65, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u0437\u0430\u043c\u0435\u0442": [0, 21, 23, 34, 38, 51, 64, 65, 72, 76, 85, 95], "\u043d\u0435\u043a\u043e\u0442\u043e\u0440": [0, 9, 21, 34, 38, 40, 42, 46, 70, 72, 74, 77, 83, 85, 86, 100, 102], "\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b": [0, 8, 21, 34, 100], "\u0432\u0435\u0434\u0443\u0442": [0, 70, 74], "\u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d": [0, 34, 37, 64, 76, 83, 100], "\u0432\u0435\u0440\u0441": [0, 5, 9, 23, 34, 52, 82, 85], "\u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a": [0, 82], "\u0432\u043b\u0438\u0432": 0, "\u043d\u0438\u0445": [0, 5, 8, 9, 11, 37, 38, 46, 72, 74, 75, 77, 82, 83, 90, 93, 94, 102], "\u0433\u043b\u0430\u0432\u043d": [0, 40, 46, 73, 74, 76, 77, 80, 82, 83, 88, 89, 90, 93, 100], "\u0431\u0440\u0430\u043d\u0447": [0, 5], "\u0442": [0, 5, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 56, 62, 65, 70, 72, 73, 74, 75, 76, 80, 82, 83, 85, 86, 88, 90, 92, 94, 95, 100, 102], "\u0435": [0, 5, 8, 9, 15, 21, 23, 34, 37, 38, 40, 46, 52, 56, 65, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u0441\u0442\u0440\u0435\u043c": [0, 21, 23, 37, 38, 73, 74, 85, 86, 90], "\u0441\u043e\u0437\u0434\u0430\u0432\u0430": [0, 8, 9, 21, 46, 70, 73, 75, 76, 85, 86, 92, 100], "\u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d": [0, 15, 26, 34, 38, 40, 70, 75, 82, 83, 85, 86, 90, 92, 94, 95, 100, 102], "\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432": 0, "\u043a\u043e\u0442\u043e\u0440": [0, 5, 8, 9, 10, 11, 13, 15, 21, 23, 29, 34, 37, 38, 40, 41, 42, 46, 47, 52, 56, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100, 102], "\u043e\u0431\u043e\u0433\u0430\u0449\u0430": 0, "\u0438\u0437": [0, 5, 8, 9, 11, 15, 21, 23, 26, 30, 34, 37, 38, 40, 47, 51, 56, 60, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 90, 92, 93, 94, 95, 100, 102], "\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a": [0, 9, 21, 23, 29, 38, 73, 74, 75, 85, 86, 90, 92], "\u0434\u0438\u0441\u0442\u0438\u043b\u043b\u0438\u0440": [0, 93], "\u043e\u0442": [0, 8, 9, 11, 29, 34, 37, 38, 40, 41, 42, 46, 47, 51, 52, 65, 68, 72, 73, 74, 76, 80, 82, 83, 85, 86, 88, 92, 93, 94, 95, 100], "\u0432\u0441\u0435\u0433": [0, 5, 8, 11, 23, 34, 37, 38, 40, 42, 46, 47, 70, 74, 76, 82, 83, 85, 86, 88, 92, 95, 100, 102], "\u043b\u0438\u0448\u043d": [0, 70, 75, 82, 100], "\u043d\u0430\u0432\u043e\u0434": [0, 8, 86], "\u043c\u044b\u0441\u043b": [0, 8, 9, 23, 56, 73, 86, 90, 92, 100], "\u0430": [0, 5, 8, 9, 10, 11, 15, 30, 34, 37, 38, 40, 41, 46, 47, 51, 56, 62, 65, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 102], "\u0435\u0441\u043b": [0, 5, 8, 9, 11, 15, 23, 30, 34, 37, 38, 40, 41, 42, 47, 51, 56, 60, 64, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 88, 90, 92, 93, 94, 102], "\u0441\u043e\u0432\u043c\u0435\u0441\u0442": [0, 86], "\u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d": [0, 70, 72, 83, 92, 97, 98], "\u0432\u044b": [0, 21, 23, 37, 38, 42, 46, 47, 51, 60, 65, 68, 70, 72, 73, 74, 75, 77, 82, 83, 85, 86, 88, 90, 92, 94, 95, 97], "\u0441\u0430\u043c": [0, 5, 8, 9, 11, 13, 21, 23, 30, 34, 37, 38, 40, 41, 46, 47, 52, 62, 65, 70, 72, 73, 74, 75, 76, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100, 102], "\u0440\u0435\u0448\u0430": [0, 21, 30, 34, 38, 40, 56, 60, 73, 74, 76, 82, 85, 86, 88, 90, 92, 100], "\u0438\u043c\u0435\u043d": [0, 8, 9, 11, 21, 23, 26, 37, 38, 40, 41, 47, 51, 56, 62, 64, 65, 70, 72, 73, 74, 75, 82, 85, 86, 90, 92, 93, 94, 100], "\u0441\u0432\u043e": [0, 5, 8, 9, 11, 21, 26, 30, 37, 38, 40, 41, 42, 46, 51, 52, 56, 65, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100], "\u0437\u0430\u043c\u0435\u0442\u043a": [0, 15, 23, 30, 37], "\u0445\u043e\u0442": [0, 8, 9, 11, 21, 23, 30, 34, 38, 40, 47, 49, 52, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 92, 100, 102], "\u043f\u043e\u0434\u0435\u043b": [0, 23, 56, 82, 88, 94, 100], "\u0434\u043e\u0431\u0430\u0432": [0, 21, 34, 46, 47, 70, 74, 76, 85, 86, 94], "\u0431\u0430\u0437": [0, 9, 23, 38, 74, 76, 83, 85, 88], "\u0443": [0, 5, 8, 9, 11, 21, 23, 26, 30, 37, 38, 40, 41, 47, 52, 64, 70, 72, 74, 75, 76, 77, 82, 83, 85, 86, 88, 92, 93, 94, 95, 100], "\u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a": [0, 30, 82, 85], "\u043e\u0441\u043d\u043e\u0432": [0, 21, 23, 30, 37, 40, 72, 73, 76, 77, 80, 85, 86, 92, 100], "wiki": [0, 5, 51, 85], "\u0434\u0432\u0438\u0436\u043a": 0, "\u044f\u0432\u043b\u044f": [0, 5, 8, 9, 11, 15, 21, 23, 29, 30, 34, 37, 38, 41, 47, 49, 52, 56, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 92, 100, 102], "\u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d": [0, 11, 15, 21, 23, 30, 47, 75, 85, 86, 88, 93, 94, 95], "\u043d\u043e\u0441\u0438\u0442\u0435\u043b": [0, 56], "\u0438\u043d\u0444\u043e\u0440\u0430\u0446": 0, "\u043c\u043e\u0436\u0435\u0442": [0, 5, 8, 9, 11, 13, 15, 22, 26, 30, 34, 37, 38, 40, 41, 42, 46, 51, 52, 62, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 95, 97, 100, 102, 111], "\u0431\u044b\u0442": [0, 5, 8, 9, 11, 21, 23, 30, 34, 37, 38, 42, 52, 64, 70, 72, 73, 74, 75, 85, 86, 92, 93, 94, 97, 100, 102], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b": [0, 34], "\u0442\u043e\u043b\u044c\u043a": [0, 5, 8, 9, 10, 11, 21, 23, 30, 34, 37, 38, 40, 41, 42, 47, 56, 70, 73, 74, 75, 82, 83, 85, 86, 88, 92, 93, 94, 100], "\u0432\u0438\u0434": [0, 5, 8, 9, 16, 21, 23, 30, 37, 38, 40, 41, 65, 66, 70, 72, 73, 74, 85, 86, 88, 89, 92, 94, 95, 100], "\u0437\u043d\u0430\u0447": [0, 8, 9, 11, 23, 30, 38, 40, 70, 72, 73, 75, 77, 83, 85, 90, 92], "\u043e\u043d": [0, 5, 8, 9, 10, 11, 13, 15, 16, 21, 23, 26, 30, 34, 37, 38, 40, 41, 42, 47, 51, 52, 53, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u043d\u0435": [0, 5, 8, 10, 11, 12, 15, 16, 30, 34, 37, 38, 40, 41, 42, 47, 49, 51, 56, 60, 62, 64, 65, 68, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 91, 92, 94, 95, 100, 102, 138], "\u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f": [0, 38, 85], "\u0440\u0430\u0437\u043b\u0438\u0447\u043d": [0, 5, 11, 23, 38, 40, 65, 75, 76, 82, 83, 100, 102], "\u0440\u0430\u0437\u043d": [0, 5, 11, 23, 60, 65, 74, 76, 77, 82, 86, 88, 90, 92, 94, 100, 102], "\u0432\u043e\u0437\u043d\u0438\u043a\u0430": [0, 5, 8, 9, 11, 21, 23, 26, 30, 34, 37, 38, 40, 41, 47, 52, 56, 64, 65, 74, 75, 82, 83, 85, 86, 92, 100, 102], "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447": [0, 9, 23, 37, 38, 40, 65, 74, 75, 92, 100], "\u043c\u0435\u0436\u0434": [0, 8, 9, 11, 21, 23, 37, 38, 41, 42, 52, 65, 72, 73, 74, 75, 76, 77, 82, 83, 85, 88, 100, 102], "\u0432\u043e": [0, 11, 23, 37, 38, 46, 56, 65, 70, 72, 73, 74, 75, 76, 77, 83, 85, 86, 88, 92, 93, 94, 100, 102], "\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432": [0, 23, 85, 92, 100, 102], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d": [0, 5, 9, 10, 70, 73, 82, 102], "\u0432\u043e\u0437\u043c\u043e\u0436\u043d": [0, 5, 8, 9, 11, 21, 23, 34, 37, 38, 39, 40, 42, 46, 47, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 90, 92, 93, 100, 102], "\u0435\u0434\u0438\u043d\u0438\u0447\u043d": [0, 82, 92], "\u0442\u0430\u043a": [0, 5, 8, 9, 11, 15, 16, 21, 23, 26, 30, 34, 38, 40, 41, 46, 54, 56, 62, 66, 67, 70, 72, 73, 74, 75, 76, 77, 79, 82, 83, 86, 88, 90, 92, 93, 94, 95, 100, 102, 126, 130, 134], "\u0436\u0435": [0, 5, 8, 9, 11, 15, 21, 23, 26, 30, 34, 37, 38, 40, 41, 42, 46, 52, 60, 65, 70, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 94, 100, 102], "\u0441\u0443\u0449\u0435\u0441\u0442\u0432": [0, 5, 8, 9, 15, 23, 30, 34, 38, 40, 46, 47, 53, 70, 72, 74, 75, 77, 82, 85, 86, 88, 90, 92, 100], "\u043f\u043e\u043b\u043d\u043e\u0442": [0, 37, 52, 65, 68, 76, 82, 88, 94, 102], "\u0434\u043b\u044f": [0, 8, 9, 15, 16, 23, 26, 30, 34, 37, 38, 40, 41, 46, 47, 51, 52, 56, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 81, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102, 135], "\u043e\u0434\u043d": [0, 5, 8, 9, 11, 13, 21, 23, 26, 30, 34, 37, 38, 40, 42, 51, 56, 60, 64, 68, 70, 72, 73, 74, 75, 77, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f": [0, 9, 38, 70, 75, 85, 86, 93, 94, 100, 102], "\u0446\u0435\u043d\u043d\u043e\u0441\u0442": [0, 8, 21, 38, 42, 70, 76, 85, 88, 93], "\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d": [0, 64, 82, 92], "\u043f\u043e\u043c\u0435\u0445": [0, 73], "\u0437\u0430\u0442\u0440\u0443\u0434\u043d\u044f": [0, 9, 11, 74, 75, 85, 86], "\u0435\u0433": [0, 5, 8, 9, 10, 21, 23, 26, 34, 37, 38, 40, 41, 42, 46, 56, 65, 68, 70, 72, 73, 74, 75, 76, 80, 83, 85, 86, 88, 90, 92, 93, 94, 100, 102], "\u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432": [0, 64, 74, 86, 92, 93], "\u043f\u043e\u043f\u044b\u0442\u043a": [0, 5, 8, 15, 82, 85, 86, 90, 92, 102], "\u0440\u0430\u0437\u0440\u0435\u0448": [0, 21, 37, 65], "\u043f\u043e\u0440\u043e\u0436\u0434\u0430": [0, 8, 11], "\u0440\u044f\u0434": [0, 5, 8, 21, 23, 37, 38, 41, 74, 80, 83, 85, 86, 88, 92, 102], "\u0432\u043e\u043f\u0440\u043e\u0441": [0, 8, 9, 11, 15, 21, 23, 30, 34, 37, 40, 41, 42, 46, 52, 56, 64, 65, 70, 72, 75, 76, 77, 83, 85, 86, 88, 92, 100], "\u043c\u043e\u0434\u0435\u0440\u0430\u0446": [0, 8], "\u0440\u0435\u0434\u0430\u043a\u0446\u0438\u043e\u043d": 0, "\u043f\u043e\u043b\u0438\u0442\u0438\u043a": [0, 90, 100], "\u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d": [0, 9, 21, 23, 38, 40, 56, 72, 73, 74, 75, 76, 83, 85, 86, 90, 100], "\u043a\u043e\u043d\u0441\u0435\u043d\u0441\u0443\u0441": [0, 38, 56], "\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d": [0, 38, 52, 65, 72, 75, 76, 80, 82, 88, 91, 94, 138], "\u0432\u044b\u0440\u0430\u0431\u043e\u0442\u043a": [0, 100], "\u043d\u043e\u0440\u043c": 0, "\u043f\u043e\u0432\u0435\u0434\u0435\u043d": [0, 9, 26, 38, 82, 85, 88, 100], "\u043f\u0440\u0430\u0432": [0, 8, 9, 38, 40, 46, 52, 56, 70, 72, 77, 80, 85, 86, 92, 94, 102], "\u0437\u0430\u0449": 0, "\u0434\u0438\u0432\u0435\u0440\u0441": 0, "\u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d": [0, 23], "\u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c": 0, "\u0438\u043b": [0, 5, 8, 9, 11, 15, 23, 26, 34, 37, 38, 40, 41, 42, 46, 51, 52, 64, 70, 72, 73, 74, 75, 77, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u043f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a": [0, 92], "\u0432\u0441\u0435": [0, 5, 8, 9, 11, 15, 21, 26, 30, 34, 37, 38, 40, 46, 47, 52, 60, 64, 68, 70, 72, 74, 75, 76, 77, 82, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u0440\u0435\u0437\u043a": [0, 100], "\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430": [0, 11, 23, 38, 85], "\u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d": [0, 8, 9, 21, 23, 38, 40, 46, 47, 62, 64, 70, 75, 82, 85], "\u0442\u0435\u0440\u044f": [0, 38, 75, 85, 88], "\u0442\u0430\u043a\u0436": [0, 5, 8, 9, 11, 15, 21, 23, 34, 37, 38, 40, 47, 51, 52, 62, 65, 74, 75, 76, 77, 82, 85, 86, 88, 90, 92, 93, 94, 102], "\u0437\u0430\u0442\u0440\u0443\u0434\u043d\u0438\u0442\u0435\u043b\u044c\u043d": [0, 38], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": [0, 5, 8, 9, 12, 21, 23, 26, 30, 34, 37, 38, 52, 56, 64, 74, 75, 85, 90, 94, 95], "offline": [0, 23, 30], "\u0440\u0435\u0436\u0438\u043c": [0, 38, 82, 85], "\u043e\u0441\u043e\u0431\u0435\u043d": [0, 21, 23, 40, 41, 73, 74, 75, 83, 85, 88, 92, 100], "\u0442\u0435\u043b\u0435\u0444\u043e\u043d": 0, "\u043e\u0442\u0434\u0435\u043b\u044c\u043d": [0, 5, 8, 9, 23, 34, 38, 60, 72, 74, 75, 82, 85, 86, 90, 94], "\u0440\u0435\u0448": [0, 8, 9, 11, 13, 38, 40, 56, 70, 72, 73, 85, 86, 88, 100], "\u043f\u0440\u043e\u0431\u043b\u0435\u043c": [0, 9, 11, 21, 26, 30, 34, 37, 38, 40, 41, 56, 64, 68, 70, 72, 73, 74, 76, 77, 80, 82, 83, 85, 86, 88, 90, 93, 94, 95, 100], "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f": [0, 5, 11, 37, 38, 46, 56, 72, 74, 85, 86, 90, 91, 100, 138], "\u0435\u0449": [0, 5, 8, 9, 11, 23, 34, 37, 38, 40, 41, 42, 52, 56, 65, 72, 74, 75, 76, 82, 83, 85, 86, 88, 90, 92, 93, 100, 102], "\u0432\u044b\u0433\u043b\u044f\u0434": [0, 8, 9, 30, 38, 46, 82, 94, 100], "\u043f\u0440\u043e\u0441\u0442": [0, 5, 8, 9, 11, 21, 23, 37, 38, 41, 46, 64, 65, 70, 72, 74, 75, 77, 82, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100], "\u0442\u0435\u043a\u0441\u0442\u043e\u0432": [0, 5], "\u0444\u0430\u0439\u043b": [0, 5, 11, 13], "\u0447\u0430\u0449": [0, 5, 8, 38, 46, 47, 70, 83], "restructuredtext": 0, "\u043a\u043e\u043d\u0442\u0440\u043e\u043b": [0, 5, 26, 38, 47, 85], "\u043e\u0431\u044b\u0447\u043d": [0, 5, 9, 23, 30, 34, 38, 40, 47, 56, 70, 77, 82, 85, 86, 90, 92, 94, 95], "git": 0, "\u0441\u0440\u0435\u0434\u0441\u0442\u0432": [0, 8, 60, 64, 72, 82, 85, 90, 92, 100], "\u0443\u0441\u0442\u0440\u0430\u043d\u044f": [0, 38, 51, 86], "\u0437\u0430\u043a\u043b\u044e\u0447\u0430": [0, 11, 15, 23, 30, 37, 41, 65, 70, 74, 75, 80, 85, 88, 90, 92, 93, 94, 100], "\u0442\u043e\u043c": [0, 5, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 41, 42, 46, 47, 52, 56, 65, 68, 70, 72, 74, 75, 76, 77, 80, 82, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u043e\u0434\u0438\u043d": [0, 5, 8, 9, 11, 15, 21, 23, 26, 34, 40, 51, 56, 70, 72, 74, 75, 82, 83, 85, 86, 90, 93, 95, 100], "\u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440": [0, 8, 23, 26, 85], "\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430": [0, 75, 92], "\u043a\u0430\u0436\u0434": [0, 5, 8, 9, 23, 26, 30, 34, 42, 62, 65, 70, 72, 73, 74, 75, 82, 83, 85, 86, 90, 92, 93, 94, 95, 100], "\u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430": [0, 8], "\u0441\u0447\u0438\u0442\u0430": [0, 21, 23, 38, 46, 73, 74, 76, 82, 85, 90, 92, 102], "\u043d\u0443\u0436\u043d": [0, 5, 9, 11, 21, 23, 26, 34, 38, 40, 41, 51, 56, 64, 65, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100], "\u043e\u0431\u043e\u0433\u0430": 0, "\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432": [0, 9, 21, 23, 30, 38, 73], "\u0438\u0434": [0, 9, 11, 23, 37, 72, 73, 74, 75, 76, 85, 86, 92, 102], "\u043f\u043e\u0441\u0442\u0440\u043e": [0, 21, 73, 83], "\u0434\u0430\u043d": [0, 9, 13, 21, 23, 34, 38, 47, 53, 65, 70, 74, 85, 86, 88, 90, 92, 100, 102], "\u043e\u0441\u043d\u043e\u0432\u043d": [0, 8, 9, 21, 23, 37, 41, 49, 56, 65, 70, 74, 76, 80, 83, 86, 88, 89, 90, 92, 93, 100], "\u0441\u0443\u0442": [0, 8, 9, 21, 23, 41, 74, 82, 85, 86, 92, 95], "\u0441\u0443\u0431\u044a\u0435\u043a\u0442": [0, 92, 100], "\u043c\u043e\u0434\u0435\u043b": [0, 9, 12, 34, 37, 38, 40, 52, 56, 64, 65, 74, 75, 76, 80, 83, 86, 88, 89], "\u0432\u0440\u0435\u043c": [0, 8, 11, 13, 15, 21, 23, 26, 29, 34, 37, 38, 40, 41, 42, 65, 68, 70, 72, 74, 76, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 102], "\u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432": [0, 13, 23, 38, 68, 74, 95, 100], "\u0441\u043a\u043e\u0440": [0, 38, 40, 42, 46, 47, 56, 83, 85, 86, 94, 95, 100, 102], "\u043e\u0431\u044a\u0435\u043a\u0442": [0, 8, 9, 15, 21, 26, 74, 75, 77, 85, 90, 92, 100, 102], "\u043f\u043e\u0434\u0445\u043e\u0434": [0, 8, 9, 15, 21, 23, 34, 38, 42, 70, 73, 77, 83, 85, 86, 88], "\u043a": [0, 5, 8, 9, 11, 15, 16, 21, 23, 30, 34, 37, 40, 41, 42, 46, 47, 53, 56, 62, 65, 68, 70, 72, 73, 74, 75, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100, 102], "\u0445\u0440\u0430\u043d\u0435\u043d": [0, 21, 23], "\u0438\u0437\u0431\u0430\u0432\u043b\u044f": [0, 70, 82], "\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d": [0, 11, 34, 56], "\u0432\u044b\u0448": [0, 37, 38, 68, 74, 75, 86, 88, 90, 100], "\u043f\u0440\u043e\u0431\u043b": [0, 8, 9, 13, 15, 21, 23, 34, 38, 41, 56, 68, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 93, 100], "\u0447\u0435\u043c": [0, 5, 8, 11, 23, 37, 38, 40, 42, 47, 51, 52, 56, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100], "\u043a\u043e\u0433": [0, 8, 40, 83], "\u0441\u0442\u0430\u0442": [0, 5, 8, 9, 15, 21, 23, 30, 34, 37, 38, 40, 46, 52, 70, 75, 76, 81, 85, 86, 88, 89, 90, 92, 93, 94, 95, 135], "\u0443\u0434\u0430\u043b\u044f": [0, 8, 21, 23, 34], "\u043d\u0435\u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d": [0, 11, 100], "\u0432\u0430\u0441": [0, 38, 41, 47, 72, 77, 82, 83, 85, 86, 94], "\u0441\u043e\u0445\u0440\u0430\u043d": [0, 5, 12, 23, 73, 75, 82, 88], "\u0441\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u043d": [0, 75], "\u0432\u043d\u0438\u043c\u0430\u043d": [0, 5, 8, 21, 23, 41, 47, 52, 65, 68, 72, 74, 75, 76, 82, 85, 86, 93, 100], "\u0434\u0435\u043b": [0, 8, 21, 23, 30, 34, 37, 38, 40, 41, 46, 70, 73, 74, 75, 76, 82, 83, 85, 86, 88, 92, 94, 95], "\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442": [0, 15, 21, 23, 37, 38, 40, 41, 51, 56, 73, 82, 83, 85, 86, 88, 92, 94, 95], "\u043f\u0443\u0431\u043b\u0438\u043a\u0443": 0, "\u0438\u0445": [0, 5, 8, 9, 11, 21, 23, 26, 29, 30, 37, 38, 40, 41, 42, 46, 52, 60, 64, 68, 70, 72, 74, 75, 76, 82, 83, 85, 86, 88, 90, 92, 93, 94, 100, 102], "\u043f\u0443\u0431\u043b\u0438\u0447\u043d": [0, 11, 21, 23, 30, 85, 86, 88, 97], "\u0437\u0430\u043a\u0440\u0435\u043f": [0, 83], "\u043f\u0440\u0438": [0, 5, 8, 9, 11, 21, 23, 26, 30, 34, 37, 38, 40, 41, 42, 53, 65, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 90, 92, 100, 102], "\u0430\u0432\u0442\u043e\u0440\u0441\u0442\u0432": [0, 75], "\u0432\u0430\u0448": [0, 21, 23, 38, 41, 42, 70, 72, 73, 74, 75, 82, 83, 85, 86, 88], "\u043e\u0431\u044f\u0437\u0430": [0, 9, 23, 38], "\u0441\u043b\u0435\u0434\u043e\u0432\u0430": [0, 11, 37, 38, 72, 85], "\u0447\u044c\u0438\u043c": 0, "\u0447\u0443\u0436": [0, 75, 89, 92], "\u0442\u043e\u0447\u043a": [0, 8, 37, 38, 51, 73, 77, 83, 85, 88, 89, 92, 94, 100], "\u0437\u0440\u0435\u043d": [0, 8, 23, 38, 51, 73, 74, 82, 83, 85, 88, 89, 92, 93, 94, 95, 100], "\u0440\u0435\u0430\u043b\u044c\u043d": [0, 8, 16, 83, 95, 100], "\u0436\u0438\u0437\u043d": [0, 8, 23, 70, 73, 83, 85, 88, 92, 100], "\u043d\u0435\u043c\u0430\u043b\u043e\u0432\u0430\u0436\u043d": [0, 23, 70, 82], "\u043f\u0441\u0438\u0445\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": [0, 37, 56, 82, 83, 85, 88, 90, 91, 92, 93, 94, 138], "\u0444\u0430\u043a\u0442\u043e\u0440": [0, 5, 42, 68, 70, 85, 100], "\u043a\u043e\u0433\u0434": [0, 9, 11, 21, 23, 26, 34, 38, 41, 45, 56, 65, 66, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 92, 95, 100, 123], "\u0447\u0435\u043b\u043e\u0432\u0435\u043a": [0, 11, 26, 38, 65, 68, 73, 74, 75, 82, 83, 85, 86, 88, 90, 92, 95, 100], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432": [0, 8, 30, 82, 85, 86], "\u0441\u0443\u0434": [0, 90, 100], "\u0431\u0443\u0434\u0435\u0442": [0, 5, 8, 9, 21, 23, 26, 30, 34, 37, 38, 40, 42, 47, 70, 73, 74, 75, 76, 77, 82, 83, 85, 86, 90, 92, 93, 94, 95, 100], "\u043e\u0446\u0435\u043d\u0438\u0432\u0430": [0, 38, 74, 95], "\u043f\u043e\u0437\u0438\u0446": [0, 38, 40, 56, 83, 86, 88, 92, 93], "\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442": [0, 38, 42, 52, 64, 65, 74, 76, 92], "\u043f\u043e\u0437\u0432\u043e\u043b\u044f": [0, 5, 11, 21, 23, 34, 37, 38, 40, 70, 73, 74, 75, 77, 85, 86, 100, 102], "\u0441\u043d\u044f\u0442": [0, 21, 72, 95, 100], "\u0431\u0430\u0440\u044c\u0435\u0440": [0, 82], "\u0443\u0441\u043a\u043e\u0440\u044f": [0, 74, 76], "\u043e\u0431\u043c": [0, 23, 86], "\u043f\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u043e\u0432\u0430": 0, "\u043f\u043e\u044f\u0432\u043b\u0435\u043d": [0, 51, 65, 68, 75, 89], "\u0441\u0435\u0433\u043e\u0434\u043d": [0, 15, 37, 38, 41, 64, 70, 74, 76, 82, 86, 92], "\u0436\u0438\u0432\u0435\u0442": 0, "\u0443\u0441\u043b\u043e\u0432": [0, 8, 9, 21, 23, 30, 33, 37, 52, 56, 65, 68, 70, 76, 85, 86, 88, 90, 92, 118], "\u0441\u0442\u0435\u0441\u043d\u0435\u043d": 0, "\u043d\u0430\u0441": [0, 5, 8, 23, 30, 37, 41, 68, 85, 88, 94, 100], "\u0435\u0441\u0442": [0, 5, 9, 11, 13, 23, 26, 34, 37, 38, 40, 42, 52, 65, 73, 74, 75, 82, 83, 85, 86, 88, 90, 92, 95, 100], "\u043e\u0431\u043e\u0433\u0430\u0442": 0, "\u043d\u043e": [0, 5, 8, 9, 11, 15, 16, 23, 30, 34, 37, 38, 40, 42, 46, 56, 65, 70, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 100, 102], "\u043f\u0440\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": 0, "\u0442\u0435\u043c": [0, 5, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 47, 52, 64, 65, 68, 72, 74, 76, 80, 82, 83, 85, 89, 90, 92, 93, 94, 95, 100], "\u043f\u043e\u044d\u0442": [0, 8, 15, 21, 23, 38, 40, 41, 46, 62, 68, 70, 72, 73, 74, 75, 77, 82, 83, 85, 86, 88, 90, 92, 94, 100, 102], "\u043a\u043e\u0440\u043e\u0442\u043a": [0, 21, 34, 37, 85, 88], "\u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d": [0, 37, 75, 76, 82, 85, 86, 95], "\u043a\u043e\u043d\u0435\u0447\u043d": [0, 8, 23, 37, 38, 40, 46, 65, 70, 73, 74, 77, 82, 85, 88, 92, 100], "\u0438\u0442\u043e\u0433": [0, 52, 72, 73, 74, 75, 77, 88], "\u043b\u044e\u0434": [0, 38, 42, 68, 70, 73, 75, 83, 85, 86, 88, 92, 94], "\u0442\u0440\u0430\u0442": [0, 47, 56, 83, 85, 92], "\u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440": 0, "\u043d\u0430\u043c\u043d": [0, 5, 21, 74, 82, 86, 88], "\u0442\u0440\u0435\u0431": [0, 8, 9, 11, 13, 21, 23, 34, 38, 40, 46, 47, 65, 70, 74, 83, 85, 86, 89, 92, 95, 100, 102], "\u043d\u0430\u043f\u0438\u0441\u0430\u043d": [0, 37, 47, 52, 53, 74, 77, 82, 85, 90], "\u0434\u0435\u043b\u0430": [0, 5, 9, 11, 23, 37, 38, 42, 45, 47, 52, 56, 65, 66, 68, 70, 72, 73, 74, 75, 83, 85, 88, 92, 93, 100, 102, 123], "\u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b": 0, "\u0445\u043e\u0440\u043e\u0448": [0, 8, 9, 21, 23, 34, 38, 40, 42, 53, 56, 64, 66, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 90, 93, 94, 95], "\u0440\u043e\u0436\u0434\u0430": 0, "\u043a\u0440\u0438\u0441\u0442\u0430\u043b\u0438\u0437\u0438\u0440": 0, "\u0437\u0430": [0, 8, 9, 11, 15, 21, 23, 26, 30, 34, 37, 42, 56, 70, 72, 74, 75, 76, 82, 83, 85, 86, 88, 90, 92, 93, 95, 100], "\u0447\u0435\u0433": [0, 21, 37, 42, 74, 75, 100], "\u0447\u0430\u0441\u0442": [0, 5, 9, 21, 23, 30, 34, 37, 42, 43, 46, 47, 65, 66, 70, 74, 75, 76, 83, 85, 86, 88, 92, 94, 100, 102, 121], "\u0442\u043e\u043d\u0443\u0442": 0, "\u0431\u0435\u0437\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430": 0, "\u0441\u0432\u0430\u043b\u043a": [0, 5], "\u0441\u0440\u0435\u0434": [0, 23, 38, 41, 74, 75, 83, 85, 86, 88, 93], "\u043e\u043a\u0435\u0430": 0, "\u043d\u0435\u0441\u043c\u043e\u0442\u0440": [0, 9, 65, 85, 88], "\u0444\u0430\u043a\u0442": [0, 9, 11, 15, 21, 30, 72, 76, 85, 92, 93, 95, 100], "\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d": [0, 9, 21, 40, 75, 92, 100, 102], "\u0431\u044b\u0441\u0442\u0440": [0, 5, 38, 40, 41, 42, 46, 74, 86], "\u0441\u0442\u0430\u043d\u043e\u0432": [0, 8, 21, 23, 37, 38, 47, 65, 68, 70, 72, 74, 76, 85, 86, 90], "\u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d": 0, "\u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432": [0, 5, 8, 9, 21, 23, 30, 34, 37, 38, 40, 83, 86, 90], "\u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430": 0, "\u0444\u043e\u0440\u043c": [0, 5, 9, 23, 38, 56, 82, 85, 86, 92, 94, 95, 100, 102], "\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d": [0, 21, 34, 82, 86], "\u0447\u0442\u043e\u0431": [0, 5, 8, 9, 11, 21, 23, 26, 34, 37, 38, 40, 41, 42, 46, 56, 60, 68, 70, 72, 73, 74, 75, 82, 83, 85, 86, 88, 90, 92, 93, 95, 100], "\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430": [0, 34, 38, 42, 62, 65, 74, 82, 86, 90, 95, 100], "\u0431\u044b": [0, 8, 9, 11, 23, 34, 38, 40, 70, 73, 75, 76, 77, 82, 83, 86, 88, 92, 94, 100], "\u043f\u0440\u0438\u0432\u0430\u0442\u043d": 0, "\u0441\u043f\u043e\u0441\u043e\u0431": [0, 5, 8, 9, 11, 13, 21, 23, 26, 34, 38, 47, 49, 52, 56, 65, 70, 73, 74, 75, 76, 77, 80, 86, 88, 90, 92, 94], "\u043d\u0430\u0432\u0435\u0440\u043d": [0, 21, 34, 41, 47, 65, 75, 83, 85, 86, 92], "\u0437\u0430\u043c\u0435\u0447\u0430": [0, 94], "\u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [0, 83, 89, 90, 92, 94, 100], "\u0447\u0430\u0442": [0, 34], "\u043c\u043e\u043b\u043e\u0434": [0, 83, 100], "\u0440\u0435\u0431\u044f\u0442": [0, 38], "\u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d": [0, 5, 82, 88, 92, 93], "\u0437\u0430\u0434\u0430": [0, 5, 23, 70, 74, 90, 94], "\u0442\u043e\u0442": [0, 8, 15, 21, 23, 26, 34, 56, 64, 75, 76, 77, 83, 85, 88, 90, 93, 100], "\u043f\u0435\u0440\u0432": [0, 8, 9, 11, 21, 23, 34, 37, 41, 42, 46, 56, 64, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 92, 94, 100, 102], "\u043a\u0442\u043e": [0, 5, 8, 9, 21, 34, 40, 51, 64, 73, 75, 83, 85, 86, 88, 90, 92, 93, 94, 100], "\u044d\u043a\u0441\u043f\u0435\u0440\u0442": [0, 8, 82], "\u043e\u0442\u0432\u0435\u0442": [0, 8, 9, 21, 23, 34, 70, 82, 88], "\u0441\u043b\u0435\u0434": [0, 5, 8, 11, 21, 23, 34, 37, 38, 46, 47, 52, 65, 70, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 92, 94, 100], "\u043f\u043e\u043f\u0443\u0433\u0430\u0439\u043d\u0438\u0447\u0430": 0, "\u0443\u0436": [0, 5, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 51, 56, 65, 74, 75, 76, 80, 82, 83, 85, 86, 88, 90, 92, 94, 95, 100, 102], "\u043d\u0438\u043a\u0442": [0, 21, 38, 40, 60, 74, 82, 88, 90, 92], "\u0445\u043e\u0447\u0435\u0442": [0, 9, 40, 46, 92], "\u0442\u043e\u0433\u0434": [0, 8, 9, 11, 15, 21, 23, 26, 34, 38, 56, 73, 75, 76, 77, 83, 85, 86, 88, 93, 95, 100], "\u043f\u044b\u0442\u0430": [0, 9, 21, 38, 65, 70, 73, 74, 85, 88, 90, 92, 94], "\u043e\u0442\u0432\u0435\u0447\u0430": [0, 8, 21, 38, 75, 76, 82, 86], "\u043c\u0430\u043b\u043e\u043e\u043f\u044b\u0442\u043d": [0, 38, 74], "\u0437\u0430\u0447\u0430\u0441\u0442": [0, 23, 38, 40, 41, 52, 68, 74, 76, 92], "\u0432\u0440\u0435\u0434": [0, 72], "\u043f\u043e\u043b\u044c\u0437": [0, 8, 9, 21, 23, 38, 40, 72], "\u0447\u0435\u0440\u0435\u0437": [0, 5, 8, 9, 11, 21, 23, 40, 70, 75, 82, 83, 84, 86, 88, 92, 136], "\u043e\u0442\u044b\u0441\u043a\u0430": [0, 23], "\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d": [0, 23, 26, 37, 38, 40, 65, 68, 70, 75, 82, 83, 85, 88, 94, 95, 100], "\u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a": [0, 5, 8, 21, 23, 65, 75, 82, 86, 92, 100], "\u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d": [0, 8, 11, 15, 23, 37, 38, 65, 70, 74, 86, 94, 100, 102], "\u0441\u043b\u043e\u0436\u043d": [0, 11, 15, 21, 30, 37, 38, 39, 43, 47, 56, 60, 66, 68, 70, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 90, 92, 121], "\u0432\u044b\u044f\u0432": [0, 92], "\u043d\u0430\u043f\u043b\u043e\u0434": 0, "\u0434\u0435\u0437\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446": 0, "\u0442\u0430\u043c": [0, 5, 9, 15, 23, 34, 37, 52, 56, 65, 70, 85, 86, 90, 92, 94], "\u0433\u0434\u0435": [0, 9, 11, 15, 21, 30, 34, 38, 40, 41, 47, 52, 56, 65, 74, 75, 83, 85, 86, 90, 92, 94, 95, 100, 102], "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430": 0, "\u043f\u0438\u0448\u0443\u0442": [0, 21, 62, 74, 90], "\u043d\u0435\u043b\u044c\u0437": [0, 9, 21, 23, 75, 76, 86, 102], "\u043b\u0438": [0, 8, 9, 11, 12, 22, 34, 38, 42, 47, 56, 70, 72, 82, 86, 90, 100, 102, 111], "\u0446\u0435\u043b": [0, 9, 11, 15, 21, 23, 29, 30, 37, 38, 40, 46, 51, 65, 70, 72, 73, 74, 75, 76, 83, 85, 86, 90, 92, 100, 102], "\u043f\u0443\u0442": [0, 5, 8, 21, 26, 34, 38, 40, 46, 56, 65, 72, 73, 76, 80, 82, 83, 85, 86, 88, 92, 93, 100], "\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d": [0, 9, 15, 21, 23, 30, 34, 37, 38, 40, 46, 67, 68, 70, 74, 75, 76, 81, 83, 85, 86, 90, 92, 93, 95, 130, 135], "\u0441\u043e\u043e\u0431\u0449\u0435\u043d": [0, 8, 21, 23, 30, 33, 118], "\u0437\u0430\u043c\u0435\u0442\u043e\u043a": 0, "\u043f\u043e\u0432\u044b\u0441": [0, 8, 37, 38, 72, 83, 85, 86, 88, 100], "\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c": 0, "\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d": [0, 37, 56, 64, 74, 75, 83, 86, 92], "\u0440\u043e\u0434": [0, 21, 42, 82, 86, 92, 93], "\u0441\u043a\u0435\u043b\u0435\u0442": [0, 86], "\u043d\u0430\u043b\u0438\u043f\u0430": 0, "\u0431\u0435\u0437": [0, 5, 8, 15, 21, 37, 38, 47, 70, 73, 74, 75, 82, 83, 85, 86, 92, 94, 95, 100, 102], "\u0431\u0435\u0441\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d": 0, "\u043e\u043a\u0435\u0430\u043d": 0, "\u0441\u043b\u044b\u0448\u0430": [0, 75, 85, 88], "\u0430\u043d\u0442\u0438\u043f\u0430\u0442\u0442\u0435\u0440\u043d": 0, "\u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u043e\u043d\u0435\u0440": [0, 37, 83, 91, 95, 138], "\u043d\u0430\u043a\u0430\u043f\u043b\u0438\u0432\u0430": [0, 38], "\u043c\u043d\u043e\u0433": [0, 9, 11, 13, 23, 37, 38, 40, 42, 46, 64, 68, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 93, 100, 102], "\u043d\u0430\u0439\u0442": [0, 8, 21, 23, 73, 74, 82, 85], "\u043d\u0438\u0431\u0443\u0434": [0, 23, 70, 73, 74], "\u043c\u0435\u0441\u0441\u0438\u0432": 0, "\u043d\u0435\u0440\u0435\u0430\u043b\u044c\u043d": 0, "\u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441": [0, 83], "\u043f\u043e\u043b\u043d\u043e\u0442\u0435\u043a\u0441\u0442\u043e\u0432": 0, "\u043f\u043e\u0438\u0441\u043a": [0, 5, 12, 41, 56, 72, 75, 76, 93, 96, 100], "\u043c\u043e\u0440\u0444\u043e\u043b\u043e\u0433": 0, "\u0434\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d": 0, "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0437\u0430\u0446": [0, 92], "\u043a\u043e\u043d\u0442\u0435\u043d\u0442": 0, "\u043f\u0440\u0438\u0447": [0, 9, 13, 23, 34, 37, 38, 74, 86, 92], "\u0434\u0435\u0440\u0435\u0432": [0, 75], "\u043c\u043e\u0433\u0443\u0442": [0, 8, 9, 11, 21, 23, 26, 38, 40, 41, 46, 47, 64, 65, 70, 72, 74, 75, 77, 82, 83, 85, 86, 92, 93, 94, 100, 102], "\u043f\u0435\u0440\u0435\u0441\u0435\u043a\u0430": [0, 9, 82, 85], "\u0441\u043e\u0431": [0, 9, 11, 23, 37, 38, 74, 75, 83, 85, 86, 102], "\u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434": [0, 8, 74], "\u0444\u0430\u0439\u043b\u043e\u0432": [0, 5, 12, 85], "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440": [0, 5, 8, 9, 12, 21, 46, 75, 77, 85], "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442": [0, 37, 52, 82], "\u0430\u043b\u0444\u0430\u0432\u0438\u0442\u043d": [0, 96], "\u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b": [0, 23, 26, 96], "\u0442\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d": 0, "\u0438\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d": 0, "\u043f\u0435\u0440\u0435\u043a\u0440\u0435\u0441\u0442\u043d": 0, "\u0434\u0430\u0436": [0, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 41, 46, 47, 52, 56, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 90, 92, 94, 102], "\u043a\u0440\u043e\u0441\u0441": 0, "\u043f\u0440\u043e\u0435\u043a\u0442\u043d": [0, 72, 73, 76, 86], "\u0441\u0441\u044b\u043b\u043a": [0, 8, 9, 11, 16, 21, 23, 75], "\u0441\u0442\u0440\u0430\u043d\u0438\u0446": [0, 38, 82, 86, 93, 95], "\u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440": [0, 70, 72, 73, 75, 76, 85, 86, 92, 93, 100, 102], "\u043a\u0430\u043d\u0430\u043b": [0, 23, 30, 34, 89], "\u043d\u043e\u0432": [0, 5, 8, 9, 23, 30, 34, 37, 38, 46, 47, 56, 62, 70, 72, 73, 74, 75, 76, 82, 83, 85, 88, 92, 93, 94, 95, 100], "\u043b\u0435\u0433\u043a": [0, 5, 9, 21, 23, 30, 37, 38, 51, 70, 73, 74, 75, 82, 85, 88, 94], "\u043e\u0442\u0440\u0430\u0436\u0430": [0, 5, 23, 34, 38, 92], "channel": [0, 23, 34], "\u0431\u043e\u0442": 0, "\u043f\u043b\u0430\u0433\u0438\u043d": [0, 5], "\u043e\u0431\u0440\u0430\u0437": [0, 5, 8, 9, 13, 15, 21, 23, 26, 30, 34, 37, 38, 41, 56, 65, 70, 72, 74, 75, 76, 80, 85, 86, 90, 92, 93, 95, 100, 102], "\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d": [0, 21, 23], "\u0441\u043e\u0445\u0440\u0430\u043d\u044f": [0, 5, 23, 82, 85, 102], "\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d": [0, 64, 76, 82], "\u043d\u0430\u0431\u043e\u0440": [0, 38, 76, 85], "\u043f\u0440\u0438\u043d\u0446\u0438\u043f": [0, 5, 8, 9, 21, 26, 37, 38, 40, 46, 52, 66, 70, 72, 73, 74, 75, 76, 85, 88, 91, 92, 93, 94, 95, 138], "\u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d": 0, "\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430": [0, 8, 9, 34, 37, 38, 65, 70, 72, 76, 80, 85], "open": [0, 5, 9, 23, 46, 51, 73, 75, 82, 86, 88], "source": [0, 5, 21, 23, 34, 37, 38, 51, 52, 60, 62, 65, 74, 75, 76, 77, 82, 85, 86, 100], "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [0, 50, 52, 125], "sphinx": 0, "doc": 0, "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0449": 0, "\u0444\u043e\u0440\u043c\u0430\u0442": [0, 9, 21], "\u0440\u0430\u0437\u043c\u0435\u0442\u043e\u043a": 0, "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f": [0, 21, 23, 38, 70, 77], "\u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432": [0, 85], "index": [0, 21, 66], "table": [0, 23, 51, 85], "of": [0, 5, 8, 9, 11, 13, 14, 15, 21, 26, 29, 30, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 53, 59, 60, 62, 63, 64, 65, 66, 68, 70, 71, 76, 77, 80, 83, 85, 88, 90, 92, 93, 94, 95, 100, 132], "content": [0, 34, 38, 49, 64, 82, 85], "toc": 0, "toctree": 0, "\u0438\u0435\u0440\u0430\u0440\u0445": [0, 46], "\u0441\u0432\u044f\u0437": [0, 5, 21, 23, 37, 38, 40, 52, 70, 72, 75, 85, 86, 88, 93, 100, 102], "\u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a": [0, 21], "js": 0, "\u0431\u0440\u0430\u0443\u0437\u0435\u0440": 0, "todo": 0, "\u043b\u0438\u0441\u0442": [0, 8, 74], "\u0441\u0442\u043e\u0440\u043e\u043d": [0, 9, 11, 21, 23, 37, 40, 68, 70, 74, 75, 80, 82, 83, 86, 88, 89, 92, 93, 94, 100, 102], "\u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a": 0, "\u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441": [0, 5, 15, 82], "\u044f\u0437\u044b\u043a": [0, 15, 21, 23, 26, 34, 37, 38, 72, 74, 75, 82, 85, 86, 93, 102], "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d": [0, 21, 26, 38, 70, 72, 75, 85, 86, 88, 89, 93, 94], "\u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c": 0, "\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432": [0, 8, 11, 23, 30, 40, 65, 70, 73, 74, 82, 85, 86, 93, 100], "\u0433\u043e\u0442\u043e\u0432": [0, 21, 23, 46, 70], "\u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a": [0, 23, 34, 38, 75, 76, 82, 92, 93], "\u0432\u0430\u0436\u043d": [0, 9, 21, 34, 37, 38, 46, 51, 62, 65, 72, 73, 74, 75, 76, 82, 83, 85, 88, 90, 92, 94, 95, 102], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443": [0, 5, 8, 13, 21, 23, 30, 34, 38, 39, 86, 90], "\u0432\u043e\u0442": [0, 5, 8, 21, 23, 30, 38, 72, 75, 82, 83, 85, 88, 89, 90, 92, 95], "\u043f\u0438\u0448\u0435\u0442": [0, 21, 38, 40, 41, 47, 51, 74, 75, 82, 85, 90], "\u0435\u0432\u0433\u0435\u043d": [0, 76], "\u043f\u0435\u0448\u043a": 0, "\u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b": [0, 38, 85], "\u0440\u043e\u0441\u0441\u0438\u0439\u0441\u043a": 0, "ddd": [0, 8, 9, 11, 14, 15, 24, 29, 30, 32, 34, 37, 75, 76, 87, 88, 100, 104, 112, 117, 137], "\u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432": [0, 13, 85, 92], "\u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0438\u0442\u0435\u043b": [0, 30, 46, 82], "\u0446\u0438\u0430": 0, "\u043b\u0435\u0442": [0, 21, 38, 73, 74, 76, 83, 86, 88, 94, 100], "2020": [0, 37, 38, 40, 86], "\u044f": [0, 9, 11, 15, 21, 23, 34, 37, 38, 40, 46, 47, 65, 70, 72, 74, 75, 82, 83, 85, 86, 88, 92, 93, 94, 95, 102], "\u043f\u0440\u043e\u0445\u043e\u0434": [0, 76, 83, 94], "\u043a\u0443\u0440\u0441": [0, 37, 38, 40, 46, 67, 68, 70, 74, 75, 82, 88, 130], "\u0441\u0438\u0441\u0442\u0435\u043c\u043d": [0, 23, 41, 64, 65, 72, 76, 80, 82, 83, 86, 100], "\u043c\u044b\u0448\u043b\u0435\u043d": [0, 23, 41, 82, 83, 89, 92], "\u043b\u0435\u0432\u0435\u043d\u0447\u0443\u043a": 0, "\u0430\u043d\u0430\u0442\u043e\u043b": 0, "\u0437\u0430\u043d\u044f\u0442": [0, 42, 85, 86], "\u0432\u0441\u044f\u0447\u0435\u0441\u043a": 0, "\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434": [0, 8, 15, 23, 72, 82, 85], "\u043f\u0438\u0441\u044c\u043c": [0, 34], "\u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430": [0, 23, 75, 80, 82, 85, 100, 102], "\u0441\u043e\u0437\u0434\u0430\u043d": [0, 8, 9, 21, 23, 38, 46, 74, 77, 85, 86, 90, 102], "\u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442": [0, 23, 82], "\u043a\u043d\u0438\u0433": [0, 8, 9, 11, 13, 21, 23, 30, 34, 37, 38, 40, 46, 51, 64, 72, 75, 76, 82, 83, 85, 86, 92, 93, 94, 95], "\u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d": 0, "\u0441\u043b\u043e\u0432": [0, 8, 10, 11, 23, 34, 37, 38, 40, 46, 52, 56, 72, 73, 74, 75, 77, 85, 86, 89, 92, 93, 94, 100], "\u043f\u043e\u043d\u0438\u043c\u0430\u043d": [0, 21, 23, 38, 64, 72, 75, 82, 83, 86, 88, 93, 94, 100, 102], "\u043f\u0440\u043e\u0439\u0434\u0435\u043d": 0, "\u043b\u0443\u0447\u0448": [0, 5, 8, 21, 23, 30, 37, 38, 40, 42, 56, 60, 68, 70, 72, 73, 74, 75, 77, 82, 83, 85, 86, 90, 92, 93, 94, 95], "\u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430": [0, 93], "\u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434": [0, 23, 30, 37, 38, 56, 70, 74, 85, 86, 88, 90, 93, 102], "\u0442\u043e\u0433": [0, 8, 9, 11, 21, 23, 30, 34, 37, 38, 40, 42, 47, 68, 70, 72, 73, 74, 75, 76, 82, 83, 85, 86, 88, 89, 90, 92, 93, 95, 100, 102], "\u043c\u044b": [0, 5, 8, 9, 11, 13, 21, 23, 30, 34, 37, 38, 40, 65, 68, 70, 72, 74, 75, 76, 83, 85, 86, 90, 93, 94, 100, 102], "\u043f\u0440\u043e\u0433\u043e\u043d\u044f": 0, "\u0441\u0435\u0431": [0, 15, 23, 37, 38, 40, 47, 56, 62, 73, 75, 82, 83, 85, 86, 88, 92, 93], "\u0432\u043d\u0443\u0442\u0440\u0435\u043d": [0, 9, 11, 23, 37, 38, 40, 73, 74, 75, 82, 85, 100], "\u0434\u0438\u0430\u043b\u043e\u0433": [0, 102], "\u043c\u0435\u0445\u0430\u043d\u0438\u0447\u0435\u0441\u043a": [0, 11, 74], "\u043f\u0430\u043c\u044f": [0, 9, 82, 85, 89, 102], "\u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d": [0, 5], "\u043f\u043e\u043d\u0438\u043c\u0430": [0, 23, 37, 38, 52, 64, 72, 75, 83, 85, 86, 93, 94, 100], "\u043d\u0430\u0448": [0, 21, 37, 38, 40, 41, 46, 68, 70, 74, 88, 94, 100], "\u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d": [0, 21, 23, 52, 68, 75, 76, 88, 92], "\u0441\u0442\u0440\u043e\u0433": [0, 8, 21, 34, 73, 92, 100], "\u0441\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430": [0, 86, 100], "\u043e\u0431\u0440\u044b\u0432\u0430": 0, "\u0441\u043e\u0441\u0442\u043e\u044f": [0, 8, 75, 85], "\u043f\u043e\u043b\u0443\u043e\u0431\u0440\u0430\u0437": 0, "\u043d\u0435\u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430": 0, "\u043b\u043e\u0436\u043d": [0, 41, 89, 100, 102], "\u043e\u0449\u0443\u0449\u0435\u043d": [0, 11, 42, 47, 83, 85], "\u043f\u043e\u043d\u044f\u0442\u043d": [0, 23, 34, 64, 70, 74, 90, 100], "\u043f\u0438\u0448": [0, 72, 85], "\u0447\u0435\u0442\u043a": [0, 23, 73, 94, 100], "\u0442\u0435\u0437\u0438\u0441": 0, "\u0441\u043b\u043e\u0436": [0, 85], "\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [0, 8, 11, 13, 21, 23, 34, 38, 56, 70, 72, 74, 77, 85, 86, 90, 92, 100], "\u043f\u043e\u0440\u044f\u0434\u043a": [0, 8, 21, 23, 34, 38, 40, 82], "\u0432\u0435\u0440\u043d\u0443\u0442": [0, 9, 23, 47], "\u0434\u043e\u043e\u0441\u043c\u044b\u0441\u043b": 0, "\u043e\u0441\u0442\u0430": [0, 9, 11, 30, 34, 38, 40, 49, 56, 65, 70, 75, 83, 85, 88, 90, 93, 95], "\u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442": [0, 86], "\u043f\u0440\u0438\u0433\u043e\u0434\u043d": 0, "\u0434\u0430\u043b\u044c\u043d": [0, 42, 72, 73, 74, 85, 88, 100], "\u043f\u0440\u043e\u0440\u0430\u0431\u043e\u0442\u043a": [0, 5, 92], "\u043e\u0442\u0447\u0443\u0436\u0434\u0430": 0, "\u043c\u043e\u0436": [0, 8, 37, 40, 70, 74, 94, 100], "\u0437\u0430\u043f\u043e\u0441\u0442": [0, 95], "\u0442\u0435\u043b\u0435\u0433\u0440": 0, "\u043e\u0442\u043f\u0440\u0430\u0432": [0, 23, 30], "\u0432\u0437\u044f\u0442": [0, 9, 38, 46, 86, 90], "\u043d\u0430\u0447\u0430": [0, 47, 70, 72, 74, 76, 83, 85, 86], "\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430": [0, 38, 74], "\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446": [0, 8, 85], "\u0431\u044b\u043b": [0, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 41, 51, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 100], "\u0443\u043a\u0430\u0437\u0430": [0, 38, 60, 90, 102], "how": [0, 9, 11, 15, 21, 23, 34, 37, 38, 39, 46, 49, 51, 60, 62, 65, 66, 70, 72, 73, 74, 75, 76, 80, 82, 85, 86, 88, 89, 90, 94, 100], "to": [0, 5, 8, 9, 11, 13, 15, 21, 23, 26, 29, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 59, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 76, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100], "take": [0, 21, 23, 34, 37, 38, 41, 46, 51, 68, 73, 74, 80, 85, 93], "smart": [0, 53, 68, 70], "notes": [0, 34, 37, 76, 82], "\u043a\u043b\u0430\u0441\u0441\u043d": [0, 30, 38], "\u043f\u043e\u0438\u043d\u0442": [0, 8], "\u043f\u0440\u0438\u0432\u044b\u043a\u0430": [0, 5], "\u043d\u0430\u043c": [0, 8, 9, 21, 23, 37, 42, 70, 74, 85, 90, 92, 100], "\u043f\u0440\u043e\u0449": [0, 70, 72, 74, 85, 88, 90], "\u043f\u0438\u0441\u0430": [0, 9, 13, 21, 38, 45, 46, 65, 66, 70, 72, 74, 75, 76, 85, 88, 92, 123], "\u0442\u0443\u0442": [0, 5, 8, 21, 23, 34, 38, 51, 56, 73, 82, 85, 88, 94, 95], "\u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": [0, 85], "\u043f\u0440\u0438\u0432\u044b\u0447\u043a": [0, 68, 82, 95], "\u043a\u0440\u043e\u043c": [0, 9, 23, 30, 34, 37, 38, 40, 56, 70, 74, 85, 86, 102], "\u0443\u043a\u0430\u0437\u044b\u0432\u0430": [0, 21, 42, 52, 75, 83, 102], "\u0440\u0430\u043d": [0, 21, 23, 34, 37, 38, 40, 46, 72, 77, 85, 86], "\u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": 0, "https": [0, 5, 8, 16, 21, 34, 37, 38, 76, 82, 89, 92, 100], "t": [0, 5, 8, 9, 11, 21, 23, 29, 30, 34, 37, 38, 39, 42, 46, 47, 49, 51, 52, 53, 60, 62, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 94, 100], "me": [0, 13, 23, 37, 38, 41, 46, 72, 74, 85, 86, 92, 100], "dddevotion": [0, 100], "176": 0, "\u043c\u0435\u043d": [0, 9, 15, 21, 23, 38, 40, 64, 70, 72, 74, 82, 83, 85, 90, 92, 93], "\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u043b": [0, 93], "\u0441\u0438\u043b\u044c\u043d": [0, 8, 9, 40, 41, 65, 68, 74, 77, 83, 85, 88, 90, 95], "\u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d": [0, 74, 93, 94], "\u043d\u0435\u0431\u043e\u043b\u044c\u0448": [0, 5, 8, 9, 23, 38, 74, 82, 85, 86, 92], "\u043a\u043d\u0438\u0436\u0435\u0447\u043a": 0, "\u0447\u0438\u0442\u0430": [0, 21, 37, 56, 64, 76, 82, 83, 85, 91, 95, 138], "\u043f\u043e\u0432\u0430\u0440\u043d\u0438\u043d": [0, 82, 93], "\u0441\u0435\u0440\u0433": [0, 5, 66, 70, 75, 82, 94, 95], "\u043f\u0440\u043e\u0447\u0435\u0441\u0442": 0, "\u0434\u0435\u043d": [0, 21, 70, 76, 82, 85, 95], "\u0441\u043a\u0430\u0447\u0430": [0, 82], "\u0437\u0434\u0435": [0, 5, 9, 11, 21, 23, 30, 34, 37, 38, 40, 52, 53, 75, 76, 80, 82, 83, 85, 86, 89, 90, 92], "\u043f\u0435\u0440\u0435\u043e\u0446\u0435\u043d": 0, "\u0432\u0435\u0441": [0, 8, 38, 73, 90, 93, 94, 100], "\u0437\u043e\u043b\u043e\u0442": [0, 93], "\u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442": [0, 34, 51, 82], "\u043f\u0440\u043e": [0, 21, 23, 38, 60, 62, 68, 75, 76, 90, 92, 100], "\u043e\u0441\u043e\u0431": [0, 8, 73, 85, 86], "\u0437\u043d\u0430\u0447\u0435\u043d": [0, 8, 9, 23, 26, 30, 34, 38, 52, 70, 75, 76, 82, 83, 85, 90, 91, 92, 93, 138], "\u043f\u0440\u0438\u043c\u0435\u043d\u044f": [0, 9, 13, 21, 23, 34, 65, 75, 83, 94], "\u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d": 0, "\u043d\u0443": [0, 21, 23, 38, 82, 85, 86, 90], "\u0440\u0430\u0437": [0, 8, 21, 23, 34, 37, 38, 46, 56, 70, 73, 74, 75, 77, 82, 85, 86, 88, 100], "\u0437\u0430\u0442\u0440\u043e\u043d\u0443\u0442": 0, "a": [0, 5, 8, 9, 11, 13, 15, 21, 23, 26, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 59, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100], "mind": [0, 23, 37, 47, 49, 51, 53, 70, 73, 75, 82, 85], "numbers": [0, 23, 34, 74, 75, 82, 86], "excel": [0, 5, 8, 82], "at": [0, 5, 9, 11, 21, 23, 29, 34, 37, 38, 39, 42, 46, 47, 49, 51, 52, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 95, 100], "math": [0, 75, 82], "and": [0, 5, 9, 11, 13, 15, 21, 31, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 76, 77, 80, 83, 85, 88, 89, 90, 92, 93, 94, 95, 100, 116], "science": [0, 23, 62, 65, 68, 73, 82, 85, 86], "by": [0, 5, 8, 9, 11, 13, 14, 15, 21, 23, 26, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 75, 77, 80, 82, 83, 85, 88, 89, 90, 92, 93, 94, 95, 100], "barbara": [0, 82], "ann": [0, 82], "oakley": [0, 82], "\u043f\u0435\u0440\u0435\u0432\u043e\u0434": [0, 8, 9, 11, 21, 26, 34, 37, 38, 42, 46, 47, 60, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 88, 90, 100], "\u0434\u0443\u043c\u0430": [0, 38, 40, 46, 72, 73, 74, 83, 85, 90, 102], "\u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a": [0, 37, 40, 62, 85, 90, 100, 102], "\u043b\u044e\u0431": [0, 5, 11, 23, 26, 37, 38, 47, 70, 72, 73, 74, 75, 82, 85, 86, 88, 90, 92, 100, 102], "\u0431\u0430\u0440\u0431\u0430\u0440": 0, "\u043e\u0430\u043a\u043b": 0, "\u043f\u0438\u0441\u044c\u043c\u0435\u043d": 0, "\u043d\u0435\u0440\u0435\u0434\u043a": [0, 37, 38, 40, 75, 76, 82, 83, 92], "\u0438\u0441\u043f\u044b\u0442\u044b\u0432\u0430": 0, "\u0437\u0430\u0442\u0440\u0443\u0434\u043d\u0435\u043d": 0, "\u0440\u0430\u0431\u043e\u0442": [0, 5, 9, 23, 37, 38, 40, 42, 46, 51, 60, 62, 64, 70, 72, 73, 74, 75, 77, 82, 85, 86, 88, 89, 90, 92, 93, 95], "\u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442": [0, 38, 60, 70, 72, 73, 74, 75, 76, 77, 90], "\u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0435\u043d": 0, "\u043f\u0430\u043c\u044f\u0442": [0, 38, 73, 74, 75, 82, 90, 92, 93, 94], "\u0438\u0441\u0445\u043e\u0434\u043d": [0, 16, 56, 85, 86, 92], "\u0441\u043d\u0438\u0436\u0430": [0, 42, 65, 74, 85, 94, 95], "\u0440\u0435\u0448\u0435\u043d": [0, 5, 8, 9, 11, 21, 34, 37, 39, 40, 41, 56, 60, 68, 72, 73, 74, 76, 77, 82, 83, 85, 86, 88, 90, 93, 94, 100], "\u0432\u044b\u0440\u0430\u0431\u043e\u0442\u0430": [0, 82, 92], "\u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d": [0, 82], "\u043f\u0440\u0435\u0436\u0434": [0, 70, 76, 85, 86, 102], "\u043e\u0442\u0440\u0430\u0437": 0, "\u043b\u0438\u0431": [0, 5, 8, 9, 11, 21, 23, 30, 34, 38, 73, 74, 75, 85, 88, 92, 94, 95, 100, 102], "\u0435\u0434\u0438\u043d": [0, 5, 11, 21, 23, 34, 37, 56, 75, 88], "\u0438\u0441\u0442\u0438\u043d": [0, 21, 73, 74, 83, 85, 86, 90, 93, 100, 102], "\u0432\u0441\u0435\u0433\u0434": [0, 9, 21, 23, 37, 38, 46, 56, 70, 75, 82, 85, 92, 93, 95, 100, 102], "\u043f\u043e\u0434": [0, 5, 21, 23, 26, 37, 38, 46, 52, 53, 56, 73, 74, 75, 76, 82, 83, 86, 92, 93, 94, 100], "\u0440\u0443\u043a": [0, 40, 56, 65, 82, 86], "\u0432\u043d\u0430\u0447\u0430\u043b": [0, 11, 46, 47, 85], "\u0443\u0441\u0438\u043b": [0, 38, 74, 83, 86, 92, 93, 95], "\u0432\u043e\u043b": [0, 38, 88], "\u0441\u0430\u043c\u043e\u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d": 0, "\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442": [0, 8, 9, 15, 22, 37, 38, 62, 65, 73, 74, 82, 83, 85, 86, 92, 93, 100, 111], "\u043f\u0440\u043e\u044f\u0432\u043b\u044f": [0, 34, 85, 94], "\u043e\u0447\u0435\u043d": [0, 5, 11, 15, 21, 23, 37, 38, 41, 56, 64, 68, 70, 73, 74, 75, 76, 82, 85, 86, 88, 89, 94, 100], "\u0432\u0435\u0434": [0, 11, 23, 37, 65, 70, 72, 85], "\u043e\u0431\u0440\u0430\u0449\u0430": [0, 5, 46, 47, 68, 85, 89], "\u0437\u0430\u043f\u0438\u0441\u0430": 0, "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432": [0, 82, 85], "\u0434\u043e\u0441\u0442\u0443\u043f": [0, 5, 8, 9, 11, 16, 21, 23, 82], "\u043a\u043e\u043c\u0430\u043d\u0434": [0, 22, 37, 38, 41, 42, 46, 49, 51, 64, 65, 70, 74, 76, 85, 87, 111, 137], "\u043a\u0440\u0430\u0442\u043d": [0, 40, 94], "\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d": [0, 5], "\u0441\u043e\u0437\u0434\u0430": [0, 5, 8, 11, 23, 30, 38, 70, 72, 73, 74, 76, 77, 85, 86, 88, 90, 93, 100], "\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u0430\u0440": 0, "\u043f\u0435\u0440\u0435\u0439\u0434": [0, 72], "private": [0, 8, 9, 11, 23, 85], "\u0438\u043c": [0, 21, 23, 26, 38, 46, 72, 74, 75, 76, 77, 85, 86, 88, 92, 102], "_html_extra": 0, "ivan": [0, 3, 4, 5, 8, 9, 10, 11, 14, 15, 18, 21, 23, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 56, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 86, 88, 89, 90, 92, 93, 94, 95, 100], "ivanov": 0, "\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440": [0, 5, 82], "\u0441\u0440\u0430\u0437": [0, 9, 21, 38, 46, 74, 86, 90, 100], "\u0432\u043d\u0435\u0441": 0, "gitignore": 0, "\u043e\u0431\u043b\u0435\u0433\u0447": [0, 9, 88, 92], "\u0447\u0438\u0442\u0430\u0442\u0435\u043b": [0, 82], "\u043e\u0447\u0435\u0432\u0438\u0434\u043d": [0, 8, 23, 38, 74, 85, 102], "sectionauthor": 0, "\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c": [0, 5, 11, 15, 37, 38, 46, 47, 51, 64, 70, 72, 74, 75, 82, 83, 85, 86, 92, 100], "\u043f\u043e\u0442": [0, 9, 11, 23, 34, 37, 38, 40, 41, 46, 53, 64, 70, 73, 74, 75, 76, 82, 83, 85, 86, 88, 92], "\u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430": [0, 37], "\u0432\u0441\u0435\u0445": [0, 5, 8, 11, 21, 34, 38, 40, 56, 70, 74, 85, 86, 90], "\u0432\u0438\u0434\u0435\u043d": [0, 56, 76, 82], "\u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u043a\u0430\u0446": [0, 8, 16], "\u0433\u0438\u0431\u043a\u043e\u0441\u0442": [0, 8, 23, 70], "\u0432\u043a\u043b\u044e\u0447\u0430": [0, 21, 23, 38, 40, 85, 92, 100, 102], "\u043f\u043e\u0434\u0434\u0435\u0440\u0435\u0432": 0, "\u0442\u0435\u0433\u0438\u0440": 0, "\u043f\u043e\u043c\u043e\u0449": [0, 5, 8, 21, 23, 34, 38, 46, 70, 74, 85, 88, 100, 102], "include": [0, 51, 77, 86], "\u0432\u0441\u0442\u0430\u0432\u043b\u044f": 0, "\u043f\u043e\u043b\u043d\u043e\u0441\u0442": [0, 8, 23, 38, 65, 72, 77, 82, 85, 86, 88, 90, 94, 100, 102], "\u0447\u0430\u0441\u0442\u0438\u0447\u043d": [0, 15, 21, 37, 40, 76], "\u0441\u043c": [0, 5, 9, 11, 23, 38, 40, 41, 51, 52, 62, 65, 70, 73, 74, 75, 76, 82, 83, 85, 86, 90, 92, 94, 100, 102], "options": [0, 38, 41, 43, 66, 70, 73, 74, 76, 121], "start": [0, 21, 23, 47, 65, 73, 74, 75, 76, 77, 82, 85, 86], "line": [0, 34, 38, 40, 66, 70, 74, 75, 76, 90], "after": [0, 15, 21, 23, 34, 37, 38, 51, 65, 72, 73, 76, 85, 86], "end": [0, 23, 34, 37, 38, 49, 52, 60, 62, 65, 73, 74, 76, 85, 86, 90], "before": [0, 21, 23, 29, 34, 37, 46, 47, 49, 51, 65, 70, 72, 74, 75, 76, 85, 86, 94], "dry": [0, 9], "\u043c\u0438\u043d\u0438\u043c\u0437\u0438\u0440\u0443": 0, "\u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d": [0, 38, 40, 65, 74], "\u043e\u0440\u0433\u0438\u043d\u0438\u0430\u043b\u044c\u043d": 0, "\u0442\u0435\u043a\u0441\u0442": [0, 23, 38, 92, 102], "\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430": 0, "\u043d\u0435\u043d\u0443\u0436\u043d": [0, 23, 82, 100], "\u0432\u0430\u043c": [0, 21, 23, 37, 38, 41, 46, 68, 70, 72, 73, 74, 76, 77, 82, 85, 86], "\u0443\u0434\u0430\u043b": [0, 5, 23, 30], "\u0446\u0435\u043b\u0438\u043a": [0, 5, 23, 72, 85], "\u0432\u044b\u0431\u043e\u0440\u043e\u0447\u043d": 0, "cherry": 0, "pick": [0, 38, 76, 86], "uuid4": 0, "\u0441\u0432\u044f\u0437\u0430": [0, 5, 11, 37, 38, 42, 46, 74, 75, 85, 102], "\u0441\u043b\u0435\u0434\u0443": 0, "\u043f\u0440\u0430\u043a\u0442\u0438\u043a": [0, 5, 13, 15, 23, 34, 37, 38, 40, 56, 65, 70, 72, 75, 76, 82, 85, 86, 88, 94, 100], "\u0432\u043c\u0435\u0441\u0442": [0, 5, 8, 9, 21, 37, 38, 40, 42, 52, 60, 70, 73, 74, 83, 85, 88, 90, 97], "uuid": [0, 21, 23], "\u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d": 0, "label": [0, 51], "names": [0, 23, 37, 73, 82], "\u043f\u0440\u0435\u0444\u0438\u043a\u0441": 0, "\u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a": [0, 11, 23, 30, 37, 38, 40, 51, 56, 65, 70, 74, 75, 76, 82, 83, 85, 86, 90, 92, 94, 102], "\u043f\u0435\u0440\u0435\u043c\u0435\u0449": [0, 8], "\u043f\u0440\u043e\u0441\u0442\u0430\u043d\u0441\u0442\u0432": 0, "ext": 0, "autosectionlabel": 0, "allow": [0, 11, 23, 37, 76, 86], "reference": [0, 8, 9, 19, 23, 34, 36, 75, 82, 86, 109, 120], "sections": 0, "using": [0, 5, 9, 11, 23, 29, 34, 72, 73, 74, 75, 76, 80, 82, 85, 86, 100], "its": [0, 9, 15, 21, 23, 26, 34, 37, 38, 47, 49, 51, 52, 62, 70, 73, 74, 75, 76, 85, 86], "title": [0, 82], "\u043e\u0431\u043b\u0435\u0433\u0447\u0430": [0, 5, 21, 75, 82], "\u0438\u0437\u043c\u0435\u043d\u0435\u043d": [0, 5, 9, 11, 15, 23, 26, 30, 37, 40, 41, 47, 64, 70, 74, 75, 76, 83, 85, 86, 90, 91, 102, 138], "\u043b\u043e\u043a\u0430\u0446": 0, "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430": 0, "seealso": 0, "intersphinx": 0, "pull": [0, 23, 38, 56, 75, 77], "request": [0, 21, 23, 56], "trunk": 0, "branch": 0, "\u044d\u0442\u043e\u0442": [0, 5, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 41, 46, 65, 70, 72, 73, 74, 75, 77, 82, 83, 85, 86, 88, 90, 92], "\u0441\u0440\u0430\u0432\u043d": [0, 23, 38, 70, 85, 86], "\u0448\u0438\u043d": [0, 23, 30], "\u0441\u043e\u0431\u044b\u0442": [0, 8, 10, 21, 38, 75, 80, 88, 94], "event": [0, 7, 8, 9, 12, 19, 21, 30, 34, 38, 56, 76, 86, 108, 109], "sourcing": [0, 12, 19, 21, 23, 34, 109], "\u043e\u043a\u0430\u0437\u0430": [0, 5, 9, 11, 70, 72, 73, 83, 88, 92, 102], "\u0434\u043e\u0441\u0442\u0443\u043f\u043d": [0, 8, 11, 21, 23, 34, 82, 85, 88, 89], "\u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442": [0, 82], "\u0434\u043e\u043c\u0435\u043d": [0, 8, 10, 12, 30, 89], "\u043f\u043e\u0438\u0441\u043a\u043e\u0432": [0, 82], "\u0442\u0440\u0430\u0444\u0444\u0438\u043a": 0, "\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d": [0, 23, 37, 70, 73, 75, 82, 92], "\u0430\u0434\u0440\u0435\u0441": 0, "\u0438\u0441\u043f\u043e\u043b\u044c\u0437": [0, 5, 9, 11, 13, 15, 21, 23, 30, 34, 37, 38, 46, 47, 53, 70, 75, 77, 82, 85, 86, 88, 100, 102], "custom": [0, 9, 85], "page": [0, 21, 23, 70, 74, 75, 85, 96], "metadata": [0, 13, 23, 34], "canonical": [0, 96, 100], "url": [0, 21], "my": [0, 21, 23, 37, 38, 41, 46, 62, 68, 72, 73, 74, 76, 83, 85, 86, 88, 90, 92], "domain": [0, 5, 8, 9, 11, 14, 16, 21, 26, 28, 29, 30, 34, 49, 65, 72, 73, 74, 75, 76, 86, 90, 103, 115], "ru": [0, 41, 64, 82, 89, 92], "path": [0, 23, 74, 82, 85], "base": [0, 21, 23, 37, 51, 62, 65, 74, 75, 77, 80], "\u0437\u0430\u043a\u0440\u044b\u0432\u0430": 0, "\u0441\u043b\u044d\u0448": 0, "html_baseurl": 0, "html_theme_options": 0, "canonical_url": 0, "\u0441\u0442\u0440\u043e\u0439\u0442": 0, "github": [0, 5, 8, 9, 16, 34, 75, 82, 89], "\u043f\u043b\u0430\u043d\u0438\u0440": 0, "\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a": [0, 8, 30, 86, 88, 100], "web": [0, 23, 37, 51, 76, 82, 86], "\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441": [0, 5, 9, 11, 21, 23, 30, 86], "desktop": 0, "client": [0, 15, 21, 23, 29, 73, 74], "gitlab": [0, 5], "\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b": [0, 9], "python": [0, 23, 34, 82], "\u0443\u0441\u0442\u0430\u043d\u043e\u0432": [0, 8, 9, 38], "\u0437\u0430\u0432\u0438\u0441\u0438\u043c": [0, 5, 9, 11, 15, 21, 34, 38, 40, 65, 74, 80, 85, 86, 94, 95, 100], "\u043a\u043e\u0440\u043d\u0435\u0432": [0, 8, 11], "\u0432\u044b\u043f\u043e\u043b\u043d": [0, 8, 40, 46, 77, 85, 86, 92], "pip": 0, "install": [0, 38], "r": [0, 38, 74, 82, 88], "requirements": [0, 23, 37, 38, 48, 59, 60, 62, 64, 65, 74, 75, 76, 77, 80, 82, 85, 124], "freeze": 0, "txt": 0, "\u043e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440": [0, 47], "conf": 0, "py": 0, "\u043f\u043e\u0434\u0440\u043e\u0431\u043d": [0, 8, 21, 23, 30, 38, 46, 86], "\u0441\u043c\u043e\u0442\u0440": [0, 23, 38, 40, 41, 74, 82, 85, 88], "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446": [0, 9, 23], "\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434": [0, 92], "\u0441\u0431\u043e\u0440\u043a": 0, "make": [0, 11, 21, 23, 29, 37, 38, 39, 41, 46, 47, 51, 53, 65, 68, 70, 73, 74, 75, 76, 77, 80, 85, 86, 90, 94, 100], "build": [0, 9, 23, 38, 46, 51, 66, 70, 73, 74, 82, 86, 92], "d": [0, 23, 38, 46, 64, 68, 70, 75, 76, 82, 85, 100], "language": [0, 5, 21, 23, 29, 51, 73, 74, 76, 82, 85, 100, 101], "b": [0, 5, 9, 21, 23, 30, 34, 37, 38, 40, 46, 65, 75, 77, 82, 88], "_build": 0, "docker": [0, 5], "sphinx_image": 0, "run": [0, 21, 23, 37, 38, 60, 62, 73, 74, 76, 85, 90], "v": [0, 8, 9, 53, 66, 82], "pwd": 0, "sphinxtechnicalwriting": 0, "\u043b\u043e\u043a\u0430\u043b\u044c\u043d": [0, 11, 21, 29], "\u0437\u0430\u043f\u0443\u0441\u043a": 0, "m": [0, 5, 23, 30, 34, 37, 38, 46, 73, 74, 75, 76, 82, 85, 88, 94, 95], "http": [0, 21, 23, 34, 76, 82, 85, 89], "server": [0, 21, 23, 34, 38, 74], "pdf": [0, 21, 23, 30, 34, 38, 82, 85], "epub": 0, "the": [0, 5, 8, 9, 11, 13, 14, 15, 21, 23, 26, 29, 30, 34, 37, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 77, 80, 82, 83, 85, 88, 90, 92, 93, 94, 95, 100], "introduction": [0, 34, 38, 75, 82], "method": [0, 9, 21, 23, 37, 38, 51, 60, 66, 72, 74, 85, 90], "\u0433\u043e\u0434": [0, 8, 37, 38, 46, 70, 73, 74, 75, 76, 83, 86, 92, 95], "\u0441\u0442\u0430\u0440\u0442\u043e\u0432": 0, "\u0442\u0440\u044e\u043a": [0, 9], "\u043d\u0435\u043c\u0435\u0446\u043a": [0, 83], "\u0443\u0447\u0435\u043d": [0, 68, 73, 85], "\u043d\u0435\u0432\u0435\u0440\u043e\u044f\u0442\u043d": [0, 37], "\u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0438\u0432\u043d": [0, 68, 86], "niklas": 0, "luhmann": 0, "\u0441\u0434\u0435\u043b\u0430": [0, 5, 8, 9, 11, 21, 23, 26, 30, 34, 37, 38, 46, 47, 56, 60, 70, 73, 74, 75, 82, 83, 85, 86, 88, 89, 90, 92, 95, 100], "\u0431\u0443\u043c\u0430\u0436\u043d": [0, 86], "\u043a\u0430\u0440\u0442\u043e\u0447\u043a": [0, 46], "\u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0430\u0446": [0, 38, 72, 73, 74, 90], "\u0440\u0438\u0441\u043a": [0, 15, 30, 38, 40, 47, 70, 86, 88, 89, 90], "\u0432\u043d\u0435\u0448\u043d": [0, 5, 9, 11, 23, 38, 56, 74, 85, 88, 92], "\u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d": [0, 8, 9, 21, 23, 34, 38, 40, 41, 70, 72, 73, 74, 75, 76, 77, 85, 88, 90, 93, 100], "\u0442\u0438\u043f": [0, 9, 38, 82, 86, 100, 102], "\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440": [0, 74, 85], "\u0432\u0435\u043d\u0434\u043e\u0440": 0, "\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0437\u043c": 0, "\u043f\u043e\u043b\u043d": [0, 8, 21, 26, 37, 38, 72, 85, 86, 102], "\u043d\u0430\u0434": [0, 5, 21, 34, 38, 46, 47, 60, 68, 70, 72, 74, 77, 82, 83, 85, 86, 88, 90, 92, 93, 95], "\u0441\u0432\u043e\u0431\u043e\u0434\u043d": [0, 38, 82], "\u043e\u0431\u043e\u0433\u0430\u0449\u0435\u043d": 0, "\u0434\u0438\u0441\u0442\u0438\u043b\u043b\u044f\u0446": 0, "in": [0, 5, 8, 9, 11, 12, 13, 15, 17, 19, 21, 24, 26, 29, 30, 34, 37, 39, 41, 42, 46, 47, 49, 51, 52, 53, 54, 59, 60, 62, 63, 64, 65, 66, 68, 70, 71, 76, 77, 80, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 95, 100, 109, 112, 126, 132], "our": [0, 21, 23, 34, 37, 38, 41, 46, 49, 51, 62, 65, 68, 70, 73, 74, 75, 76, 85, 86, 90, 100], "age": [0, 9, 37], "when": [0, 9, 21, 23, 26, 29, 34, 37, 38, 40, 42, 46, 47, 49, 51, 52, 53, 65, 68, 72, 73, 74, 75, 76, 82, 85, 86, 88, 100], "cloud": [0, 34, 82], "services": [0, 23, 64, 74, 75, 82, 86, 93], "can": [0, 5, 8, 9, 11, 13, 15, 21, 23, 29, 34, 37, 38, 39, 41, 42, 46, 49, 51, 52, 59, 62, 65, 66, 68, 70, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 95, 100], "shut": 0, "down": [0, 21, 23, 37, 38, 41, 51, 74, 76, 78, 80, 82, 85, 133], "get": [0, 8, 9, 21, 23, 34, 37, 38, 51, 52, 60, 62, 65, 68, 74, 76, 77, 80, 85, 86, 100], "bought": 0, "or": [0, 5, 8, 9, 11, 15, 21, 23, 26, 34, 37, 38, 39, 40, 42, 46, 49, 51, 52, 53, 60, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 86, 90, 100], "change": [0, 9, 11, 21, 23, 26, 37, 38, 39, 46, 47, 49, 52, 64, 65, 66, 70, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88], "privacy": [0, 11], "policy": [0, 23], "any": [0, 9, 11, 21, 23, 37, 38, 39, 41, 42, 49, 51, 65, 70, 72, 73, 74, 76, 85, 86, 90, 100], "day": [0, 23, 34, 37, 38, 46, 47, 70, 74, 76, 82, 85, 95], "last": [0, 23, 34, 37, 52, 65, 68, 85], "thing": [0, 9, 21, 23, 29, 34, 37, 38, 46, 51, 70, 72, 73, 74, 85, 88, 90], "you": [0, 8, 9, 13, 15, 21, 23, 29, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 60, 62, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 93, 94, 95, 100], "want": [0, 9, 21, 23, 37, 38, 46, 51, 60, 62, 65, 72, 74, 75, 76, 77, 80, 85, 90, 100], "is": [0, 5, 8, 9, 11, 13, 15, 21, 26, 29, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 59, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 76, 77, 80, 82, 83, 85, 86, 88, 90, 92, 93, 94, 100], "proprietary": 0, "formats": 0, "data": [0, 9, 21, 23, 29, 34, 38, 65, 74, 75, 82, 85, 86, 90, 93, 100], "lock": [0, 23, 30, 82], "with": [0, 6, 8, 9, 11, 15, 21, 23, 26, 29, 30, 34, 37, 38, 39, 41, 47, 49, 51, 52, 59, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88, 90, 93, 94, 95, 100, 107], "your": [0, 9, 21, 23, 34, 37, 38, 41, 42, 46, 62, 65, 70, 73, 74, 75, 77, 82, 85, 86, 90, 100], "sits": 0, "local": [0, 21, 23, 86], "folder": 0, "never": [0, 23, 29, 34, 37, 38, 41, 47, 70, 73, 75, 76, 77, 82, 100], "leave": [0, 23, 37, 86], "life": [0, 23, 34, 36, 37, 38, 49, 51, 52, 59, 60, 62, 63, 65, 70, 74, 76, 77, 82, 85, 86, 100, 120], "s": [0, 8, 9, 13, 21, 23, 26, 29, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 56, 60, 64, 65, 66, 68, 70, 73, 74, 76, 77, 80, 82, 85, 86, 88, 89, 90, 92, 93, 100], "work": [0, 9, 15, 21, 23, 34, 37, 38, 39, 41, 42, 51, 62, 65, 66, 70, 73, 74, 75, 76, 77, 80, 82, 85, 86, 92, 93, 94, 95], "held": [0, 37], "hostage": 0, "again": [0, 21, 23, 29, 37, 52, 74, 76, 77, 85], "plain": [0, 9, 23, 34, 52, 75, 82], "text": 0, "also": [0, 9, 15, 21, 23, 26, 34, 37, 38, 51, 68, 73, 74, 76, 82, 85, 86, 100], "gives": [0, 5, 11, 23, 38, 52, 62, 75, 76, 85, 86, 100], "unparalleled": 0, "interoperability": [0, 38], "use": [0, 9, 11, 15, 21, 23, 29, 34, 37, 38, 49, 51, 52, 65, 73, 75, 76, 82, 85, 86, 94, 100], "kind": [0, 9, 23, 47, 74, 85], "sync": 0, "encryption": 0, "processing": [0, 21, 23, 34, 74, 90], "that": [0, 9, 11, 15, 21, 23, 26, 29, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 59, 60, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 93, 94, 100], "works": [0, 23, 42, 46, 51, 68, 75, 77, 85, 93], "files": [0, 5, 23, 75], "md": [0, 86], "template": [0, 51, 82], "based": [0, 11, 21, 23, 34, 37, 38, 49, 52, 63, 72, 74, 76, 80, 82, 85, 86, 88, 100], "on": [0, 5, 9, 11, 13, 15, 21, 23, 30, 34, 37, 38, 41, 46, 47, 49, 51, 52, 62, 63, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88, 90, 92, 95, 100], "was": [0, 15, 21, 23, 34, 37, 38, 39, 41, 51, 62, 65, 70, 72, 73, 74, 75, 76, 80, 85, 86, 93], "designed": [0, 9, 23, 29, 37, 74, 86], "these": [0, 9, 21, 23, 29, 37, 38, 46, 51, 65, 70, 72, 74, 75, 76, 85, 86, 100], "criteria": [0, 5, 38, 51, 53, 86], "future": [0, 21, 23, 34, 37, 38, 39, 65, 68, 74, 75, 76, 85], "proof": 0, "store": [0, 21, 23, 34, 37, 51, 82], "locally1": 0, "as": [0, 9, 11, 13, 15, 21, 23, 26, 29, 34, 37, 38, 39, 41, 46, 47, 49, 51, 52, 60, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 94, 100], "not": [0, 5, 8, 9, 11, 15, 21, 23, 26, 29, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 59, 62, 65, 70, 73, 74, 76, 80, 82, 85, 86, 90, 92, 93, 94, 95, 100], "tied2": 0, "single": [0, 11, 21, 23, 34, 38, 62, 74, 75, 76, 85, 86, 94, 100], "editor": [0, 23], "statically": 0, "generated": [0, 13, 21, 23, 74, 82], "site": [0, 82], "browsing": 0, "publishing": [0, 23, 34, 88], "remain": [0, 34], "simple": [0, 9, 23, 29, 34, 37, 38, 70, 73, 74, 75, 77, 82, 85, 86, 90], "possible": [0, 21, 23, 34, 37, 38, 49, 51, 68, 73, 74, 75, 76, 85, 86], "whilst": 0, "being": [0, 11, 21, 23, 34, 37, 38, 39, 42, 46, 49, 51, 70, 73, 74, 75, 76, 82, 85, 100], "feature": [0, 21, 23, 34, 38, 51, 62, 70, 74, 86], "rich": [0, 82], "via": [0, 23, 85, 86], "plugins": [0, 5], "zettel": 0, "philosophy": [0, 38], "\u0438\u043d\u0442\u0435\u0440\u0435\u0441": [0, 21, 37, 40, 41, 42, 44, 46, 66, 70, 72, 76, 82, 86, 100, 122], "\u0442\u0435\u0445": [0, 21, 37, 38, 46, 83, 85, 88, 90], "\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430": [0, 13], "tutorial": [0, 34, 64, 74, 82], "srid": 0, "io": [0, 34], "readme": [0, 23], "com": [0, 5, 8, 9, 16, 21, 23, 34, 37, 75, 80, 82, 85, 89], "\u0441\u0440\u0430\u0432\u043d\u0435\u043d": [0, 46, 65, 92, 100], "multi": [0, 21, 85, 86, 88], "repository": [0, 9, 17, 23, 28, 37, 51, 76, 82, 115], "documentation": [0, 23, 37, 49, 51, 64, 76, 82, 86], "generator": 0, "tech": [0, 37, 38], "writers": [0, 75], "who": [0, 23, 37, 38, 39, 46, 49, 51, 62, 65, 73, 74, 75, 76, 85, 86, 90, 94], "writing": [0, 23, 37, 42, 46, 47, 53, 72, 74, 76, 77, 82, 85, 90], "asciidoc": 0, "compatible": 0, "favorite": [0, 76, 85, 88, 92], "apps": [0, 21, 23, 82], "aims": 0, "be": [0, 8, 9, 11, 21, 23, 26, 29, 34, 37, 38, 39, 41, 46, 47, 49, 51, 52, 53, 59, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88, 90, 94, 100], "extremely": [0, 37, 42, 76, 80, 100], "configurable": 0, "idea": [0, 23, 34, 38, 49, 52, 65, 73, 75, 85, 86, 94, 100], "another": [0, 9, 11, 21, 23, 26, 29, 34, 49, 51, 70, 72, 74, 82, 85, 86, 93, 100], "silo": 0, "instead": [0, 5, 21, 23, 37, 39, 42, 47, 49, 52, 70, 73, 75, 85, 86, 93, 100], "integrate": [0, 23, 29, 86], "into": [0, 9, 11, 15, 21, 23, 29, 34, 37, 38, 41, 49, 51, 52, 60, 62, 65, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 100], "existing": [0, 9, 21, 23, 37, 38, 46, 47, 66, 70, 73, 74, 82, 85, 95], "workflow": [0, 8, 82], "no": [0, 8, 21, 23, 26, 34, 37, 38, 42, 46, 49, 51, 52, 60, 62, 65, 70, 72, 73, 74, 76, 77, 82, 85, 86, 90, 100], "two": [0, 11, 15, 21, 26, 29, 34, 37, 38, 52, 65, 70, 73, 74, 75, 76, 82, 85, 86, 90, 95], "people": [0, 11, 23, 37, 38, 40, 41, 46, 49, 65, 68, 70, 73, 74, 75, 76, 85, 86, 88, 100], "are": [0, 5, 9, 11, 15, 21, 23, 29, 34, 37, 38, 40, 41, 42, 46, 47, 49, 51, 52, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 94, 100], "same": [0, 9, 21, 23, 26, 34, 37, 38, 39, 41, 52, 73, 74, 75, 76, 77, 85, 86, 90, 93], "multiple": [0, 23, 34, 74, 75, 77, 85, 86, 90, 100], "editors": [0, 74], "all": [0, 9, 11, 21, 23, 29, 34, 37, 38, 41, 42, 46, 47, 49, 51, 52, 60, 62, 64, 70, 72, 73, 74, 75, 76, 82, 85, 86, 90, 100], "stored": [0, 9, 21], "however": [0, 23, 34, 38, 46, 47, 51, 52, 70, 72, 73, 76, 85, 86, 100], "edit": [0, 74, 85], "many": [0, 9, 11, 15, 21, 23, 34, 37, 38, 46, 51, 62, 65, 68, 73, 74, 75, 76, 82, 85, 86, 92, 93, 95, 100], "different": [0, 21, 23, 29, 34, 38, 46, 51, 60, 65, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 100], "ways": [0, 15, 21, 23, 29, 34, 37, 38, 52, 73, 74, 75, 82, 85, 86, 90], "depending": [0, 74, 85, 100], "task": [0, 9, 21, 23, 38, 73, 82, 86, 92], "100": [0, 41, 51, 62, 70, 73, 75, 85], "will": [0, 9, 21, 23, 26, 29, 34, 37, 38, 42, 46, 47, 49, 51, 52, 65, 68, 72, 73, 74, 75, 76, 77, 82, 85, 86, 92, 100], "always": [0, 9, 14, 21, 23, 34, 38, 46, 65, 70, 73, 74, 75, 76, 85, 86, 100], "completely": [0, 9, 23, 34, 37, 46, 65, 73, 85], "join": 0, "community": [0, 34, 37, 38, 76, 82, 85, 86], "help": [0, 23, 29, 37, 38, 41, 51, 62, 65, 73, 77, 82, 83, 85, 86, 100], "us": [0, 9, 21, 23, 34, 37, 38, 41, 46, 51, 52, 62, 65, 68, 70, 72, 74, 75, 76, 85, 86, 100], "ideal": [0, 34, 37, 38], "note": [0, 15, 21, 23, 34, 38, 46, 52, 74, 85], "taking": [0, 23, 38, 62, 73, 82, 85], "app": [0, 21, 23, 37], "why": [0, 21, 23, 29, 34, 37, 38, 51, 65, 70, 74, 75, 82, 86, 100], "create": [0, 11, 21, 23, 34, 38, 49, 51, 52, 74, 82, 85, 86, 100], "there": [0, 8, 9, 11, 15, 21, 23, 34, 37, 38, 39, 41, 42, 46, 49, 51, 65, 70, 72, 73, 74, 75, 76, 77, 80, 85, 86, 100], "but": [0, 5, 9, 11, 15, 21, 23, 29, 34, 37, 38, 39, 41, 42, 46, 49, 51, 52, 59, 60, 62, 65, 70, 72, 73, 74, 75, 76, 77, 80, 85, 86, 93, 94, 100], "mobile": [0, 37, 52], "space": [0, 23, 38, 75, 76, 80, 82, 83, 86, 100], "lacking": 0, "good": [0, 9, 23, 29, 37, 38, 42, 52, 53, 65, 70, 72, 73, 74, 75, 76, 82, 85, 86, 95, 100], "which": [0, 9, 11, 13, 15, 21, 23, 34, 37, 38, 39, 41, 51, 52, 60, 64, 65, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 93], "give": [0, 11, 37, 38, 46, 73, 74, 85, 86], "control": [0, 11, 23, 26, 34, 37, 38, 47, 72, 73, 76, 85, 86], "over": [0, 9, 23, 29, 34, 37, 38, 39, 41, 51, 62, 65, 73, 74, 76, 82, 85, 86, 94], "operate": [0, 86], "protocols": 0, "support": [0, 21, 23, 34, 38, 46, 49, 51, 74, 82, 85, 86, 92, 94], "\u043a\u043b\u0430\u0441\u0441": [0, 8, 9, 15, 23, 30, 46, 70, 74, 75, 77, 85, 90, 102], "\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442": [0, 13, 38, 82, 85, 92, 94, 100], "\u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d": [0, 93, 100], "\u0433\u0435\u043d\u0435\u0440\u0430\u0446": 0, "\u0431\u043b\u043e\u0433": [0, 23, 75], "\u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b": [0, 34, 82, 92], "\u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d": [0, 23, 38, 100], "\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430": [0, 5, 9, 15, 21, 23, 30, 34, 37, 38, 74, 82, 85, 90], "\u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d": [0, 5, 38, 46, 72, 85, 86, 100], "\u0440\u0430\u0437\u043c\u0435\u0442\u043a": 0, "shortcodes": 0, "\u0443\u043f\u0440\u043e\u0449\u0430": [0, 8, 37, 73, 74, 75], "\u0432\u0441\u0442\u0430\u0432\u043a": [0, 23], "\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c": [0, 5, 56, 82], "\u0444\u043e\u0440\u043c\u0443\u043b": [0, 89], "\u0441\u043d\u043e\u0441\u043e\u043a": 0, "\u0441\u0441\u044b\u043b\u043e\u043a": 0, "\u0442\u0432\u0438\u0442": 0, "\u0432\u0438\u0434\u0435": [0, 21, 66, 73, 82, 95], "\u044d\u043b\u0435\u043c\u0435\u043d\u0442": [0, 5, 11, 21, 37, 38, 42, 62, 73, 74, 75, 77, 85, 88, 90, 92, 94, 100], "\u043d\u0430\u0438\u0431\u043e\u043b": [0, 8, 9, 21, 23, 38, 42, 43, 47, 64, 66, 73, 75, 83, 85, 86, 95, 121], "\u0438\u0437\u0432\u0435\u0441\u0442\u043d": [0, 5, 9, 13, 21, 23, 38, 40, 53, 56, 65, 73, 75, 76, 83, 85, 86, 88, 92, 100], "c\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 0, "hugo": 0, "\u043d\u0430\u043f\u0438\u0441\u0430": [0, 21, 47, 72, 74, 77, 83, 85], "go": [0, 9, 11, 21, 23, 34, 37, 38, 42, 47, 65, 68, 70, 73, 74, 76, 77, 82, 85, 86], "\u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f": [0, 21, 23, 52], "\u0431\u0438\u043d\u0430\u0440\u043d": 0, "\u0438\u0441\u043f\u043e\u043b\u043d\u044f": [0, 23], "jekyll": 0, "\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a": [0, 102], "ruby": [0, 72, 75, 82, 85], "p\u0430ges": 0, "\u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": [0, 21, 23, 85], "\u0433\u0440\u0443\u043f\u043f": [0, 30, 34, 38, 40, 73, 86, 90, 92, 100], "javascript": 0, "\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a": [0, 9, 72, 86], "gastby": 0, "next": [0, 34, 37, 38, 49, 62, 65, 74, 80, 85, 86], "nuxt": 0, "vuepress": 0, "\u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d": [0, 8, 23, 75, 86], "hexo": 0, "eleventy": 0, "mkdocs": 0, "pelican": 0, "middleman": 0, "\u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d": [0, 53], "\u043a\u0440\u0430\u0441\u0438\u0432": [0, 34, 73, 85, 90, 100], "\u0434\u0438\u0437\u0430\u0439\u043d": [0, 37, 70, 72, 74, 75, 83, 85], "material": [0, 82], "doks": 0, "docsy": 0, "just": [0, 11, 21, 23, 29, 34, 37, 38, 39, 42, 46, 47, 49, 51, 52, 60, 65, 70, 72, 73, 74, 76, 77, 82, 85, 86, 88, 90, 92, 95, 100], "docs": [0, 34, 73, 82], "theme": 0, "\u043d\u0430\u0446\u0435\u043b": [0, 86], "\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d": 0, "\u043a\u043d\u0438\u0436\u043d": 0, "c": [0, 5, 9, 14, 15, 21, 23, 30, 34, 37, 38, 40, 41, 46, 66, 68, 70, 74, 75, 76, 80, 82, 85, 93], "\u043e\u0433\u043b\u0430\u0432\u043b\u0435\u043d": 0, "\u0441\u043b\u0435\u0432": 0, "mdbook": 0, "\u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d": [0, 9, 23, 37, 73, 82], "\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d": [0, 23, 75], "rust": 0, "\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f": 0, "jupyterbook": 0, "bookdown": 0, "\u0441\u043f\u0438\u0441\u043e\u043a": [0, 5, 34, 38, 81, 83, 85, 86, 88, 91, 92, 93, 94, 95, 135, 138], "\u043f\u043e\u043b\u0443\u044f\u0440\u043d": 0, "\u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442": [0, 8, 9, 11, 23, 34, 37, 53, 74], "imdone": 0, "core": [0, 23, 34, 37, 75, 76, 82, 85, 86, 100], "kanban": [0, 51, 52, 70, 82, 86, 95], "processor": [0, 23], "coddx": 0, "alpha": 0, "board": [0, 37, 73, 86], "manages": [0, 86], "tasks": [0, 9, 23, 38, 51, 74, 86, 90], "save": [0, 5, 9, 21, 23, 37, 42, 51, 76], "them": [0, 11, 21, 23, 29, 34, 37, 38, 46, 51, 53, 62, 72, 73, 74, 75, 76, 77, 80, 85, 86, 89, 94], "file": [0, 5, 37, 75, 76], "orgzly": 0, "outliner": 0, "notebooks": 0, "code": [0, 5, 9, 11, 13, 15, 21, 23, 29, 34, 37, 38, 46, 47, 51, 57, 60, 62, 66, 68, 70, 72, 73, 74, 75, 76, 77, 86, 89, 90, 93, 95, 100, 127], "joplin": 0, "an": [0, 5, 9, 11, 15, 21, 23, 26, 29, 34, 37, 38, 39, 41, 49, 51, 52, 62, 65, 68, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 94, 100], "do": [0, 9, 11, 15, 21, 23, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 59, 62, 65, 66, 72, 73, 74, 76, 82, 85, 86, 90, 100], "application": [0, 8, 9, 13, 19, 21, 23, 34, 38, 41, 51, 52, 64, 72, 75, 76, 82, 85, 86, 100, 109], "synchronization": 0, "capabilities": [0, 23, 34, 59, 65, 86], "windows": 0, "macos": 0, "linux": [0, 82], "ios": 0, "taskjuggler": 0, "modern": [0, 65, 74, 82, 90], "powerful": [0, 9, 38, 60, 62, 85, 86, 90], "free": [0, 15, 21, 39], "software": [0, 5, 8, 9, 11, 15, 21, 23, 26, 29, 34, 37, 38, 40, 41, 42, 46, 49, 51, 52, 53, 59, 60, 62, 63, 64, 65, 66, 67, 68, 70, 72, 73, 75, 76, 77, 80, 82, 90, 92, 100, 130], "project": [0, 23, 37, 38, 42, 46, 49, 51, 52, 64, 65, 68, 72, 74, 76, 77, 80, 82, 85, 86, 100], "tool": [0, 23, 51, 60, 62, 73, 90], "new": [0, 5, 8, 9, 15, 21, 23, 34, 37, 38, 46, 47, 51, 60, 62, 65, 70, 72, 74, 75, 76, 77, 82, 85, 86, 88, 90], "approach": [0, 5, 9, 15, 21, 23, 34, 37, 38, 51, 52, 60, 62, 65, 66, 70, 74, 75, 76, 82, 85, 86], "planning": [0, 37, 38, 51, 59, 60, 62, 65, 73, 74, 76, 80, 82, 83, 86, 95], "tracking": [0, 38], "more": [0, 9, 11, 13, 15, 21, 23, 29, 34, 37, 38, 39, 40, 46, 47, 49, 51, 52, 62, 64, 65, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88, 90, 100], "flexible": [0, 70, 85], "superior": [0, 5, 23, 37], "commonly": [0, 37], "used": [0, 5, 9, 21, 23, 29, 34, 37, 38, 47, 52, 62, 65, 70, 73, 74, 75, 76, 82, 85, 86, 94], "gantt": [0, 65], "chart": [0, 34, 65], "editing": 0, "tools": [0, 23, 37, 38, 65, 73, 76, 82, 85, 86], "\u0438\u043c\u043f\u043e\u0440\u0442\u0435\u0440": 0, "jira": 0, "org": [0, 34, 62, 82, 86, 92, 95], "download": [0, 5, 34, 82], "workshop": [0, 38, 82, 86], "tj3": 0, "manual": [0, 38, 51, 73], "\u043f\u0440\u0438\u043c\u0435\u0440": [0, 8, 9, 21, 23, 30, 34, 38, 39, 70, 72, 73, 74, 82, 85, 86, 90, 92, 93, 97, 98, 100, 102], "\u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043c": [0, 15], "\u043d\u0430\u0447\u0430\u043b": [0, 23, 37, 40, 72, 76, 83, 85], "\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d": [0, 5, 9, 21, 23, 37, 38, 39, 64, 72, 73, 75, 76, 86, 88, 92], "\u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432": [0, 5, 21, 23, 38, 73, 82, 86, 88], "myst": 0, "parser": 0, "\u0440\u043e\u043b": [0, 23, 38, 40, 73, 75, 83, 85, 87, 88, 95, 100, 102, 137], "\u043c\u043e\u0441\u0442": 0, "docutils": 0, "it": [0, 1, 8, 9, 11, 13, 15, 21, 26, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 59, 60, 62, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 89, 90, 92, 93, 94, 96, 99, 100, 105], "commonmark": 0, "\u0432\u0430\u0440\u0438\u0430\u043d\u0442": [0, 5, 8, 9, 11, 13, 21, 23, 34, 37, 38, 70, 72, 73, 77, 82, 83, 85, 88, 90, 92, 93], "\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446": 0, "m2r": 0, "converter": 0, "mdtorst": 0, "library": [0, 23, 52, 75, 82], "convert": 0, "restructed": 0, "rst": [0, 51], "markor": 0, "f": [0, 21, 23, 37, 38, 46, 82, 85, 86], "droid": 0, "google": [0, 34, 82], "play": [0, 23, 74], "termux": 0, "unix": [0, 82], "like": [0, 9, 11, 21, 23, 29, 34, 38, 41, 46, 47, 51, 73, 74, 75, 76, 80, 85, 86, 100], "environment": [0, 21, 23, 37, 38, 51, 65, 76, 85, 86], "python3": 0, "first": [0, 15, 21, 23, 34, 37, 38, 42, 46, 47, 72, 73, 74, 76, 77, 82, 85, 86, 88, 89, 94, 95, 100], "integrated": [0, 49, 86], "mgit": 0, "working": [0, 23, 37, 49, 51, 62, 65, 66, 70, 72, 73, 74, 76, 77, 82, 85, 86, 90, 95, 100], "copy": [0, 21, 23, 26, 34, 85], "1writer": 0, "beautiful": [0, 21, 88], "ia": 0, "writer": 0, "award": 0, "winning": [0, 39, 66, 74], "design": [0, 5, 8, 9, 11, 19, 21, 23, 26, 34, 37, 38, 40, 41, 46, 49, 56, 59, 60, 64, 65, 66, 67, 68, 70, 73, 75, 76, 78, 80, 86, 90, 92, 94, 95, 100, 109, 130, 133], "delivers": [0, 86], "essential": [0, 37, 38, 51, 52, 62, 64, 65, 66, 73, 74, 76, 82, 86, 90, 100], "experience": [0, 21, 23, 29, 37, 38, 46, 65, 68, 74, 77, 82, 85, 86, 88], "editorial": 0, "great": [0, 21, 23, 37, 38, 73, 74, 75, 82, 85, 86, 95], "automation": [0, 82], "scripts": [0, 86], "unofficial": [0, 82], "itexteditors": 0, "roundup": 0, "\u0441\u0435\u0440\u0432\u0438\u0441": [0, 5, 23, 86], "\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d": [0, 21, 23, 34, 46, 75, 85, 89], "\u043f\u0440\u0435\u0434\u0435\u043b": [0, 8, 23, 37, 40, 65, 73, 74, 75, 76, 80, 83, 86, 90, 92, 100], "\u0438\u0434\u0435": [0, 23, 37, 38, 76, 85, 86, 88], "markown": 0, "gui": [0, 5], "\u043a\u043b\u0438\u0435\u043d\u0442": [0, 9, 11, 15, 21, 23, 100], "\u043d\u0435\u0434\u0430\u0432\u043d": [0, 38, 75, 85, 89, 94], "\u043f\u043e\u044f\u0432": [0, 8, 13, 21, 34, 37, 38, 40, 47, 72, 75, 76, 85, 86], "\u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a": [0, 75, 82, 92], "\u043e\u0437\u043d\u0430\u0447\u0430": [0, 21, 23, 30, 37, 40, 41, 72, 73, 74, 75, 76, 83, 85], "\u0448\u0430\u0440": [0, 74, 90, 100], "\u0434\u0432\u0443\u043c": [0, 8, 26, 38, 86, 94, 100, 102], "\u043f\u0440\u043e\u0431\u043e\u0432\u0430": [0, 9, 38], "\u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u0442": 0, "\u0440\u0430\u0441\u0441\u043a\u0430\u0436": [0, 38], "\u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442": 0, "\u043f\u043e\u043b\u0443\u0447": [0, 9, 21, 23, 30, 34, 56, 70, 73, 75, 82, 83, 85, 88, 92, 100, 102], "\u0437\u0430\u0442": [0, 5, 9, 21, 23, 34, 70, 74, 75, 77, 82, 85, 94, 95], "\u0434\u0430\u0435\u0442": [0, 5, 8, 11, 23, 46, 51, 70, 74, 75, 82, 85, 86, 93], "\u0434\u0435\u043b\u044c\u043d": 0, "\u0441\u043e\u0432\u0435\u0442": [0, 23, 38, 40, 46, 82, 92], "\u043f\u043e\u043c\u0438\u043c": [0, 23, 38, 86], "publish": [0, 5, 9, 23, 34], "\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430": 0, "\u043c\u0430\u0441\u0441\u043e\u0432": [0, 37, 72, 75, 76], "\u0438\u043c\u043f\u043e\u0440\u0442": [0, 11], "\u0432\u0441\u0442\u0440\u0435\u0447\u0430": [0, 38, 65, 75, 82, 100], "so": [0, 9, 13, 21, 23, 34, 37, 38, 39, 42, 46, 49, 51, 52, 62, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 95, 100], "importer": [0, 9], "\u044d\u043a\u0441\u043f\u043e\u0440\u0442": [0, 5, 9], "evernote2md": 0, "enex": 0, "ever2simple": 0, "migrate": [0, 65], "from": [0, 8, 9, 11, 21, 23, 29, 34, 37, 38, 39, 42, 51, 52, 64, 65, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 93, 95], "simplenote": 0, "formatting": 0, "ever2text": 0, "exports": 0, "\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a": [0, 8, 9, 21, 23, 30, 34, 41, 46, 47, 72, 74, 75, 77, 85, 86, 88, 90, 92, 94, 100], "\u043a\u043e\u0440\u043e\u0431\u043e\u0447\u043d": 0, "feed": [0, 96], "contrib": 0, "yasfb": 0, "lsaffre": 0, "sphinxfeed": 0, "prometheusresearch": 0, "sphinxcontrib": 0, "newsfeed": 0, "issues": [0, 23, 26, 38, 65, 72, 77, 85, 86], "2": [0, 8, 11, 21, 23, 29, 34, 37, 38, 46, 49, 51, 52, 64, 65, 66, 70, 73, 74, 75, 76, 77, 82, 85, 86, 90, 100, 102], "integrations": [0, 23], "rssfeed": 0, "plugin": [0, 5, 75], "wbernest": 0, "bokker": 0, "bot": 0, "thefeedreaderbot": 0, "www": [0, 5, 34, 76, 85, 89, 92], "integromat": 0, "en": [0, 9, 82], "bots": 0, "faq": 0, "jdillard": 0, "needs": [0, 21, 23, 34, 37, 38, 49, 52, 59, 62, 65, 74, 75, 76, 77, 80, 86, 100], "allows": [0, 9, 23, 34, 37, 62, 65, 74, 76, 85], "definition": [0, 21, 23, 34, 37, 38, 51, 59, 60, 74, 75, 76, 77, 80, 101], "linking": 0, "filtering": 0, "need": [0, 15, 21, 23, 26, 34, 37, 38, 46, 47, 49, 51, 52, 65, 70, 72, 73, 74, 75, 76, 77, 80, 85, 86, 100], "objects": [0, 9, 11, 21, 23, 25, 26, 29, 41, 51, 72, 73, 74, 75, 77, 82, 85, 90, 100, 113], "default": [0, 9, 23, 34, 85], "specifications": [0, 29, 37, 49, 51, 65, 76], "implementations": [0, 23, 38, 73], "test": [0, 47, 49, 51, 72, 73, 74, 82, 86, 93], "cases": [0, 15, 21, 23, 34, 38, 41, 46, 49, 51, 52, 75, 86], "traceability": [0, 49], "extension": [0, 9, 21, 49, 52, 64, 74, 75, 82], "defining": [0, 23, 51], "items": [0, 34, 38, 49, 51, 52, 64, 65, 74, 82, 86, 90], "relations": [0, 5, 75, 82], "between": [0, 9, 11, 21, 23, 26, 29, 37, 38, 42, 46, 47, 51, 52, 62, 72, 74, 75, 76, 77, 82, 85, 86, 100], "those": [0, 9, 21, 23, 37, 38, 41, 42, 46, 60, 65, 70, 74, 75, 76, 77, 85, 86, 90, 100], "e": [0, 8, 9, 21, 23, 37, 38, 39, 46, 49, 53, 62, 64, 65, 73, 76, 77, 82, 85, 86, 88], "g": [0, 8, 23, 30, 34, 38, 46, 49, 60, 64, 74, 77, 82, 86, 88, 90], "iso26262": 0, "projects": [0, 23, 37, 38, 49, 51, 52, 64, 65, 72, 74, 76, 77, 82, 85, 86], "kroki": 0, "embed": 0, "plantuml": [0, 5, 82], "dot": 0, "etc": [0, 21, 23, 34, 37, 38, 40, 65, 76, 82, 86, 100], "diagrams": [0, 82], "\u0441\u043e\u0441\u0442\u043e\u044f\u043d": [0, 5, 9, 11, 15, 21, 23, 38, 47, 72, 82, 85, 86, 100, 102], "\u0440\u0430\u0437\u0432\u0438\u0442": [0, 13, 15, 38, 70, 73, 85, 86, 92, 94], "\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d": [0, 77, 82], "\u043f\u043e\u043a": [0, 5, 8, 9, 11, 21, 26, 34, 38, 77, 82, 85, 88, 90, 92], "\u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440": [0, 34], "\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a": [0, 5, 8, 9, 11, 23, 37, 41, 44, 46, 51, 66, 70, 72, 73, 74, 75, 82, 90, 122], "\u043e\u0442\u0434\u0430\u043b\u0435\u043d": 0, "\u043f\u0435\u0440\u0441\u043f\u0435\u043a\u0442\u0438\u0432": [0, 40, 75], "\u043f\u0440\u0438\u0441\u043f\u043e\u0441\u043e\u0431": 0, "\u043c\u043e\u043c\u0435\u043d\u0442": [0, 5, 8, 9, 11, 21, 23, 34, 37, 38, 47, 52, 68, 72, 73, 74, 76, 77, 83, 85, 86, 88, 90, 95, 100], "\u0441\u0442\u043e": [0, 9, 23, 56, 82, 83, 85, 86], "\u0432\u044b\u0431\u0438\u0440\u0430": [0, 38, 76], "\u043f\u043e\u0434\u043f\u0438\u0441\u043e\u043a": 0, "\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430": [0, 5], "\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440": [0, 5, 8], "\u043f\u0440\u0438\u043d\u044f\u0442": [0, 21, 23, 37, 38, 70, 76, 77, 88, 92, 94], "\u043a\u043e\u043c\u043c\u0438\u0442": [0, 5, 23], "\u043a\u043e\u043c\u043c": 0, "\u0441\u043e\u0434\u0435\u0440\u0436": [0, 9, 23, 74, 77, 82, 85, 90], "\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d": [0, 21, 23], "\u043f\u0440\u0438\u043d\u0438\u043c\u0430": [0, 8, 9, 15, 23, 37, 38, 40, 68, 70, 75, 82, 86], "\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a": [0, 5, 51, 72, 85], "p": [0, 38, 41, 65, 73, 75, 82, 86, 88, 93], "\u043b\u0438\u0447\u043d": [0, 13, 38, 75, 82, 85], "\u0437\u0430\u043f\u0438\u0441\u043d": 0, "\u043a\u043d\u0438\u0436\u043a": 0, "\u0443\u0447\u0435\u0431\u043d": [0, 82, 88], "\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a": [0, 92], "soft": [1, 23, 37, 82, 89, 96, 105], "skills": [1, 49, 82, 86, 89, 96, 105], "saga": [2, 8, 21, 82, 106], "transaction": [2, 21, 23, 106], "\u0440\u0430\u0437\u0434\u0435\u043b": [3, 4, 5, 8, 9, 10, 11, 14, 15, 16, 18, 21, 23, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 56, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 86, 88, 89, 90, 92, 93, 94, 95, 100, 102], "zakrevsky": [3, 4, 5, 8, 9, 10, 11, 14, 15, 18, 21, 23, 29, 30, 34, 37, 38, 39, 40, 41, 42, 46, 47, 49, 51, 52, 53, 56, 59, 60, 62, 63, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 86, 88, 89, 90, 92, 93, 94, 95], "\u0438\u0441\u0447\u0435\u0440\u043f\u0430": [5, 8], "\u043d\u0435\u0447\u0438\u0442\u0430": [5, 75], "\u043d\u0435\u0443\u043f\u0440\u0430\u0432\u043b\u044f": 5, "\u0432\u044b\u0440\u043e\u0432\u043d\u044f": [5, 37], "\u0431\u0435\u0437\u0443\u0441\u043f\u0435\u0448\u043d": [5, 90], "\u043d\u0430": [5, 8, 9, 10, 11, 13, 15, 21, 23, 26, 34, 37, 39, 40, 41, 42, 47, 49, 52, 53, 56, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 80, 83, 86, 88, 89, 91, 93, 94, 100, 102, 138], "\u0441\u0435\u0440\u0432\u0435\u0440": [5, 21, 23, 38], "\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430": [5, 100], "\u043f\u043e": [5, 8, 9, 11, 13, 15, 16, 21, 23, 34, 37, 38, 41, 46, 47, 51, 52, 53, 56, 60, 62, 64, 65, 67, 68, 70, 72, 73, 74, 75, 76, 77, 83, 85, 89, 90, 92, 93, 94, 102, 130], "miro": [5, 82], "\u0432\u044b\u043d\u0443\u0436\u0434\u0430": [5, 37, 38, 56, 76, 92], "\u0437\u043d\u0430\u0447\u0438\u043c": [5, 83], "\u043f\u043e\u043a\u0438\u0434\u0430": [5, 23], "\u043f\u0435\u0440\u0438\u043c\u0435\u0442\u0440": 5, "\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d": [5, 21, 26, 47, 73, 74, 90], "\u043b\u0438\u0446\u0435\u043d\u0437\u0438\u043e\u043d": 5, "\u043d\u0430\u0445\u043e\u0434": [5, 23, 26, 34, 38, 40, 41, 47, 65, 70, 73, 74, 75, 85, 86, 88, 90, 92, 94, 102], "\u0434\u0430\u0432\u043b\u0435\u043d": [5, 38, 88], "\u0433\u0435\u043e\u043f\u043e\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a": 5, "\u043a\u0430\u043a": [5, 8, 11, 12, 13, 15, 16, 21, 23, 26, 29, 30, 34, 37, 38, 41, 42, 46, 47, 51, 52, 56, 60, 65, 68, 72, 73, 74, 75, 76, 77, 80, 81, 82, 85, 86, 89, 90, 91, 92, 94, 95, 96, 100, 102, 135, 138], "\u0432\u0432\u0438\u0434": [5, 23], "\u043d\u0435\u043c": [5, 8, 21, 30, 74, 76, 83, 85, 86, 102], "\u043d\u0435\u043f\u043b\u043e\u0445": [5, 37, 64, 74, 82, 86, 89], "\u043d\u0430\u0434\u0435\u0436\u0434": [5, 70], "\u043f\u043e\u0434\u0430": 5, "domorobo": 5, "\u0441\u044b\u0440\u043e\u0432\u0430\u0442": 5, "\u043f\u0440\u043e\u0446\u0435\u0441\u0441": [5, 8, 15, 21, 23, 37, 38, 40, 46, 47, 51, 56, 64, 65, 70, 74, 75, 76, 77, 82, 85, 86, 88, 89, 90, 93, 94, 100], "\u043f\u0440\u0438\u0432\u043b\u0435\u043a\u043b": 5, "figure": [5, 23, 37, 51, 65, 70, 74, 76, 77, 82, 85, 86, 94], "13": [5, 8, 21, 23, 29, 38, 74, 82, 83, 100], "agile": [5, 8, 23, 29, 40, 41, 46, 61, 62, 64, 65, 66, 68, 70, 71, 77, 83, 85, 88, 92, 94, 100, 129, 132], "modeling": [5, 8, 21, 23, 30, 34, 37, 52, 76, 100], "archimate": [5, 76, 82], "jean": [5, 82], "baptiste": [5, 82], "sarrodie": [5, 82], "presentation": [5, 21, 82], "enterprise": [5, 13, 23, 34, 38, 51, 52, 64, 65, 72, 82, 100], "modelling": 5, "scale": [5, 23, 34, 37, 38, 46, 49, 74, 82, 86], "programme": [5, 82], "\u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430": [5, 9, 11, 38], "\u043e\u0431\u043d\u0430\u0440\u0443\u0436": [5, 9, 11, 46, 47, 75, 83, 92, 102], "\u0441": [5, 8, 9, 11, 15, 23, 30, 34, 37, 38, 40, 41, 42, 46, 47, 51, 56, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 89, 90, 92, 93, 94, 100, 102], "\u043b\u0435\u0433\u043a\u043e\u0441\u0442": [5, 73, 75, 86, 93], "\u0440\u0430\u0437\u0432": [5, 74, 75], "\u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446": [5, 21], "\u0434\u0440\u0443\u0433": [5, 8, 9, 11, 15, 21, 23, 26, 29, 30, 34, 37, 38, 39, 40, 42, 46, 47, 51, 52, 56, 70, 72, 74, 75, 77, 80, 83, 85, 88, 90, 92, 93, 94, 100, 102], "\u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a": [5, 8, 56, 83, 86, 90, 92, 102], "\u043a\u043b\u0438\u043a": 5, "\u043c\u044b\u0448\u043a": 5, "\u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d": 5, "jarchi": 5, "\u043f\u043e\u0434\u0442\u044f\u0433\u0438\u0432\u0430": 5, "\u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430": [5, 88], "\u0444\u043e\u043d\u043e\u0432": [5, 82, 102], "\u043d\u043e\u0442\u0430\u0446": [5, 82], "\u0446\u0432\u0435\u0442": 5, "\u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d": [5, 75, 85], "10": [5, 8, 21, 23, 34, 37, 38, 52, 65, 70, 74, 76, 80, 82, 85, 86, 95], "business": [5, 21, 23, 34, 37, 38, 39, 40, 46, 49, 51, 52, 62, 64, 65, 66, 70, 73, 76, 80, 82, 86, 88, 100], "process": [5, 21, 30, 34, 37, 38, 46, 51, 52, 62, 64, 65, 66, 70, 73, 74, 75, 76, 77, 82, 85, 86, 100], "cooperation": 5, "viewpoint": [5, 21], "premise": [5, 37], "\u0437\u0430\u043a\u0440\u044b\u0442": [5, 85], "under": [5, 37, 38, 49, 51, 73, 74, 76, 85, 86, 100], "mit": [5, 82], "license": [5, 51], "\u043d\u0430\u043b\u0438\u0447": [5, 21, 74, 102], "\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f": [5, 11, 30, 37, 38, 64, 65, 73, 75, 77, 82, 100, 102], "\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d": [5, 8, 9, 11, 21, 23, 38, 65, 73, 74, 82, 86, 90, 92], "\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442": [5, 11, 21, 23, 34, 41, 65, 73, 75, 76, 77, 86, 92, 93, 94], "\u0441\u043b\u0435\u0434\u0441\u0442\u0432": [5, 11, 37, 38, 88, 93], "\u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430": [5, 13], "\u0432\u044b\u0434\u0435\u043b\u044f": [5, 11, 64, 92, 95], "\u0441oupling": 5, "\u0441ohesion": 5, "\u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a": [5, 30, 38, 60, 75, 82, 85, 90, 100], "\u0442\u043e\u0447\u043d\u043e\u0441\u0442": [5, 37, 65, 80, 83, 86, 100], "\u043d\u0430\u0438\u043b\u0443\u0447\u0448": [5, 38, 41, 65, 86], "\u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430": [5, 8, 9, 11, 21, 23, 34, 38, 64, 70, 73, 74, 75, 77, 85, 86, 90, 92, 93], "\u043c\u0433\u043d\u043e\u0432\u0435\u043d": [5, 72, 85], "\u043f\u0435\u0440\u0435\u0439\u0442": [5, 8, 94], "context": [5, 23, 29, 34, 37, 38, 49, 75, 76, 86, 92, 100, 101], "map": [5, 82, 86], "\u0432\u043a\u043b\u0430\u0434\u043a": 5, "properties": [5, 21, 23, 30, 34, 38, 52], "\u0432\u044b\u0431\u0440\u0430": [5, 23, 37, 38, 64, 73, 75, 88, 90], "\u0441\u0435\u043a\u0446": 5, "analisis": 5, "\u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430": [5, 85], "\u0442\u0440\u0430\u0441\u0441\u0438\u0440\u043e\u0432\u043a": 5, "\u0434\u043e": [5, 8, 21, 23, 30, 37, 41, 47, 65, 70, 73, 74, 75, 76, 82, 83, 86, 88, 90, 92], "\u043f\u043e\u0441\u043b": [5, 8, 15, 21, 23, 30, 34, 37, 38, 46, 72, 74, 75, 76, 85, 86, 90, 102], "\u043d\u0435\u0433": [5, 8, 23, 47, 52, 85, 86, 88, 92, 94], "\u043e\u043a\u043d": [5, 74], "window": [5, 38, 74], "navigator": 5, "\u0434\u0432\u0435": [5, 11, 21, 23, 34, 40, 75, 76, 85, 86, 88, 100, 102], "\u043a\u043d\u043e\u043f\u043a": 5, "show": [5, 74, 82], "target": [5, 15, 21, 23, 51], "\u0440\u0430\u0437\u0431\u0438\u0435\u043d": [5, 37, 74, 86, 90], "\u043d\u0435\u043a": [5, 8, 9, 88], "\u043f\u0440\u0438\u0437\u043d\u0430\u043a": [5, 9, 29, 75, 82, 86, 92], "\u0431\u0430\u0437\u043e\u0432": [5, 52, 77, 82, 88, 100], "\u0441\u0446\u0435\u043d\u0430\u0440": [5, 8, 23, 51, 83, 85, 92], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d": [5, 8, 9, 11, 15, 21, 23, 26, 37, 38, 40, 65, 66, 70, 72, 75, 85, 86, 90, 94, 102], "\u0446\u0435\u043b\u0435\u0432": 5, "\u043e\u0442\u0440\u0430\u0436": [5, 102], "\u043e\u0441\u0442\u0430\u043b\u044c\u043d": [5, 8, 21, 23, 38, 40, 70, 82, 83, 85, 86, 90], "\u0443\u0434\u0435\u0448\u0435\u0432\u043b\u044f": 5, "\u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d": [5, 9, 70, 74], "\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d": [5, 9, 13, 23, 46, 56, 70, 72, 74, 76, 85, 86], "\u043d\u0438\u043c": [5, 15, 23, 38, 70, 73, 75, 80, 83, 88, 95], "\u0434\u043e\u0431\u0430\u0432\u043b\u044f": [5, 37, 46, 70, 74, 85], "\u043e\u0442\u043a\u0440\u044b\u0432\u0430": [5, 9, 21, 37, 74, 88], "\u0438\u0441\u0442\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 5, "\u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d": [5, 30, 95], "\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449": [5, 23, 34, 40, 62, 74, 82, 85, 86, 94], "\u0436\u0443\u0440\u043d\u0430\u043b\u0438\u0440\u043e\u0432\u0430\u043d": 5, "\u0432\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d": [5, 23], "\u043e\u0442\u0432\u0435\u0442\u0432\u043b\u0435\u043d": 5, "\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d": [5, 21, 37, 82], "\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a": [5, 23, 37, 38, 41, 42, 46, 47, 51, 52, 62, 64, 65, 67, 68, 70, 72, 73, 74, 75, 76, 80, 82, 83, 84, 86, 89, 90, 92, 93, 130, 136], "\u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432\u043d": [5, 83, 92], "\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446": [5, 86], "motivation": [5, 21, 38, 75], "elements": [5, 9, 21, 37, 51, 62, 72, 73, 74, 75, 77, 82, 86], "stakeholder": [5, 37, 38, 75], "driver": [5, 9, 86], "assessment": [5, 64, 82], "goal": [5, 9, 21, 23, 37, 38, 51, 52, 73, 74, 76, 77, 86, 90, 100], "outcome": [5, 38], "principle": [5, 15, 21, 23, 49, 52, 73, 74, 85, 86, 93], "requirement": [5, 38, 51, 52, 70], "constraint": 5, "\u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446": [5, 95], "\u0432\u043b\u0438\u044f\u043d": [5, 38, 41, 64, 72, 75, 80, 86, 88], "\u0444\u0438\u043a\u0441\u0430\u0446": [5, 92], "\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d": [5, 16, 21, 23, 34, 37, 38, 40, 47, 49, 51, 53, 65, 70, 74, 75, 76, 80, 82, 83, 86], "\u0432\u043e\u043f\u043b\u043e\u0449\u0435\u043d": [5, 56, 73], "twin": [5, 77], "peak": [5, 23], "\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442": 5, "\u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430": [5, 23, 38], "\u0434\u0440\u0430\u0439\u0432\u0435\u0440": 5, "\u0432\u043b\u0438\u044f": [5, 38, 40, 46, 70, 74, 76, 83, 102], "\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a": [5, 37, 64, 86], "\u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430": [5, 11, 41, 74, 76, 92, 94], "pbi": [5, 49, 52, 80, 86], "\u0431\u043e\u0433\u0430\u0442": 5, "\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d": [5, 11, 23, 34], "api": [5, 21, 23, 73, 75, 85], "\u0441\u0432\u0435\u0440\u043a": 5, "\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446": [5, 9, 11, 21, 23, 30, 34, 37, 38, 40, 41, 51, 56, 65, 72, 74, 75, 76, 80, 82, 83, 85, 86, 90, 94, 100], "\u043a\u043e\u0434": [5, 9, 11, 15, 16, 23, 34, 37, 38, 41, 42, 47, 64, 66, 70, 72, 75, 76, 82, 85, 86, 90, 94], "\u0440\u0435\u0437\u043e\u043b\u044c\u0432": 5, "\u0432\u043e\u0437\u043c\u043e\u0436": [5, 8, 83], "\u0432\u044b\u0431\u043e\u0440": [5, 23, 37, 38, 64, 65, 70, 76, 80, 88, 89], "\u0434\u0432\u0443\u0445": [5, 23, 37, 70, 72, 82, 85, 86, 88, 92, 102], "\u0441\u043b\u0438\u0432\u0430": 5, "\u0440\u0430\u0437\u043b\u0438\u0447": [5, 52, 77], "\u043d\u0438\u043a\u0430\u043a": [5, 26, 34, 38, 70, 77, 83, 100], "\u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430": 5, "temp": 5, "\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437": 5, "\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440": 5, "\u0443\u0447\u0438\u0442\u044b\u0432\u0430": [5, 34, 38, 65, 75, 83, 85], "\u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442": [5, 9, 11, 21, 23, 75, 83, 92, 93, 100], "\u043c\u043d\u0435": [5, 23, 34, 40, 46, 72, 74, 75, 83, 85, 86, 88, 92, 93, 100], "\u0434\u0432\u0430": [5, 13, 21, 23, 26, 34, 38, 64, 72, 73, 74, 75, 85, 86, 90, 92, 100], "\u0441\u043b\u0438\u0442": 5, "\u0441\u043b\u0443\u0447\u0430": [5, 8, 9, 11, 15, 21, 23, 30, 34, 37, 38, 40, 41, 46, 47, 52, 56, 65, 75, 77, 82, 83, 85, 86, 88, 93, 94, 100, 102], "\u0443\u0442\u0440\u0430\u0442": [5, 23, 40], "\u043e\u0431\u043e": [5, 21, 37, 65, 85], "\u0443\u0440\u043e\u0432\u043d": [5, 8, 11, 15, 21, 23, 30, 34, 37, 52, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 94, 100], "\u043e\u043f\u0438\u0441\u0430\u043d": [5, 8, 23, 51, 82, 93, 100, 102], "grafico": 5, "format": [5, 9, 23], "\u0434\u0435\u0439\u0441\u0442\u0432\u0435\u043d": [5, 88], "\u0432\u043f\u0440\u043e\u0447": [5, 11, 21, 23, 75, 83], "views": [5, 11, 49, 74, 75, 77, 82], "\u0443\u0441\u043b\u043e\u0436\u043d\u044f": [5, 73, 75, 94], "\u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432": [5, 23, 70, 75, 86, 102], "\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440": [5, 10, 23, 30, 34], "\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e": 5, "\u0441\u043e\u043e\u0431\u0449\u0430": [5, 74], "\u043e": [5, 8, 9, 11, 13, 15, 23, 30, 33, 38, 40, 41, 42, 46, 47, 51, 52, 56, 60, 64, 66, 68, 72, 74, 75, 76, 80, 82, 83, 86, 89, 90, 93, 94, 95, 100, 102, 118], "\u043e\u043f\u0440\u0435\u0434\u0435\u043b": [5, 38, 46, 70, 85, 86, 92, 100, 102], "\u0441\u043c\u044b\u0441\u043b": [5, 8, 9, 23, 41, 52, 74, 75, 82, 85, 92, 94, 100, 102], "\u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d": [5, 9, 23, 74], "\u0437\u0430\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430": 5, "csv": 5, "\u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d": [5, 8, 23, 65, 72, 76, 85, 94, 100], "\u043a\u043e\u043f": [5, 26, 82, 100], "\u043f\u0435\u0440\u0435\u0434": [5, 8, 9, 15, 23, 38, 40, 46, 47, 75, 85, 92], "\u0433\u0440\u0435\u043f\u0430": 5, "\u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443": 5, "\u043c\u0435\u043d\u044c\u0448": [5, 38, 40, 52, 70, 73, 74, 85, 86, 88, 90, 93, 94, 100], "\u0443\u043c\u0435\u043d\u044c\u0448\u0430": [5, 75, 102], "\u0432\u0435\u0440\u043e\u044f\u0442\u043d": [5, 9, 15, 23, 37, 38, 70, 73, 74, 82, 83, 85, 88, 90, 92], "\u0434\u043e\u043f\u0443\u0449\u0435\u043d": [5, 65, 92], "\u043e\u0448\u0438\u0431\u043a": [5, 15, 38, 43, 46, 47, 65, 66, 73, 74, 75, 82, 83, 86, 89, 90, 92, 94, 121], "\u043d\u0435\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d": 5, "\u0438\u0437\u0431\u0435\u0433\u0430": [5, 15, 21, 47, 83], "\u0434\u043e\u0441\u043a": [5, 95], "\u0432\u0440\u0435\u043c\u0435\u043d": [5, 8, 11, 23, 34, 37, 38, 42, 46, 47, 56, 72, 73, 74, 75, 76, 82, 83, 85, 86, 90, 92, 94, 95], "\u043f\u0435\u0440\u0435\u0434\u0430": [5, 9, 21, 26, 102], "\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a": [5, 8, 23, 30], "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u043e\u043d": [5, 86], "\u043c\u0435\u0440": [5, 8, 23, 38, 40, 46, 47, 52, 65, 70, 72, 83, 85, 86, 94], "\u0441\u043d\u0438\u0437": [5, 13, 37, 46, 72, 74, 77, 85, 86, 88, 90], "\u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d": [5, 30, 73, 85, 92], "\u0434\u0438\u0441\u0442\u0440\u0438\u0431\u0443\u0442": 5, "coarchi": 5, "\u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d": [5, 21, 37, 38, 52, 82], "rsa": 5, "\u043a\u043b\u044e\u0447": [5, 8, 9, 21, 23, 30, 38], "\u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d": [5, 41, 46, 70, 74, 75, 85, 90], "\u0434\u043e\u043f\u0443\u0441\u043a\u0430": [5, 8, 23, 34, 40, 73, 92, 102], "\u0430\u0433\u0440\u0435\u0433\u0430\u0442": [5, 10, 12, 23, 30, 34, 75], "\u0431\u043e\u043b\u0442\u043b\u0438\u0432": 5, "\u043f\u0440\u043e\u0431\u0443": [5, 77], "\u043e\u0431\u044a\u0435\u0434\u0438\u043d": 5, "\u043e\u0431\u0449": [5, 11, 21, 34, 73, 74, 75, 77, 82, 85, 86, 88, 90, 92, 100], "\u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430": [5, 21, 85, 86], "\u0438\u0437\u043c\u0435\u043d": [5, 23, 26, 34, 37, 38, 46, 52, 74, 76, 83, 85, 88, 90], "\u0441\u043e\u0432\u043e\u043a\u0443\u043f\u043d": [5, 41, 65, 75, 83, 85, 92, 102], "coupling": [5, 9, 11, 13, 23, 37, 72, 73, 74, 75, 82, 85, 86, 100], "\u043e\u0432": 5, "cohesion": [5, 9, 11, 73, 74, 82, 86, 100], "\u0432\u043d\u0443\u0442\u0440": [5, 9, 11, 23, 30, 56, 86, 100], "\u0443\u043f\u0430": [5, 8], "\u0435\u0434\u0438\u043d\u0438\u0446": [5, 23, 74, 75, 85, 86, 95, 102], "\u0432\u043e\u0437\u0440\u043e\u0441": 5, "\u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d": [5, 8, 16, 30, 77, 92, 100], "\u043e\u043f\u0440\u0430\u0432\u0434\u0430": [5, 38, 70, 72, 85, 86], "_coupling": 5, "_cohesion": 5, "\u043b\u043e\u0433\u0438\u043a": [5, 34, 74, 75, 82, 92], "\u0432\u044b\u043d\u0435\u0441": [5, 83], "\u0442\u0435\u043a\u0443\u0449": [5, 8, 23, 38, 70, 82, 85, 86, 95, 100], "\u043f\u043e\u043d\u0430\u0434\u043e\u0431": [5, 70, 82, 86, 100], "readmodels": 5, "measuring": [5, 37, 86], "information": [5, 9, 21, 23, 34, 38, 39, 49, 51, 52, 64, 65, 68, 74, 76, 82, 85, 86, 90], "theory": [5, 70, 74, 75, 76, 82, 85, 86, 92, 93], "edward": [5, 13, 23, 72, 82], "allen": [5, 9, 82], "taghi": 5, "khoshgoftaar": 5, "florida": 5, "atlantic": 5, "university": [5, 23, 30, 34, 60, 77, 82, 90], "boca": 5, "raton": 5, "usa": 5, "analysis": [5, 23, 37, 38, 49, 52, 54, 59, 60, 64, 65, 66, 72, 74, 75, 76, 77, 80, 82, 85, 86, 100, 126], "identifying": [5, 38, 77, 82], "microservice": [5, 23, 82, 86, 100], "boundaries": [5, 9, 11, 23, 29, 82, 85, 86], "bounded": [5, 23, 29, 34, 37, 86, 92, 100], "contexts": [5, 11, 23, 34, 74, 82, 86, 92, 100], "vladik": [5, 37, 73, 82], "khononov": [5, 37, 73, 82], "tackling": [5, 11, 23, 26, 34, 73, 74, 75, 82, 90, 100], "complexity": [5, 11, 23, 26, 34, 38, 60, 62, 70, 73, 74, 76, 77, 82, 85, 90, 100], "learning": [5, 37, 41, 65, 73, 75, 76, 82, 85, 88], "driven": [5, 9, 11, 21, 23, 26, 34, 37, 38, 46, 72, 73, 74, 75, 76, 82, 85, 86, 90, 93, 100], "aligning": [5, 82], "strategy": [5, 23, 38, 46, 65, 66, 68, 70, 72, 73, 76, 77, 82, 85, 86, 94], "1st": [5, 8, 23, 37, 38, 42, 46, 47, 64, 66, 68, 70, 73, 74, 82, 83, 94, 95], "edition": [5, 8, 15, 21, 23, 34, 37, 38, 42, 46, 47, 49, 51, 52, 53, 60, 62, 64, 65, 66, 68, 70, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 94, 95], "vlad": [5, 82], "balancing": [5, 34, 37, 38, 64, 68, 70, 74, 78, 82, 133], "successful": [5, 23, 37, 38, 46, 62, 64, 70, 72, 73, 74, 76, 82, 85, 100], "general": [5, 21, 23, 29, 34, 70, 73, 74, 76, 77, 82, 85, 90, 93], "systems": [5, 21, 23, 34, 36, 37, 38, 40, 41, 49, 52, 59, 60, 62, 63, 65, 66, 73, 75, 76, 77, 82, 85, 86, 100, 120], "vladislav": [5, 82], "\u043a\u043e\u0440\u043e\u0431\u043a": [5, 23], "exarchi": 5, "contribs": 5, "script": [5, 23, 85], "database": [5, 9, 21, 23, 29, 34, 76, 82, 85, 86], "\u0432\u044b\u0433\u0440\u0443\u0436\u0430": 5, "rdbms": [5, 23, 82], "\u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d": 5, "sql": [5, 9, 13, 21, 23, 30, 75, 82], "\u043f\u043e\u0434\u043e\u0431\u043d": [5, 37, 38, 47, 56, 72, 74, 75, 83, 85, 86, 88], "\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430": 5, "acceptance": [5, 49, 51, 82], "bdd": 5, "specification": [5, 9, 12, 21, 38, 51, 52, 65, 74, 75, 82], "\u0442\u0435\u0441\u0442\u043e\u0432": [5, 9, 85], "\u043a\u0435\u0439\u0441": [5, 9, 21, 82], "stands": [5, 65], "friendly": 5, "collection": [5, 29, 38, 75], "way": [5, 8, 9, 21, 23, 26, 34, 38, 39, 41, 46, 47, 49, 51, 52, 70, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 95, 100], "persist": [5, 51], "bunch": [5, 37, 38, 74], "xml": 5, "one": [5, 9, 11, 15, 21, 26, 29, 34, 37, 38, 39, 42, 49, 51, 52, 60, 62, 64, 65, 70, 73, 74, 76, 77, 82, 86, 90, 93, 94, 95, 100], "per": [5, 23, 38, 46, 74, 82], "element": [5, 9, 21, 49, 62, 74, 100], "view": [5, 9, 21, 37, 38, 46, 52, 74, 77, 85, 86, 90, 100], "explained": [5, 21, 37, 38, 42, 46, 47, 52, 64, 65, 66, 68, 70, 73, 74, 76, 82, 83, 86, 94], "\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443": 5, "ci": [5, 86], "\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d": 5, "maxim": [5, 66, 82], "levchenko": 5, "container": [5, 23, 82], "gh": 5, "action": [5, 21, 23, 34, 38, 82], "pages": [5, 37, 52, 76, 82, 95], "htmlreport": 5, "example": [5, 8, 9, 15, 21, 23, 34, 37, 38, 46, 51, 52, 65, 70, 72, 73, 76, 82, 85, 86, 93, 100], "others": [5, 9, 23, 34, 37, 38, 49, 51, 52, 72, 74, 75, 82, 85, 86, 88, 90], "\u0441\u043e": [5, 23, 26, 37, 38, 46, 47, 51, 52, 72, 74, 76, 77, 80, 83, 85, 86, 88, 90, 92, 94, 95, 100], "sketch": 5, "\u0441\u0442\u0440": 5, "110": 5, "\u043f\u0440\u043e\u0432\u043e\u0434": 5, "\u0441\u0435\u0430\u043d\u0441": [5, 74], "mapping": [5, 13, 21, 29, 76, 82, 86], "\u0433\u0430\u0440\u043c\u043e\u043d\u0438\u0447\u043d": 5, "\u0441\u043e\u0447\u0435\u0442\u0430": [5, 21, 70, 75], "\u0433\u043e\u0432\u043e\u0440": [5, 8, 9, 11, 21, 23, 30, 34, 37, 38, 40, 46, 51, 56, 68, 70, 72, 75, 76, 82, 83, 85, 86, 88, 90, 92, 93, 94, 95, 100, 102], "\u0431\u0430\u0440\u0430\u043d": [5, 82], "\u0434\u043e\u043a\u043b\u0430\u0434": [5, 76, 100], "\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d": [5, 21, 23, 34, 38, 65, 82, 85, 86, 89, 90, 95], "simon": [5, 76], "brown": [5, 38, 76, 82], "\u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0440\u0443\u0447\u043d": [5, 21], "\u0441\u0441\u044b\u043b\u0430": [5, 34, 86], "guide": [5, 9, 21, 37, 40, 41, 49, 51, 52, 62, 64, 65, 66, 73, 74, 75, 76, 80, 82, 85], "\u0441\u0430\u0439\u0442": [5, 34, 52, 53, 82, 85], "omg": 5, "\u0432\u044b\u043b\u043e\u0436": 5, "\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d": [5, 9, 23, 75], "\u043e\u0448\u0438\u0431\u043e\u043a": [5, 15, 74, 77, 82, 83, 90], "\u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d": 5, "\u043d\u0435\u0437\u0430\u043a\u043e\u043c\u043c\u0438\u0447\u0435\u043d": 5, "\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d": [5, 8, 9, 10, 34, 100], "7": [5, 8, 21, 23, 38, 42, 66, 70, 74, 82, 85, 86, 88, 90, 100], "if": [5, 8, 9, 11, 15, 21, 23, 29, 34, 37, 38, 39, 41, 42, 46, 49, 51, 52, 60, 62, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 92, 94, 95, 100], "import": [5, 8, 9, 11], "refresh": [5, 21], "error": [5, 8, 9, 15, 21, 34, 73, 74, 77, 90], "archi": [6, 82, 107], "storming": [7, 56, 76, 86, 108], "\u043e\u043f\u0438\u0441\u0430": [8, 15, 16, 23, 34, 38, 46, 65, 76, 85, 88, 100], "6": [8, 9, 16, 21, 23, 34, 37, 38, 46, 51, 64, 65, 75, 76, 82, 85, 86, 88], "\u0441\u0438\u0441\u0442\u0435\u043c": [8, 9, 16, 21, 23, 34, 37, 38, 40, 46, 47, 65, 68, 70, 72, 73, 74, 75, 77, 85, 86, 89, 90, 92, 100], "\u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d": [8, 16, 86], "\u0447\u043b\u0435\u043d": [8, 16, 42, 74, 85, 90], "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446": [8, 16, 23, 30, 38, 76, 82, 83, 86, 88], "\u0443\u0441\u0442\u0430\u0432": [8, 16], "\u0440\u0435\u0433\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [8, 16], "\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d": [8, 16], "\u0438\u0442": [8, 16, 37, 82, 100], "\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440": [8, 16, 38, 51, 70, 73, 74, 86, 89, 94, 100], "\u0432\u044b\u0434\u0435\u043b": [8, 38, 86, 94], "\u043e\u0442\u0434\u0430": 8, "20": [8, 23, 38, 52, 66, 70, 76, 77, 85, 86], "\u043f\u0440\u0438\u0437\u043d\u0430\u043d": [8, 88], "\u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u043c": 8, "\u0440\u0430\u0432\u043d\u043e\u0446\u0435\u043d": 8, "\u0438\u0437\u043b\u0438\u0448\u043a": 8, "\u043f\u0435\u0440\u0435\u043d\u043e\u0441": [8, 9, 21], "\u043d\u0438\u0437\u043a": [8, 11, 21, 38, 56, 70, 74, 75, 88], "\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c": 8, "\u0442\u0440\u0435\u0431\u0443\u0435\u043c": [8, 21, 75, 94, 95], "40": [8, 73, 83, 93], "\u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442": 8, "\u0433\u043e": [8, 83], "14": [8, 23, 38, 51, 66, 76, 100], "3": [8, 21, 23, 34, 37, 38, 40, 51, 64, 65, 66, 70, 74, 75, 76, 77, 82, 85, 86, 100], "\u0443\u043c\u043e\u043b\u0447\u0430\u043d": [8, 85], "\u043d\u0430\u0441\u0442\u043e\u044f": [8, 38, 70, 82, 85, 86, 92, 102], "\u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d": [8, 11, 23, 42, 73, 86, 100, 102], "\u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d": [8, 100], "\u0440\u0430\u0441c\u043c\u043e\u0442\u0440": 8, "relationships": [8, 11, 23, 34, 74, 75, 85, 100], "vladimir": [8, 9, 14, 15, 21, 23, 75, 82], "khorikov": [8, 9, 14, 15, 21, 23, 75, 82], "\u0431\u0443\u0434": [8, 21, 23, 34, 46, 70, 74, 85], "\u043f\u0440\u0438\u0432\u0435\u0434": [8, 23, 38, 82, 100], "\u0437\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d": 8, "\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442": [8, 11, 37, 38, 73, 74, 75, 77, 83, 85, 90, 100, 102], "stackoverflow": [8, 9], "public": [8, 9, 11, 23, 82, 85, 89], "class": [8, 9, 21, 23, 38, 70, 74, 75, 85, 86, 90], "student": 8, "entity": [8, 9, 11, 21, 23, 65], "string": [8, 9], "name": [8, 9, 23, 26, 49, 75], "email": [8, 23, 82], "readonly": 8, "ilist": 8, "studentinstructor": 8, "_studentinstructors": 8, "ireadonlylist": 8, "instructor": 8, "instructors": 8, "select": [8, 38, 82], "x": [8, 21, 34, 37, 85, 86], "orderby": 8, "dateadded": 8, "tolist": 8, "internal": [8, 9, 21, 34, 37, 38, 74, 76, 85, 86], "void": [8, 9, 21, 23, 70], "addinstructor": 8, "add": [8, 23, 38, 46, 47, 51, 70, 74, 76, 77, 85, 86], "students": 8, "addstudent": 8, "var": 8, "this": [8, 9, 11, 15, 21, 23, 26, 29, 34, 37, 38, 39, 41, 42, 46, 47, 49, 51, 52, 62, 63, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 93, 94, 100], "datetime": 8, "now": [8, 21, 23, 29, 34, 38, 46, 65, 70, 74, 75, 76, 85, 86], "\u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430": [8, 70, 75, 85, 102], "\u043f\u0440\u0435\u0434\u043f\u0440\u0438\u043d\u044f\u0442": 8, "\u043a\u043e\u043d\u0442\u0443\u0440": [8, 89], "\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d": [8, 15, 21, 23, 30, 37, 38, 42, 47, 70, 72, 73, 74, 80, 85, 88, 90, 92, 100, 102], "\u043f\u0435\u0440\u0435\u0440\u0430\u0431\u043e\u0442\u043a": [8, 46, 47], "\u043c\u043e\u0433\u043b": [8, 9, 21, 38, 74, 83, 88, 90], "\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430": 8, "\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u043e\u043d": 8, "online": [8, 23, 92], "\u0442\u0430\u0431\u043b\u0438\u0446": [8, 9, 30, 70, 85], "\u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b": 8, "\u043f\u0440\u0438\u043c\u0435\u0440\u043d": [8, 40, 76, 83], "package": [8, 9, 11, 23, 85], "grade_1": [8, 9], "errors": [8, 15, 21, 74, 90], "time": [8, 9, 21, 23, 34, 37, 38, 39, 41, 46, 47, 49, 51, 52, 53, 62, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 95], "type": [8, 9, 21, 23, 34, 37, 38, 46, 74, 76], "memberid": [8, 9], "uint64": [8, 9], "grade": [8, 9, 19, 109], "uint": [8, 9], "availableendorsementcount": [8, 9], "receivedendorsementcount": 8, "endorsementid": 8, "artifactdescription": 8, "weight": [8, 38, 85, 86], "uint8": [8, 9], "const": 8, "peerweight": 8, "higherweight": 8, "expert": [8, 72, 74, 92, 100], "candidate": [8, 51, 77], "grade1": 8, "grade2": 8, "grade3": 8, "withoutgrade": 8, "0": [8, 9, 49, 51, 64, 74, 82, 86], "specialist": 8, "struct": [8, 9], "id": [8, 9, 21, 23, 34, 82], "assignments": 8, "assignment": [8, 21], "version": [8, 9, 23, 34, 49, 52, 64, 74, 75, 82], "createdat": [8, 9], "func": [8, 9], "getid": [8, 9], "return": [8, 9, 15, 21, 23, 26, 38, 51, 70, 86], "getgrade": 8, "getversion": 8, "increasereceivedendorsementcount": 8, "w": [8, 38, 64, 74, 75, 82, 92], "setgrade": [8, 9], "else": [8, 23, 74, 76, 86], "append": 8, "increaseversion": 8, "specialistid": 8, "specialistversion": 8, "assignedgrade": 8, "endorser": [8, 9], "endorse": 8, "adesc": 8, "allowed": [8, 11, 23, 34, 38], "only": [8, 9, 11, 21, 23, 34, 37, 38, 41, 47, 49, 62, 65, 72, 74, 75, 76, 77, 80, 82, 85, 86, 100], "members": [8, 9, 11, 23, 38, 42, 51, 74, 86, 90], "equal": [8, 38], "lower": [8, 38, 39, 75, 77, 85], "have": [8, 9, 11, 21, 23, 29, 34, 37, 38, 39, 46, 47, 49, 51, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90, 92, 95, 100], "reached": [8, 23], "limit": [8, 11, 38, 74, 86], "available": [8, 9, 38, 51, 82], "recommendations": 8, "year": [8, 23, 46, 62, 70, 76, 86], "himself": [8, 37, 76, 82, 95], "nil": [8, 9], "decreaseavailableendorsementcount": 8, "endorserid": [8, 9], "endorsergrade": [8, 9], "endorserversion": 8, "specialistgrade": 8, "\u043c\u0435\u0442\u043e\u0434": [8, 9, 11, 15, 21, 23, 34, 65, 72, 74, 75, 76, 77, 85, 90, 92, 93], "\u0444\u0430\u0431\u0440\u0438\u0447\u043d": 8, "\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449": [8, 23, 82], "\u0438\u0437\u0432\u043b\u0435\u043a\u0430": [8, 100], "\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f": [8, 34], "\u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a": [8, 23, 30, 33, 118], "\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c": [8, 21, 23, 30, 37, 85, 86], "\u0434\u043e\u0441\u0442\u0430\u0432\u043a": [8, 23, 30, 34, 86], "\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430": [8, 30, 34], "\u0441\u0438\u043d\u0445\u0440\u043e\u043d": [8, 23, 34], "\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446": [8, 23, 30], "mediator": [8, 23, 72, 73], "observer": [8, 23], "\u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d": [8, 21, 23], "message": [8, 21, 23, 34], "broker": 8, "endorsementcreated": 8, "\u043f\u043e\u0434\u043f\u0438\u0441\u0430": 8, "\u0432\u044b\u0437\u044b\u0432\u0430": [8, 9, 23, 38, 56, 65, 74, 95], "\u0432\u044b\u0447\u0438\u0442\u0430\u043d": 8, "\u0441\u0447\u0435\u0442\u0447\u0438\u043a": 8, "\u0443\u043a\u0430\u0437\u0430\u043d": [8, 30, 100, 102], "\u0437\u0430\u0432\u0438\u0441\u044f": 8, "\u043e\u0442\u043d\u043e\u0448\u0435\u043d": [8, 23, 38, 42, 65, 75, 85, 88, 94, 100, 102], "\u043e\u0431\u0440\u0430\u0442": [8, 21, 23, 37, 38, 52, 56, 65, 72, 76, 82, 85, 86, 92, 93, 100], "\u0438\u043c\u0435\u0435\u0442": [8, 9, 21, 23, 29, 34, 37, 38, 40, 65, 70, 72, 74, 75, 76, 82, 83, 85, 86, 94, 100, 102], "\u0443\u0441\u0435\u0447": 8, "\u0441\u043d\u044d\u043f\u0448\u043e\u0442": 8, "sourced": [8, 23, 30, 34, 82], "log": [8, 23], "\u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430": [8, 38], "\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d": [8, 42, 85, 86], "\u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d": [8, 37, 38, 65, 73, 75, 76, 92, 93, 94, 100], "\u043f\u0435\u0440\u0438\u043e\u0434": [8, 95], "\u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u043d": 8, "\u043a\u043b\u0430\u0441\u0441\u043d\u043e\u0441\u0442": 8, "\u043f\u043e\u043b\u0433\u043e\u0434": 8, "\u0442\u0440\u0435\u0431\u043e\u0432\u0430": [8, 11, 23, 65, 72, 73, 85], "\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d": [8, 21, 88, 89, 94], "\u0442\u0435\u0447\u0435\u043d": [8, 70, 74, 85], "\u0438\u043d": [8, 10, 21, 23, 34, 37, 38, 40, 41, 46, 56, 70, 72, 75, 85, 88, 89, 92, 94, 102], "\u043c\u043e\u0433": [8, 21, 38, 70, 74, 82, 83, 85, 86], "readmodel": 8, "\u043e\u0447\u0435\u0440\u0435\u0434": [8, 23, 34, 37, 38, 56, 70, 74, 85, 86, 90, 93, 100], "\u0441\u043c\u043e\u0433": [8, 74, 75, 85, 88], "\u043f\u043e\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430": 8, "artifact": [8, 73, 74, 76, 100], "\u0434\u0432\u0430\u0436\u0434": [8, 40], "\u043f\u0440\u043e\u0439\u0434": 8, "\u0440\u0435\u0430\u043b\u0438\u0437": [8, 29, 34, 75, 82, 86], "\u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442": [8, 9, 11, 15, 23, 26, 100], "\u043f\u0440\u0435\u0432\u044b\u0448\u0430": [8, 73, 74, 86], "\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d": [8, 15, 102], "\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a": [8, 10, 23, 30], "\u0432\u044b\u0437\u043e\u0432": [8, 9, 23, 62, 86], "\u043e\u0431\u0441\u0443\u0434": [8, 15, 23], "\u043f\u0440\u043e\u0441\u043b\u0435\u0436\u0438\u0432\u0430": [8, 85], "\u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440": [8, 23, 30, 72, 100], "\u0434\u0430\u0432\u0430": [8, 21, 30, 38, 56, 73, 75, 86], "endorsera": 8, "specialista": 8, "\u043f\u0440\u0438\u0441\u0432\u043e\u0435\u043d": 8, "\u0445\u0432\u0430\u0442\u0430": [8, 38], "\u043f\u0440\u043e\u0432\u0435\u0440\u043a": [8, 92], "\u0434\u0435\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 8, "endorserb": 8, "\u0443\u0441\u043f\u0435\u0442": [8, 74], "\u0434\u0430\u0442": [8, 62, 82, 85, 88], "\u0437\u0430\u0447\u0442": 8, "\u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a": [8, 70, 85, 86, 92], "\u043d\u0430\u0440\u0443\u0448\u0430": [8, 9, 21], "\u0437\u0430\u043f\u0440\u0435\u0442": [8, 21, 40, 75], "\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d": 8, "\u0441\u0438\u0442\u0443\u0430\u0446": [8, 21, 37, 38, 47, 82, 85, 88, 92, 93, 100, 102], "\u043d\u0430\u043b\u043e\u0436": [8, 37, 38], "\u043f\u043e\u043a\u0440\u044b\u0432\u0430": [8, 86], "\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0442\u043d": [8, 9, 15], "\u0438\u043d\u0434\u0435\u043a\u0441": 8, "\u043f\u043e\u043b": [8, 9, 13, 60, 85, 90], "\u043e\u0441\u0442\u0430\u0432\u0430": [8, 37], "\u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b": [8, 37, 38, 72, 85, 86, 94], "\u0437\u0430\u0434\u0435\u0440\u0436\u043a": [8, 21], "\u043f\u0440\u0438\u0447\u0438\u043d": [8, 11, 15, 21, 30, 37, 38, 41, 56, 65, 70, 75, 76, 82, 83, 85, 86, 88, 89, 92, 93, 94, 100], "\u0432\u0441\u0442\u0430\u043b": 8, "\u0437\u0430\u0442\u0443\u043f": 8, "\u0447\u0435\u043a": 8, "\u0431\u0434": [8, 12, 21, 23], "\u0437\u0430\u043f\u0443\u0441\u0442": [8, 34, 73], "\u0441\u0435\u0442": [8, 34], "\u0440\u0430\u0437\u0434\u0430": 8, "\u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430": [8, 92], "\u0443\u043f\u0440\u0435\u0436\u0434\u0430": [8, 37], "\u0432\u044b\u0434\u0432\u0438\u0433\u0430": [8, 23, 65], "\u043f\u0430\u0440\u0442\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430": 8, "\u043e\u0431": [8, 9, 11, 15, 21, 34, 37, 38, 40, 65, 70, 75, 76, 77, 82, 83, 85, 86, 92, 100, 102], "\u0437\u0430\u043d\u0438\u043c\u0430": [8, 9, 34, 38, 41, 46, 51, 70, 72, 74, 75, 76, 82, 83, 85, 86, 92, 93, 100], "\u043f\u0430\u0440\u0442\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d": [8, 23, 30, 34], "\u0437\u043d\u0430\u0435\u0442": [8, 21, 38, 47, 82, 83, 85, 86, 90, 92, 102], "\u043f\u0430\u0440\u0442\u0438\u0446": [8, 30], "\u0430\u0432\u0442\u043e\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [8, 30], "\u043f\u0435\u0440\u0432\u0438\u0447\u043d": [8, 9, 10, 23, 30, 37, 65, 92], "\u0433\u043b\u0430\u0441": [8, 38, 92], "\u0434\u0443\u0431\u043b\u0438\u043a\u0430\u0442": 8, "\u043d\u0435\u0447\u0435\u0442\u043a": 8, "\u0432\u0432\u043e\u0434": [8, 21, 23, 34, 65, 70, 74, 75, 85, 100], "\u043f\u0440\u0435": 8, "\u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": [8, 30], "\u0434\u043b\u0438\u0442": 8, "\u0447\u0430\u0441": [8, 30, 74, 85, 86, 95], "\u0434\u043d\u044f\u043c": 8, "\u0432\u0440\u044f\u0434": [8, 9, 21, 82], "\u0431\u0443\u0434\u0443\u0442": [8, 21, 23, 26, 34, 38, 46, 47, 82, 83, 85, 86, 88, 95], "\u0432\u043e\u0441\u0442\u043e\u0440\u0433": 8, "\u043a\u0430\u0436\u0435\u0442": [8, 21, 38, 47, 83, 85], "\u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442": [8, 11, 75, 88], "\u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d": 8, "\u043e\u0434\u043e\u0431\u0440\u0435\u043d": 8, "\u043d\u0435\u043e\u0434\u043e\u0431\u0440\u0435\u043d": 8, "\u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430": 8, "\u0441\u043c\u043e\u0436\u0435\u0442": [8, 42, 46, 70, 75, 82, 85, 86, 92], "\u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430": 8, "\u043e\u0431\u043b\u0430\u0441\u0442": [8, 11, 21, 23, 34, 37, 38, 40, 60, 64, 65, 68, 72, 74, 75, 80, 82, 88, 90, 92, 102], "\u044d\u043a\u0441\u043f\u0435\u0440\u0442\u043d": 8, "\u0432\u043d\u043e\u0441": [8, 23, 38, 65, 74], "\u043f\u0440\u0430\u0432\u043a": [8, 13], "artifactid": 8, "status": [8, 15, 21, 23, 51, 73, 85], "artifactstatus": 8, "description": [8, 23, 38, 52, 74, 82, 83], "competenceids": 8, "competenceid": 8, "competence": 8, "competencename": 8, "\u0437\u0430\u0434\u0430\u0447": [8, 23, 34, 37, 41, 46, 51, 60, 73, 74, 75, 76, 83, 85, 86, 88, 90, 94, 95, 100], "\u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440": 8, "\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430": [8, 75, 82], "\u0441\u0442\u0440\u0430\u0442\u0435\u0433": [8, 34, 37, 38, 46, 68, 70, 72, 77, 85, 86], "\u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440": 8, "\u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430": [8, 9, 11, 26], "\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442": [8, 9, 15, 26, 34, 38, 40, 52, 65], "\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d": [8, 37, 38, 88, 100], "\u0432\u044b\u0434\u0435\u043b\u0435\u043d": [8, 9, 38, 41, 70, 86], "\u043d\u0443\u0436": [8, 10, 94], "\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430": [8, 9, 38, 41, 70], "trilemma": [8, 14], "\u0443\u0447\u0438\u0442\u044b\u0432": [8, 86], "\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d": [8, 89], "model": [8, 9, 11, 14, 21, 23, 28, 29, 30, 34, 37, 38, 51, 52, 59, 60, 62, 65, 74, 75, 76, 77, 82, 86, 88, 103, 115], "purity": [8, 82], "completeness": [8, 52, 82], "\u0440\u0430\u0437\u043c\u0435\u0441\u0442": [8, 11], "\u043f\u043e\u0434\u0441\u043a\u0430\u0436\u0435\u0442": 8, "\u0441\u0435\u0439\u0447\u0430\u0441": [8, 38, 70, 95], "\u043f\u0440\u0438\u0432\u043e\u0434": [8, 21, 23, 34, 40, 41, 56, 65, 68, 77, 82, 83, 85, 86, 90, 95], "\u0445\u0440\u0430\u043d": [8, 11, 23], "\u043d\u0430\u0433\u0440\u0430\u0434\u043d": 8, "\u043f\u043e\u0447\u0435\u0442\u043d": 8, "\u0433\u0440\u0430\u043c\u043e\u0442": 8, "\u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442": 8, "\u0434": [8, 75, 76, 82, 86, 88, 90, 92, 95, 100, 102], "\u043d\u0430\u0433\u0440\u0430\u0436\u0434\u0430": 8, "\u0434\u043e\u043b\u0436\u043d": [8, 9, 10, 11, 23, 30, 34, 37, 38, 40, 41, 42, 46, 47, 51, 64, 68, 70, 72, 74, 75, 82, 85, 86, 88, 90, 92, 93, 94, 100], "\u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0430": [8, 85, 100], "\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0430": 8, "\u0434\u043e\u043b\u0436": [8, 9, 23, 34, 38, 51, 73, 74, 75, 83, 85, 86, 88], "\u0443\u0434\u0430\u043b\u0435\u043d": [8, 9, 29, 34, 37], "\u0432\u0440\u043e\u0434": [8, 75], "\u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430": [8, 23, 38, 72, 83, 85, 92, 94], "\u0438\u043c\u0435\u0442": [8, 11, 23, 40, 73, 74, 75, 83, 90], "\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d": [8, 9, 92], "\u0441\u0432\u0435\u0440\u0442\u043a": 8, "left": [8, 37, 72, 73, 85], "fold": [8, 75], "\u043f\u0440\u043e\u0435\u043a\u0446": [8, 100], "\u0442\u0435\u043f\u0435\u0440": [8, 21, 23, 30, 38, 40, 70, 74, 82, 83, 85, 86, 88, 92], "\u0435\u043c": [8, 9, 15, 23, 38, 83, 86, 88, 100], "\u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d": [8, 38], "\u0443\u0441\u043f\u0435\u0435\u0442": 8, "\u0433\u043b\u0430\u0432": [8, 11, 13, 21, 23, 30, 34, 38, 51, 64, 70, 74, 76, 85, 86, 100], "9": [8, 23, 38, 74, 76, 85], "coding": [8, 37, 74, 76, 90], "up": [8, 21, 23, 34, 37, 38, 51, 52, 62, 65, 70, 72, 73, 74, 75, 76, 78, 80, 82, 85, 86, 95, 100, 133], "lean": [8, 23, 38, 46, 51, 52, 64, 65, 76, 77, 82, 88], "development": [8, 23, 36, 38, 46, 47, 49, 51, 52, 54, 58, 61, 65, 66, 70, 72, 73, 74, 75, 76, 82, 85, 86, 88, 90, 92, 93, 94, 95, 100, 120, 126, 128, 129], "james": [8, 38, 75, 76, 82, 95], "o": [8, 15, 21, 82], "coplien": [8, 76, 82], "gertrud": [8, 76, 82], "bj\u00f8rnvig": [8, 76, 82], "\u0434\u0435\u043d\u0435\u0436\u043d": 8, "\u0441\u0447\u0435\u0442": [8, 42, 70, 77, 83, 85, 90, 100], "\u043f\u043e\u0445\u043e\u0436": [8, 9, 23, 38, 75], "\u0432\u0442\u043e\u0440": [8, 9, 11, 13, 21, 23, 34, 37, 40, 46, 52, 72, 74, 76, 77, 83, 85, 86, 88, 89, 92, 94, 100], "\u043e\u043f\u0438\u0441\u044b\u0432\u0430": [8, 11, 38, 64, 72, 74, 85, 86, 92, 94, 102], "vaughn": [8, 9, 21, 23, 29, 30, 34, 82, 100], "vernon": [8, 9, 21, 23, 29, 30, 34, 82, 100], "\u0438\u043d\u0442\u0435\u0440\u0432": [8, 21, 30, 73], "uncertainty": [8, 30, 34, 38, 65, 76], "reactive": [8, 23, 30, 34, 82], "reviewed": [8, 30, 34, 37, 76], "thomas": [8, 30, 34, 37, 76, 82, 90, 94], "betts": [8, 23, 30, 34, 82], "\u0441\u044e\u0434": [8, 21, 23, 38, 82], "\u043e\u0442\u043d\u0435\u0441\u0442": [8, 30, 94], "engines": [8, 82], "\u043f\u0435\u0441\u0441\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": 8, "\u044d\u0442\u0430\u043f": [8, 9, 13, 73, 77, 82, 85, 86], "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u0435\u043d": [8, 38, 75, 83, 100], "\u043d\u0435\u0443\u0434\u0430\u0447": [8, 64, 83], "\u043e\u0442\u043f\u0443\u0441\u043a\u0430": 8, "\u0443\u0441\u043f\u0435\u0445": [8, 38, 64, 73, 83, 85, 89, 95], "receiveendorsement": 8, "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432": [8, 60, 70, 83, 86, 90], "\u043e\u0442\u043f\u0443\u0441\u0442": 8, "\u043f\u043e\u0437\u0432\u043e\u043b": [8, 37, 72, 76, 85, 86, 88, 100], "\u0437\u0430\u0432\u0435\u0440\u0448": [8, 23, 74, 83], "\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c": [8, 23, 30, 34, 100], "\u0437\u0430\u043c\u0435\u043d": [8, 23, 38, 82, 92, 102], "pendingendorsementcount": [8, 9], "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [8, 30], "\u043e\u0441\u0442\u0430\u043d\u043e\u0432": [8, 9, 83, 86, 100], "\u0438\u0441\u043a\u043b\u044e\u0447": [8, 30, 34, 56, 73, 76], "\u0431\u0443\u0434\u0443\u0449": [8, 21, 23, 38, 47, 68, 70, 76, 85, 86], "\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d": [8, 11], "grade_2": [8, 9], "endorsementcount": [8, 9], "lowerweight": 8, "proposed": [8, 65, 86], "accepted": [8, 23, 34, 38, 51, 53], "receivedendorsements": 8, "aid": [8, 46], "receive": [8, 23, 34, 37], "endorsements": 8, "higher": [8, 23, 38, 39, 70, 74, 75, 77, 86, 90], "cancompleteendorsement": 8, "able": [8, 37, 38, 39, 46, 62, 65, 73, 74, 75, 76, 85, 86], "complete": [8, 23, 34, 38, 51, 52, 60, 62, 65, 73, 74, 75, 77, 82, 86, 90, 95], "_": [8, 9, 73], "range": [8, 38, 51, 85], "isendorsedby": 8, "has": [8, 9, 15, 21, 23, 29, 34, 37, 38, 39, 49, 52, 64, 65, 72, 73, 74, 75, 76, 85, 86, 90, 100], "already": [8, 15, 21, 23, 34, 73, 74, 85, 86], "been": [8, 9, 21, 23, 34, 37, 38, 41, 49, 51, 52, 65, 70, 72, 73, 74, 75, 76, 86, 90], "endorsed": 8, "recogniser": 8, "actualizegrade": 8, "getreceivedendorsementcount": 8, "counter": [8, 74], "getspecialistgrade": 8, "getweight": 8, "rid": [8, 37, 76], "bool": [8, 9, 23], "canreserveendorsement": 8, "reserveendorsement": 8, "reserved": 8, "releaseendorsementreservation": 8, "completeendorsement": 8, "reservation": 8, "emacsway": [8, 16, 96], "tree": [8, 85, 86], "main": [8, 9, 23, 77, 86], "\u043f\u0440\u043e\u0435\u043a\u0442": [8, 12, 13, 23, 37, 38, 40, 41, 42, 46, 64, 65, 68, 70, 72, 74, 75, 76, 77, 80, 82, 85, 86, 92], "\u043f\u0440\u0435\u0434\u0443\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430": [8, 70], "multitenancy": 8, "\u0441\u0432\u0435\u0442": [8, 21, 38, 47, 75, 86, 88, 92], "\u0433\u0438\u0431\u043a": [8, 23, 37, 51, 70, 75, 76, 85], "\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 8, "tenant": 8, "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440": [8, 9, 23, 73], "\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d": [8, 92, 100, 102], "\u043f\u0435\u0440\u0435\u0435\u0445\u0430": 8, "\u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430": 8, "\u0440\u043e\u0441\u0442": [8, 21, 37, 40, 41, 64, 65, 70, 73, 74, 75, 76, 80, 83, 85, 86, 90, 94, 100], "\u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442": [8, 74, 77, 85, 100], "rules": [8, 23, 34, 72, 75, 82, 85, 86, 94], "engine": 8, "aka": [8, 9, 34, 82], "production": [8, 9, 23, 37, 70, 76, 82, 85, 86], "rule": [8, 9, 21, 23, 34, 46, 52, 62, 72, 85], "grule": 8, "implementation": [8, 14, 21, 23, 34, 38, 51, 60, 65, 68, 72, 74, 75, 76, 77, 82, 85, 86, 90, 100], "golang": [8, 9, 11, 12, 13, 15, 17, 19, 21, 23, 34, 82, 109], "\u043b\u0438\u0448": [9, 21, 23, 38, 40, 70, 74, 83, 85, 86, 102], "\u0434\u044b\u0440\u044f\u0432": 9, "\u0440\u0435\u0448\u0435\u0442": 9, "\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d": [9, 72, 85, 86], "\u0437\u0430\u043f\u0440\u043e\u0441": [9, 21, 23, 30, 34], "\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d": [9, 15, 23, 38, 40, 41, 46, 73, 74, 85, 86, 90, 92], "\u0431\u043b\u0438\u0437\u043a": [9, 41], "\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d": [9, 21, 72, 82, 90, 94, 100], "\u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430": [9, 21, 23, 30, 52, 56, 82, 85], "\u043d\u0438\u043a": [9, 21, 88, 94], "\u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b": [9, 100], "preserving": 9, "encapsulation": 9, "avoids": [9, 23], "exposing": [9, 23], "originator": 9, "should": [9, 11, 21, 23, 29, 37, 38, 46, 49, 51, 53, 62, 65, 70, 72, 73, 74, 75, 76, 80, 85, 86, 90, 100], "manage": [9, 23, 51, 74, 86], "must": [9, 21, 23, 26, 29, 34, 37, 38, 51, 73, 74, 75, 76, 85, 86, 88], "nevertheless": [9, 34], "outside": [9, 21, 23, 38, 76, 86], "shields": 9, "other": [9, 21, 23, 26, 29, 34, 37, 38, 39, 41, 42, 49, 51, 52, 65, 70, 72, 73, 74, 75, 76, 77, 82, 85, 86, 90, 94, 95, 100], "potentially": [9, 23, 38, 51], "complex": [9, 21, 23, 38, 60, 62, 70, 74, 75, 76, 77, 85, 86, 90, 100], "internals": [9, 11, 23, 34, 82], "thereby": [9, 65, 86], "patterns": [9, 11, 13, 23, 30, 34, 37, 66, 71, 73, 74, 75, 76, 82, 86, 92, 94, 132], "reusable": [9, 72, 73, 82], "object": [9, 15, 21, 23, 26, 29, 37, 38, 64, 72, 73, 74, 75, 76, 77, 82, 85, 90, 100], "oriented": [9, 15, 21, 23, 37, 64, 72, 73, 74, 75, 76, 77, 82, 86, 90], "erich": [9, 72, 73, 82], "gamma": [9, 23, 72, 73, 82], "richard": [9, 49, 51, 64, 72, 73, 82, 86, 88], "helm": [9, 72, 73, 82], "ralph": [9, 72, 73, 76, 80, 82, 85], "johnson": [9, 72, 73, 76, 82, 85], "john": [9, 23, 34, 38, 46, 66, 70, 72, 73, 82, 85, 88, 95], "vlissides": [9, 72, 73, 82], "\u0430\u0432\u0442\u043e\u0440\u0438\u0442\u0435\u0442\u043d": [9, 15, 40, 41, 75, 82, 85, 92], "some": [9, 21, 23, 26, 34, 37, 38, 42, 46, 49, 51, 60, 63, 65, 70, 72, 73, 74, 75, 76, 82, 85, 86, 90, 95, 100], "form": [9, 21, 23, 38, 49, 51, 52, 74, 75, 85, 86], "serialization": 9, "rest": [9, 21, 23, 52, 70, 73, 74, 75, 82, 85], "discussion": [9, 21, 23], "mechanism": [9, 23, 34], "assumed": 9, "built": [9, 38, 65, 77, 85, 86, 100], "although": [9, 21, 23, 34, 65, 70, 77, 85], "highly": [9, 21, 23, 37, 76, 82, 86], "advantageous": [9, 100], "their": [9, 21, 23, 26, 34, 37, 38, 39, 46, 49, 51, 52, 64, 65, 72, 73, 74, 75, 76, 82, 85, 86, 92], "platform": [9, 37, 65, 74], "results": [9, 34, 37, 38, 51, 74, 82, 85], "though": [9, 23, 34, 37, 38, 74, 75, 76, 77], "quite": [9, 21, 23, 34, 37, 47, 51, 73, 76, 85], "useful": [9, 21, 23, 29, 34, 37, 53, 82, 86], "dealing": [9, 23, 34, 65, 73, 82], "snapshots": 9, "better": [9, 15, 21, 23, 34, 37, 38, 42, 51, 65, 70, 72, 73, 74, 75, 77, 82, 85], "insulates": 9, "serializer": 9, "versioning": [9, 23, 34, 82], "problems": [9, 15, 21, 37, 38, 63, 65, 68, 72, 74, 77, 82, 85, 86, 100], "released": [9, 38, 49, 86], "either": [9, 15, 21, 23, 26, 34, 37, 38, 51, 65, 75, 76, 85], "deleted": 9, "recreated": 9, "updated": [9, 21, 23, 52, 62], "match": [9, 49, 76, 82], "schema": [9, 23], "separated": 9, "snapshot": 9, "itself": [9, 21, 23, 34, 38, 62, 65, 72, 73, 74, 76, 85, 86], "cqrs": [9, 11, 19, 28, 34, 75, 109, 115], "documents": [9, 21, 37, 38, 82], "greg": [9, 21, 23, 34, 82], "young": [9, 21, 23, 34, 64, 82], "\u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446": [9, 21, 46, 70, 73], "\u043f\u0430\u0442\u0442\u0435\u0440\u043d": [9, 21, 23, 34, 75, 82, 85, 88, 94], "visitor": 9, "\u0447\u0438\u0441\u043b": [9, 11, 23, 34, 38, 41, 74, 85, 86, 90, 93, 100], "\u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a": [9, 23, 30, 56, 72, 77, 82, 85, 88, 91, 94, 138], "\u043e\u0442\u043d\u043e\u0441": [9, 23, 38, 74, 80, 83, 86, 92, 100], "breaking": [9, 23, 85, 86], "assumes": [9, 65], "concreteelement": 9, "enough": [9, 21, 23, 37, 38, 49, 51, 60, 62, 65, 70, 73, 74, 76, 82, 86, 90, 100], "let": [9, 23, 34, 37, 38, 72, 74, 76, 85, 86], "visitors": 9, "job": [9, 15, 21, 37, 38, 42, 46, 72, 73, 74, 76, 85, 86], "result": [9, 13, 15, 21, 23, 37, 38, 51, 64, 74, 76, 85, 86], "often": [9, 21, 23, 34, 37, 38, 46, 49, 51, 52, 68, 72, 74, 76, 77, 85, 86, 92, 94, 100], "forces": [9, 38, 65, 75, 85, 86], "provide": [9, 23, 34, 38, 42, 49, 74, 77, 86, 90, 100], "operations": [9, 21, 23, 29, 34, 85, 86, 90], "access": [9, 11, 21, 23, 51], "state": [9, 11, 21, 23, 34, 37, 72, 74, 89], "may": [9, 21, 23, 34, 37, 38, 46, 51, 65, 73, 74, 75, 76, 77, 85, 86], "compromise": 9, "\u043e\u0431\u0445\u043e\u0434": [9, 23, 37, 83], "\u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0447\u0435\u0441\u043a": 9, "\u0432\u043b\u043e\u0436\u0435\u043d": [9, 11, 23, 30, 41], "\u0441\u0443\u0449\u043d\u043e\u0441\u0442": [9, 13, 23, 30, 73, 100], "\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440": [9, 70], "\u0432\u044b\u0440\u0430\u0436\u0435\u043d": [9, 21, 23, 37, 85, 102], "\u043b\u0438\u0448\u0430": [9, 23, 40, 83], "\u0432\u043e\u0437\u0432\u0440\u0430\u0442": [9, 15, 21], "\u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430": 9, "walkable": 9, "accept": [9, 21, 23, 34, 37, 38, 73], "setfield": 9, "walkwalkable": 9, "walkuint8": 9, "walkuint64": 9, "walkuint": 9, "walktime": 9, "endorsement": 9, "interfaces": [9, 51, 72, 74, 82, 86], "value": [9, 11, 21, 23, 25, 26, 37, 38, 39, 41, 42, 49, 52, 62, 66, 70, 73, 74, 76, 82, 85, 86, 93, 100, 113], "\u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d": [9, 65, 74, 90], "\u043f\u0440\u043e\u0441\u0442\u0430\u0432": 9, "\u043e\u0441\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d": [9, 73, 92], "\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d": [9, 11, 30, 86, 92, 93], "\u0440\u0430\u0437\u043c\u0430\u0437\u044b\u0432\u0430": 9, "walkers": 9, "repositories": [9, 23], "\u0440\u0430\u0437\u043b\u0435\u0442": [9, 13], "\u0434\u0440\u043e\u0431": [9, 13], "smell": [9, 13, 76], "\u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d": [9, 86, 100], "\u0434\u0438\u0430\u043b\u0435\u043a\u0442": 9, "\u0432\u043d\u0435\u0434\u0440\u0435\u043d": [9, 73, 86, 88], "querybuilder": 9, "\u043d\u0430\u0447\u0438\u043d\u0430": [9, 21, 23, 38, 40, 46, 47, 52, 56, 70, 74, 77, 82, 83, 85, 86, 88, 92, 94, 95, 100], "\u0441\u043b\u0438\u0448\u043a": [9, 11, 23, 38, 46, 74, 76, 82, 85, 86, 88, 94], "\u0434\u0435\u0442\u0430\u043b": [9, 74, 90, 100], "\u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d": [9, 21, 23, 37, 40, 64, 65, 75, 76, 80, 86], "\u0432\u043e\u0437\u043b\u043e\u0436": 9, "\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 9, "\u043e\u0441\u0432\u043e\u0431\u043e\u0434": 9, "\u0440\u0430\u0437\u0440\u044b\u0432\u0430": 9, "\u043e\u0431\u044f\u0437\u0430\u043d": [9, 38, 73, 75, 83, 85], "\u043f\u043e\u0434\u0440\u044b\u0432\u0430": [9, 88], "\u0434\u0432\u0435\u0440": 9, "\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c": [9, 21, 76], "valueobject": 9, "\u0431\u0440\u0435\u0448": 9, "\u0441\u043f\u0440\u0430\u0432\u0435\u0434\u043b\u0438\u0432": [9, 23, 42], "\u0440\u0430\u0434": [9, 38, 75], "\u043e\u0442\u043c\u0435\u0442": 9, "\u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d": [9, 30, 40], "\u043c\u0443\u0442\u0438\u0440\u0443\u0435\u043c": 9, "\u043f\u0440\u043e\u0432\u0435\u0440": [9, 37, 74], "scan": 9, "src": 9, "\u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432": [9, 21, 23, 83, 85, 88], "special": [9, 23, 34, 51, 85], "case": [9, 21, 23, 29, 34, 37, 38, 51, 52, 70, 73, 74, 76, 82, 85, 86, 100], "null": [9, 70], "\u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430": [9, 46], "\u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f": [9, 11, 26], "\u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a": [9, 75, 76, 88], "\u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430": [9, 15, 23, 86], "validating": [9, 65], "historical": [9, 37, 76], "valid": [9, 14, 23], "orms": [9, 21], "within": [9, 11, 23, 34, 37, 38, 51, 52, 65, 73, 74, 75, 76, 77, 85, 86], "boundary": [9, 11, 23, 86], "\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430": [9, 15, 22, 26, 74, 76, 111], "\u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d": 9, "\u043f\u0440\u0438\u0433\u043e\u0434": 9, "handled": [9, 23, 76, 86], "namedvaluechecker": 9, "instance": [9, 21, 23, 26, 73, 85, 93], "types": [9, 21, 23, 38, 51, 65, 74, 75], "int64": 9, "float64": 9, "byte": [9, 23], "\u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043d": [9, 102], "\u0437\u0430\u0449\u0438\u0449\u0435\u043d": [9, 11], "\u0430\u0442\u0440\u0438\u0431\u0443\u0442": [9, 11, 26, 51, 75], "\u0440\u0435\u0444\u043b\u0435\u043a\u0446": 9, "\u0440\u0435\u0444\u043b\u0435\u043a\u0441": [9, 100], "\u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430": [9, 70], "\u0447": [9, 38], "\u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d": [9, 34, 77], "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d": [9, 34], "\u043f\u0440\u043e\u0431": [9, 77], "marshal": 9, "protected": 9, "inner": 9, "hidden": [9, 23], "fmt": 9, "reflect": [9, 23, 34, 41, 65, 77, 100], "bitly": 9, "simplejson": 9, "json": [9, 23, 82, 89], "j": [9, 23, 30, 34, 38, 51, 64, 70, 74, 82, 86, 88, 90], "va": 9, "valueof": 9, "vt": 9, "elem": 9, "typeof": 9, "i": [9, 11, 13, 21, 23, 34, 37, 38, 39, 41, 46, 51, 53, 60, 62, 65, 70, 72, 73, 74, 75, 76, 82, 85, 86, 92, 94, 95], "numfield": 9, "set": [9, 15, 21, 23, 37, 38, 46, 49, 52, 53, 62, 65, 72, 74, 75, 76, 85, 100], "field": [9, 21, 23, 38, 74, 76], "tag": 9, "sprintf": 9, "indirect": 9, "marshaljson": 9, "jessonchan": 9, "abc": 9, "println": 9, "implementing": [9, 11, 21, 23, 29, 34, 38, 46, 51, 65, 70, 75, 76, 82, 86, 100], "aggregate": [9, 11, 23, 30, 34], "around": [9, 11, 23, 37, 38, 62, 70, 73, 75, 76, 82, 86, 95], "problem": [9, 21, 23, 26, 37, 38, 49, 60, 62, 65, 70, 72, 73, 74, 75, 76, 77, 80, 82, 83, 85, 86, 90, 100], "tight": [9, 86], "clients": [9, 21, 23, 65], "choose": [9, 11, 23, 37, 38, 76, 77, 85, 86], "et": [9, 23, 74, 86], "al": [9, 23, 74, 86], "double": [9, 86], "dispatch": [9, 23], "callback": [9, 21], "publishes": [9, 21, 23], "would": [9, 11, 21, 23, 26, 34, 37, 38, 41, 46, 51, 65, 70, 72, 75, 76, 85, 86, 100], "implement": [9, 11, 23, 37, 49, 70, 72, 76, 80, 82, 85], "passing": [9, 23, 26, 37], "implementer": 9, "argument": [9, 21, 23, 26, 37, 65, 74, 76, 77, 82, 85, 86, 94], "then": [9, 11, 21, 23, 26, 29, 34, 37, 38, 41, 46, 51, 60, 62, 70, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 90], "requested": 9, "without": [9, 11, 21, 23, 34, 37, 38, 51, 65, 70, 74, 76, 85, 86], "revealing": 9, "shape": [9, 86, 100], "trick": [9, 23], "wed": 9, "sort": [9, 37, 72, 85], "keep": [9, 23, 37, 38, 51, 53, 73, 74, 85, 86, 90], "focused": [9, 23, 38, 82, 85, 86, 100], "rendering": 9, "states": [9, 23, 75], "interest": [9, 21, 23, 37, 38, 41, 42, 70, 76, 77, 100], "backlogitem": [9, 23], "providebacklogiteminterest": 9, "backlogiteminterest": 9, "aninterest": 9, "informtenantid": 9, "tenantid": 9, "informproductid": 9, "productid": 9, "informbacklogitemid": 9, "backlogitemid": 9, "informstory": 9, "story": [9, 23, 37, 38, 49, 51, 53, 65, 73, 76, 82], "informsummary": 9, "summary": [9, 86], "informtype": 9, "tostring": 9, "providetasksinterest": 9, "tasksinterest": 9, "alltasks": 9, "informtaskcount": 9, "size": [9, 73, 74, 76, 86, 92], "various": [9, 23, 37, 38, 51, 76], "providers": 9, "implemented": [9, 21, 23, 37, 38, 82, 100], "classes": [9, 23, 70, 74, 75, 77, 85, 90], "much": [9, 21, 23, 37, 38, 42, 46, 47, 68, 70, 72, 73, 74, 75, 77, 82, 85, 86, 88, 100], "entities": [9, 11, 23, 75, 82], "describe": [9, 37, 86], "validation": [9, 15, 23, 38, 59, 60, 82], "delegated": 9, "separate": [9, 23, 38, 51, 52, 74, 75, 82, 85, 86, 90, 95], "validator": 9, "aware": [9, 23, 38, 51, 73, 85, 92], "consider": [9, 21, 23, 34, 37, 38, 51, 70, 74, 77, 86, 90], "responsibility": [9, 21, 23, 34, 37, 38, 75, 86], "natural": [9, 23, 86], "well": [9, 23, 37, 38, 39, 46, 51, 60, 62, 64, 66, 70, 73, 74, 75, 76, 77, 85, 86, 90, 93, 100], "such": [9, 15, 21, 23, 34, 37, 38, 46, 49, 51, 52, 65, 72, 74, 75, 76, 77, 85, 86, 90, 94, 100], "trade": [9, 23, 37, 38, 74, 76, 77, 82, 85, 86], "offs": [9, 38, 77, 85, 86], "discussed": [9, 23, 34, 37, 86], "technical": [9, 11, 21, 23, 37, 38, 39, 43, 46, 49, 52, 65, 66, 70, 72, 73, 76, 82, 85, 86, 90, 100, 121], "team": [9, 23, 32, 38, 42, 46, 49, 51, 52, 73, 74, 76, 80, 86, 100, 117], "getters": 9, "setters": 9, "holub": 9, "load": [9, 23, 51, 74, 86, 90], "java": [9, 21, 23, 34, 75, 82, 85], "util": 9, "locale": 9, "employee": [9, 23], "employeeid": 9, "money": [9, 38, 41, 65, 74, 82], "salary": 9, "addname": 9, "addid": 9, "addsalary": 9, "providename": 9, "provideid": 9, "providesalary": 9, "close": [9, 15, 21, 49, 52, 68, 73, 75], "builder": 9, "export": 9, "setstate": 9, "exportable": [9, 11], "exportto": 9, "exportableuint": 9, "ex": 9, "endorserexportersetter": 9, "setid": 9, "setavailableendorsementcount": 9, "setpendingendorsementcount": 9, "setversion": 9, "setcreatedat": 9, "uintexporter": 9, "endorserexporter": 9, "val": 9, "personimporter": 9, "int": 9, "getage": 9, "personexporter": 9, "setdetails": 9, "person": [9, 11, 26, 39, 74, 76, 82, 85, 86, 90, 95], "\u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d": 9, "\u0438\u043d\u0442\u0435\u0440\u0435\u0444\u0435\u0439\u0441": 9, "\u043f\u043e\u043b\u0443\u0447\u0430": [9, 21, 23, 37, 38, 41, 47, 62, 77, 85, 86, 88], "\u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0432\u043d": 9, "\u0434\u0435\u043a\u043b\u0430\u0440\u0438\u0440\u043e\u0432\u0430": 9, "\u0441\u0435\u0442\u0442\u0435\u0440": 9, "\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440": [9, 21, 23, 34, 37, 38, 40, 41, 56, 65, 72, 73, 74, 75, 76, 87, 88, 90, 92, 93, 100, 137], "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d": [9, 21, 23, 37, 38, 40, 46, 64, 67, 68, 70, 73, 74, 75, 76, 81, 83, 85, 86, 92, 93, 95, 130, 135], "\u0443\u043c\u0435\u043d\u044c\u0448": [9, 37, 56, 72, 75, 85, 86, 88], "\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a": [9, 40, 42, 74, 75, 85, 90, 92], "\u0442\u0440\u0443\u0434\u043e\u0437\u0430\u0442\u0440\u0430\u0442": [9, 56, 70, 74], "minimize": [9, 38, 74, 90], "human": [9, 37, 38, 42, 74, 90], "resources": [9, 23, 38, 49, 65, 74, 82, 86], "required": [9, 23, 38, 46, 49, 62, 72, 74, 75, 85, 86], "maintain": [9, 23, 34, 38, 51, 52, 70, 73, 74, 85], "clean": [9, 21, 23, 37, 38, 40, 41, 66, 68, 73, 74, 75, 76, 82], "craftsman": [9, 21, 40, 41, 66, 73, 74, 75, 76, 82, 85], "robert": [9, 13, 21, 23, 34, 37, 38, 40, 41, 64, 66, 68, 72, 75, 76, 77, 80, 82, 85, 92, 93], "martin": [9, 13, 14, 21, 23, 34, 37, 38, 40, 41, 46, 62, 65, 66, 68, 70, 72, 75, 76, 80, 82, 85, 86, 92, 93, 95], "\u043e\u043e": [9, 21, 37, 38, 42, 46, 47, 68, 70, 74, 86], "\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432": [9, 21, 37, 38, 42, 46, 47, 68, 70, 74, 86, 88], "\u043f\u0438\u0442\u0435\u0440": [9, 21, 37, 38, 42, 46, 47, 68, 70, 74, 82, 86, 88], "\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d": [9, 23, 37, 47, 75, 102], "\u043f\u0430\u043a\u0435\u0442\u0438\u0440\u043e\u0432\u0430": [9, 23, 34], "\u0443\u0441\u0442\u0443\u043f\u0430": [9, 38, 88], "\u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d": [9, 23], "\u043e\u0431\u043e\u0439\u0442": [9, 15, 21, 23, 37, 70, 94, 102], "\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0435\u0440": [9, 11], "\u0443\u0434\u043e\u0431\u043d": [9, 11, 15, 23, 74], "\u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d": [9, 75], "\u0441\u043f\u0438\u0441\u043a": [9, 11, 21, 23, 30, 34, 38, 75], "\u043f\u0440\u0438\u0434\u0435\u0442": [9, 34, 46, 85, 92, 94, 100], "\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430": 9, "\u043a\u043e\u043d\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d": 9, "\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d": [9, 23], "\u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434\u0441\u0442\u0432": [9, 75, 76, 85, 88, 90, 95], "\u043e\u0431\u043b\u0430\u0434\u0430": [9, 11, 38, 60, 65, 68, 74, 75, 85, 86, 90, 92, 93, 95, 100], "\u0445\u0440\u0443\u043f\u043a\u043e\u0441\u0442": 9, "\u043d\u0435\u043c\u043d": [9, 21, 38, 40, 65, 72, 75, 82, 83, 86], "\u0441\u043c\u0443\u0449\u0430": [9, 15], "\u0441\u043c\u0435\u0448\u0438\u0432\u0430\u043d": 9, "\u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c": [9, 21, 82], "fp": [9, 21], "oop": [9, 21, 37, 75, 76], "\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [9, 21, 23, 34, 38, 40, 46, 47, 51, 74, 85, 93], "\u0447\u0438\u0441\u0442": [9, 11, 21, 70, 74, 85], "\u043c\u0443\u0442\u0438\u0440": [9, 11], "\u0441\u043c\u0443\u0449\u0435\u043d": 9, "\u043f\u043e\u0447": [9, 21, 30, 37, 38, 40, 41, 70, 73, 74, 75, 86, 88, 89, 90, 94, 100], "generics": 9, "exporterfactory": 9, "function": [9, 15, 21, 23, 38, 46, 49, 62, 65, 74, 75, 85], "attr1": 9, "attr2": 9, "attr3": 9, "\u043e\u0434\u043d\u0430\u043a": [9, 11, 21, 23, 30, 34, 37, 38, 42, 46, 47, 52, 70, 72, 74, 76, 85, 86, 88, 92, 93, 100], "\u043f\u0440\u043e\u0434\u043e\u043b\u0436": [9, 38, 100], "\u0440\u0430\u0437\u0432\u0438\u0432\u0430": [9, 74, 82, 83, 85, 86], "\u0432\u044b\u0437\u0432\u0430": [9, 15, 21, 38, 72, 86, 94], "michael": [9, 23, 30, 34, 38, 64, 66, 70, 74, 82], "feathers": [9, 66, 70, 82], "oo": [9, 82], "makes": [9, 11, 13, 21, 23, 34, 37, 38, 51, 62, 65, 66, 68, 70, 74, 75, 76, 85, 86, 93, 100], "understandable": 9, "encapsulating": [9, 23], "moving": [9, 42, 60, 76], "parts": [9, 11, 23, 34, 37, 46, 47, 72, 75, 76, 82, 85, 86], "minimizing": [9, 37, 73, 74, 76, 86, 90], "\u0441\u043a\u0430\u0437\u0430": [9, 21, 23, 46, 60, 65, 70, 73, 74, 82, 85, 86, 90, 94, 100], "\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430": [9, 47, 85], "\u0447\u0435\u0440\u043d": [9, 85], "\u044f\u0449\u0438\u043a": [9, 85], "\u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d": [9, 21, 37, 46, 73, 82], "\u0432\u0435\u0440\u043d": [9, 21, 23, 37, 38, 40, 41, 73, 77, 86, 88], "\u0432\u0432\u0435\u0434\u0435\u043d": [9, 23, 34, 70, 82, 100], "\u0434\u0430\u0432\u043d": [9, 88], "\u043f\u0440\u043e\u0441\u0442\u043e\u0442": [9, 21, 23, 30, 38, 73, 74, 75, 90], "\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [9, 42, 46, 47, 74, 84, 136], "\u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d": [9, 73, 100, 102], "\u0448\u0430\u0431\u043b\u043e\u043d": [9, 23, 37, 76], "\u0441\u043a\u0440\u043e\u043c\u043d": [9, 73, 83], "\u0442\u044f\u0436\u0435\u043b": [9, 68, 74, 85, 100], "\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c": 9, "\u0441\u043e\u0432\u043f\u0430\u0434\u0430": [9, 82, 100], "\u0433\u0440\u0430\u043d\u0438\u0446": [9, 11, 12, 23, 29, 34, 75, 86, 92, 93, 100], "\u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0442\u043e\u0440": 9, "long": [9, 23, 37, 38, 41, 62, 73, 74, 76, 82, 85, 86, 95], "known": [9, 21, 23, 37, 38, 39, 41, 65, 74, 85, 90], "testability": 9, "attribute": [9, 15, 21, 23, 29, 38, 86], "architectures": [9, 23, 37, 38, 66, 75, 76, 82, 86], "humble": [9, 73, 82], "because": [9, 11, 21, 23, 34, 37, 38, 46, 51, 62, 65, 70, 73, 74, 75, 76, 77, 80, 85, 86, 100], "separation": [9, 21, 23, 37, 75, 76, 85, 86], "behaviors": 9, "testable": [9, 49, 53, 85], "non": [9, 21, 23, 38, 51, 62, 76, 77, 86], "defines": [9, 23, 51, 86], "architectural": [9, 37, 38, 46, 51, 52, 60, 64, 74, 76, 77, 82, 86], "presenter": 9, "\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 9, "\u043f\u0440\u0438\u0434\u0430": [9, 38, 94], "\u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440": [9, 11], "endorserstate": 9, "dto": 9, "\u043e\u0442\u043b\u0438\u0447": [9, 34, 38, 52, 85, 88, 92, 95], "\u0441\u0435\u0442\u0435\u0432": [9, 21, 34, 86], "\u0447\u0443\u0442": [9, 82, 83], "\u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d": [9, 88], "\u043a\u043e\u043d\u0442\u0440\u0430\u0441\u0442\u0438\u0440": 9, "\u0440\u0430\u0437\u043d\u043e\u0432\u0438\u0434\u043d": [9, 85], "\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [9, 37, 46, 60, 65, 68, 70, 72, 73, 74, 75, 76, 77, 85, 86, 90, 93, 94], "\u043f\u043e\u043c\u043e\u0433\u0430": [9, 23, 38, 70, 74, 82, 85, 90, 92, 93, 100], "\u0432\u044b\u044f\u0432\u043b\u044f": [9, 93], "\u0437\u0430\u0449\u0438\u0449\u0430": [9, 56, 92], "presenters": 9, "helps": [9, 23, 38, 53, 73, 74, 85, 86, 90, 100], "identify": [9, 46, 85], "protect": [9, 26], "\u0436\u0435\u043b\u0430\u043d": [9, 38, 70, 85, 86, 100], "\u043f\u0435\u0440\u0435\u0434\u0430\u0447": [9, 23, 34, 56, 86], "transfer": [9, 34, 82], "\u0444\u0443\u043d\u043a\u0446": [9, 23, 38, 41, 46, 62, 70, 74, 85, 86], "\u0443\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430": 9, "\u0430\u0441\u0441\u043e\u0446\u0438\u0430\u0442\u0438\u0432\u043d": 9, "\u043c\u0430\u0441\u0441\u0438\u0432": 9, "\u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430": [9, 73, 74, 75, 83, 85, 90], "\u0445\u0438\u0442\u0440": 9, "\u0437\u0430\u043f\u0438\u0441": [9, 21, 23], "\u043d\u0430\u0437\u0432\u0430": [9, 75, 76, 100], "\u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f": [9, 74, 90], "\u0437\u043d\u0430\u0442": [9, 21, 56, 82, 83, 93, 95], "\u0438\u0442\u0430\u043a": [9, 21, 23, 40, 52, 75, 83], "typically": [9, 23, 29, 37, 38, 49, 51, 74, 77, 85, 86], "crosses": 9, "consists": [9, 62, 86, 100], "structures": [9, 37, 38, 64, 75, 76, 82, 86], "basic": [9, 38, 42, 72, 75, 86], "structs": 9, "simply": [9, 21, 23, 38, 41, 51, 74, 75, 76, 86, 90], "arguments": [9, 21, 85], "calls": [9, 21, 23, 74, 85, 86], "pack": [9, 73], "hashmap": 9, "construct": [9, 29], "important": [9, 15, 21, 23, 34, 37, 38, 39, 41, 49, 51, 65, 73, 74, 75, 76, 85, 86, 90], "isolated": [9, 82, 86], "passed": [9, 11, 23, 26, 34, 37], "across": [9, 23, 29, 34, 38, 46, 75, 76, 85, 86], "we": [9, 21, 23, 34, 37, 38, 41, 46, 51, 52, 62, 64, 65, 68, 70, 72, 73, 74, 75, 76, 82, 85, 86, 90, 92, 94, 95, 100], "don": [9, 21, 23, 30, 34, 37, 38, 42, 46, 47, 49, 51, 60, 62, 66, 68, 70, 73, 74, 75, 76, 77, 82, 85, 86, 95], "cheat": [9, 82, 89], "pass": [9, 34, 85], "rows": [9, 23], "dependency": [9, 34, 75], "violates": 9, "frameworks": [9, 64, 76, 85], "convenient": [9, 23], "response": [9, 21, 23, 37, 77], "query": [9, 15, 23, 29, 75, 82], "might": [9, 21, 23, 26, 29, 34, 37, 38, 42, 49, 51, 62, 70, 73, 74, 75, 76, 77, 85, 86, 90, 100], "call": [9, 21, 23, 38, 51, 75, 76, 85, 86], "row": [9, 23], "inward": 9, "doing": [9, 15, 21, 23, 37, 38, 39, 41, 42, 72, 73, 76, 80, 82, 85, 86], "violate": [9, 38, 75], "force": [9, 21, 23, 38, 65, 75, 85, 86], "circle": 9, "know": [9, 23, 37, 38, 41, 47, 51, 60, 62, 73, 74, 75, 76, 82, 85, 100], "something": [9, 21, 23, 37, 38, 41, 42, 46, 49, 51, 52, 65, 70, 72, 73, 74, 76, 85], "about": [9, 11, 21, 23, 34, 37, 38, 41, 42, 51, 52, 62, 65, 70, 72, 73, 74, 77, 80, 82, 85, 86, 90, 100], "outer": [9, 38], "thus": [9, 23, 34, 62, 70, 75], "most": [9, 23, 29, 37, 38, 42, 47, 51, 52, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 82, 85, 86, 90], "dataaccessinterface": 9, "\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d": [9, 23, 70], "usecaseinteractor": 9, "\u0437\u0430\u0431\u0438\u0440\u0430": [9, 23], "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440": 9, "outputdata": 9, "outputboundary": 9, "uses": [9, 21, 23, 75, 85, 86], "bring": [9, 23, 38, 47, 77, 86, 100], "memory": [9, 21, 23, 29], "upon": [9, 21, 23, 38, 76, 85, 86], "completion": [9, 23], "gathers": 9, "constructs": [9, 21], "old": [9, 37, 46, 47, 74, 76, 77, 85], "through": [9, 11, 21, 23, 34, 37, 38, 49, 51, 72, 74, 76, 77, 82, 85, 88, 94], "\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440": [9, 23, 38, 40, 82, 85, 93], "es": [9, 82], "\u043a\u043e\u043d\u0442\u0440\u0438\u0431\u044c\u044e\u0442\u043e\u0440": 9, "eventstore": [9, 34, 82], "nick": [9, 82, 86, 88], "tune": [9, 82, 86, 88], "\u0443\u0441\u043f\u0435\u043b": [9, 23], "\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430": [9, 23, 38], "\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c": 9, "\u043e\u0431\u043e\u0431\u0449\u0435\u043d": [9, 72, 85, 93], "\u043f\u043b\u043e\u0434": [9, 100], "\u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d": [9, 34], "\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430": 9, "\u043f\u043e\u0434\u0442\u0430\u043b\u043a\u0438\u0432\u0430": [9, 23], "\u043d\u0435\u0441\u043b\u043e\u0436\u043d": [9, 70, 74, 90], "\u0438\u0437\u0431\u0435\u0436\u0430": [9, 23, 26, 34, 38, 77, 86, 93, 102], "\u0442\u0438\u043f\u0438\u0437\u0430\u0446": 9, "\u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d": [9, 34], "\u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u043e\u0432\u0430": [9, 38], "\u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u043d": 9, "\u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d": [9, 23, 85], "\u0433\u043e\u0440\u0430\u0437\u0434": [9, 21, 38, 70, 73, 74, 90, 92], "\u043c\u0430\u0441\u0441": [9, 38, 76, 86, 92], "\u0441\u0440\u0435\u0437": 9, "\u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a": [9, 100], "\u0442\u0435\u0440\u043c\u0438\u043d": [10, 21, 23, 34, 38, 41, 52, 65, 74, 75, 83, 85, 86, 90, 100, 102], "streamid": [10, 34], "streamname": 10, "streamtype": 10, "streamposition": 10, "\u043d\u0435\u0441\u0443\u0442": 10, "\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0432\u043d": 10, "\u043f\u043e\u044f\u0432\u043b\u044f": [10, 68, 70, 72, 76, 85], "\u0441\u0442\u0430\u0434": [10, 40, 46, 72, 85, 94], "\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430": 10, "\u0441\u0442\u0440\u043e\u043a": [10, 30, 47, 72, 93], "\u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430": 11, "commands": [11, 21, 23], "events": [11, 25, 30, 34, 86, 113], "integration": [11, 30, 32, 34, 76, 82, 86, 117], "\u043f\u043e\u0434\u0447\u0435\u0440\u043a\u043d\u0443\u0442": [11, 76, 100], "high": [11, 23, 29, 38, 65, 66, 70, 73, 74, 75, 76, 77, 80, 82, 85, 86, 100], "chapter": [11, 15, 21, 23, 29, 34, 37, 38, 42, 46, 51, 64, 65, 66, 68, 70, 73, 74, 75, 76, 77, 82, 85, 86, 100], "five": [11, 51, 74], "expressed": [11, 21, 37, 52, 86, 100], "modules": [11, 15, 21, 74, 75], "heart": [11, 23, 26, 34, 38, 70, 73, 74, 75, 76, 82, 90, 100], "eric": [11, 23, 26, 34, 38, 46, 74, 75, 76, 82, 90, 100], "evans": [11, 23, 26, 34, 74, 75, 76, 82, 90, 100], "\u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u044f\u0446": [11, 12], "\u043e\u0433\u0440\u0430\u043d\u0438\u0447": [11, 23, 38, 90, 100, 102], "\u0438\u0437\u0432\u043d": [11, 38], "\u043c\u043e\u0434\u0443\u043b": [11, 74], "\u0434\u0430\u044e\u0442": [11, 74, 75, 82, 85], "\u0438\u0437\u0443\u0447": [11, 38, 74, 77], "\u043f\u043e\u0434\u0440\u043e\u0431": [11, 74], "\u043d\u043e\u0441\u0442": [11, 74], "\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432": [11, 34, 72, 74, 75, 82], "\u0432\u043d\u0438\u043a": [11, 74, 82], "\u0432\u0437\u0430\u0438\u043c\u043e\u043e\u0442\u043d\u043e\u0448\u0435\u043d": [11, 38, 74, 85], "\u0432\u0434\u0430\u0432": [11, 74], "\u0434\u0435\u0442\u0430": [11, 60, 74, 77, 90, 100], "\u0434\u0435\u043b\u0435\u043d": [11, 74], "\u0441\u043e\u0431\u043b\u044e\u0434\u0430": [11, 23, 74], "low": [11, 23, 30, 34, 38, 70, 73, 74, 75, 77, 90], "\u0441\u0432\u044f\u0437\u043d\u043e\u0441\u0442": [11, 74], "\u0433\u0440\u0435\u0448\u0430\u0442": [11, 74], "\u0443\u043a\u043b\u043e\u043d": [11, 74], "\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442": [11, 74], "\u0432\u0435\u043d": [11, 74], "\u043a\u0440\u0438\u0442\u0435\u0440": [11, 30, 37, 40, 50, 64, 74, 125], "\u044f\u043a\u043e\u0431": [11, 23, 74, 75], "\u0438\u0437\u043c\u0435\u0440": [11, 74], "\u043f\u043e\u0434\u0441\u0447\u0438\u0442\u0430": [11, 74], "\u0430\u0441\u0441": [11, 74], "\u0446\u0438\u0430\u0446": [11, 74], "\u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432": [11, 21, 42, 74], "\u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a": [11, 73, 74, 100, 102], "\u043f\u043e\u0434\u0440\u0430\u0437\u0434": [11, 74], "\u043b\u0435\u043d": [11, 74], "\u0438\u0434\u0435\u0439\u043d": [11, 74], "\u043a\u043e\u043d\u0446\u0435\u043f\u0446": [11, 23, 74, 85, 86], "\u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d": [11, 15, 21, 23, 38, 40, 74, 86, 88, 100], "\u0443\u0434\u0435\u0440": [11, 74], "\u0436\u0438\u0432\u0430": [11, 74], "\u0443\u043c": [11, 37, 60, 74, 75, 76, 90], "\u043f\u0440\u0435\u0434\u043c\u0435\u0442": [11, 74, 100, 102], "\u043e\u0442\u0441\u044e\u0434": [11, 21, 74, 75, 90], "\u043f\u043b\u043e\u0445": [11, 21, 46, 73, 74, 76, 85], "\u0442\u0440\u0443\u0434\u043d": [11, 70, 74, 75, 82], "\u043f\u043e\u043d\u044f": [11, 21, 23, 38, 41, 46, 60, 73, 74, 77, 82, 83, 90, 102], "\u043d\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430": [11, 74], "\u043a\u0430\u0448": [11, 74], "they": [11, 21, 23, 29, 34, 37, 38, 42, 46, 47, 49, 51, 52, 62, 65, 68, 72, 73, 74, 75, 76, 77, 85, 86, 90, 92, 100], "look": [11, 21, 34, 41, 60, 62, 70, 74, 77, 82, 85, 86, 90], "detail": [11, 34, 49, 72, 74, 77, 82, 86, 100], "module": [11, 74, 75, 86], "overwhelmed": [11, 74], "whole": [11, 15, 21, 23, 37, 38, 39, 52, 74, 75, 76, 77, 82, 86, 90, 100], "exclude": [11, 74], "interior": [11, 74], "truism": [11, 74], "explanations": [11, 74], "tend": [11, 23, 38, 74, 85, 86, 100], "sound": [11, 23, 37, 73, 74, 76, 77], "metrics": [11, 23, 37, 74, 82], "judged": [11, 74], "mechanically": [11, 74], "distributions": [11, 74], "associations": [11, 23, 74], "interactions": [11, 42, 52, 74, 76], "yet": [11, 23, 34, 74, 76, 82, 85, 86, 88], "isn": [11, 23, 29, 37, 38, 49, 51, 52, 65, 68, 73, 74, 76, 85], "divided": [11, 21, 72, 74, 86], "concepts": [11, 21, 23, 64, 72, 74, 82, 100], "things": [11, 15, 21, 23, 34, 37, 38, 41, 46, 47, 65, 70, 73, 74, 75, 77, 82, 85, 86, 88, 94], "think": [11, 13, 23, 29, 37, 38, 41, 46, 49, 70, 72, 73, 74, 76, 85, 86, 90, 100], "once": [11, 21, 23, 38, 46, 51, 52, 65, 70, 73, 74, 76, 85, 90], "hence": [11, 21, 23, 51, 74, 76, 86], "incoherent": [11, 74], "fragments": [11, 74], "ideas": [11, 23, 34, 37, 38, 65, 72, 73, 74, 75, 82, 85, 88, 92], "hard": [11, 23, 37, 38, 66, 68, 70, 73, 74, 76, 82, 85, 86, 88], "understand": [11, 21, 23, 37, 38, 46, 60, 62, 70, 72, 73, 74, 75, 80, 82, 85, 86, 90], "undifferentiated": [11, 74], "soup": [11, 74], "\u043b": [11, 26, 74, 75, 82, 88, 92, 100], "\u0431\u0440\u043e\u0434\u043e\u0432": [11, 26, 74, 75, 100], "\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": [11, 15, 65, 80, 89, 92, 93], "\u0432\u0438\u043d\u0435\u0433\u0440\u0435\u0442": 11, "\u043f\u043e\u0432\u044b\u0448\u0430": [11, 37, 72, 73, 74, 77, 85, 86], "\u043a\u043e\u0433\u043d\u0438\u0442\u0438\u0432\u043d": [11, 37, 38, 40, 85, 86, 88, 89, 100], "\u043d\u0430\u0433\u0440\u0443\u0437\u043a": [11, 37, 46, 74, 85, 86, 90, 92, 100], "\u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [11, 65], "\u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d": [11, 23], "\u043a\u043e\u043d\u0442\u0440\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442": 11, "\u043a\u0440\u0430\u0442\u043a\u043e\u0432\u0440\u0435\u043c\u0435\u043d": [11, 85], "\u043e\u0442\u0434\u0430\u0432\u0430": [11, 23], "\u043d\u0430\u0440\u0443\u0436": [11, 21, 47], "\u0433\u0440\u0443\u043f\u043f\u0438\u0440": 11, "\u0432\u044b\u0431\u0435\u0440": 11, "\u0434\u0438\u043d": 11, "\u043e\u0431\u0440\u0430\u0449\u0435\u043d": [11, 86, 92], "\u0440\u0430\u0437\u0440\u0435\u0448\u0430": [11, 37, 38, 40, 65], "\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d": 11, "\u043e\u043f\u0435\u0440\u0430\u0446": [11, 23, 74, 85, 93], "\u043a\u043e\u043d": [11, 83], "\u0442\u0440\u043e\u043b\u0438\u0440": 11, "\u043d\u0435\u043e\u0436\u0438\u0434\u0430": 11, "\u0441\u0445\u0435\u043c": [11, 23, 38], "\u0440\u0430\u0437\u0443\u043c\u043d": [11, 72], "\u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u0435\u043d": [11, 38, 75], "cluster": [11, 23], "aggregates": [11, 23, 82], "define": [11, 23, 37, 49, 51, 52, 76, 77, 86, 100], "each": [11, 21, 23, 26, 34, 37, 38, 42, 51, 60, 62, 72, 73, 74, 75, 76, 82, 85, 86, 90, 94, 95, 100], "root": [11, 23, 37, 38], "inside": [11, 23, 51, 76, 82, 86], "external": [11, 37, 38, 74, 75, 76, 85, 86], "hold": [11, 21, 23, 51], "references": [11, 21, 23, 82], "transient": 11, "out": [11, 21, 26, 29, 30, 34, 37, 38, 39, 41, 52, 60, 62, 65, 70, 72, 73, 74, 76, 85, 86, 90], "operation": [11, 15, 21, 23, 34, 49], "controls": [11, 23, 86], "cannot": [11, 21, 23, 26, 34, 37, 38, 52, 74, 76, 86, 90], "blindsided": [11, 23], "changes": [11, 21, 23, 34, 37, 38, 47, 62, 65, 70, 74, 75, 76, 77, 85, 86], "arrangement": [11, 38], "practical": [11, 21, 23, 34, 37, 38, 51, 52, 64, 65, 66, 75, 76, 82, 85, 86, 95, 100], "enforce": [11, 82, 86], "invariants": [11, 21, 23, 26], "\u043f\u0430\u043a\u0435\u0442": [11, 34, 74, 85, 90], "\u043d\u0435\u0436\u0435\u043b": [11, 40, 73, 76, 95], "\u043f\u043e\u0441\u0442\u043e\u0440\u043e\u043d": [11, 86], "\u043f\u043e\u043b\u0443\u0447\u0430\u0442": [11, 21], "law": [11, 38, 74, 76, 86], "demeter": 11, "\u043f\u0440\u044f\u043c": [11, 37, 56, 70, 74, 75, 85, 95], "\u043f\u043b\u043e\u0441\u043a": 11, "\u043e\u0431\u0435\u0441\u043f\u0435\u0447": [11, 73, 75, 85, 86, 88, 90, 95, 100], "\u0430\u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a": 11, "\u0433\u0440\u0430\u0444": 11, "\u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d": [11, 21, 70, 72, 83, 85, 92, 100], "\u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a": 11, "\u0438\u043c\u0435\u043b": [11, 37, 38, 73, 75], "\u043e\u0441\u0432\u0435\u0434\u043e\u043c\u043b": 11, "\u0438\u043d\u0430\u0447": [11, 26, 30, 38, 73, 83, 85, 94, 95, 100, 102], "\u043f\u0440\u0438\u0448\u043b": [11, 38, 56, 73, 83, 88], "\u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d": [11, 38, 85], "c\u0443\u0449\u043d\u043e\u0441\u0442": 11, "\u0440\u0430\u0437\u043c\u0435\u0442": 11, "\u043d\u0430\u0432\u0438\u0433\u0430\u0446": [11, 90, 100], "\u043f\u043e\u0437\u0436": [11, 23, 37, 38, 68, 72, 76, 83, 85], "\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u0432\u0430": 11, "\u043a\u0440\u0430\u0439\u043d": [11, 23, 38, 83, 88, 100], "shared": [11, 23, 26, 38, 72, 74, 76, 85, 86], "common": [11, 15, 21, 23, 34, 37, 38, 52, 64, 74, 76, 80, 85, 86], "aggregate_name": 11, "\u0432\u043e\u0441\u0442\u0440\u0435\u0431\u043e\u0432\u0430": [11, 34, 41, 65, 70, 90], "\u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436": 11, "\u043f\u043e\u0434\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440": 11, "\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d": [11, 23, 26, 51, 85, 86], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c": [11, 86, 100, 102], "\u043d\u0430\u0437\u0432\u0430\u043d": [11, 21, 23, 75, 90], "\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d": 11, "part": [11, 21, 23, 34, 37, 38, 42, 46, 51, 52, 65, 74, 75, 76, 77, 82, 85, 86, 90], "customer": [11, 23, 29, 37, 38, 46, 51, 52, 64, 68, 70, 73, 74, 75, 76, 77, 86], "live": [11, 23, 38, 86], "subpackage": 11, "named": [11, 37], "circular": 11, "dependencies": [11, 23, 30, 34, 65, 73], "put": [11, 21, 23, 38, 41, 46, 70, 75, 77, 85], "functions": [11, 15, 21, 23, 49, 62, 74, 75, 82, 85, 100], "having": [11, 21, 34, 37, 52, 65, 75, 85, 86, 93], "additionally": [11, 38], "even": [11, 21, 23, 34, 37, 38, 46, 51, 52, 62, 65, 70, 73, 74, 76, 82, 85, 86, 95, 100], "modify": [11, 21, 23, 34, 37, 38, 70, 72, 74], "proper": [11, 15, 21, 23, 34, 38, 41, 74], "methods": [11, 21, 23, 37, 38, 49, 65, 74, 76, 85, 86], "hexagonal": [11, 72], "anton": [11, 82], "st\u00f6ckl": [11, 82], "tactical": [11, 19, 23, 34, 37, 74, 82, 109], "layer": [11, 16, 23, 31, 75, 80, 116], "\u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0435\u043d": 11, "\u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d": 11, "\u043f\u0440\u043e\u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430": 11, "\u043f\u0440\u0438\u0432\u0435\u043b": [11, 37, 41, 86], "\u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d": [11, 34], "\u0442\u0430\u0449": 11, "\u043a\u0443\u0447": [11, 64], "\u043e\u0431\u044a\u044f\u0432\u043b": [11, 85], "\u0438\u0437\u0431\u044b\u0442\u043e\u043a": [11, 93], "\u043f\u0435\u0440\u0435\u0443\u0441\u043b\u043e\u0436\u043d\u0435\u043d": [11, 70], "\u0431\u043b\u0438\u0436": 11, "\u0432\u044b\u0440\u0430\u0436\u0430": [11, 37, 75, 80, 88, 92, 102], "\u0442\u043e\u0447\u043d": [11, 21, 23, 70, 100, 102], "\u0432\u044b\u043d\u0435\u0441\u0442": [11, 23], "\u0441\u043e\u0434\u0435\u0440\u0436\u0430": [11, 21, 23, 26, 74, 85, 90, 100, 102], "\u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d": [11, 75], "\u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u043e\u043d\u0438\u0440": 11, "\u043b\u043e\u0433\u0438\u0447\u043d": [11, 23, 30], "\u0441\u043b\u0443\u0436\u0430\u0442": [11, 38, 100], "\u043c\u043e\u0434\u0435\u043b\u0438\u0440": 11, "\u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d": [11, 21, 23, 34, 37, 74, 75, 80, 85], "\u0432\u043e\u0437\u0440\u0430\u0441\u0442": 11, "\u0444\u0438\u043a\u0441\u0438\u0440": 11, "values": [11, 21, 23, 38, 42, 76, 86], "\u0438\u043c\u0435\u044e\u0442": [11, 23, 40, 65, 75, 77, 85, 86, 92], "\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d": [11, 23], "\u043a\u043e\u043b\u043b\u0438\u0437": 11, "\u0440\u0430\u0437\u0440\u0443\u0448": 12, "shotgun": 12, "surgery": [12, 85], "canexecute": 12, "pattern": [12, 14, 21, 23, 29, 34, 37, 38, 72, 73, 76, 82, 85, 86, 93], "raw": [13, 75, 82], "\u043e\u0431\u0440\u0435\u0442\u0430": [13, 37, 41, 72, 75, 76, 83], "\u0438\u0431": [13, 23, 38, 88, 92], "fowler": [13, 14, 21, 23, 37, 38, 40, 41, 46, 62, 65, 66, 70, 72, 75, 76, 80, 82, 85, 86, 92, 94, 95], "reflective": 13, "program": [13, 23, 41, 51, 52, 60, 65, 73, 74, 76, 77, 82, 85, 88, 90, 100], "generation": [13, 23, 82, 89, 95], "explicit": [13, 23, 38, 46, 100], "see": [13, 21, 23, 34, 37, 38, 39, 51, 60, 62, 65, 70, 73, 74, 75, 76, 82, 85, 86, 90, 100], "what": [13, 21, 23, 34, 37, 38, 41, 42, 47, 49, 51, 52, 60, 62, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 82, 85, 86, 90, 100], "going": [13, 21, 23, 29, 37, 38, 70, 73, 74, 85, 100], "debugger": 13, "usually": [13, 21, 23, 29, 37, 38, 41, 52, 72, 74, 76, 77, 85, 100], "prefer": [13, 34, 65, 85], "reflection": [13, 68], "easier": [13, 21, 23, 37, 70, 73, 74, 85, 90], "less": [13, 23, 38, 49, 51, 64, 65, 68, 70, 72, 74, 75, 76, 82, 85], "sophisticated": 13, "developers": [13, 23, 37, 38, 46, 49, 51, 72, 74, 75, 76, 77, 82, 85, 86, 90], "guess": [13, 68, 70], "unsophisticated": 13, "david": [13, 23, 30, 34, 37, 70, 72, 82, 88, 94], "rice": [13, 23, 72, 82], "matthew": [13, 23, 72, 82, 86], "foemmel": [13, 23, 72, 82], "hieatt": [13, 23, 72, 82], "mee": [13, 23, 72, 82], "randy": [13, 23, 38, 72, 82], "stafford": [13, 23, 72, 82], "\u043f\u043e\u0434\u0430\u0432\u043b\u044f": [13, 38], "orm": [13, 21], "\u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d": [13, 52, 80, 86], "\u0448\u0438\u0440\u043e\u043a": [13, 21, 37, 38, 65, 75, 76, 85, 88, 90, 92, 102], "\u043a\u043e\u0434\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446": 13, "sqlc": 13, "vs": [14, 21, 41, 64, 65, 74, 75, 76, 82, 83, 86, 94], "\u0441\u043c\u0435\u043b": [15, 73], "\u043f\u0435\u0440\u0432\u043e\u043f\u0440\u043e\u0445\u043e\u0434\u0446": 15, "\u043f\u043e\u0432\u043b\u0438\u044f": [15, 37], "\u0438\u043d\u0434\u0443\u0441\u0442\u0440": [15, 21, 37, 75, 76, 83, 85, 92, 95], "\u043c\u043e": [15, 21, 23, 34, 38, 46, 68, 70, 72, 74, 75, 82, 83, 85, 88, 90, 92, 93, 94, 100], "\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d": 15, "\u043f\u0440\u0438\u0437\u043d\u0430\u0442\u0435\u043b": 15, "\u0432\u043b\u0430\u0434\u0438\u043c\u0438\u0440": 15, "\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d": [15, 21, 34, 38, 40, 42, 68, 70, 74, 75, 82, 85, 86, 90, 93, 100, 102], "\u043e\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d": [15, 40, 70, 92], "\u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440": 15, "\u0432\u0430\u043b\u0438\u0434\u043d": 15, "\u0430\u0442\u043e\u043c\u0430\u0440\u043d": [15, 30, 34], "\u0432\u0430\u043b\u0438\u0434\u0430\u0446": [15, 21], "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u043c": [15, 86, 102], "\u0443\u0431\u0435\u0434": [15, 37, 38, 85], "\u043a\u043b\u044e\u0447\u0435\u0432": [15, 21, 23, 38, 40, 52, 56, 62, 64, 73, 75, 83, 85, 90, 94, 102], "\u0441\u0432\u043e\u0434": [15, 21, 23, 30, 74, 75, 102], "cqs": [15, 23], "\u0441\u043e\u0433\u043b\u0430\u0441": [15, 38, 40, 46, 56, 88], "\u0441\u043e\u0432\u0441": [15, 16, 23, 37, 75, 83, 85, 88, 94], "\u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d": [15, 21, 23, 100, 102], "\u0434\u0435\u0439\u0441\u0442\u0432": [15, 23, 34, 38, 42, 46, 72, 85, 86, 90, 100], "\u0438\u0441\u0445\u043e\u0434": [15, 23, 38, 40, 56, 70, 72, 75, 83, 85], "\u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0435\u043d": [15, 37, 40, 68, 70, 85], "command": [15, 23, 75], "\u0441\u043b\u0443\u0436\u0435\u0431\u043d": 15, "\u0443\u0441\u043f\u0435\u0448\u043d": [15, 38, 64, 75, 76, 81, 86, 92, 100, 135], "\u043f\u043e\u0432\u0442\u043e\u0440": [15, 37, 46, 65, 85], "here": [15, 21, 23, 34, 37, 38, 46, 51, 62, 65, 75, 82, 85, 86, 93], "deal": [15, 21, 23, 38, 59, 62, 65, 70, 73, 74, 76, 86, 90], "objections": [15, 21, 23], "side": [15, 23, 76, 82, 85], "effect": [15, 23, 42, 46, 72, 74, 76, 85, 86], "style": [15, 21, 23, 37, 38, 39, 62, 65, 72, 76, 80, 85], "handling": [15, 21, 23, 29, 34, 38, 51, 73], "sometimes": [15, 21, 23, 34, 38, 49, 60, 68, 72, 73, 77, 85], "effects": [15, 21, 23, 38, 75, 77, 85, 86, 88], "really": [15, 21, 23, 34, 37, 38, 52, 65, 68, 70, 74, 75, 76, 77, 80, 82, 85, 86, 90, 100], "procedure": [15, 21, 23], "addition": [15, 21, 23, 39, 65, 86], "returns": [15, 21, 23], "indicating": [15, 21], "went": [15, 21, 38, 76, 85, 100], "roughly": [15, 21, 38, 74, 82, 85, 95], "speaking": [15, 21, 23], "technique": [15, 21, 34, 52, 85, 86], "enable": [15, 21, 37, 74, 77, 85, 86], "perform": [15, 21, 23, 38, 46, 62, 85, 86], "represented": [15, 21], "some_operation": [15, 21], "how_did_it_go": [15, 21], "returning": [15, 21, 23, 38, 46, 85], "lame": [15, 21], "anyway": [15, 21, 23, 46, 76], "transforms": [15, 21], "adding": [15, 21, 23, 38, 41, 70, 74, 85, 86], "does": [15, 21, 23, 34, 37, 38, 41, 46, 49, 51, 52, 62, 65, 73, 74, 76, 80, 85, 86, 88, 100], "routine": [15, 21], "own": [15, 21, 23, 26, 37, 38, 49, 73, 74, 76, 85, 86, 92], "problematic": [15, 21, 38], "than": [15, 21, 23, 29, 34, 37, 38, 39, 46, 47, 49, 51, 62, 65, 70, 72, 73, 74, 75, 76, 77, 85, 86, 90, 94, 100], "indicator": [15, 21], "structure": [15, 21, 23, 37, 38, 40, 41, 66, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 88], "equivalent": [15, 21, 23], "several": [15, 21, 23, 64, 70, 74, 75, 85, 86, 90], "components": [15, 21, 23, 34, 51, 72, 74, 75, 82, 85, 86], "getting": [15, 21, 34, 38, 42, 51, 73, 75, 82, 85, 86, 88], "above": [15, 21, 23, 51, 70, 85, 86], "scheme": [15, 21, 23, 38, 52], "global": [15, 21, 23, 82], "variables": [15, 21, 38, 42, 74, 85, 93], "raises": [15, 21, 38], "especially": [15, 21, 38, 65, 74, 85, 88], "large": [15, 21, 23, 34, 46, 52, 64, 75, 76, 82, 85, 86, 100], "where": [15, 21, 23, 29, 34, 37, 38, 41, 47, 49, 62, 65, 73, 74, 75, 76, 82, 85, 86, 100], "trigger": [15, 21, 23], "construction": [15, 21, 23, 37, 59, 67, 75, 76, 77, 82, 86, 130], "2nd": [15, 21, 23, 34, 37, 38, 46, 52, 60, 62, 65, 66, 70, 73, 74, 76, 77, 82, 85, 86, 90], "bertrand": [15, 21, 23, 38, 52, 75, 82], "meyer": [15, 21, 23, 38, 52, 75, 82], "23": [15, 21, 23, 38, 66, 76, 85, 94], "\u043d\u0435\u0442": [15, 21, 23, 34, 38, 40, 41, 46, 73, 75, 77, 83, 86, 88, 90, 94, 95, 100], "\u0440\u0430\u0437\u0434\u0435\u043b\u044f": [15, 23, 60, 74, 75, 88, 90], "\u043f\u0440\u043e\u0432\u0435\u0440\u044f": [15, 85], "infrastructure": [16, 21, 23, 34, 38, 86], "\u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447": 16, "\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446": 16, "\u0432\u044b\u043f\u043e\u043b\u043d\u044f": [16, 23, 40, 41, 46, 73, 85, 86, 95], "\u0431\u0438\u0437\u043d\u0435\u0441": [16, 34, 37, 39, 40, 41, 44, 51, 56, 65, 66, 70, 72, 75, 80, 86, 100, 122], "practice": [19, 21, 23, 34, 37, 38, 42, 49, 51, 52, 64, 65, 66, 72, 74, 75, 76, 77, 82, 85, 90, 92, 93, 100, 109], "strategic": [19, 75, 82, 86, 100, 109], "tbd": [20, 55, 65, 110], "\u043f\u043e\u0441\u0432\u044f\u0449": [21, 23, 34, 37, 38, 75, 76, 82, 86], "\u0434\u043e\u0432\u043e\u043b\u044c\u043d": [21, 38, 73, 86], "\u0434\u0438\u0441\u043a\u0443\u0441\u0441\u0438\u043e\u043d": 21, "\u043f\u043e\u0441\u043b\u0435\u0434\u043d": [21, 37, 73, 74, 85, 88, 92], "\u043d\u0430\u043c\u0435\u0442": 21, "\u043f\u043e\u043b\u044f\u0440\u0438\u0437\u0430\u0446": 21, "\u0441\u0442\u0440\u0435\u043c\u0438\u0442\u0435\u043b\u044c\u043d": [21, 76, 86], "\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d": [21, 23, 64, 65, 87, 100, 137], "\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a": [21, 23, 30, 37, 56, 65, 76, 80], "\u043f\u0440\u043e\u0431\u0443\u0434": 21, "\u0433\u043e\u043d\u043a": [21, 23, 30, 33, 118], "race": 21, "condition": [21, 76, 85], "\u0432\u0437\u0430\u0438\u043c\u043e\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a": 21, "deadlocks": 21, "\u043e\u0431\u0443\u0441\u043b\u043e\u0432\u043b": [21, 94], "\u043f\u0435\u0440\u0435\u043c\u0435\u043d": [21, 34, 38, 40, 41, 52, 65, 74, 85], "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c": [21, 37, 38, 40, 42, 46, 60, 70, 73, 74, 75, 77, 85, 90, 94], "\u0438\u0437\u043c\u0435\u043d\u044f": [21, 23, 65, 74, 82, 85, 86], "\u043d\u0438\u043a\u043e\u0433\u0434": [21, 23, 38, 47, 75, 83, 88, 92], "\u043e\u043a\u0430\u0436\u0435\u0442": [21, 37, 38, 70, 90], "\u0441\u0442\u043e\u043b\u043a\u043d\u0435\u0442": 21, "\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a": 21, "\u043f\u043e\u043f\u0430\u0441\u0442": [21, 83], "conditions": [21, 51, 52, 76], "deadlock": 21, "concurrent": [21, 23, 51, 82], "update": [21, 23, 34, 37, 62, 65], "due": [21, 23, 38, 65, 70, 76, 77, 86], "mutable": [21, 82], "variable": [21, 38, 74, 76, 85], "ever": [21, 23, 37, 38, 74, 76, 86], "locks": [21, 23], "\u043e\u0442\u043a\u0430\u0437\u0430": [21, 23, 34, 37, 70, 76, 94], "\u0438\u043c\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d": 21, "\u043f\u043e\u0434\u0432\u0438\u0434": 21, "\u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432": [21, 23, 30, 77, 85, 92], "\u043c\u0443\u043b\u044c\u0442\u0438\u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u0435\u043d": 21, "scala": [21, 23, 30, 34, 82], "elixir": 21, "\u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0430": [21, 30, 51, 74], "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f": [21, 85, 102], "\u0434\u043e\u043f\u043e\u043b\u043d\u044f": [21, 65, 77], "\u0431\u0435\u0440\u0442\u0440\u0430\u043d": 21, "\u043c\u0435\u0439\u0435\u0440": [21, 73], "\u0442\u0435\u043d\u0434\u0435\u043d\u0446": [21, 40, 47, 65, 93, 94], "\u043f\u043e\u043f\u0443\u043b\u044f\u0440\u0438\u0437\u0430\u0446": 21, "\u0441\u043a\u0430\u0436": [21, 23, 92], "\u043e\u0431\u044a\u0435\u043a\u0442\u043d": [21, 37, 77], "\u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433": [21, 38, 64, 73, 86], "\u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442": 21, "\u0432\u0437\u0433\u043b\u044f\u0434": [21, 72, 82, 85], "\u0440\u0435\u0447": [21, 23, 65, 75, 83, 86, 102], "\u0438\u0434\u0435\u0442": [21, 23, 38, 65, 74, 75, 85, 86, 100], "\u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432": [21, 37, 77], "\u043d\u0438\u0447": [21, 46, 64, 70, 82, 83, 85, 95], "\u0432\u0438\u0436": [21, 70], "\u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d": [21, 23, 73], "\u043f\u043e\u043b\u0435\u0437\u043d": [21, 64, 70, 82, 86], "\u0434\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432": [21, 92], "\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d": [21, 23, 83, 85], "\u043d\u0430\u0437\u0430\u0434": [21, 30, 47, 60, 74, 90], "\u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430": [21, 23, 75, 86], "\u0444\u043f": 21, "\u043f\u043e\u0441\u0442\u0430\u0440\u0430": 21, "\u0434\u0430": [21, 38, 46, 75, 76, 92, 94], "\u0432\u043e\u0448\u043b": 21, "\u043a\u0430\u0447\u0435\u0441\u0442\u0432": [21, 23, 26, 30, 37, 38, 42, 46, 50, 51, 70, 73, 75, 76, 83, 85, 86, 88, 93, 94, 100, 125], "\u0432\u043f\u0435\u0447\u0430\u0442\u043b": 21, "\u0441\u043c\u0435": 21, "\u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a": [21, 37, 38, 70, 74], "\u043f\u043e\u043c\u043d": [21, 38, 83, 90, 92, 94], "\u0441\u0430\u0439\u043c\u043e\u043d": 21, "\u043f\u0435\u0439\u0442\u043e\u043d": 21, "\u0434\u0436\u043e\u043d\u0441": 21, "\u0441\u0442\u0430\u0440\u0430": [21, 70, 83, 85, 88, 100], "\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d": [21, 86], "\u043f\u0440\u0438\u043c\u0435\u0447\u0430\u043d": 21, "\u0431\u0435\u0440\u0442\u0440\u0430": 21, "functional": [21, 37, 38, 51, 52, 75, 82, 86], "\u0438\u0434\u0435\u0430\u043b\u044c\u043d": [21, 38, 73, 75, 94, 102], "\u0432\u0435\u0434\u0443\u0449": [21, 37, 76, 88], "\u043a\u0440\u0430\u0441\u043e\u0442": 21, "composing": 21, "contracts": [21, 86], "adventure": 21, "financial": [21, 38, 39, 41], "engineering": [21, 23, 34, 37, 38, 49, 51, 52, 59, 60, 62, 63, 64, 65, 66, 73, 74, 75, 76, 77, 80, 82, 85, 86], "\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432": [21, 42, 70, 74, 85, 86, 90], "eiffel": 21, "\u0441\u0431\u043b\u0438\u0436\u0435\u043d": 21, "\u044f\u0441\u043d": [21, 23, 70, 73, 86], "\u0440\u0430\u0437\u043b\u0438\u0447\u0430": [21, 52], "\u0440\u0430\u0437\u043d\u0438\u0446": [21, 23, 30, 40, 73, 74, 82, 88], "\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d": 21, "\u0437\u043d\u0430": [21, 74, 92, 93, 100], "\u043f\u043e\u0439\u0442": [21, 34], "\u0434\u0430\u043b\u044c\u0448": [21, 23, 85], "\u0440\u0430\u0431\u043e\u0442\u0430": [21, 23, 26, 37, 38, 40, 42, 46, 47, 65, 68, 70, 73, 74, 82, 83, 85, 86, 88, 90, 93, 94, 100], "\u043f\u043e\u0431\u043e\u0447\u043d": [21, 34], "\u044d\u0444\u0444\u0435\u043a\u0442": [21, 34, 38, 40, 46, 56, 65, 74, 76, 83, 85, 86, 88, 91, 92, 94, 95, 138], "\u0441\u0435\u0440\u0433\u0435": [21, 82, 94], "\u0442\u0435\u043f\u043b\u044f\u043a\u043e\u0432": [21, 82, 94], "both": [21, 23, 29, 34, 37, 38, 49, 52, 64, 74, 76, 77, 85, 86, 100], "theoretical": [21, 37], "reasons": [21, 23, 37, 38, 65, 75, 77, 82, 85, 86], "detailed": [21, 37, 52, 65, 74, 76, 77], "elsewhere": 21, "methodological": [21, 38], "serious": [21, 38, 74], "developed": [21, 23, 37, 38, 51, 52, 76, 85, 86, 100], "observes": 21, "scrupulously": 21, "advantage": [21, 23, 37, 85], "schools": [21, 85], "programming": [21, 23, 37, 42, 46, 47, 52, 56, 64, 65, 66, 68, 70, 72, 73, 74, 75, 76, 82, 83, 85, 92, 94, 95], "regrettable": 21, "apply": [21, 23, 34, 49, 51, 72, 75, 77, 82, 85, 86], "continuing": [21, 73, 85, 86, 100], "calling": 21, "rather": [21, 23, 29, 37, 38, 46, 49, 74, 75, 76, 85, 86, 90, 94], "procedures": [21, 38, 49, 86], "achieve": [21, 23, 34, 38, 73, 74, 86], "key": [21, 23, 37, 38, 46, 51, 52, 62, 74, 76, 77, 85, 86], "seems": [21, 38, 73], "viable": 21, "obtain": [21, 23], "since": [21, 23, 34, 38, 74, 76, 77, 85, 86], "expressions": [21, 85], "involve": [21, 23], "queries": [21, 23, 34, 51], "understood": [21, 34, 38, 41, 72, 74, 75], "traditional": [21, 23, 49, 52, 74, 82], "mathematics": [21, 62, 65, 82, 85], "while": [21, 23, 26, 34, 37, 38, 39, 49, 52, 62, 73, 74, 76, 85, 86, 90, 100], "acknowledging": 21, "notion": [21, 74, 76, 85, 95], "fundamental": [21, 37, 49, 52, 74, 76, 80, 82], "role": [21, 37, 38, 51, 66, 70, 71, 76, 82, 85, 86, 92, 132], "concept": [21, 23, 34, 38, 70, 72, 86], "computations": [21, 23, 34], "rober": 21, "blog": [21, 82], "cleancoder": 21, "uncle": [21, 37, 74], "bob": [21, 37, 74, 75], "2014": [21, 34, 82, 88], "11": [21, 23, 38, 70, 85, 86], "24": [21, 23, 66, 68, 70, 73], "fpvsoo": 21, "html": [21, 34], "2018": [21, 38, 52, 64, 65, 77, 82], "04": 21, "\u043f\u043e\u043a\u043b\u043e\u043d\u043d\u0438\u043a": 21, "emacs": [21, 23, 74], "lisp": 21, "clojure": [21, 82], "2019": [21, 38, 46, 64, 82], "08": 21, "22": [21, 23, 37, 38], "whyclojure": 21, "\u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d": [21, 23, 86], "\u0432\u0432\u0435\u043b": [21, 23, 38, 74], "starting": [21, 23, 37, 74, 76, 85, 86], "creation": [21, 23, 38, 77], "previously": [21, 23], "occurs": [21, 23, 38, 76], "whether": [21, 23, 34, 38, 51, 74, 76, 85, 86, 90, 100], "mutates": [21, 23], "entirety": 21, "nothing": [21, 23, 37, 38, 42, 65, 74, 76, 85, 88, 92], "uis": [21, 23, 82], "agh": [21, 23, 82], "segregation": [21, 23, 75], "originally": [21, 38, 51], "considered": [21, 23, 37, 51, 52, 63, 75, 86], "originated": [21, 52], "maintains": 21, "pure": [21, 86], "difference": [21, 23, 51, 52, 74, 76, 77, 82, 85, 100], "split": [21, 38, 52, 82, 85, 86], "containing": [21, 23, 64, 82, 86], "\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440": [21, 23, 38], "\u0432\u043d\u0438\u0437": [21, 65, 74, 77], "\u043f\u0440\u043e\u0440\u0435\u0446\u0435\u043d\u0437\u0438\u0440\u043e\u0432\u0430": 21, "eshoponcontainers": [21, 23, 75, 82], "\u043a\u0440\u0430\u0441\u043d": [21, 56, 85], "devised": [21, 23], "asserts": [21, 23, 38, 85], "following": [21, 23, 37, 38, 39, 49, 62, 74, 75, 76, 85], "every": [21, 23, 29, 34, 37, 38, 72, 73, 74, 75, 76, 77, 80, 82, 85, 86, 95, 100], "performs": [21, 23, 62], "caller": [21, 23, 52], "words": [21, 23, 29, 37, 41, 75, 85, 86], "asking": [21, 23, 41], "question": [21, 23, 74, 85, 88, 94], "answer": [21, 23, 38, 70, 85], "formally": [21, 23], "referentially": [21, 23], "transparent": [21, 23], "possess": [21, 23, 51], "wikipedia": [21, 23, 39, 85], "level": [21, 23, 37, 38, 51, 52, 64, 70, 74, 75, 76, 77, 82, 86, 88, 90, 100], "means": [21, 23, 34, 37, 38, 39, 42, 49, 62, 65, 74, 75, 76, 77, 85, 90], "modifies": [21, 23], "declared": [21, 23, 85], "directly": [21, 23, 38, 46, 64], "indirectly": [21, 23], "cause": [21, 23, 34, 37, 38, 75], "modification": [21, 23, 75], "alter": [21, 23, 37, 74, 85], "journey": [21, 23, 34, 73, 82], "introducing": [21, 23, 76, 82, 85], "\u043d\u0430\u0443\u043a": [21, 41, 68, 73, 82, 92, 93, 102], "\u043a\u043e\u043d\u0441\u0443\u043b\u044c\u0442\u0430\u043d\u0442": 21, "cesar": [21, 75, 82], "de": [21, 34, 38, 75, 82], "la": [21, 75, 82], "torre": [21, 75, 82], "nilsson": 21, "udi": [21, 75, 82], "dahan": [21, 75, 82], "\u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441": [21, 38], "\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446": [21, 88], "\u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d": 21, "\u043f\u043e\u043f\u044b\u0442\u0430": [21, 74, 85, 88, 90, 92], "\u043d\u0430\u0447\u043d": [21, 38, 72, 100], "produce": [21, 23, 37, 38, 49, 62, 73], "produces": [21, 52, 85, 86], "body": [21, 38, 64, 66, 75], "contains": [21, 23, 37, 51, 74, 76, 77, 82, 86, 90], "attempt": [21, 76, 85, 86, 100], "instruction": [21, 23], "whose": [21, 38, 39, 85, 86], "accompanied": 21, "full": [21, 23, 26, 34, 52, 70, 73, 75, 76, 82, 85, 92, 94], "fledged": [21, 23], "underlying": [21, 37, 65], "usable": 21, "difficult": [21, 23, 37, 38, 40, 46, 70, 73, 74, 75, 85, 100], "defined": [21, 23, 29, 52, 65, 74, 75, 82, 86, 90], "interface": [21, 23, 29, 74, 75, 85, 86], "offered": [21, 85], "short": [21, 37, 38, 62, 65, 74, 76, 77, 82, 90], "affect": [21, 34, 85], "accessible": 21, "secret": [21, 88], "refers": [21, 49], "exported": 21, "reason": [21, 23, 29, 34, 37, 38, 46, 51, 74, 75, 85, 86], "generally": [21, 23, 38, 49, 51, 52], "fully": [21, 23, 51, 73, 74, 82, 86, 92], "permit": [21, 23], "selectively": 21, "soon": [21, 23, 38, 42, 46, 47, 68, 74, 76, 82, 95], "none": [21, 74], "changing": [21, 23, 37, 74, 76, 80, 82, 85], "visible": [21, 37, 38, 52, 73, 76], "least": [21, 23, 29, 37, 38, 75, 76, 85], "brings": [21, 38], "back": [21, 23, 34, 37, 38, 41, 47, 60, 62, 65, 74, 75, 76, 77, 82, 85, 86, 90, 100], "expression": [21, 75, 85], "exchange": 21, "subexpression": 21, "\u043f\u043e\u0434\u0432\u0435\u0434": [21, 52, 77], "\u0440\u0435\u0437\u044e\u043c": [21, 38], "\u0432\u0441\u0435\u043c": [21, 30, 38, 42, 73, 74, 85, 86, 88, 90, 100], "\u0437\u0430\u043f\u0440\u0435\u0449\u0430": 21, "\u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d": [21, 38], "\u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d": [21, 23, 37], "\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": [21, 83, 93, 95, 96], "\u0437\u0430\u043f\u0440\u0435\u0449": 21, "\u043f\u043e\u043b\u0443\u0447\u0435\u043d": [21, 23, 38, 56, 65, 77, 83], "\u0443\u0447\u0442": [21, 88], "railway": [21, 82], "\u043f\u043e\u044f\u0441\u043d\u0435\u043d": 21, "\u0438\u0437\u0431\u0435\u0433\u0430\u043d": 21, "\u043e\u0442\u043b\u0438\u0447\u043d": [21, 37, 74, 86, 100], "\u0432\u044b\u044f\u0441\u043d": [21, 37, 74], "\u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436": 21, "few": [21, 23, 37, 38, 65, 73, 76, 77, 86, 100], "reminders": 21, "terminology": [21, 64, 82, 86], "features": [21, 37, 38, 41, 47, 51, 52, 62, 65, 70, 74, 76, 82, 85, 86], "characterize": 21, "serves": [21, 38, 49], "say": [21, 23, 34, 38, 41, 46, 72, 74, 75, 85, 86], "reserving": 21, "corresponding": [21, 23, 51, 52], "algorithm": [21, 23], "computes": 21, "needed": [21, 23, 37, 38, 49, 70, 76, 77, 85, 86, 100], "associated": [21, 23, 34, 37, 52, 74, 75, 76], "together": [21, 23, 38, 74, 75, 76, 85], "called": [21, 23, 34, 37, 38, 41, 52, 68, 72, 74, 75, 85, 94], "routines": [21, 34, 74, 86, 90], "specify": [21, 37, 49, 51, 65], "course": [21, 34, 37, 38, 41, 46, 65, 70, 73, 74, 76, 82, 85], "producing": [21, 38, 42, 49, 73], "obviously": [21, 74, 85], "yes": [21, 23, 37, 76], "among": [21, 23, 34, 37, 38, 85, 86], "sense": [21, 23, 37, 38, 51, 62, 70, 74, 75, 85, 86], "accessing": [21, 29], "anything": [21, 23, 26, 38, 42, 62, 65, 73, 85, 86], "performed": [21, 23, 86], "indicate": [21, 23, 34, 38, 52], "ancillary": 21, "official": 21, "purpose": [21, 23, 34, 49, 73, 74, 86, 100], "answering": 21, "\u043b\u0435\u0436": [21, 23, 41, 42, 74, 76, 90], "\u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442": [21, 88, 90, 100], "glossary": [21, 52, 53, 62, 82], "\u0432\u044b\u0440\u0430\u0437": [21, 23, 75, 100], "\u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c": [21, 93, 94, 100, 102], "\u0432\u0430\u0436": [21, 76], "\u0434\u0430\u043b": [21, 23, 72, 82, 83, 88, 92, 100], "\u0434\u043d\u0438": 21, "\u043d\u0430\u043f\u043e\u043c\u043d": [21, 70, 74, 75, 88], "\u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d": [21, 34, 38, 56], "\u043d\u0435\u0437\u0430\u0441\u043b\u0443\u0436\u0435\u043d": 21, "\u043e\u043f\u0443\u0441\u043a\u0430": [21, 85], "\u043a\u0440\u043e\u0435\u0442": [21, 23, 85], "\u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430": [21, 85], "\u0437\u0430\u0432\u0438\u0441": [21, 23, 34, 38, 40, 41, 65, 70, 82, 83, 85, 86, 88, 93], "point": [21, 23, 34, 37, 38, 39, 46, 49, 51, 72, 73, 74, 75, 76, 77, 85, 86, 94], "clarified": [21, 23, 75, 82], "examine": [21, 74], "further": [21, 34, 38, 65, 70, 74, 76, 82, 92], "consequences": [21, 23, 38], "treat": [21, 23], "seen": [21, 23, 34, 51, 52, 74, 85, 92], "endanger": 21, "assume": [21, 23, 34, 75, 85, 86], "allocate": 21, "mathematical": [21, 23, 60, 62, 82, 85, 90], "perspective": [21, 23, 38, 52, 77, 86], "pretend": [21, 23], "times": [21, 23, 34, 37, 38, 46, 65, 74, 75, 76, 77, 82, 85, 86, 100], "past": [21, 23, 73], "present": [21, 23, 34, 38, 49, 70], "inscribed": [21, 23], "book": [21, 23, 38, 82, 85, 95], "legitimate": [21, 23], "initialize": [21, 23], "observations": [21, 23], "second": [21, 23, 34, 37, 38, 46, 52, 72, 75, 76, 80, 82, 85, 86, 100], "created": [21, 23, 34, 37, 51, 86, 100], "\u0437\u0430\u043c\u0435\u0447\u0430\u043d": 21, "rfc": [21, 23], "7231": [21, 23], "post": [21, 23, 74, 94], "origin": [21, 23, 34], "send": [21, 23, 34], "201": [21, 23], "location": [21, 23], "header": [21, 23], "provides": [21, 23, 29, 34, 38, 42, 51, 59, 60, 63, 76, 82, 85], "identifier": [21, 23, 34], "primary": [21, 23, 37, 38, 52, 73, 76, 90], "resource": [21, 23, 82, 92], "section": [21, 23, 74, 75], "representation": [21, 23, 85], "describes": [21, 23, 65], "referring": [21, 23, 72, 73, 75], "\u043f\u043e\u044f\u0441\u043d\u044f": [21, 37], "\u043f\u0440\u043e\u0447\u0442\u0435\u043d": [21, 82], "\u0442\u043e\u0436": [21, 23, 30, 38, 72, 76, 83, 85, 86, 88, 92, 100], "unfortunately": [21, 68, 75, 76], "unacceptably": 21, "restrictive": 21, "explaining": [21, 74], "prohibits": 21, "harmless": [21, 23], "necessary": [21, 23, 38, 49, 51, 65, 73, 76, 77, 85, 86], "kinds": [21, 23, 75], "acceptable": [21, 23, 38, 51, 65], "category": [21, 82], "affecting": 21, "depth": [21, 86], "sure": [21, 23, 29, 34, 38, 47, 82, 85, 86], "familiar": [21, 37, 76, 85], "abstraction": [21, 23, 51, 74, 75, 76, 77, 85, 86, 90, 100], "contract": [21, 23, 75, 85, 86], "particular": [21, 23, 38, 52, 54, 75, 100], "accompanying": 21, "figures": [21, 74], "saw": [21, 23, 85], "represent": [21, 23, 51, 86, 100], "stack": [21, 23], "representations": [21, 82], "made": [21, 23, 26, 37, 38, 39, 42, 62, 68, 74, 75, 76, 80, 82, 86, 100], "array": [21, 23], "top": [21, 38, 74, 76, 78, 82, 86, 92, 133], "marker": [21, 23], "count": [21, 23, 64, 82, 85, 95], "differ": [21, 52], "sizes": 21, "indices": 21, "terms": [21, 23, 37, 38, 46, 62, 73, 74, 85, 90, 100], "belongs": 21, "c1": 21, "c2": [21, 37, 80, 85], "still": [21, 23, 37, 38, 39, 70, 73, 76, 85, 86], "represents": [21, 23, 49, 52, 76, 100], "yields": [21, 23], "stacks": [21, 23], "some_value": [21, 23], "guarantee": [21, 23, 34], "capacity": [21, 23, 38, 74, 90], "significant": [21, 23, 34, 38, 46, 77, 85, 86], "ill": [21, 23, 86], "appear": [21, 34, 62, 68], "shortly": 21, "machine": [21, 73], "metaphor": [21, 41, 65], "correspond": [21, 64], "buttons": 21, "absolutely": [21, 23, 38, 88], "answers": [21, 38, 85, 92], "given": [21, 34, 37, 38, 42, 49, 74, 75, 76, 86], "button": 21, "energy": [21, 70, 72, 85], "automatically": [21, 73, 74], "switching": [21, 34], "off": [21, 23, 37, 38, 70, 72, 74, 76, 82, 85, 94], "circuits": 21, "nobody": [21, 34, 38], "presses": 21, "turning": 21, "whenever": [21, 23, 85], "someone": [21, 38, 73, 86], "included": [21, 23, 74], "unnoticeable": 21, "\u0443\u0432\u0438\u0434": [21, 23, 75], "\u043d\u0438\u0436": [21, 23, 68, 75], "\u043e\u0431\u0448\u0438\u0440\u043d": [21, 34], "\u0442\u043e\u043d\u043a": 21, "\u043e\u0441\u0432\u043e": [21, 82, 86, 93], "\u043f\u043e\u0433\u0440\u0443\u0436\u0435\u043d": 21, "clone": 21, "creates": [21, 23, 38, 46, 52, 73, 77], "carbon": 21, "exists": 21, "overwrite": 21, "fields": 21, "achieves": 21, "y": [21, 34, 37, 73, 88], "8": [21, 23, 37, 38, 64, 66, 82, 86], "copying": [21, 85], "\u043e\u0441\u043d\u043e\u0432\u0430": [21, 38, 40, 72, 85, 92], "notification": [21, 23, 34], "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430": [21, 23, 74, 75, 86, 90], "\u0430\u0434\u0440\u0435\u0441\u0430\u0446": 21, "pop": 21, "\u0431\u0443\u0444\u0444\u0435\u0440": 21, "buffer": [21, 23, 34], "queue": [21, 23, 34], "next_element": [21, 23], "item": [21, 23, 51], "remove": [21, 23, 38, 85], "notation": [21, 23], "easy": [21, 23, 37, 38, 41, 62, 70, 72, 74, 75, 76, 85], "exclusive": [21, 23], "sacrificing": [21, 23, 38, 70, 74], "enclose": [21, 23], "instructions": [21, 23], "replaced": [21, 23], "formal": [21, 23], "30": [21, 23, 37, 38, 80, 85], "12": [21, 23, 38, 46, 66, 74, 76, 85], "\u0434\u043e\u0433\u0430\u0434\u0430": [21, 37, 38], "\u043f\u043e\u0434\u0432\u043e\u0436": 21, "asynchronous": [21, 23, 34, 35, 119], "reply": [21, 23], "202": [21, 23], "\u0432\u0435\u0440\u043d\u0443\u043b": [21, 30], "\u0432\u043e\u043e\u0431\u0449": [21, 34, 40, 46, 51, 75, 83, 92, 94, 100, 102], "\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432": [21, 70, 88], "submitted": [21, 23], "poll": [21, 23], "easily": [21, 23, 37, 70, 74, 85, 86], "solved": [21, 23, 65], "guids": [21, 23], "ids": [21, 23, 34], "comment": [21, 23, 34, 52], "68": [21, 23], "\u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430": 21, "ulid": 21, "hi": [21, 23], "lo": [21, 23], "\u043f": [21, 23, 37, 56, 70, 72, 82, 83, 85, 88, 90, 92, 94, 100], "requests": [21, 23], "enclosed": [21, 23], "payload": [21, 23], "current": [21, 23, 34, 38, 39, 47, 51, 65, 73, 82, 85, 86], "successfully": [21, 23, 86], "inform": [21, 23, 38], "user": [21, 23, 38, 49, 51, 53, 59, 65, 74, 75, 77, 82, 86], "agent": [21, 23], "sending": [21, 23], "\u0432\u044b\u0433\u043e\u0434": [21, 37, 56, 65, 70, 80, 86], "\u0432\u044b\u0437": [21, 62, 76, 88], "\u043c\u043d\u043e\u0433\u043e\u043a\u0440\u0430\u0442\u043d": [21, 72, 85], "\u043f\u043e\u0432\u0442\u043e\u0440\u044f": [21, 72, 85], "\u0443\u0449\u0435\u0440\u0431": [21, 38, 40, 56, 66, 86], "\u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430": [21, 23, 30, 37, 86, 88], "truth": [21, 37, 80, 86], "redux": [21, 75, 82], "steps": [21, 23, 34, 38, 77], "flux": 21, "attempts": 21, "mutations": 21, "predictable": [21, 38, 62], "imposing": [21, 76], "certain": [21, 38, 49, 75, 86, 100], "restrictions": 21, "updates": [21, 23], "happen": [21, 23, 26, 34, 74, 86, 100], "reflected": [21, 23, 34, 76], "three": [21, 37, 38, 46, 73, 76, 85, 86], "principles": [21, 23, 34, 37, 38, 49, 65, 66, 70, 71, 72, 73, 74, 76, 82, 85, 86, 100, 132], "described": [21, 23, 51, 74, 75], "read": [21, 23, 34, 38, 49, 72, 73, 74, 82, 86, 95], "emit": 21, "describing": [21, 86], "happened": [21, 23, 72, 74, 85], "flow": [21, 23, 37, 38, 72, 82, 86], "fundamentals": [21, 64, 82], "handle": [21, 23, 34, 38], "bi": 21, "directional": 21, "uni": 21, "particularly": [21, 23, 46, 65, 73, 75, 86], "aren": [21, 39, 70, 73, 75, 76, 77, 82, 85, 86], "too": [21, 23, 37, 38, 51, 65, 68, 73, 74, 75, 80, 85, 86, 100], "comfortable": [21, 23], "hate": 21, "ui": [21, 80, 83, 86], "\u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446": 21, "\u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d": 21, "\u0443\u0441\u0442\u0440\u0430\u043d": [21, 30, 34, 88], "\u043c\u043e\u043d\u0443\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [21, 82], "\u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d": [21, 38, 82], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442": [21, 23, 70, 85, 86], "\u043a\u043e\u0440\u0437\u0438\u043d": 21, "\u0442\u043e\u0432\u0430\u0440": 21, "\u0441\u043e\u0432\u043c\u0435\u0449\u0435\u043d": 21, "\u0441\u043e\u043e\u0431\u0449": [21, 23, 92], "\u043f\u0440\u043e\u0434\u0430\u0436": 21, "\u043e\u0431\u043d\u043e\u0432": 21, "\u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430": 21, "\u0437\u0430\u043a\u0430\u0437\u0430": 21, "\u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d": 21, "\u043d\u0430\u043c\u0435\u0440\u0435\u043d": [21, 42, 72, 85, 92], "\u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u0438\u0437\u0438\u0440": 21, "logic": [21, 34, 73, 74, 82, 86], "overbooking": 21, "nosql": [21, 23, 82], "distilled": [21, 23, 34, 82, 86], "\u0434\u0432\u0443\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d": 21, "\u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f": 21, "\u0447\u0442\u0435\u043d": [21, 74, 82, 83, 85, 92], "\u0441\u043e\u0432\u043c\u0435\u0449": 21, "\u0437\u0430\u043a\u0430\u0437": 21, "\u0440\u0435\u043f\u043b\u0438\u043a": 21, "staleness": 21, "fact": [21, 23, 26, 34, 37, 38, 47, 65, 68, 70, 74, 76, 85, 86, 100], "shown": [21, 23, 38, 51], "changed": [21, 23, 26, 38, 74, 75, 76, 85], "actor": [21, 23, 30, 34, 75, 82], "stale": [21, 82], "almost": [21, 38, 74, 85, 86, 100], "cache": 21, "serving": 21, "performance": [21, 34, 38, 51, 73, 82, 86], "entirely": [21, 38], "trust": 21, "users": [21, 23, 34, 38, 51, 52, 75, 76], "decisions": [21, 29, 37, 38, 62, 65, 68, 74, 75, 76, 77, 80, 85, 86], "could": [21, 23, 26, 29, 34, 37, 38, 51, 70, 73, 74, 76, 77, 80, 85, 86], "date": [21, 23, 37, 65, 82, 85], "\u043e\u0442\u0434\u0435\u043b\u0435\u043d": [21, 86], "\u0437\u0430\u043a\u043e\u043d\u0447": [21, 46, 74, 85], "image": [21, 23, 37, 60, 62, 65, 74, 76, 77, 86], "autonomous": [21, 86], "component": [21, 23, 73, 75, 86], "decided": [21, 23, 72, 76, 85], "modifying": [21, 23, 41, 72, 75], "persistent": [21, 23, 51], "notifying": 21, "world": [21, 23, 37, 38, 39, 49, 51, 62, 64, 73, 76, 82, 83, 85, 86, 94, 100], "coming": [21, 23, 52, 62, 85], "appropriate": [21, 23, 29, 38, 76, 77, 85, 86], "explicitly": [21, 23, 72, 73, 85], "takes": [21, 23, 38, 51, 65, 73, 74, 76, 86], "account": [21, 23, 34, 64, 86], "factors": [21, 38, 65, 70, 85], "volatility": 21, "exploits": 21, "characteristics": [21, 23, 51, 65, 76], "creating": [21, 23, 38, 49, 74, 80, 85, 86, 100], "simpler": [21, 23, 37, 70, 73, 76, 85], "scalable": [21, 23, 34, 51, 52, 82, 86], "\u043f\u043e\u043d\u0438\u043c": [21, 23, 83, 100], "\u0432\u0430\u0436\u043d\u043e\u0441\u0442": [21, 38, 75, 88, 90], "evironment": 21, "sandbox": 21, "\u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a": 21, "\u043d\u0430\u0440\u0443\u0448": [21, 23, 34], "\u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430": [21, 74], "\u043a\u043e\u043b\u043b\u0435\u043a\u0446": [21, 23], "\u0440\u0430\u0437\u0443\u043c\u0435\u0435\u0442": [21, 23, 37, 86], "\u0438\u043d\u0438\u0446\u0438\u0430\u0442\u043e\u0440": 21, "\u0432\u043a\u043b\u044e\u0447": [21, 75, 82, 100], "\u043a\u0430\u043d\u0430": [21, 34, 100], "\u043f\u043e\u0440": [21, 73, 75, 82, 88, 90], "\u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436": 21, "\u043d\u0438": [21, 34, 37, 38, 52, 70, 72, 74, 75, 82, 83, 85, 86, 90, 100], "\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432": [21, 56, 74, 86], "\u0443\u0432\u0435\u0434\u043e\u043c\u043b": 21, "\u0435\u0434\u0438\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d": [21, 74], "\u043f\u043e\u0432\u043e\u0434": [21, 23, 72, 74, 83, 86, 88, 93], "seem": [21, 23, 85], "strange": [21, 23, 74], "parameters": [21, 23], "registry": [21, 23], "static": [21, 23, 29, 52], "re": [21, 23, 37, 38, 47, 52, 64, 65, 68, 70, 74, 75, 77, 82, 85, 86, 92, 100], "querying": [21, 23], "collecting": [21, 23, 52], "parameter": [21, 23, 39], "redirect": [21, 23], "screen": [21, 23, 37], "showing": [21, 23, 38], "very": [21, 23, 29, 38, 62, 70, 74, 76, 85, 86, 94, 100], "accomplished": [21, 23, 37, 38, 86], "bit": [21, 23, 37, 46, 51, 74, 75, 76, 90], "controversial": [21, 23, 46], "frankly": [21, 23, 37, 76], "care": [21, 23, 34, 37, 42, 85], "simplest": [21, 23, 51, 70, 73, 75, 85], "possibly": [21, 23, 37, 51, 64, 70, 85], "steal": [21, 23], "unit": [21, 23, 38, 45, 46, 52, 66, 70, 74, 82, 85, 86, 123], "controllers": [21, 23], "diet": [21, 23], "posts": [21, 23, 82], "\u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d": [21, 37], "myth": [21, 23, 86], "requires": [21, 23, 34, 38, 46, 73, 74, 86, 90], "eventual": [21, 30, 34], "consistent": [21, 23, 34, 82], "immediately": [21, 23, 34, 38, 76, 86], "succeeds": [21, 23], "legacy": [21, 23, 38, 45, 66, 70, 76, 82, 83, 123], "transitioning": [21, 23, 46], "eventually": [21, 23, 34, 37, 38, 41, 65, 73, 74, 82, 86], "stores": [21, 23], "bogus": [21, 23], "hoops": [21, 23], "mimicking": [21, 23], "synchronous": [21, 23], "bang": [21, 23], "door": [21, 23, 41, 65], "pitchforks": [21, 23], "torches": [21, 23], "try": [21, 23, 38, 47, 51, 52, 65, 68, 73, 74, 77, 85, 90, 100], "transition": [21, 23, 38, 49], "immediate": [21, 23, 38, 76, 85], "consistency": [21, 31, 34, 82, 116], "unless": [21, 23, 34, 86], "expects": [21, 23], "confirmation": [21, 23], "making": [21, 23, 26, 34, 37, 38, 47, 65, 66, 70, 73, 74, 76, 82, 85, 88, 89, 100], "series": [21, 23, 51, 59, 60, 74, 75, 77, 82, 86], "confirmations": [21, 23], "received": [21, 23, 34], "annoy": [21, 23], "snot": [21, 23], "bus": [21, 23, 34], "queues": [21, 23, 82], "messaging": [21, 23, 30, 34, 82], "says": [21, 23, 37, 62, 75, 76], "thou": [21, 23], "shalt": [21, 23], "nservicebus": [21, 23], "merely": [21, 23, 37, 76], "separating": [21, 23, 38, 90, 100], "varied": [21, 23], "until": [21, 23, 26, 34, 37, 38, 39, 51, 65, 68, 73, 77, 85, 86], "prove": [21, 23, 65, 74], "models": [21, 23, 29, 34, 36, 37, 38, 49, 51, 52, 54, 62, 64, 65, 76, 82, 100, 120], "decision": [21, 23, 38, 39, 46, 65, 68, 70, 76, 82, 86, 88, 89], "impacts": [21, 23, 86], "slip": [21, 23], "emulate": [21, 23], "attempting": [21, 23, 49, 76], "wrong": [21, 23, 37, 38, 52, 65, 72, 75, 76, 85, 86], "busting": [21, 23, 82], "myths": [21, 23, 38, 82], "\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430": [21, 23], "scaling": [21, 23, 34, 64, 73, 82, 86], "orthogonal": [21, 23], "contextual": [21, 23], "certainly": [21, 23, 29, 37, 70, 74, 85], "doesn": [21, 23, 29, 34, 37, 38, 42, 51, 68, 72, 73, 74, 77, 85, 86, 94, 100], "require": [21, 23, 34, 37, 51, 73, 74, 75, 76, 86], "async": [21, 23], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442": [21, 23], "\u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440": [21, 23], "\u043d\u0438\u0447\u0442": [21, 23, 40, 42, 82], "\u0432\u043d\u043e\u0432": [21, 23], "\u0443\u043f\u0440\u043e\u0441\u0442": [21, 23, 37, 74, 76], "\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d": 21, "\u0441\u043b\u0443\u0447": [21, 26, 70, 74], "\u0441\u043c\u043e\u0433\u0443\u0442": [21, 38, 72, 85], "\u0442\u0443": [21, 88], "\u0440\u0430\u0437\u0431\u0438\u0440\u0430": [21, 40, 70, 83], "\u0437\u0430\u0431\u043b\u0443\u0436\u0434\u0435\u043d": [21, 65, 73, 85, 86, 92], "\u043c\u0430\u043a\u0441": 21, "\u0430\u0440\u0448\u0438\u043d": 21, "oskar": [21, 86], "dudycz": [21, 86], "facts": [21, 23], "versus": [21, 23, 37, 38, 41, 65, 74, 76, 85, 86], "mark": [21, 38, 65, 82, 88], "seemann": 21, "handlers": [21, 23, 34], "steven": [21, 82, 88], "van": [21, 34, 82], "deursen": 21, "\u0441\u043f\u043e\u0440\u043d": [23, 46], "\u0442\u043e\u0447\u0435\u043a": [23, 74, 82, 93, 94], "\u0432\u0435\u0449": [23, 37, 38, 74, 75, 82, 85, 100], "\u043f\u0435\u0440\u0432\u043e\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a": [23, 53, 85, 94], "\u043c\u043e\u0442\u0438\u0432": 23, "\u0442\u0435": [23, 38, 46, 70, 74, 75, 76, 85, 92, 100, 102], "zealots": 23, "extreme": [23, 37, 42, 46, 47, 52, 64, 65, 66, 68, 70, 73, 74, 76, 82, 83, 94, 95], "creators": 23, "royalist": 23, "king": [23, 76, 92], "captures": [23, 76, 77], "phenomenon": [23, 77], "find": [23, 34, 37, 38, 46, 47, 51, 65, 72, 73, 74, 77, 82, 85, 95], "foundational": 23, "texts": 23, "beck": [23, 37, 38, 41, 42, 46, 47, 52, 64, 65, 66, 68, 70, 72, 75, 76, 82, 83, 85, 86, 88, 92, 93, 94, 95], "larman": [23, 37, 38, 40, 41, 64, 75, 82, 83, 88, 94], "cockburn": [23, 37, 52, 76], "occupy": [23, 100], "plane": 23, "discourse": 23, "avoid": [23, 34, 38, 49, 65, 73, 74, 76, 85, 86, 89], "below": [23, 42], "belt": 23, "hits": 23, "approaches": [23, 37, 38, 42, 49, 51, 52, 65, 73, 76, 78, 85, 86, 92, 133], "hype": [23, 52, 82], "ugly": [23, 47, 52, 82], "\u0434\u0440": [23, 41, 88, 92, 102], "\u043e\u0431\u0437\u043e\u0440": [23, 37], "\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b": 23, "\u043a\u043e\u043b\u043b\u0435\u043a\u0442": [23, 88, 92], "\u0441\u0447\u0430\u0441\u0442": [23, 68, 82, 90], "\u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d": 23, "experts": [23, 51, 82, 95], "activity": [23, 37, 38, 46, 62, 74, 77, 100], "discrete": [23, 74, 90], "distinct": [23, 85, 100], "related": [23, 34, 38, 49, 75, 82], "arises": [23, 38, 46, 74], "kept": [23, 74], "internally": [23, 38, 86], "asynchronously": 23, "propagate": [23, 74], "nodes": [23, 34], "network": [23, 34, 86], "resolve": [23, 34, 38, 77, 86], "arriving": 23, "order": [23, 26, 34, 37, 38, 51, 74, 76, 82, 86], "sources": 23, "supposed": [23, 37, 49], "conceptually": [23, 75, 86], "constituent": 23, "cautious": 23, "locking": 23, "schemes": [23, 38], "interfere": 23, "pointlessly": 23, "unusable": 23, "similar": [23, 29, 39, 46, 74], "arise": [23, 26, 76, 86], "distributing": [23, 77], "servers": 23, "designing": [23, 34, 38, 65, 74, 76, 82, 86], "transactions": [23, 34, 82], "govern": 23, "distribution": [23, 82], "synchronously": 23, "\u043a\u0440\u0430\u0435\u0443\u0433\u043e\u043b\u044c\u043d": 23, "\u0441\u0438\u043b": [23, 38, 40, 73, 83, 86, 88, 90, 92, 95], "cap": [23, 34, 82], "\u0442\u0435\u043e\u0440\u0435\u043c": 23, "\u0440\u0443\u0441\u0441\u043a": [23, 34, 38, 40, 41, 60, 64, 66, 73, 74, 77, 82, 88, 90], "\u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442": [23, 38, 56, 65, 76, 83, 86, 88, 92, 94], "availability": [23, 34, 38], "partition": 23, "tolerance": 23, "\u0442\u0430": [23, 26, 38, 65, 76, 82, 86, 88, 100], "\u0443\u0437\u043b": [23, 34, 86], "\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430": [23, 100], "\u043c\u0438\u043d\u0443\u0442\u043a": 23, "\u0430\u0432\u0442\u043e\u043c\u043e\u0431\u0438\u043b": 23, "\u043f\u0440\u0438\u0439\u0442": [23, 70, 100], "\u0442\u0438\u043f\u043e\u0440\u0430\u0437\u043c\u0435\u0440": 23, "\u0432\u0435\u0440\u043d\u043e\u043d": [23, 100], "\u043f\u0440\u0438\u0431\u0435\u0433\u0430": 23, "commit": 23, "\u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d": [23, 34, 76, 86, 92], "\u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441": [23, 34, 75, 87, 92, 93, 100, 137], "\u043f\u0440\u0430\u0432\u0434": [23, 34, 73, 75, 88, 92, 95, 100], "\u0443\u0445\u0443\u0434\u0448": 23, "\u0443\u0440\u043e\u0432\u0435\u043d": [23, 72, 73, 75, 77, 83, 85, 86, 88, 94, 95], "\u043d\u0430\u0438\u043c\u0435\u043d": [23, 38], "\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446": [23, 72], "\u043c\u043e\u043d\u043e\u043b\u0438\u0442": 23, "\u0441\u0442\u0440\u0435\u043c\u043b\u0435\u043d": [23, 37, 38, 73, 74, 85, 86, 90], "eliminate": [23, 38, 70, 74, 86], "commits": 23, "modified": [23, 34, 52, 86], "dependent": [23, 34, 38, 65, 85], "occur": [23, 34, 38, 70, 75], "instances": [23, 26, 34], "synchronized": 23, "remote": [23, 82], "latency": [23, 30, 34], "decoupling": [23, 73, 74], "performing": [23, 38, 74, 90], "cooperating": 23, "loose": [23, 72, 73], "\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d": [23, 34, 37, 86], "\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432": [23, 90], "\u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d": [23, 37, 75, 86], "\u043e\u0437\u0432\u0443\u0447\u0438\u0432\u0430": 23, "relational": 23, "fine": [23, 75, 76, 82, 86], "grained": [23, 82, 86], "rationale": 23, "embracing": [23, 52, 76], "spanning": 23, "number": [23, 34, 37, 38, 51, 52, 65, 74, 75, 76, 80, 85, 86, 90], "substantial": 23, "scalability": 23, "instant": 23, "accepting": [23, 38, 51], "atomic": 23, "larger": [23, 38, 73, 86], "correctly": [23, 65, 85], "bill": [23, 37, 38, 82], "wagner": [23, 82], "mike": [23, 52, 76, 82, 83, 88, 92], "rousos": [23, 82], "\u0443\u0445\u0443\u0434\u0448\u0435\u043d": [23, 38, 74], "\u043a\u0440\u0443\u043f\u043d": [23, 74, 76, 83, 86, 90], "\u0432\u0438\u0434\u043d": [23, 46, 75, 83, 92], "\u0441\u0442\u043e\u043b\u044c\u043a": [23, 41, 75, 85], "\u0441\u043a\u043e\u043b\u044c\u043a": [23, 38, 41, 75, 83, 86, 92, 100], "\u0440\u0430\u0437\u043c\u0435\u0440": [23, 73, 76, 86, 92, 93, 100], "smaller": [23, 34, 38, 52, 72, 73, 74, 75, 85, 86, 90], "biased": 23, "toward": [23, 38, 76, 77, 82, 95], "success": [23, 37, 38, 46, 51, 62, 76, 85, 86], "meaning": [23, 38, 74, 75, 100], "conflicts": [23, 38, 82], "preventing": [23, 74, 85], "rare": 23, "small": [23, 38, 53, 65, 72, 73, 74, 75, 76, 86], "\u043f\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0447\u0438\u043d": 23, "\u0432\u043e\u0432\u0441": [23, 38, 76, 85, 93, 102], "maintained": [23, 37, 51, 76], "spans": 23, "expected": [23, 37, 38, 65, 76, 85, 86], "batch": 23, "mechanisms": [23, 82, 86], "resolved": [23, 38, 65, 72], "specified": [23, 49, 65], "applied": [23, 37, 38, 64, 75, 76, 82, 88], "enforced": [23, 34, 49], "six": [23, 37, 74, 76, 86], "cycle": [23, 36, 37, 38, 49, 51, 52, 59, 60, 62, 63, 65, 74, 76, 77, 82, 86, 88, 120], "insert": 23, "delete": 23, "ordinarily": 23, "tempting": [23, 47, 74], "saving": [23, 34], "presumably": 23, "initiate": 23, "units": [23, 34, 52, 75, 85], "keeps": [23, 72, 82, 85, 95], "hands": [23, 34, 73, 77, 82, 86, 100], "\u043a\u043e\u0440\u043d": [23, 38, 73], "ownership": [23, 86, 94], "rigorous": 23, "includes": [23, 51, 60, 72, 74, 82, 85, 86, 94, 100], "owners": [23, 38, 65, 86], "identity": [23, 26], "traffic": [23, 34], "involved": [23, 37, 38, 39, 40, 80, 86], "\u043a\u0441\u0442\u0430\u0442": [23, 34, 65, 74, 75, 83, 85, 94, 95], "siegel": 23, "1990s": [23, 76], "published": [23, 38, 46, 76, 82], "specific": [23, 34, 38, 49, 51, 52, 53, 72, 82, 85, 86, 100], "contained": [23, 86], "member": [23, 38, 73, 86], "distinguishable": 23, "\u0441\u043e\u0436\u0430\u043b\u0435\u043d": [23, 38, 68, 70, 75, 82], "\u0443\u0434\u0430": [23, 37, 56, 74, 76, 85, 88, 93, 102], "\u0443\u043f\u043e\u043c\u0438\u043d\u0430": [23, 38, 40, 53, 86, 89], "poeaa": [23, 72], "\u0437\u0432\u0443\u0447": [23, 38, 40], "coarse": 23, "alternative": [23, 34, 38, 49, 65, 70, 76], "16": [23, 51, 72, 74, 76, 83, 88, 93], "contention": [23, 34], "concurrency": [23, 32, 117], "\u043d\u0430\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d": 23, "\u043e\u0431\u044a\u044f\u0441\u043d\u044f": [23, 30, 37, 74, 75, 85, 92, 94, 100], "\u0432\u044b\u0441\u043e\u043a\u043e\u043d\u0430\u0433\u0440\u0443\u0436\u0435\u043d": 23, "\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c": [23, 64, 76, 86], "\u0431\u044b\u0432\u0430": [23, 34, 83, 86, 88, 92, 100], "executing": [23, 37, 76], "additional": [23, 37, 38, 76, 86], "execute": [23, 38, 65, 76], "invariant": [23, 34, 82], "discussing": 23, "logically": 23, "everything": [23, 34, 37, 38, 46, 65, 70, 72, 73, 76, 82, 85, 86], "adheres": 23, "matter": [23, 38, 51, 66, 74, 86, 100], "irrelevant": 23, "synonymous": 23, "employing": 23, "typical": [23, 70, 86], "persistence": [23, 82], "properly": [23, 38, 74, 82, 85], "applying": [23, 62, 65, 72, 75, 82, 85], "limiting": [23, 37, 76, 86], "overly": [23, 38, 76], "strict": 23, "thumb": [23, 62], "addresses": [23, 75], "true": [23, 37, 38, 73, 74, 85, 86, 100], "remember": [23, 37, 38, 51, 53, 74, 85, 90, 94], "drivers": [23, 77, 85, 86], "determining": [23, 86], "\u0447\u0435\u0442\u044b\u0440": [23, 38, 40, 42, 82], "\u0446\u0438\u0442\u0438\u0440\u043e\u0432\u0430": 23, "\u043a\u043e\u043c": [23, 85], "\u0432\u043f\u043b\u043e\u0442": [23, 30, 37, 88], "gaining": 23, "insight": [23, 77, 100], "discovery": [23, 86], "\u043e\u0442\u0440\u044b\u0432\u043e\u043a": 23, "scenarios": [23, 52, 86], "challenging": 23, "determine": [23, 65, 85], "classic": [23, 74, 76, 85], "correct": [23, 26, 100], "neither": [23, 38], "tendencies": 23, "preference": [23, 76], "break": [23, 73, 74, 82, 86, 88, 90], "tie": 23, "revealed": 23, "guideline": [23, 38, 46, 85], "examining": 23, "transactionally": 23, "adhering": 23, "wisdom": [23, 74], "breaker": 23, "gain": [23, 37, 47, 70], "deeper": [23, 42, 73], "understanding": [23, 37, 38, 41, 49, 51, 65, 72, 73, 74, 77, 82, 86, 100], "exposes": [23, 85], "real": [23, 62, 65, 75, 76, 82, 85, 86, 100], "ones": [23, 34, 64, 70, 75, 82, 95], "valuable": [23, 29, 37, 38, 53, 62, 65, 70, 73, 77, 85], "defaulting": 23, "leaning": 23, "\u0446\u0438\u0442\u0430\u0442": [23, 37, 38], "\u0432\u043e\u043d": 23, "\u044d\u0440\u0438\u043a": [23, 100], "\u044d\u0432\u0430\u043d\u0441": [23, 100], "\u0441\u043f\u0435\u0448": [23, 88], "\u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430": [23, 38, 70, 86, 88], "architects": [23, 38, 46, 86], "okay": 23, "original": [23, 37, 74, 75, 76, 82, 86], "\u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430": [23, 46], "\u0443\u0433\u043b": 23, "\u043e\u043f\u044f": [23, 82, 85, 86, 92, 94], "ll": [23, 34, 37, 41, 74, 75, 76, 77, 80, 82, 85, 86, 90, 95], "theorem": [23, 34, 82], "optimally": 23, "incredibly": 23, "concerned": [23, 86], "according": [23, 38, 52, 64, 73, 82, 100], "committing": [23, 65], "modifications": [23, 37, 38, 76], "succeed": [23, 37, 38, 65, 76, 100], "techniques": [23, 38, 74, 82, 86, 90], "big": [23, 34, 37, 38, 46, 51, 60, 65, 70, 73, 74, 76, 77, 80, 82, 86, 90], "initial": [23, 59, 60, 62, 65, 76, 80, 86], "step": [23, 52, 65, 77, 82, 85, 86], "meant": [23, 75, 85], "failures": [23, 38, 64], "\u0437\u0430\u0431\u0435\u0433": 23, "\u043d\u0430\u043f\u0435\u0440\u0435\u0434": 23, "\u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d": [23, 41, 74, 85, 92], "confuse": 23, "loading": [23, 82], "perfectly": [23, 72, 74, 76, 85, 86], "equally": 23, "permissible": 23, "practices": [23, 34, 37, 38, 49, 51, 52, 53, 54, 64, 65, 74, 75, 76, 77, 82, 85, 88, 94, 126], "19": [23, 38, 82], "\u043e\u0431\u0440\u0430\u0449": [23, 65], "highload": [23, 34], "throughput": 23, "persists": 23, "batches": 23, "timescaledb": 23, "batched": 23, "inserts": 23, "databases": [23, 37, 82], "employed": 23, "environments": [23, 75, 76], "ingesting": 23, "kafka": [23, 34, 82], "timescale": 23, "ingest": 23, "130k": 23, "3m": 23, "approximately": [23, 86], "15x": 23, "vanilla": 23, "postgresql": [23, 82], "couple": 23, "100m": 23, "freedman": [23, 30, 34], "cto": [23, 34, 86], "co": [23, 76, 86], "founder": [23, 86], "professor": [23, 37], "computer": [23, 38, 62, 65, 68, 73, 74, 82, 85, 90], "princeton": [23, 30, 34, 60, 82, 90], "rates": [23, 34, 70], "bulk": 23, "parallel": [23, 34, 77, 86], "hundreds": [23, 37, 74, 76], "thousands": [23, 37], "spend": [23, 38, 47, 49, 72, 73, 74, 86], "connection": 23, "overhead": [23, 46, 73, 74, 86], "parsing": 23, "tips": 23, "improve": [23, 74, 85, 86], "postgres": [23, 82], "extra": [23, 38, 46, 73, 74], "coordination": [23, 82, 86], "completed": [23, 37, 74, 76, 86], "write": [23, 47, 49, 51, 72, 73, 74, 77, 85, 86, 90], "wrap": [23, 85], "nice": [23, 76, 85, 86, 94], "gains": [23, 38, 42], "begin": [23, 34, 38, 51, 85, 86, 88], "took": [23, 73, 74], "15": [23, 37, 38, 64, 66, 70, 73, 80, 82, 85, 86], "minutes": [23, 38, 46, 74], "seconds": [23, 51], "ve": [23, 37, 38, 51, 62, 65, 70, 74, 75, 82, 85, 86], "suddenly": [23, 73], "boosted": 23, "3x": 23, "3k": 23, "batching": 23, "performant": 23, "manner": [23, 38, 76], "running": [23, 37, 38, 65, 85, 93, 94, 100], "completes": [23, 38], "82": [23, 34, 38, 75, 82], "10k": 23, "writes": [23, 65, 76], "fairly": [23, 85], "modest": [23, 85], "hardware": [23, 64], "faster": [23, 37, 38, 42, 73, 74, 86], "craig": [23, 34, 37, 38, 40, 41, 64, 75, 82, 83, 88, 94], "kerstiens": 23, "citusdata": 23, "turn": [23, 37, 38, 72, 73, 75, 76, 85, 86], "autocommit": 23, "issuing": 23, "libraries": 23, "behind": [23, 29, 34, 37, 38, 73, 74, 82, 85], "done": [23, 34, 37, 38, 41, 42, 46, 51, 62, 65, 70, 72, 73, 74, 76, 86, 88], "insertion": 23, "committed": 23, "separately": [23, 86, 100], "lot": [23, 29, 37, 38, 70, 73, 76, 86], "added": [23, 29, 34, 38, 51, 74, 86], "populating": 23, "disable": 23, "\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d": [23, 77, 100], "\u0440\u0435\u0446\u0435\u043f\u0442": 23, "\u0430\u043a\u0442\u0443\u0430\u043b": 23, "\u0441\u0435\u0440\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430": 23, "\u0441\u0432\u043e\u0431\u043e\u0434": [23, 38], "\u0432\u0441\u044f": [23, 37, 41, 70, 86, 95], "postgrespro": [23, 82], "\u043f\u0430\u043a\u0435\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [23, 30], "\u0432\u0441\u043f\u043e\u043c\u043d": [23, 60, 72, 85, 86, 90, 94], "\u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448": [23, 34, 77], "\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d": [23, 34], "blue": 23, "green": [23, 85], "deployment": [23, 75, 82, 86], "\u044f\u0432\u043d": [23, 29, 38, 102], "preferred": [23, 73], "triggered": 23, "\u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c": [23, 30, 74, 85], "\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440": 23, "come": [23, 37, 38, 52, 74, 85, 86, 92], "span": [23, 39], "ef": [23, 82], "cosmosdb": 23, "deferred": [23, 76], "raise": 23, "actually": [23, 37, 38, 49, 70, 74, 76, 100], "right": [23, 34, 37, 38, 39, 42, 52, 68, 70, 73, 74, 75, 76, 80, 82, 85, 86, 88], "depends": [23, 29, 74], "tell": [23, 37, 38, 46, 74, 76, 86], "service": [23, 34, 41, 70, 75, 82, 86], "granular": 23, "impact": [23, 34, 38, 49, 76], "regard": [23, 76, 85], "investment": [23, 37, 38, 46, 72], "willing": [23, 73, 85], "detect": [23, 34, 65], "inconsistencies": 23, "compensatory": 23, "actions": [23, 34, 38, 51], "afterwards": 23, "dispatched": [23, 34, 86], "issue": [23, 34, 37, 38], "tables": 23, "detects": [23, 34], "runs": [23, 37, 38, 73, 76, 82], "comparing": [23, 38, 41, 66, 86], "list": [23, 38, 52, 82, 86], "topic": [23, 34, 38, 74, 76, 90], "deep": [23, 34, 38, 82], "raising": [23, 38], "ordering": [23, 34, 38, 63], "guidelines": [23, 37, 76, 82], "exist": 23, "place": [23, 37, 38, 51, 65, 74, 75, 76], "ignoring": [23, 85], "cost": [23, 34, 37, 38, 39, 41, 52, 60, 63, 65, 66, 70, 74, 76, 77, 80, 86, 89], "exceptional": 23, "circumstances": [23, 76, 85], "tells": [23, 37, 38, 76, 86], "unsatisfactory": 23, "shouldn": [23, 37, 68, 73, 74, 82, 90, 100], "wants": [23, 42, 46, 73, 75, 86], "elaborate": [23, 38, 49, 76, 86], "costs": [23, 37, 70, 73, 74, 86], "informed": [23, 37, 38, 65, 68, 77], "later": [23, 29, 34, 38, 51, 60, 62, 65, 68, 72, 76, 82, 85, 86], "robust": [23, 34, 82], "utilize": 23, "workflows": 23, "summarize": [23, 37, 77], "collaborate": [23, 38, 86], "assess": [23, 38, 51, 53], "consciously": [23, 38, 72, 85], "ignore": [23, 34, 38, 85], "worthwhile": 23, "align": [23, 41], "greater": [23, 86], "chance": [23, 37, 52, 70, 75], "failure": [23, 37, 38, 51, 65, 76, 85], "therefore": [23, 38, 39, 46, 65, 73, 74, 86, 92], "strive": [23, 38], "sign": [23, 37, 38, 76], "aligned": [23, 38, 82, 86], "fail": [23, 38, 65, 100], "managing": [23, 38, 40, 49, 60, 62, 73, 74, 82, 86, 88, 90, 100], "demonstrated": 23, "recommendafriendservice": 23, "imagine": [23, 73, 85], "referral": 23, "encapsulates": 23, "accounts": [23, 82, 95], "25": [23, 68], "logical": [23, 85], "necessarily": [23, 74, 76, 86], "scope": [23, 37, 38, 41, 52, 65, 74, 85, 86, 95], "respective": 23, "eventing": 23, "fired": 23, "strengthening": 23, "18": [23, 82, 85], "wrapping": 23, "thread": [23, 29], "raised": 23, "ensure": [23, 38, 51, 86], "entire": [23, 34, 75, 76, 85, 86, 100], "stays": [23, 37, 74, 75, 86], "notify": 23, "roots": [23, 85], "happens": [23, 34, 38, 70, 76, 86], "locked": 23, "risk": [23, 37, 38, 63, 70, 73, 77, 82, 86], "charged": 23, "fee": [23, 38, 46], "face": [23, 37, 38, 74, 76, 86], "applicable": [23, 38, 64, 86], "blocking": 23, "revert": [23, 38], "normal": [23, 47, 52], "disconnected": [23, 52], "intuitive": [23, 74], "cared": 23, "myself": [23, 37, 38, 85], "dispatching": 23, "handler": [23, 34], "recorded": 23, "benefits": [23, 37, 38, 51, 65, 70, 77, 86, 94], "besides": [23, 38], "tearing": 23, "hair": 23, "domainevents": 23, "execution": [23, 86], "opinion": [23, 37, 38], "initializing": 23, "connections": 23, "thanks": [23, 37], "andreas": 23, "books": [23, 38, 82], "practitioner": [23, 66, 82], "distlled": 23, "impossible": [23, 37, 38, 65, 70, 76], "notifications": 23, "becomes": [23, 37, 38, 40, 72, 73, 74, 85, 86], "responsible": [23, 38, 49, 51, 65, 75, 86], "behavior": [23, 26, 38, 68, 72, 75, 85, 88, 100], "communication": [23, 35, 38, 51, 52, 68, 73, 86, 119], "subscribe": [23, 34], "missing": [23, 82], "placement": 23, "payment": 23, "emails": 23, "started": [23, 38, 74, 82, 85, 86], "invoked": 23, "\u0432\u044b\u0445\u043e\u0434\u044f": 23, "channels": [23, 34, 86], "annotation": 23, "ispublic": 23, "emitting": 23, "knows": [23, 37, 39, 52, 82], "mathias": [23, 82, 92], "verraes": [23, 82, 92, 94], "sample": [23, 34, 75, 82, 85], "dotnet": [23, 82], "late": [23, 37, 38, 51, 63, 77, 86], "ends": [23, 37, 74], "scoping": 23, "dosomething": 23, "messages": [23, 34], "sent": [23, 34], "salvation": 23, "120": [23, 83], "lars": 23, "asks": 23, "didn": [23, 37, 38, 70, 74, 85], "maybe": [23, 85], "situation": [23, 37, 38, 47, 74, 76, 86], "explain": [23, 39, 41, 66], "bcs": 23, "deals": 23, "merging": [23, 94], "fire": [23, 37], "specifying": [23, 65], "merged": 23, "bc": 23, "react": [23, 37, 76], "won": [23, 37, 38, 74, 75, 85, 86], "vital": [23, 38, 73, 74], "am": [23, 38, 85], "solution": [23, 34, 38, 49, 52, 62, 65, 70, 73, 76, 77, 82, 83, 86, 100], "suggest": [23, 75, 86], "ergo": 23, "deploying": [23, 34, 82], "enlisted": 23, "rolled": 23, "wouldn": [23, 37, 74, 85, 100], "arrives": [23, 34], "permanent": 23, "agree": [23, 38, 49, 74, 75], "ready": [23, 38, 51, 80, 82], "coincides": 23, "technology": [23, 30, 34, 38, 64, 70, 73, 76, 77, 82, 86, 88], "choice": [23, 29, 86], "updating": 23, "transmitted": [23, 86], "gets": [23, 37, 38, 51, 73, 74, 76, 88], "routed": 23, "subscribers": [23, 34], "subscribed": 23, "aggregateroot": 23, "ensuring": [23, 38], "principal": [23, 41, 52, 86], "manager": [23, 37, 38, 46, 73, 74, 76, 86], "revisited": [23, 34, 82], "werner": [23, 34, 82], "vogels": [23, 34, 82], "amazon": [23, 34, 86], "\u0441\u0443\u0433\u0443\u0431": [23, 38, 65], "\u043f\u043e\u0434\u0440\u0430\u0437\u0434\u0435\u043b\u044f": 23, "loop": [23, 34, 72, 77, 85], "await": 23, "mediatr": 23, "amqp": 23, "rabbitmq": 23, "mentioned": 23, "conclusions": [23, 37], "\u043c\u0435\u0442\u043e\u0434\u0438\u043a": [23, 37, 38, 40, 42, 74, 75, 76, 82, 83, 85, 90, 95], "anti": [23, 37, 76, 82, 94], "corruption": 23, "\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d": [23, 38, 40, 47, 70, 74, 76, 80, 82, 85, 90, 94, 100, 102], "\u0437\u0430\u0449\u0438\u0442": [23, 38, 40, 56, 82, 88, 89, 92], "\u0447\u0430\u0441\u0442\u043e\u0442": 23, "share": 23, "occurred": [23, 34, 64], "interested": [23, 76], "parties": [23, 52, 86], "outward": 23, "subdomains": [23, 100], "emphasizes": [23, 37, 85], "word": [23, 37, 52, 75, 76, 86, 100], "term": [23, 37, 38, 52, 62, 74, 76, 85, 86, 100], "wide": [23, 38], "potential": [23, 38, 52, 70, 75, 76, 86], "broad": [23, 70], "broader": [23, 34, 86], "broadcast": 23, "forbid": 23, "delivery": [23, 34, 37, 38, 52, 59, 60, 77, 82], "consumers": [23, 34], "\u043e\u0442\u0434\u0435\u043b\u044f": 23, "saved": [23, 70], "telling": 23, "noteworthy": 23, "conformists": 23, "wondering": 23, "consumed": 23, "\u0432\u043e\u043b\u043d": [23, 83], "\u043f\u0440\u0438\u043c": [23, 34], "consuming": [23, 34, 74], "conformist": 23, "relationship": [23, 34, 38, 64, 72, 74, 85], "recommended": [23, 60, 62, 65, 76, 90], "iddd": [23, 82], "specifically": [23, 37], "integrating": [23, 86], "publisher": 23, "depend": [23, 75], "perhaps": [23, 34, 37, 38, 47, 75, 85], "economical": [23, 64], "consumer": [23, 34, 86], "consume": [23, 34, 74], "attributes": [23, 26, 38, 40, 51, 75], "\u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430": [23, 29, 100, 102], "\u043f\u043e\u0437\u0434\u043d": [23, 37, 56, 68, 76, 94], "\u0438\u0437\u0434\u0430\u043d": [23, 38, 64, 76, 82, 86], "\u0433\u043e\u0444": 23, "\u0438\u0432\u0435\u043d\u0442": 23, "\u043a\u0430\u0442\u0435\u0433\u043e\u0440": [23, 38, 40, 82, 83, 90, 102], "\u0440\u0435\u0437\u043e\u043d": [23, 56], "\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f": [23, 34], "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446": [23, 37, 73, 93], "\u0432\u044b\u0445\u043e\u0434": [23, 38, 47, 56, 74, 75, 86, 92], "\u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430": 23, "\u043d\u0430\u0437\u044b\u0432": [23, 73], "outbox": [23, 30], "comes": [23, 38, 70, 72, 73, 74, 75, 85, 86], "communicate": [23, 73, 100], "3rd": [23, 49, 51, 52, 53, 64, 82], "party": [23, 38, 46, 85, 86], "mail": 23, "generic": 23, "gave": [23, 41, 46, 72, 85], "fits": 23, "best": [23, 34, 37, 38, 49, 52, 53, 64, 65, 68, 72, 74, 75, 76, 82, 85, 86, 100], "trasactional": 23, "were": [23, 34, 37, 38, 41, 47, 52, 62, 70, 73, 74, 75, 76, 85, 86, 94, 100], "introduced": [23, 38, 52, 75], "\u0441\u0432\u044f\u0437\u044b\u0432\u0430": 23, "\u043e\u043a\u043e\u043d\u0447\u0430\u043d": 23, "\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b": [23, 85], "\u0442\u0440\u0438": [23, 38, 64, 76, 82, 85, 100], "\u0443\u0442\u043e\u0447\u043d\u0435\u043d": [23, 100, 102], "persisted": 23, "ul": 23, "pl": 23, "\u043d\u0430\u0431\u043b\u044e\u0434\u0430": [23, 38, 40, 74, 75, 76, 77, 82, 85, 88, 92, 95, 102], "processed": [23, 34], "\u0441\u0441\u044b\u043b": 23, "\u043f\u0440\u0438\u0440\u0430\u0432\u043d\u0438\u0432\u0430": 23, "\u0432\u043d\u0435": [23, 30, 86], "\u043f\u0443\u0431\u043b\u0438\u043a": 23, "twitter": [23, 82], "\u0440\u0430\u0437\u044a\u044f\u0441\u043d\u0435\u043d": 23, "sth": 23, "occured": 23, "\u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430": [23, 38, 70, 74, 86], "\u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446": [23, 74, 90, 100], "\u0438\u0434\u0443\u0442": [23, 38], "pppddd": 23, "distinction": [23, 38, 46, 85], "confusion": [23, 52, 82], "lead": [23, 37, 38, 70, 82, 85, 86], "poor": [23, 37, 74], "crucial": [23, 100], "whereas": [23, 34, 85], "ii": [23, 85], "differentiating": 23, "limited": [23, 38, 49, 73, 77, 86, 92], "ok": [23, 37, 38, 39], "listing": [23, 85], "showed": 23, "poses": 23, "become": [23, 34, 37, 49, 51, 74, 75, 82, 85, 86, 95], "coupled": [23, 37, 74, 76, 85], "conversely": 23, "flat": 23, "correlational": 23, "typified": 23, "learned": [23, 37, 38, 65, 76, 77, 86], "versioned": 23, "differentiator": 23, "compile": 23, "compiled": [23, 75], "illustrates": [23, 86], "sequence": [23, 34, 38], "differences": [23, 38, 85, 86, 100], "namespaces": 23, "accentuate": 23, "basically": 23, "solve": [23, 37, 38, 60, 73, 76, 82, 86, 90, 100], "scoped": 23, "eventbus": 23, "anymore": 23, "semantically": 23, "pushed": 23, "dispatcher": 23, "ioc": [23, 94], "hand": [23, 38, 77, 85, 100], "subsystems": [23, 51, 74, 86, 90], "otherwise": [23, 47], "inter": [23, 86], "commercial": [23, 38], "mailbox": [23, 34], "ideally": 23, "push": [23, 38], "generate": [23, 38, 72, 85, 86], "finally": [23, 37, 76], "mention": 23, "propagation": [23, 86], "carrying": [23, 38], "importantly": [23, 51], "tightly": [23, 38, 75], "feeling": [23, 73, 85], "seldom": 23, "chosen": [23, 38], "carefully": [23, 29, 34, 37, 38, 65, 74, 86, 88, 90, 100], "ubiquitous": [23, 38, 100], "granularity": [23, 52], "stable": [23, 38, 46, 62, 65, 77, 86], "quickly": [23, 37, 46, 47, 49, 51, 73, 74, 76, 82, 86], "during": [23, 37, 38, 49, 70, 75, 86, 88, 100], "rarely": [23, 37, 38, 76, 86], "altered": [23, 76], "said": [23, 34, 37, 38, 41, 46, 65, 73, 74, 75, 85, 86, 92], "universally": 23, "heuristic": [23, 77], "closed": [23, 75], "forward": [23, 38, 47], "storing": 23, "forwarding": 23, "xa": 23, "middleware": 23, "shares": 23, "band": 23, "arrange": 23, "refer": [23, 74, 75, 85], "\u0441\u0442\u0443\u043f\u0435\u043d": [23, 73], "gof": [23, 37, 76, 85, 94], "\u043f\u043e\u0442\u043e\u043a": [23, 30, 34], "effective": [23, 37, 38, 46, 72, 74, 76, 77, 80, 82, 85], "lightweight": [23, 38, 51, 86], "sake": [23, 37, 76], "naming": [23, 85], "acknowledged": [23, 34, 38], "examples": [23, 34, 38, 51, 82, 85, 89, 93], "subscribing": 23, "registered": 23, "subscriber": 23, "notified": 23, "implies": [23, 38, 74, 75, 85, 86], "controlled": 23, "direct": 23, "considering": [23, 74], "halves": 23, "register": 23, "prior": [23, 51], "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0435\u0440\u0435\u0436\u0435\u043d": [23, 88], "breaks": [23, 77], "\u043c\u0435\u0441\u0442": [23, 38, 40, 46, 70, 72, 73, 75, 76, 83, 85, 86, 88, 90, 92, 102], "\u0438\u043b\u043b\u044e\u0437": [23, 40, 93], "\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f": 23, "\u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d": [23, 70, 102], "\u043e\u0434\u043d\u043e\u0444\u0430\u0437\u043d": 23, "delivered": [23, 34, 38, 59, 74, 77, 86], "retrieves": 23, "executes": 23, "obeying": 23, "\u0440\u0430\u0441\u0441\u0435\u0438\u0432\u0430": 23, "pretty": [23, 70], "looks": [23, 73, 74, 75], "invoke": 23, "collections": 23, "db": [23, 82], "\u043f\u0440\u0435\u0434\u043b\u043e\u0436": [23, 38, 86], "emitted": 23, "causes": [23, 34, 38], "caused": [23, 34], "timer": [23, 34], "expires": 23, "week": [23, 37, 38, 65, 72, 82, 85, 95], "month": [23, 38, 41, 65, 74, 76, 82, 86], "ending": 23, "period": [23, 34, 41], "reject": [23, 34], "frame": [23, 37], "expired": 23, "cares": [23, 73], "expiration": 23, "modeled": [23, 51], "occurrence": 23, "initiates": 23, "retained": 23, "removal": [23, 74], "record": 23, "happening": 23, "implicit": 23, "filter": 23, "consequence": [23, 76], "initiated": [23, 65], "leanpub": [23, 82], "eventstorming": [23, 76, 82], "alberto": [23, 82, 86], "brandolini": [23, 82, 86], "immutable": [23, 26, 82], "timestamp": 23, "rejected": [23, 34], "inappropriate": [23, 75], "supply": 23, "product": [23, 37, 38, 40, 41, 46, 51, 65, 74, 75, 76, 80, 85, 86, 100], "funds": 23, "history": [23, 34, 37, 76, 82], "denied": 23, "carry": [23, 29, 60, 62, 66, 70, 73, 86, 90], "statement": [23, 52, 76, 85, 94], "verb": 23, "tense": 23, "productcreated": 23, "scrum": [23, 37, 40, 49, 51, 52, 64, 65, 66, 76, 80, 82], "releasescheduled": 23, "sprintscheduled": 23, "backlogitemplanned": 23, "backlogitemcommitted": 23, "clearly": [23, 38, 76, 82, 85], "concisely": 23, "noted": [23, 65], "earlier": [23, 29, 70, 74, 86], "characteristic": [23, 86], "previous": [23, 34, 85], "\u043f\u0440\u043e\u0448\u043b": [23, 38, 73, 94, 102], "\u0438\u043d\u0438\u0446\u0438\u0438\u0440\u043e\u0432\u0430": [23, 88], "\u043a\u043e\u043c\u043f\u0435\u043d\u0441\u0430\u0446\u0438\u043e\u043d": 23, "undo": 23, "\u043a\u043e\u043c\u043f\u0435\u043d\u0441\u0438\u0440": [23, 74, 90], "redo": 23, "moment": [23, 65, 68, 72, 85], "themselves": [23, 37, 74, 76, 86, 90], "placed": [23, 38], "undone": 23, "harmlessly": 23, "undoing": 23, "\u0440\u0430\u043c\u043a": [23, 37, 38, 46, 47, 70, 85, 92, 100, 102], "\u043f\u043e\u0441\u0442": [23, 34, 75, 83], "undesirable": 23, "roll": 23, "currently": 23, "lives": [23, 74], "probably": [23, 42, 85, 86], "failed": [23, 37, 41], "her": [23, 38, 86], "she": 23, "tries": [23, 34], "trying": [23, 37, 74, 76, 85], "fault": 23, "tolerant": 23, "sacrifices": 23, "upsetting": 23, "customers": [23, 37, 38, 49, 52, 76, 82, 85], "orders": [23, 82], "everybody": [23, 38, 42], "inconsistent": [23, 49], "wishes": 23, "processes": [23, 37, 38, 49, 52, 59, 60, 62, 63, 64, 65, 76, 77, 82, 85, 86], "building": [23, 34, 37, 38, 46, 52, 65, 70, 74, 76, 82, 86, 100], "commerce": [23, 37, 76], "inconsistency": 23, "\u0437\u0430\u0442\u0440\u0430\u0442": [23, 37, 38, 40, 70, 72, 86, 94], "\u0431\u0430\u0437\u0438\u0440\u043e\u0432\u0430": 23, "\u0440\u0435\u043b\u0438\u0433\u0438\u043e\u0437\u043d": 23, "\u0434\u043e\u0433\u043c\u0430\u0442\u0438\u0437\u043c": 23, "\u043e\u0441\u043d\u043e\u0432\u044b\u0432": 23, "\u0431\u0435\u0437\u0434\u0443\u043c\u043d": 23, "\u0432\u0435\u0440": [23, 83, 92, 93, 94], "\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d": 23, "\u0441\u0442\u043e\u044f": [23, 38, 83], "\u0443\u0434\u0438\u0432": 23, "\u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d": [23, 34, 92], "\u0443\u043f\u0440\u043e\u0449\u0435\u043d": [23, 38, 73, 74, 100], "\u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430": [23, 72, 83], "\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d": [23, 40, 72, 85, 92], "26": [23, 100], "\u0447\u0438\u0441\u0442\u043e\u0442": 23, "abstract": [23, 85], "machines": 23, "\u043d\u0430\u0433\u043b\u044f\u0434\u043d": [23, 38, 82, 85, 90, 93], "\u0438\u0437\u0443\u0447\u0430": [23, 65, 90], "\u0432\u044b\u0432\u043e\u0434": [23, 38, 65, 70, 75, 80, 83, 85, 86, 90, 92, 100], "\u0432\u0438\u043a\u0438\u043f\u0435\u0434": [23, 34, 75, 85, 100], "\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443": 23, "\u0431\u0443\u0444\u0435\u0440": 23, "\u0442\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u043e\u0432\u0430": 23, "pseudo": [23, 74], "random": 23, "generators": 23, "exercise": [23, 38, 39, 46, 70, 74, 86], "\u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440": 23, "\u0441\u043b\u0443\u0447\u0430\u0439\u043d": [23, 92], "\u0447\u0438\u0441\u0435\u043b": [23, 93], "\u0440\u0435\u0441\u0443\u0440\u0441": [23, 34, 38, 40, 70, 85, 86, 92, 95, 100], "\u0438\u0433\u0440\u0430": [23, 85, 86, 92, 95], "\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d": [23, 75, 89], "\u043a\u0440\u0438\u0432": [23, 37, 70, 89, 94], "\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d": [23, 42, 46, 70, 72, 73, 75, 76, 85, 86, 100, 102], "concrete": [23, 37, 62, 65, 77, 82, 85, 93], "\u0438\u0437\u0443\u0447\u0435\u043d": [23, 93], "\u0433\u043b\u0443\u0431\u043e\u043a": [23, 37, 73], "\u0441\u043f\u0435\u043a\u0442\u0440": [23, 100, 102], "\u0434\u043e\u0433\u043c\u0430\u0442\u0438\u0447\u043d": 23, "\u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442": [23, 86], "\u043e\u0442\u043a\u0430\u0442": 23, "\u0443\u0442\u0440\u0430\u0447": 23, "\u0430\u0432\u0430\u0440\u0438\u0439\u043d": [23, 86], "\u043e\u0442\u043f\u0440\u0430\u0432\u043b": [23, 34], "\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442": [23, 82, 86, 92], "chris": [23, 34, 82], "richardson": [23, 34, 82], "\u043d\u0430\u0437\u044b\u0432\u0430": [23, 37, 41, 52, 70, 74, 75, 76, 80, 86, 93, 100], "\u043f\u043e\u0441\u0432\u044f\u0449\u0430": [23, 46, 83], "spreading": 23, "news": 23, "endpoints": 23, "solutions": [23, 34, 37, 38, 70, 82, 86], "gregor": [23, 34, 38, 39, 65, 66, 75, 76, 82, 88, 92], "hohpe": [23, 34, 38, 39, 65, 66, 75, 76, 82, 88, 92], "bobby": [23, 34, 82], "woolf": [23, 34, 82], "akka": [23, 30, 34, 82], "front": [23, 29, 37, 52, 65, 74, 76, 80], "sender": 23, "mining": 23, "\u0432\u043f\u0435\u0440\u0432": [23, 37, 75, 82], "acid": 23, "partitioned": [23, 86], "trading": [23, 38, 68, 70, 82], "dramatic": 23, "improvements": [23, 38], "acm": [23, 34], "ebay": 23, "architect": [23, 37, 38, 51, 74, 76, 82, 86], "dan": [23, 82, 88], "pritchett": 23, "2008": [23, 64, 88], "\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d": [23, 30, 34, 40, 41, 86], "\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b": [23, 34, 100], "\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432": [23, 42, 47, 70, 73, 83, 85, 86, 94], "\u043e\u0436\u0438\u0434\u0430": [23, 68, 70, 88], "causal": [23, 31, 34, 116], "arrive": [23, 34], "recognize": [23, 34, 37, 76, 86, 100], "causality": [23, 34], "wait": [23, 34, 65], "newly": [23, 34], "arrived": [23, 34], "latent": [23, 34], "superseded": [23, 34], "dismissible": [23, 34], "actors": [23, 34, 82], "prepared": [23, 34, 46, 73], "perfect": [23, 34, 77, 82], "timing": [23, 34], "reaction": [23, 34], "beforehand": [23, 34], "dealt": [23, 34, 38, 86], "gracefully": [23, 34], "routing": 23, "resequencer": [23, 34], "framework": [23, 34, 37, 38, 49, 51, 52, 64, 75, 82], "camel": [23, 34], "\u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440": 23, "nats": [23, 34, 82], "option": [23, 34, 38, 39, 70, 74], "sessions": [23, 34, 86], "guarantees": [23, 34, 38], "session": [23, 34, 74], "timestamps": [23, 34], "receiving": [23, 34], "rejects": [23, 34], "puts": [23, 34, 37, 74], "onto": [23, 34, 37, 86], "dominic": [23, 34, 82], "juli\u00e1n": [23, 34, 82], "dom\u00ednguez": [23, 34, 82], "grigori": [23, 34, 82], "melnik": [23, 34, 82], "fernando": [23, 34, 82], "simonazzi": [23, 34, 82], "mani": [23, 34, 82], "subramanian": [23, 34, 82], "\u043a\u043e\u043d\u043a\u0443\u0440\u0438\u0440": [23, 30, 33, 77, 118], "competing": [23, 34, 38, 77], "receivers": [23, 34], "redelivery": [23, 34], "guaranteed": [23, 34, 77, 85], "resend": [23, 34], "suppose": [23, 34, 70], "receives": [23, 34], "acknowledge": [23, 34, 37, 38, 76], "produced": [23, 34, 38, 49, 74], "sends": [23, 34], "kicks": [23, 34], "conclusion": [23, 34, 37, 70, 80, 86], "offer": [23, 34], "redeliver": [23, 34], "startup": [23, 34, 38, 46, 76], "durable": [23, 34], "stalled": [23, 34], "outstanding": [23, 34], "maxinflight": [23, 34], "resumes": [23, 34], "acking": [23, 34], "redelivered": [23, 34], "interleaved": [23, 34], "streaming": [23, 34], "187": [23, 34], "kozlovic": [23, 34], "combining": 23, "specialized": 23, "deriving": [23, 37], "capture": 23, "intensive": [23, 34, 37, 76, 82], "reliable": [23, 34, 82], "maintainable": [23, 34, 82], "kleppmann": [23, 34, 82], "\u043e\u0441\u0432\u0435\u0449\u0430": [23, 34, 40, 76, 83, 92], "reliability": [23, 34, 51, 73, 82], "operating": [23, 34, 82], "resilient": [23, 34, 37, 64, 76, 82], "laine": [23, 34, 82], "campbell": [23, 34, 82], "charity": [23, 34, 82], "majors": [23, 34, 82], "settle": [23, 30, 34], "stronger": [23, 30, 34, 38], "geo": [23, 30, 34], "replicated": [23, 30, 34], "storage": [23, 30, 34], "wyatt": [23, 30, 34], "lloyd": [23, 30, 34], "facebook": [23, 30, 34], "kaminsky": [23, 30, 34], "intel": [23, 30, 34], "labs": [23, 30, 34], "andersen": [23, 30, 34], "carnegie": [23, 30, 34], "mellon": [23, 30, 34], "bolt": [23, 30, 34], "peter": [23, 30, 34, 66, 82, 88], "bailis": [23, 30, 34], "ali": [23, 30, 34, 82], "ghodsi": [23, 30, 34], "joseph": [23, 30, 34], "hellerstein": [23, 30, 34], "ion": [23, 30, 34], "stoica": [23, 30, 34], "uc": [23, 30, 34], "berkeley": [23, 30, 34], "kth": [23, 30, 34], "royal": [23, 30, 34], "institute": [23, 30, 34, 37, 38, 52, 64, 82, 86], "detecting": [23, 34], "search": [23, 34, 51], "holy": [23, 34], "grail": [23, 34], "reinhard": [23, 34], "schwarz": [23, 34], "friedemann": [23, 34], "mattern": [23, 34], "sebastian": [23, 34], "burckhardt": [23, 34], "research": [23, 34, 38, 72, 85], "eventsourcing": [23, 34, 82], "bywater": [23, 34, 82], "vclock": [23, 34], "offers": [23, 86], "vector": [23, 34], "clock": [23, 34, 86], "clocks": 23, "recording": 23, "analyzing": [23, 62], "inherent": [23, 52, 74, 90], "partial": 23, "gustavo": [23, 34], "niemeyer": [23, 34], "info": [23, 82], "\u043e\u0431\u0437\u043e\u0440\u043d": [23, 82, 89], "guest": 23, "logs": 23, "byron": 23, "ruth": 23, "\u0443\u0432\u0438\u0434\u0435\u0442": [23, 56, 74, 85, 86], "\u0436\u0438\u0432": [23, 90], "\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a": 23, "\u0443\u043d\u0438\u0447\u0442\u043e\u0436": 23, "\u0438\u0437\u044a\u044f": [23, 86], "\u043a\u043e\u043c\u043d\u0430\u0442": [23, 100], "\u0437\u0430\u043d\u043e\u0437": 23, "\u043f\u0440\u0438\u043c\u0435\u043d": [23, 37, 72, 85], "\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430": [23, 74, 76], "\u0432\u0441\u0442\u0430\u0432\u043b": 23, "\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d": [23, 38, 51, 82, 83, 86, 88, 90, 93], "\u0436\u0438\u0437\u043d\u0435\u043d": [23, 64, 65, 74, 76, 82, 86], "\u0446\u0438\u043a\u043b": [23, 37, 41, 64, 65, 76, 82, 85, 86], "\u0443\u043c\u0435\u0441\u0442\u043d": [23, 34, 72, 85, 92, 94], "\u043f\u0435\u0440\u0435\u0445\u043e\u0434": [23, 34, 37, 46, 47, 74, 77, 85, 88, 95], "\u0437\u0430\u043c\u0435\u0442\u043d": [23, 88, 94, 100], "\u0432\u043b\u0430\u0434\u0435\u044e\u0449": [23, 86], "\u0441\u043a\u0440\u044b\u0442": [23, 29, 85], "domainobject": 23, "markremoved": 23, "registration": 23, "onus": 23, "removed": [23, 29, 52], "usual": [23, 38, 70, 74], "registers": 23, "setting": [23, 86], "dirty": [23, 74], "tedious": 23, "aspect": [23, 60, 73, 75, 76, 85, 90, 100], "nongenerated": 23, "turns": [23, 74], "suited": [23, 38], "examined": 23, "looked": [23, 70, 86], "inserted": 23, "finicking": 23, "feels": [23, 46, 47], "separates": [23, 38], "regular": 23, "cleanly": 23, "commonplace": 23, "expect": [23, 62, 73, 75, 86], "\u0432\u0441\u0442\u0430\u0432": 23, "\u043d\u0435\u043e\u0431\u0445\u043e\u0434": 23, "\u0430\u0432\u0442\u043e\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u043d": 23, "\u0432\u043b\u043e\u0436": 23, "\u043f\u0440\u0438\u0441\u0432\u043e": 23, "\u0441\u043d\u0430\u0431\u0434": 23, "istransient": 23, "\u043e\u0442\u043b\u043e\u0436\u0435\u043d": [23, 41], "\u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446": [23, 37, 70, 73, 74, 75, 77, 90, 93, 100], "\u0445\u043e\u0447": [23, 73], "\u0432\u043e\u0437\u044c\u043c": [23, 74, 92], "\u0444\u0440\u0430\u0437": [23, 37, 38, 40, 85, 86, 88, 100], "\u043f\u043e\u0441\u043b\u0443\u0436": 23, "\u043c\u043d": 23, "\u0432\u0437\u0430\u0438\u043c\u043e\u0441\u0432\u044f\u0437": [23, 86], "\u0441\u043e\u0441\u0442\u0430\u0432": [23, 38, 70, 75], "\u0432\u0441\u044f\u043a": [23, 75, 88, 92, 100], "\u0435\u0434": 23, "\u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d": [23, 38, 75, 86], "\u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432": [23, 34, 85], "\u043f\u0430\u043a\u0435\u0442\u043d": 23, "\u0438\u043c\u0435\u044e\u0449": [23, 34, 75, 100], "\u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d": [23, 38], "\u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d": [23, 37, 38, 41, 70, 75, 83, 85, 88, 90, 92], "clear": [23, 34, 37, 51, 70, 74, 76, 86, 100], "spoken": 23, "goes": [23, 37, 38, 41, 62, 74, 76, 82, 86, 95], "beyond": [23, 34, 49, 76, 82, 85, 86], "leaves": [23, 73, 85], "\u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u0434\u0448": 23, "\u043c\u0430\u0441\u0448\u0442\u0430\u0431": 23, "\u043f\u0440\u0435\u0434\u043f\u0440\u0438\u044f\u0442": [23, 100], "\u0434\u0430\u043b\u0435\u043a": [23, 82, 85, 86, 92], "\u043e\u0431\u043b\u0435\u0433\u0447\u0435\u043d": 23, "\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442": [23, 29, 75, 92], "\u0438\u0437\u0434\u0430\u0442\u0435\u043b": 23, "\u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442": [23, 30, 74], "\u0442\u0440\u0430\u043a\u0442\u043e\u0432\u043e\u043a": 23, "\u0442\u0440\u0430\u043a\u0442": 23, "\u0440\u0438\u0441": [23, 73, 86, 94, 100], "\u043f\u043b\u0430\u0441\u0442": 23, "\u043f\u0440\u0435\u0434\u0441\u0442\u043e": [23, 82, 88], "\u043f\u0435\u0440\u0435\u0440\u0430\u0431\u043e\u0442\u0430": [23, 47], "\u043f\u043e\u0441": 23, "\u0443\u0434\u0435\u043b\u044f": 23, "\u043e\u0441\u043e\u0437\u043d\u0430\u0432": 23, "footnotes": [23, 85], "v2": [23, 82], "mirror": [23, 82], "17": [23, 51, 66, 68, 70, 75, 82, 83, 85], "encapsulated": [23, 29, 82], "21": [23, 37, 70, 85], "uncovering": 23, "27": [23, 74, 75], "28": [23, 38, 74], "\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432": 26, "\u043a\u043e\u043f\u0438\u0440": 26, "\u043d\u0443\u0436\u0434\u0430": [26, 82, 86, 92], "\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446": 26, "\u043f\u043e\u0442\u0440\u0435\u0431": [26, 70, 85, 86], "\u0437\u0430\u043f\u0440\u0435\u0449\u0435\u043d": 26, "\u0437\u0430\u043c": [26, 102], "\u0443\u0433\u043e\u0434\u043d": [26, 38, 70, 85, 100], "\u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446": 26, "3\u043d\u0430\u0447\u0435\u043d": 26, "\u043f\u043e\u0432\u0440\u0435\u0436\u0434": 26, "\u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446": 26, "\u0438\u0441\u043a\u0430\u0436\u0435\u043d": [26, 38, 40, 88, 89, 92, 100], "pointer": 26, "against": [26, 42, 63, 68, 76, 85, 86], "safely": [26, 37, 74, 90], "except": [26, 52, 73, 85], "replacement": [26, 52, 86], "passes": [26, 34, 85, 86], "wandering": 26, "owner": [26, 38, 40, 51, 65, 80, 86], "corrupts": 26, "violating": [26, 75], "avoided": [26, 38, 46], "immutability": [27, 82, 114], "dddesign": 29, "adapter": 29, "acl": 29, "translator": 29, "translate": 29, "reshaped": 29, "hydrating": 29, "languages": [29, 37, 38, 51, 75, 82], "translating": [29, 38], "adapting": 29, "shapes": [29, 76], "duplicate": [29, 46, 82], "replicating": 29, "duplicating": 29, "bad": [29, 65, 74, 75, 76, 82, 85, 88, 94], "demonstrates": [29, 38, 85, 86], "challenges": [29, 38, 88], "pm": 29, "autonomy": [29, 86], "quality": [29, 37, 38, 40, 41, 42, 46, 51, 53, 64, 65, 66, 73, 74, 75, 82, 86], "collaboration": [29, 37, 49, 76, 85, 86], "saasovation": 29, "had": [29, 37, 38, 41, 70, 72, 73, 74, 76, 77, 85, 86, 94], "imperfect": 29, "continuous": [29, 37, 38, 51, 68, 74, 75, 76, 82, 85, 86, 94], "improvement": [29, 73, 75, 86], "matters": [29, 37, 38, 52, 73, 74, 76, 86], "deliver": [29, 37, 38, 52, 62, 73, 76, 77], "outcomes": [29, 37, 51], "choices": [29, 68], "clearer": [29, 85], "\u043e\u0442\u043b\u0438\u0447\u0438\u0442\u0435\u043b\u044c\u043d": [29, 82, 92, 100], "ports": 29, "port": 29, "\u043f\u043e\u0434\u0434\u0435\u043b\u0430": 29, "mediates": 29, "layers": [29, 76], "acting": [29, 75], "declaratively": 29, "submit": 29, "satisfaction": 29, "scenes": 29, "homepage": 29, "optimistic": 30, "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440": 30, "\u043e\u0431\u0441\u0442\u043e": [30, 75, 86], "\u043f\u043e\u043b\u043e\u0436\u0435\u043d": [30, 38, 56, 73, 74, 83, 86, 88, 92], "\u0436\u0443\u0440\u043d\u0430\u043b": 30, "\u0432\u0437\u0430\u0438\u043c\u043e\u0441\u0432\u044f\u0437\u0430": 30, "\u043f\u043e\u043c\u0435\u0447\u0430": 30, "correlationid": [30, 34], "\u043d\u0430\u0440\u0443\u0448\u0435\u043d": [30, 85], "\u043e\u0447\u0435\u0440\u0435\u0434\u043d": [30, 38, 85, 86], "\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d": [30, 34, 82], "\u043d\u0430\u043f\u0440\u0430\u0432\u043b": [30, 75], "\u043f\u0435\u0442\u043b": 30, "\u0442\u043e\u043f\u043e\u043b\u043e\u0433": [30, 83, 86], "\u043c\u0430\u0440\u0448\u0440\u0443\u0442": [30, 90], "\u043e\u0441\u0442\u0430\u0432\u043b\u044f": [30, 82, 85, 86], "\u0436\u0435\u043b\u0430": [30, 42, 46, 73, 77, 82, 86], "\u0441\u043f\u0430\u0441\u0430": 30, "\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430": 30, "\u0433\u0440\u0443\u0431": [30, 38, 86, 92], "\u043e\u0442\u0441\u044b\u043b\u0430": [30, 75, 85], "\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a": 30, "\u043a\u043e\u043c\u0438\u0442\u0435\u0442": 30, "\u0448\u043a\u043e\u043b\u044c\u043d": 30, "\u0440\u0430\u0441\u0441\u044b\u043b\u043a": 30, "e1": 30, "\u0440\u0430\u0437\u043e\u0441\u043b\u0430": 30, "\u0441\u0431\u043e\u0440": [30, 86], "\u0434\u0435\u043d\u0435\u0433": 30, "\u043f\u043e\u0434\u0430\u0440\u043e\u043a": 30, "e2": 30, "e3": 30, "\u0437\u0430\u0434\u0435\u0440\u0436\u0430": 30, "\u0432\u0435\u043a\u0442\u043e\u0440\u043d": 30, "\u0441\u043d\u0430\u0431\u0436\u0430": [30, 85], "\u043e\u0431\u043d\u0430\u0436\u0430": [30, 72], "\u0435\u0434\u0438\u043d\u043e\u0436\u0434": [30, 74], "\u043f\u043e\u0440\u044f\u0434\u043a\u043e\u0432": 30, "\u043d\u043e\u043c\u0435\u0440": [30, 34, 93], "\u043f\u043e\u043d\u0438\u0436\u0435\u043d": [30, 65], "sequential": [30, 34, 86], "\u0442\u0440\u0443\u0434\u043e\u0435\u043c\u043a": 30, "\u043c\u0438\u0433\u0440\u0430\u0446": 30, "\u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436": [30, 70, 72, 85, 88], "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430": 30, "\u043e\u0431\u0449\u0435\u043f\u0440\u0438\u043d\u044f\u0442": [30, 74], "agregate": 30, "\u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d": [30, 73, 74, 75, 90], "\u0443\u0441\u043b\u043e\u0436\u043d\u0435\u043d": [30, 70, 73, 77], "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u0446": 30, "\u0432\u044b\u0431\u043e\u0440\u043a": 30, "\u043e\u0431\u043d\u043e\u0432\u043b\u044f": 30, "\u0432\u044b\u0447\u0438\u0441\u043b\u044f": 30, "\u0441\u0434\u0432\u0438\u0433\u0430": 30, "\u0432\u044b\u043d\u0435\u0441\u0435\u043d": 30, "\u043d\u0435\u0438\u0437\u043c\u0435\u043d": [30, 38, 65, 85], "anticorruption": [31, 116], "sdlc": [32, 52, 65, 76, 80, 100, 117], "\u0441\u0430\u043c\u043e\u043e\u0431\u0443\u0447\u0435\u043d": [32, 83, 92, 93, 95, 117], "tdd": [32, 37, 72, 74, 76, 93, 94, 117], "topologies": [32, 76, 82, 86, 117], "\u043d\u0435\u043f\u0440\u043e\u0441\u0442": 34, "\u043d": [34, 38, 46, 74, 82, 83, 86, 88, 92], "\u043f\u043e\u043f\u0430\u0434\u0430": [34, 73], "\u043e\u0431\u043e\u0433\u043d\u0430": 34, "\u0438\u0437\u0434\u0435\u0440\u0436\u043a": [34, 86], "\u0441\u0431\u043e\u0440\u0449\u0438\u043a": 34, "\u043c\u0443\u0441\u043e\u0440": 34, "\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434": 34, "ack": 34, "round": [34, 86], "robin": 34, "\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a": [34, 73], "\u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d": 34, "jetstream": [34, 82], "rely": [34, 77, 85, 86], "slow": [34, 37, 38, 41, 47, 74, 76, 86], "\u043e\u0431\u0445\u043e\u0434\u043d": 34, "subject": [34, 51], "namespace": 34, "distribute": 34, "forethought": [34, 37, 76], "preserve": 34, "wildcard": 34, "subscriptions": 34, "giving": [34, 38, 85, 86, 93], "yourself": [34, 37, 47, 70, 73, 82, 85, 95], "room": [34, 37, 74, 76], "expand": 34, "telemetry": 34, "iot": 34, "devices": 34, "located": 34, "throughout": [34, 37, 52, 70, 74, 75, 76], "city": 34, "sensors": 34, "north": 34, "south": [34, 75], "east": 34, "west": [34, 38], "initially": [34, 38, 72], "grows": [34, 74, 75, 80], "exceed": [34, 64], "replace": [34, 52], "four": [34, 37, 38, 42, 74, 85, 86], "representing": [34, 85], "segment": [34, 86], "untouched": 34, "subscription": [34, 38, 46], "serially": 34, "concurrently": 34, "move": [34, 37, 62, 72, 73, 74, 76, 85], "picked": 34, "threads": 34, "\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446": [34, 86], "\u0437\u0430\u043f\u043e\u043c\u043d": [34, 38, 82, 85], "\u0441\u043e\u0446": 34, "\u0434\u0440\u0443\u0437": [34, 82], "\u0448\u043b\u0435\u0442": 34, "\u0434\u0438\u0441\u043a\u0440\u0435\u0434\u0438\u0442\u0438\u0440": 34, "\u043e\u0442\u043f\u0440\u0430\u0432\u043a": 34, "\u0445\u0440\u043e\u043d\u043e\u043b\u043e\u0433": 34, "\u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430": [34, 75], "\u043d\u0438\u0432\u0435\u043b\u0438\u0440\u043e\u0432\u0430": 34, "\u0441\u0438\u043c\u043f\u0442\u043e\u043c": [34, 100], "\u043f\u043e\u043e\u0447\u0435\u0440\u0435\u0434\u043d": 34, "\u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440": [34, 37, 40, 75, 81, 83, 92, 93, 95, 135], "lecture": [34, 82], "including": [34, 37, 52, 74, 76, 82], "exercises": [34, 82], "video": [34, 82], "dive": [34, 82], "alex": [34, 82], "petrov": [34, 82], "paradigms": [34, 82], "3d": [34, 37, 49, 51, 64, 66, 75, 76, 82, 86, 90], "andrew": [34, 82, 94], "tanenbaum": [34, 82], "maarten": [34, 82], "steen": [34, 82], "\u043a\u043e\u0441\u044f\u043a": [34, 82], "\u043c": [34, 37, 56, 73, 75, 76, 82, 83, 88, 92, 102], "\u0441\u043f\u0431": [34, 82, 88], "\u0438\u0442\u043c": [34, 82], "75": [34, 38, 73, 82], "155": [34, 82], "adam": [34, 82], "bellemare": 34, "deterministic": 34, "stream": 34, "fun": [34, 38, 47, 82], "profit": [34, 38, 82], "2013": [34, 38, 49, 82], "tyler": 34, "akidau": 34, "slava": 34, "chernyak": 34, "reuven": 34, "lax": 34, "watermarks": 34, "dataflow": 34, "correctness": 34, "massive": [34, 38, 46, 76], "unbounded": 34, "bradshaw": 34, "chambers": [34, 38], "rafael": 34, "fernandez": 34, "moctezuma": 34, "sam": [34, 77, 82, 86, 92], "mcveety": 34, "daniel": 34, "mills": [34, 86], "frances": 34, "perry": 34, "schmidt": [34, 82], "whittle": 34, "blocks": [34, 82], "\u043c\u0438\u0445\u0430": 34, "\u0442\u044e\u043b\u0435\u043d": 34, "mongodb": 34, "\u0442\u0435\u043e\u0440": [34, 75, 82, 86, 89, 102], "unmesh": 34, "joshi": [34, 86], "marc": 34, "graauw": 34, "apache": 34, "gerardo": 34, "villeda": 34, "claus": 34, "ibsen": 34, "jonathan": [34, 86], "anstey": 34, "vaughnvernon": 34, "reactivemessagingpatterns_actormodel": 34, "latest": [34, 38], "eips": 34, "camelinaction": 34, "camelinaction2": 34, "enterpriseintegrationpatterns": 34, "\u043a\u0430\u0442\u0430\u043b\u043e\u0433": 34, "jepsen": [34, 82], "\u0448\u043f\u0430\u0440\u0433\u0430\u043b\u043a": [34, 75, 82, 89], "eip": [34, 82], "prescriptive": [34, 82], "guidance": [34, 82], "homer": [34, 82], "sharp": [34, 82, 86], "larry": [34, 75, 82], "brader": [34, 82], "masashi": [34, 82], "narumoto": [34, 82], "trent": [34, 82], "swanson": [34, 82], "samples": [34, 82], "ms": 34, "corporation": [34, 82], "\u043f\u043e\u0434\u0440\u044f\u0434": 34, "carried": [34, 38], "martinfowler": 34, "articles": [34, 82], "201701": 34, "\u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430": 34, "\u043f\u0440\u043e\u043a\u0430\u0442\u044b\u0432\u0430": 34, "\u0443\u0445\u0443\u0434\u0448\u0430": [34, 73, 75, 100], "\u043a\u0430\u0441\u043a\u0430\u0434\u043d": [34, 65, 86], "\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d": [34, 92], "\u043f\u043e\u0441\u043b\u0435\u0434": [34, 40, 77, 90, 94], "m\u0435ssaging": 34, "router": 34, "\u0434\u043e\u0431\u0438\u0432\u0430": [34, 82, 83], "\u0443\u0437\u0435\u043b": 34, "\u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0446": 34, "rmpwam": 34, "cfm": 34, "2610533": 34, "papers": [34, 82], "bolton": 34, "sigmod2013": 34, "\u043f\u0430\u0440": [34, 40, 68, 74, 85, 86], "\u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434\u043d": [34, 37, 64, 66, 82], "\u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d": [34, 38, 74, 85, 92, 94], "\u0432\u0438\u0434\u0435\u043b": [34, 88, 90], "english": [34, 38, 75, 82, 92, 100], "kaushik": [34, 82], "sathupadi": [34, 82], "\u0442\u0440\u0435\u0442": [34, 46, 52, 85, 88, 94], "\u0445\u044c\u044e\u0438\u0442\u0442": 34, "\u043f\u0440\u043e\u0442": [34, 38, 68, 72, 76, 85, 88, 90], "\u0432\u043a\u043b\u044e\u0447\u0435\u043d": [34, 86, 100, 102], "\u043f\u0440\u0438\u0431\u044b\u0432\u0430": 34, "\u0430\u043a\u0442\u043e\u0440": 34, "\u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447": 34, "\u0432\u0445\u043e\u0434\u044f": [34, 75], "\u0441\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430": 34, "\u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430": 34, "\u043f\u043e\u0441\u0442\u0443\u043f\u0430": [34, 74], "fifo": 34, "m1": 34, "m2": 34, "\u0440\u0430\u043d\u044c\u0448": [34, 47, 64, 80], "p\u0430\u0437\u0434\u0435\u043b": 34, "\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d": 34, "\u0447\u0435\u0442\u0432\u0435\u0440\u0442": [34, 38], "\u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430": [34, 40, 85], "\u043f\u043e\u0441\u0442\u0443\u043f": [34, 83], "\u043f\u0440\u0435\u0434\u0448\u0435\u0441\u0442\u0432": [34, 37, 80, 86], "\u043e\u0441\u0442\u0430\u0432": [34, 37, 73, 76, 82], "\u0432\u044b\u044f\u0441\u043d\u0435\u043d": 34, "\u043f\u043e\u0442\u0440\u0430\u0442": [34, 38], "\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430": [34, 85], "\u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u044f": 34, "alexey": [34, 82, 89, 100], "zimarev": [34, 82, 100], "occasionally": 34, "connected": [34, 38], "\u0437\u0435\u0440\u043a\u0430\u043b\u044c\u043d": 34, "\u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0446": 34, "\u0433\u0430\u0440\u0430\u043d\u0442": [34, 88], "\u0431\u0443\u0444\u0435\u0440\u0438\u0437\u043e\u0432\u0430": 34, "\u043f\u043e\u0432\u0442\u043e\u0440\u043d": [34, 66, 70, 75], "\u043f\u0435\u0440\u0435\u0441\u044b\u043b\u0430": 34, "\u043f\u043e\u0432\u0440\u0435\u0436\u0434\u0435\u043d": 34, "generalizations": 34, "packets": 34, "internet": 34, "computing": [34, 73, 75, 82], "packet": 34, "paths": 34, "damaged": 34, "optimizations": [34, 73], "pipeline": [34, 82, 86], "designate": 34, "finished": [34, 38, 85], "mean": [34, 37, 38, 46, 51, 73, 75, 76, 85], "pipelined": 34, "tradeoff": [34, 38, 74], "computation": 34, "carl": [34, 76, 86], "hewitt": [34, 82], "mailboxes": 34, "\u0440\u0430\u0432\u043d": [34, 38, 40, 42, 70, 74, 85, 100, 102], "introduce": [34, 37, 74, 100], "third": [34, 46, 85, 86], "implied": [34, 38, 52], "individual": [34, 38, 51, 85, 86], "follow": [34, 62, 72, 73, 85, 86], "routes": 34, "likely": [34, 38, 52, 73, 74, 75, 76, 86, 90], "sooner": [34, 62, 74, 85], "resulting": [34, 38, 46, 52, 65, 70, 74, 76], "subsequent": [34, 59], "referential": 34, "integrity": [34, 86], "numbered": 34, "undergo": 34, "transformation": [34, 37, 82], "odd": 34, "output": [34, 38, 85, 86], "bringing": [34, 85], "acknowledgment": 34, "conservative": 34, "drawbacks": 34, "significantly": [34, 65, 74], "severely": 34, "underutilize": 34, "power": [34, 37, 38, 41, 74, 76, 88], "increase": [34, 37, 38, 74, 77, 86], "throttling": 34, "erase": 34, "ourselves": [34, 38], "amc": 34, "130": 34, "preserved": 34, "journal": [34, 88], "causally": 34, "node": 34, "\u0432\u0436\u0438\u0432": 34, "\u0441\u0442\u0440\u043e\u0433\u043e\u0441\u0442": 34, "\u043b\u0438\u043d\u0435\u0430\u0440\u0438\u0437\u0430\u0446": 34, "\u043f\u043e\u0432\u044b\u0448\u0435\u043d": [34, 37, 74, 85, 86, 92], "\u0432\u044b\u0441\u0442\u0443\u043f\u0430": [34, 37, 52, 88, 102], "position": 34, "\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a": 34, "\u0443\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044c\u043d": [34, 86], "\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0435\u043d": [34, 73], "\u043e\u0431\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u0441\u0442\u0432": [34, 38, 85, 92, 102], "relating": 34, "po": [34, 38], "purchase": 34, "price": [34, 39, 85], "addressed": [34, 38, 86], "outdated": 34, "prices": 34, "exempt": 34, "looser": 34, "realities": 34, "tightening": 34, "followed": 34, "\u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d": 34, "correlation": 34, "\u043c\u0435\u0442\u0430\u0434\u0430": 34, "causationid": 34, "misunderstood": 34, "causation": 34, "responding": [34, 37, 62], "conversation": [34, 52, 72], "cheers": 34, "discuss": [34, 86], "828": 34, "projections": [34, 38, 82], "putting": [34, 70, 74, 75, 82, 100], "\u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [36, 37, 38, 52, 56, 65, 70, 76, 80, 88, 95, 100, 120], "iterative": [37, 61, 64, 65, 75, 76, 77, 82, 86, 129], "frequent": [37, 38], "inspection": [37, 51, 76], "adaptation": [37, 38, 40, 52, 62, 64, 66, 68, 70, 74, 78, 80, 85, 86, 133], "incremental": [37, 38, 61, 62, 63, 64, 65, 70, 76, 85, 90, 129], "deliveries": 37, "evolve": [37, 52, 65], "cross": [37, 38, 76, 86], "teams": [37, 38, 46, 49, 51, 52, 64, 65, 74, 75, 76, 82, 88], "continual": 37, "feedback": [37, 38, 42, 51, 65, 68, 85, 86], "iso": [37, 38, 49, 52, 59, 60, 62, 63, 64, 65, 76, 77, 82], "iec": [37, 38, 49, 52, 59, 60, 62, 63, 64, 65, 76, 77, 82, 92], "ieee": [37, 38, 49, 52, 59, 60, 62, 63, 64, 65, 74, 76, 77, 82, 92], "12207": [37, 49, 52, 59, 60, 62, 63, 64, 65, 76, 82], "2017": [37, 38, 49, 52, 59, 60, 62, 63, 64, 65, 76, 82, 88], "reader": [37, 49], "supposedly": 37, "family": 37, "evolved": [37, 85], "born": 37, "belief": 37, "grounded": 37, "reality": [37, 77, 100], "innovation": [37, 38, 46, 86], "yield": 37, "jeff": [37, 38, 60, 62, 65, 82, 86], "sutherland": [37, 38, 65, 82, 86], "handbook": [37, 38, 52, 64, 65, 68, 73, 74, 82, 85, 86], "variety": [37, 76, 77], "evolutionary": [37, 38, 61, 65, 70, 74, 76, 82, 85, 129], "lifecycle": [37, 52, 64, 76, 86], "stages": [37, 59, 60, 76, 86, 92], "emphasis": [37, 65, 76, 100], "rapid": [37, 38, 65, 74, 76, 82, 85, 86], "unlike": [37, 52], "waterfall": [37, 52, 62, 65, 76, 80], "pieces": [37, 42, 70, 73, 74, 75, 77, 86, 90], "cycles": [37, 38, 77], "sprints": [37, 76, 86], "today": [37, 39, 65, 70, 74, 76, 85], "widely": [37, 38, 53], "forms": [37, 77, 85], "weeks": [37, 73, 74, 76], "winter": [37, 76], "getaway": [37, 76], "turned": [37, 52, 76], "upside": [37, 76], "caroline": [37, 76], "mimbs": [37, 76], "nyce": [37, 76], "contrasts": 37, "styles": [37, 76, 82, 85], "prediction": [37, 65, 68, 70, 78, 86, 133], "\u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442": [37, 38, 39, 41, 46, 64, 65, 70, 72, 73, 75, 80, 83, 86], "\u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u043d": [37, 65, 80], "\u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d": [37, 86], "\u043e\u0431\u0440\u0430\u0442\u043d": [37, 38, 40, 74, 76], "\u044d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d": [37, 38, 40, 41, 80], "\u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430": [37, 75, 86], "\u043b\u043e\u0433\u0430\u0440\u0438\u0444\u043c\u0438\u0447\u0435\u0441\u043a": [37, 80], "\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0447\u0435\u0441\u043a": [37, 38, 40, 64, 65, 66, 75, 76, 80, 86], "\u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d": [37, 65, 80, 85], "\u0433\u0440\u0430\u0444\u0438\u043a": [37, 40, 46, 56, 65, 76, 80, 82, 83, 86, 94], "\u0432\u044b\u0447\u0435\u0442": 37, "\u043f\u0440\u0435\u0432\u044b\u0441": [37, 86], "\u0432\u044b\u043d\u0443\u0436\u0434": [37, 100], "\u043d\u0430\u0438\u043c\u0435\u043d\u044c\u0448": [37, 38, 56, 75, 90, 100], "catch": [37, 74, 86], "\u0441\u043e\u0433\u043b\u0430\u0441\u043d": [37, 85, 102], "\u0437\u0430\u043a\u043e\u043d": [37, 38, 72, 73, 74, 76, 82, 88, 89, 92, 94], "\u0434\u0438\u0430\u043b\u0435\u043a\u0442\u0438\u043a": [37, 100], "\u043f\u0440\u0438\u0432\u0435\u0441\u0442": [37, 38, 56, 72, 75, 86, 100], "\u0441\u0438\u043d\u0442\u0435\u0437": [37, 100], "\u0441\u0445\u043e\u0436": [37, 74], "\u0431\u0440\u0443\u043a\u0441": [37, 38, 56, 65, 72, 92, 100], "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0438\u0432": [37, 73, 75, 92], "\u043d\u0435\u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d": [37, 38, 75, 88, 89], "\u043e\u0442\u0441\u0442\u0443\u043f\u0430": 37, "\u0438\u0442\u0435\u0440\u0430\u0446": [37, 60, 62, 65, 77, 86, 90], "\u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d": [37, 38, 72, 85, 100], "\u044d\u0432\u043e\u043b\u044e\u0446": [37, 38, 68, 85, 86, 92], "\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d": [37, 38, 40, 52, 62, 64, 65, 75, 76, 77, 80], "\u043a\u0440\u0430\u0442\u043a": [37, 38, 40, 46, 64, 67, 68, 70, 74, 75, 82, 102, 130], "brief": [37, 82], "pdsa": 37, "\u0438\u0437\u0432\u0435\u0441\u0442": [37, 75, 85, 88, 90], "1930": 37, "1957": [37, 60, 62, 90], "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [37, 65, 88], "1968": [37, 38], "\u0443\u0434\u0435\u0448\u0435\u0432\u043b\u0435\u043d": [37, 72, 76], "\u0434\u043e\u043b\u0433": [37, 38, 40, 41, 85, 92], "\u043d\u0435\u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d": 37, "\u0431\u044b\u0441\u0442\u0440\u043e\u0440\u0430\u0441\u0442\u0443\u0449": 37, "\u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440": [37, 40, 41, 64, 65, 70, 75, 80, 82, 83, 86, 100, 102], "\u043f\u0440\u0438\u0431\u043b\u0438\u0436\u044e\u0449": 37, "\u0437\u0430\u0431\u043b\u0430\u0433\u043e\u0432\u0440\u0435\u043c\u0435\u043d": [37, 65, 68, 75, 76, 80], "bduf": [37, 40, 65, 75, 76], "empirical": [37, 80], "observation": [37, 74, 80], "years": [37, 38, 65, 73, 74, 76, 80, 82, 86, 92], "ago": [37, 62, 74, 76, 80], "ref": [37, 80], "barryboehm": [37, 80], "economics": [37, 66, 70, 80], "prentice": [37, 80], "hall": [37, 80], "1981": [37, 80], "rises": [37, 80], "exponentially": [37, 74, 80], "phases": [37, 65, 80], "expensive": [37, 70, 74, 76, 77, 80], "water": [37, 80], "fall": [37, 38, 80], "rising": 37, "kent": [37, 38, 41, 42, 46, 47, 52, 64, 65, 66, 68, 70, 72, 75, 76, 82, 83, 85, 86, 88, 92, 93, 94, 95], "\u043a\u043e\u043d\u0446": [37, 76, 82, 85, 88], "1990": [37, 76, 88], "\u0445": [37, 38, 74, 76], "2000": [37, 74, 75, 76, 85], "\u043e\u0431\u0440\u0435\u043b": [37, 76], "\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430": [37, 77, 85, 86, 93, 100], "rom": [37, 76], "posa": [37, 76], "ooad": [37, 76], "solid": [37, 70, 71, 76, 77, 132], "refactoring": [37, 38, 41, 45, 47, 66, 70, 72, 73, 74, 75, 76, 77, 82, 85, 93, 95, 123], "\u0443\u043d\u0438\u0444\u0438\u043a\u0430\u0446": [37, 72], "\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [37, 40], "\u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 37, "\u0441\u043e\u043a\u0440\u0430\u0442": [37, 74, 86, 92, 93], "\u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0442\u0438\u0432\u043d": [37, 83, 86, 100, 102], "\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a": [37, 38, 41, 43, 46, 68, 70, 72, 74, 75, 81, 85, 86, 88, 90, 92, 93, 94, 95, 135], "\u043f\u043e\u0440\u043e\u0433": [37, 72, 85, 86], "\u0432\u0445\u043e\u0436\u0434\u0435\u043d": [37, 72], "\u0441\u043c\u044f\u0433\u0447": 37, "\u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d": [37, 38, 56, 72, 75], "\u0432\u043e\u0437\u0434\u0435\u0439\u0441\u0442\u0432": [37, 42, 88, 90, 93], "exploration": 37, "popular": [37, 38, 51, 52, 64, 65, 66, 76, 82, 85], "kenneth": [37, 38, 51, 52, 64, 65, 66, 76, 82], "rubin": [37, 38, 51, 52, 64, 65, 66, 76, 82], "\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435\u043d": 37, "\u0430\u0434\u0430\u043f\u0442\u0430\u0446": [37, 56, 75, 76, 85, 86], "\u043f\u043e\u043b\u043e\u0433": [37, 40, 75, 76, 83], "\u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d": [37, 38, 65, 75, 76], "\u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d": [37, 65, 75, 76, 90], "\u0430\u0441\u0438\u043c\u043f\u0442\u043e\u0442": [37, 65, 75], "\u0437\u0430\u0432\u0438\u0441\u0435\u043b": [37, 76], "\u043e\u0442\u043a\u043b\u0430\u0434\u044b\u0432\u0430": [37, 40, 68, 76], "\u043d\u0430\u0438\u0431\u043e\u043b\u044c\u0448": [37, 38, 47, 68, 76, 94, 100], "\u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d": [37, 68, 76, 85, 88, 92], "\u043f\u0440\u043e\u0434\u0443\u043a\u0442": [37, 38, 42, 65, 76, 86, 100], "paid": 37, "whatnot": 37, "got": [37, 74, 85, 86], "somewhere": [37, 70, 76], "rise": [37, 75, 85], "overtime": 37, "rose": 37, "slowly": [37, 47], "reaching": 37, "asymptote": 37, "tomorrow": [37, 38, 70], "draws": 37, "dramatically": [37, 85], "\u0430\u0441\u0438\u043c\u0442\u043e\u0442": [37, 76], "284": 37, "\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a": [37, 64, 93], "\u0432\u044b\u0441\u0448": 37, "\u0432\u044b\u0433\u043e\u0434\u0441\u043a": [37, 82], "\u0430\u0432": 37, "\u043b\u0438\u043d": [37, 73, 92, 94], "l": [37, 62, 65, 75, 82, 85, 88], "\u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d": 37, "\u043c\u043a": 37, "\u0447\u0435\u0440\u0442": [37, 38, 73], "297": 37, "\u043d\u0443\u043b": 37, "\u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d": [37, 75, 76, 86, 94, 100], "\u043e\u0441": 37, "\u0430\u0431\u0441\u0446\u0438\u0441\u0441": 37, "\u0440\u0430\u0437\u044b\u0441\u043a\u0430\u043d": 37, "\u0438\u0449": 37, "lim": 37, "\u0432\u043f\u0440\u0430\u0432": 37, "299": 37, "\u0444\u0438\u043b\u043e\u0441\u043e\u0432\u0441\u043a": 37, "\u043d\u0430\u043f\u0440\u044f\u0436\u0435\u043d": [37, 41, 70, 73, 77, 83, 88], "\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u0435\u043b": [37, 38, 39, 40, 41, 100], "\u043c\u043e\u0440\u0430\u043b\u044c\u043d": [37, 94, 95], "\u043a\u043b\u0438\u043c\u0430\u0442": [37, 94], "\u043c\u044f\u0433\u043a": [37, 38, 75], "ultimately": [37, 76], "mushroomed": [37, 76], "pair": [37, 56, 76, 85], "taken": [37, 76], "developer": [37, 38, 46, 49, 52, 53, 76, 82, 85, 86], "freed": [37, 76], "baggage": [37, 73, 76], "dilbertesque": [37, 76], "corporations": [37, 76], "early": [37, 38, 41, 46, 51, 52, 63, 65, 76, 77, 80, 85], "he": [37, 38, 51, 73, 74, 76, 82, 85, 86, 92, 95], "estimated": [37, 38, 76], "effort": [37, 38, 46, 49, 51, 70, 74, 75, 76, 86, 100], "his": [37, 38, 73, 74, 76, 82, 83, 85, 86, 92, 94, 95], "reassigned": [37, 76], "programmer": [37, 38, 72, 73, 74, 75, 76, 82, 85, 86, 92, 94, 95], "beginning": [37, 52, 76, 85, 86], "twelve": [37, 74, 76, 86], "felt": [37, 76], "terrible": [37, 76], "boss": [37, 41, 76], "harangued": [37, 76], "somewhat": [37, 76, 77, 86], "despondent": [37, 76], "realized": [37, 76], "estimate": [37, 70, 76, 80], "accurate": [37, 49, 76, 100], "indeed": [37, 38, 49, 62, 65, 74, 75, 76, 85, 86], "standard": [37, 52, 64, 82, 86], "fixed": [37, 38, 73, 76, 85], "mindset": [37, 62, 65, 76], "frequently": [37, 38, 46, 49, 51, 62, 65, 75, 76, 86], "plagues": [37, 76], "industry": [37, 39, 51, 74, 76, 82, 85, 95], "marketing": [37, 38, 76, 100], "impose": [37, 73, 74, 76], "irrational": [37, 76], "demands": [37, 76, 86], "imposition": [37, 76], "corporate": [37, 76, 82], "organizations": [37, 38, 76, 86], "economy": [37, 76], "aggressively": [37, 76], "era": [37, 76], "companies": [37, 38, 76], "dilbert": [37, 76], "manifestations": [37, 76], "arcane": [37, 76], "policies": [37, 75, 76], "freedom": [37, 76], "inanities": [37, 76], "attracts": [37, 76], "proponents": [37, 76, 85], "methodologies": [37, 64, 76], "scares": [37, 76], "begeebers": [37, 76], "shit": [37, 76], "professional": [37, 38, 52, 64, 73, 74, 76, 82, 85, 95], "paper": [37, 76, 85, 94], "traditionalists": [37, 76], "scare": [37, 76], "bureaucrats": [37, 76], "happy": [37, 68, 76], "pushing": [37, 38, 75, 76], "timely": [37, 64, 76, 86], "tangible": [37, 76], "promised": [37, 76], "places": [37, 70, 76, 100], "hide": [37, 73, 76, 85, 86], "movement": [37, 76, 85], "methodology": [37, 62, 65, 76, 82, 86], "restore": [37, 76], "credibility": [37, 76], "balance": [37, 38, 76, 77, 86], "embrace": [37, 73, 76], "diagram": [37, 38, 51, 76, 100], "dusty": [37, 76], "tomes": [37, 76], "plan": [37, 38, 60, 62, 76, 86, 90], "limits": [37, 38, 74, 76, 86, 90], "turbulent": [37, 76], "brand": [37, 76], "xp": [37, 42, 46, 47, 52, 65, 66, 68, 70, 73, 76, 82, 85, 86], "hackers": [37, 76], "ignorant": [37, 76], "hacker": [37, 76], "manifesto": [37, 38, 62, 65, 73, 75, 76], "helped": [37, 86], "rethink": 37, "priorities": [37, 38], "humanize": 37, "dave": [37, 76, 85], "\u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a": 37, "rights": [37, 38], "\u0442\u0440\u0443\u0434": [37, 56, 68, 83, 86, 88, 92], "\u043f\u0441\u0438\u0445\u043e\u043b\u043e\u0433": [37, 38, 75, 82, 83, 85, 88, 94], "\u044d\u0440\u0443\u0434\u0438\u0440\u043e\u0432\u0430\u043d": 37, "\u0444\u0438\u043b\u043e\u0441\u043e\u0444": [37, 56, 92, 102], "\u043c\u0435\u043d\u0435\u0434\u0436\u043c\u0435\u043d\u0442": [37, 40, 83, 86, 95], "overall": [37, 51, 70, 76, 77, 86], "progress": [37, 41, 47, 74, 86, 94], "proven": [37, 86], "repeatable": [37, 72, 85], "tests": [37, 38, 45, 46, 49, 51, 52, 66, 70, 73, 74, 82, 85, 86, 123], "substitute": 37, "functionality": [37, 38, 46, 47, 49, 51, 52, 60, 63, 74, 77, 82, 85], "paying": [37, 41, 85], "exorbitant": 37, "schedule": [37, 38, 46, 60, 74, 86], "reduce": [37, 38, 73, 74, 76, 82, 85, 90], "cancel": 37, "reflecting": [37, 38], "declarations": 37, "priority": [37, 38, 51], "ask": [37, 38, 70, 74, 85, 86, 88], "peers": 37, "managers": [37, 38, 80], "estimates": [37, 38, 60, 65, 73], "responsibilities": [37, 38], "assigned": [37, 86], "snowbird": [37, 38], "meeting": [37, 38, 51], "heal": [37, 38], "divide": [37, 38, 60, 86, 90], "ward": [37, 38, 41, 65, 74, 82, 85], "cunningham": [37, 38, 41, 65, 74, 82, 85], "ron": [37, 38, 85], "jeffries": [37, 38, 85], "basics": [37, 38, 82], "\u0437\u0430\u0449\u0438\u0442\u043d": 37, "\u0441\u043f\u0440\u043e\u0432\u043e\u0446\u0438\u0440\u043e\u0432\u0430": [37, 92], "\u0441\u0442\u0440\u0430\u0445": [37, 38, 83], "declaration": [37, 76], "independence": [37, 76, 86], "risky": [37, 38], "fears": [37, 38], "develop": [37, 38, 41, 49, 51, 65, 73, 74, 77, 82, 86, 92], "effectively": [37, 38, 66, 70, 74, 82, 86], "laws": [37, 38, 72, 74, 88], "governments": [37, 38], "taxes": [37, 38], "fear": [37, 38, 85], "liberty": 37, "pursuit": [37, 73], "happiness": 37, "secure": [37, 82], "instituted": [37, 38, 73], "men": [37, 86], "powers": 37, "consent": 37, "governed": 37, "profundity": 37, "distract": [37, 38], "afraid": [37, 85, 88], "losing": 37, "token": [37, 41], "asked": [37, 74, 76], "pay": [37, 41, 85], "little": [37, 38, 49, 65, 73, 74, 75, 76, 82, 85, 86, 88, 95], "surrender": 37, "career": [37, 74, 83], "techies": 37, "meaningful": [37, 75], "plans": [37, 49, 62, 65, 76], "fairy": 37, "tales": 37, "told": 37, "stupid": [37, 73], "falling": 37, "technically": [37, 38, 85], "authority": [37, 38], "definitions": [37, 51, 70, 82], "sacrifice": 37, "deadlines": [37, 74], "nestled": 37, "white": [37, 82], "capped": 37, "mountains": 37, "ski": 37, "resort": 37, "group": [37, 38, 46, 74, 75, 82, 86, 88], "rebels": 37, "gathered": [37, 38], "2001": [37, 92], "\u043c\u0435\u0442\u043a": [37, 70], "\u0432\u044b\u0440\u0430\u0436": [37, 40, 77, 86], "\u043a\u0435\u043d\u0442": [37, 82, 85], "\u0431\u0435\u043a": [37, 82, 85], "continued": 37, "beauty": [37, 75], "maintenance": [37, 38, 49, 73, 74, 86, 100], "europe": [37, 100], "youtu": 37, "ybytgii151g": 37, "9808": 37, "\u0442\u0430\u043b\u0430\u043d\u0442": [37, 73, 83], "\u043a\u0440\u0438\u0441\u0442\u0430\u043b\u043b\u0438\u0437\u0430\u0446": [37, 83, 91, 95, 138], "\u043f\u0440\u0435\u0432\u0440\u0430\u0442": [37, 38, 75, 83, 88, 91, 95, 138], "\u043d\u0435\u043e\u0431\u044b\u0447\u0430\u0439\u043d": 37, "c\u043f\u0438\u0441\u043e\u043a": 37, "\u043e\u0448\u0435\u043b\u043e\u043c\u043b\u044f": 37, "\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442": [37, 75], "curve": [37, 65, 74, 75, 82], "fix": [37, 38, 46, 47, 73, 74, 85], "ironic": 37, "ad": [37, 74], "hoc": [37, 74], "phase": [37, 52, 65, 72, 76, 85], "exponentiation": 37, "exponential": [37, 65], "conveys": 37, "planned": [37, 62, 76, 77], "mistakes": [37, 76, 86], "assumption": [37, 38, 85], "flatten": 37, "flattening": 37, "enabled": [37, 49], "exploited": 37, "exploit": 37, "flattened": 37, "controversy": 37, "criticize": 37, "exploitation": 37, "enabling": [37, 38, 86], "criticisms": 37, "stem": 37, "critics": 37, "exploiting": 37, "burned": 37, "dead": [37, 60, 62, 66, 72, 73, 74, 85, 90, 94], "\u043f\u0440\u0435\u0434\u043f\u043e\u0441\u044b\u043b\u043e\u043a": 37, "\u0445\u0440": [37, 38, 42, 46, 47, 68, 70, 85], "\u043f\u0440\u0435\u0434\u043f\u043e\u0441\u044b\u043b\u043a": 37, "\u0432\u043d\u0435\u0441\u0435\u043d": [37, 70], "\u0440\u0430\u0441\u0442\u0435\u0442": [37, 86, 95], "\u043c\u0435\u0434\u043b\u0435\u043d": [37, 47, 89], "\u0441\u0440\u043e\u043a": [37, 38, 46, 70, 86], "\u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a": [37, 73, 74, 86, 90], "\u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430": [37, 41, 83, 85, 88], "\u043e\u0442\u043b\u043e\u0436": [37, 40], "\u0437\u0430\u0432\u0442\u0440": [37, 38, 41, 70], "\u0440\u0430\u0437\u0432\u0435\u044e\u0442": 37, "\u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0443\u0442": 37, "\u043e\u0431\u043e\u0439\u0434\u0435\u0442": [37, 70], "\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u044c\u043a": 37, "\u0441\u0443\u043c\u043c": [37, 41, 65], "\u0441\u043e\u0439\u0434\u0435\u0442": 37, "\u043f\u044b\u0442": [37, 82], "\u043f\u0440\u0435\u0434\u0443\u0433\u0430\u0434\u0430": 37, "\u0434\u0435\u0448\u0435\u0432": 37, "\u0440\u0438\u0441\u043a\u043d\u0443\u0442": 37, "premises": 37, "act": [37, 76], "differently": [37, 38, 41, 51, 70, 74, 76, 85], "defer": [37, 38, 39, 51], "greatest": [37, 38, 74], "hopes": [37, 74], "anticipate": [37, 49, 76], "simplified": [37, 86], "steep": 37, "ruinously": 37, "crazy": [37, 73], "charge": [37, 38], "ahead": [37, 70], "careful": [37, 73], "cheap": [37, 38, 65, 85, 86, 94], "reduced": [37, 38, 46, 73, 74, 85, 86, 90], "outweighs": 37, "\u043f\u0440\u043e\u0438\u0437\u043d\u0435\u0441": 37, "\u0432\u0441\u0442\u0440\u0435\u0447": [37, 75], "\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u043d": 37, "\u0447\u0430\u0441\u0442\u043d": [37, 92, 100], "engineers": [37, 38, 65, 73, 86], "growth": 37, "economies": 37, "kick": 37, "wildly": 37, "incorrect": [37, 38], "attention": [37, 47, 72, 74, 85], "excellence": [37, 74], "enhances": [37, 38, 74], "agility": [37, 49, 51, 64, 66, 74, 82, 86], "nature": [37, 38, 73, 76, 86], "facilitate": [37, 38, 49, 76], "efficient": [37, 38, 72, 73, 76, 85], "comparison": [37, 76], "managed": [37, 38, 39, 64, 76, 86], "continuum": [37, 76], "seek": [37, 76], "total": [37, 41, 76, 85, 86], "rework": [37, 74, 76], "points": [37, 38, 42, 74, 75, 76, 82, 86], "baselining": [37, 76], "traced": [37, 76], "welcome": 37, "harness": [37, 38], "competitive": [37, 74], "agreed": 37, "captured": [37, 51, 76], "adaptiveness": 37, "oh": [37, 74], "finalist": 37, "adaptive": [37, 62, 65, 76], "predictive": [37, 62, 65, 76], "\u0432\u044b\u0441\u043a\u0430\u0437\u044b\u0432\u0430": 37, "primarily": [37, 76, 86], "dominant": [37, 38], "90s": [37, 74], "00s": 37, "became": [37, 85, 86], "noughties": 37, "catalyst": 37, "\u0441\u043e\u0441\u0442\u043e": [37, 38, 46, 72, 85, 86, 100, 102], "\u0437\u0430\u0431\u044b\u0432\u0430": [37, 38, 85], "\u0440\u044b\u043d\u043a": [37, 38, 39, 76, 83, 92], "\u043d\u0435\u0442\u0440\u0443\u0434\u043d": 37, "\u043d\u0435\u0434\u0430\u043b\u0435\u043a": 37, "\u0443\u0440\u043e\u0431\u043e\u0440\u043e\u0441": [37, 74, 75], "2015": [37, 38, 52, 64, 82, 88], "keynote": [37, 66, 74, 76, 86], "adopt": [37, 51, 65, 86], "consistently": 37, "velocity": [37, 38, 76, 83], "debt": [37, 38, 39, 43, 46, 65, 66, 70, 74, 86, 121], "accumulated": [37, 92], "starts": [37, 74, 77], "grind": [37, 38], "halt": [37, 38], "far": [37, 38, 65, 74, 76, 85, 86, 100], "stuck": [37, 74], "clue": 37, "bernstein": 37, "\u0443\u0437\u043d\u0430": [37, 38, 70, 75, 77, 86, 88, 94], "ken": [37, 38, 52, 76, 86], "schwaber": [37, 38, 52, 76, 86], "\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d": [37, 73], "\u0431\u0440\u0430\u0442": [37, 68], "\u0443\u0441\u043a\u043e\u0440": 37, "\u0441\u0442\u0440\u0430\u0434\u0430": [37, 38, 83], "\u043f\u043e\u0441\u0442\u043e\u044f": [37, 38, 68, 72, 74, 82, 85, 88], "\u0442\u0435\u043c\u043f": [37, 38, 70, 72, 74, 86], "did": [37, 38, 41, 60, 62, 72, 74, 85, 86, 90], "convinced": 37, "him": [37, 86], "spread": 37, "downside": [37, 70], "suffer": [37, 74], "lack": [37, 86], "sustainable": [37, 82], "trenches": [37, 38, 82], "henrik": [37, 38, 82, 86], "kniberg": [37, 38, 82, 86], "\u0440\u0435\u0434\u0430\u043a\u0446": [37, 38, 41, 46, 56, 60, 73, 74, 77, 90, 92], "\u0430\u043b\u0435\u043a\u0441\u0435": [37, 38], "\u043a\u0440\u0438\u0432\u0438\u0446\u043a": [37, 38], "2004": [37, 56, 82, 92], "\u0433": [37, 82, 90, 92, 102], "\u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433": [37, 82, 92], "\u043f\u043e\u0437\u0432\u043e\u043b\u044c\u0442": [37, 72, 85], "education": [37, 52, 64, 73, 82], "skimp": 37, "productivity": [37, 38, 46, 74, 86], "responsiveness": 37, "stranding": 37, "fluency": 37, "stress": [37, 38, 74, 85], "worry": [37, 85], "reworking": [37, 38, 74, 85], "reducing": [37, 72, 74, 82, 85], "manageable": [37, 77], "levels": [37, 38, 65, 74, 75, 76, 77, 85], "prohibitive": 37, "usage": [37, 74], "disaster": [37, 74], "aggregation": [37, 74, 90], "harder": [37, 68, 70, 74, 76], "argue": [37, 74], "leads": [37, 38, 62, 74, 77, 85], "deteriorates": [37, 74], "ability": [37, 38, 65, 74, 75, 86], "entropy": [37, 74], "worse": [37, 70, 73, 74, 86], "bugs": [37, 38, 73, 74, 85], "breed": [37, 74], "kill": [37, 74], "nightmare": [37, 74], "poorly": [37, 38, 74], "\u0443\u0434\u0430\u0447\u043d": [37, 64, 73], "\u0432\u044b\u0441\u043a\u0430\u0437\u0430": 37, "grady": [37, 64, 75, 76, 82, 90], "booch": [37, 64, 75, 76, 82, 90], "provided": [37, 49, 76], "imply": [37, 38, 76], "duties": [37, 38, 76], "claims": [37, 38, 46, 74, 76, 86], "loosely": [37, 76], "composed": [37, 72, 74, 75, 76, 100], "reasoned": [37, 76], "wiggle": [37, 76], "refactorings": [37, 38, 46, 76, 82, 85], "ruining": [37, 76], "grow": [37, 47, 73, 76, 80], "incrementally": [37, 76, 77, 86], "matures": [37, 76], "decomposability": [37, 76], "concerns": [37, 38, 51, 74, 76, 85, 86, 90], "near": [37, 38, 74, 76], "modifiability": [37, 38, 40, 64, 66, 75, 76], "tactics": [37, 76], "self": [37, 38, 40, 76, 86, 88], "evident": [37, 76], "cutting": [37, 38, 76, 86], "obvious": [37, 38, 51, 65, 74, 76, 85], "communicated": [37, 51, 76], "defended": [37, 76], "whatever": [37, 38, 73, 76, 85], "socialize": [37, 76], "len": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "bass": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "paul": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "clements": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "rick": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "kazman": [37, 38, 49, 51, 64, 66, 75, 76, 77, 82, 86, 90], "witness": 37, "pitfalls": [37, 82], "trap": 37, "firsthand": 37, "nokia": 37, "noticed": [37, 72, 85], "digital": [37, 49, 82], "trained": [37, 38, 86], "onboarded": 37, "proxy": [37, 38], "efforts": [37, 41, 65, 77], "address": [37, 38, 46], "company": [37, 38, 76], "adapt": [37, 65, 75, 76, 85], "market": [37, 38, 39, 65, 74, 86], "spite": 37, "appeared": 37, "realize": [37, 38, 52, 74, 85], "watched": 37, "frustration": [37, 38, 70], "lost": [37, 86], "heroic": 37, "colleagues": [37, 86], "attained": 37, "upstream": [37, 86], "downstream": [37, 77], "deployed": [37, 38, 75], "slowing": 37, "narrow": [37, 100], "minded": [37, 73], "fast": [37, 38, 51, 65, 73, 74, 76, 82, 86], "iteration": [37, 38, 49, 51, 52, 62, 65, 72, 76, 77, 86], "delivering": [37, 38, 62, 65, 82], "elegant": [37, 38, 73, 85], "home": [37, 38, 74, 86, 96], "hindered": 37, "learn": [37, 38, 41, 62, 65, 73, 75, 82, 85], "inability": 37, "factor": [37, 38, 74, 76, 85, 86], "downfall": [37, 65], "survive": [37, 38], "thrive": [37, 76], "disruption": 37, "mik": 37, "kersten": 37, "c\u043c": [37, 76, 77], "\u043f\u0440\u0435\u043e\u0431\u043b\u0430\u0434\u0430\u043d": 37, "\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u043a": [37, 38, 40, 46, 67, 68, 70, 72, 74, 75, 130], "\u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0440\u043e\u0447\u043d": [38, 40, 46, 73, 74, 85, 90], "\u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d": [38, 40, 46], "\u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d": [38, 83, 92], "\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442": [38, 72, 77, 82, 83, 88, 91, 94, 100, 138], "\u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d": [38, 56, 76, 82, 83, 85, 88, 92, 102], "\u043e\u0431\u0449\u0435\u0441\u0442\u0432": 38, "\u043f\u043e\u0434\u043a\u0440\u0435\u043f\u043b\u0435\u043d": 38, "\u043c\u0438\u0444": [38, 85, 100], "\u0440\u0438\u0442\u0443\u0430\u043b": [38, 75], "\u043d\u0430\u043a\u0430\u0437\u0430\u043d": 38, "\u043d\u0430\u0433\u0440\u0430\u0434": 38, "\u0443\u0432\u0430\u0436\u0435\u043d": [38, 42, 83], "\u043d\u0443\u0436\u0434": 38, "\u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446": [38, 68, 82, 100, 102], "simplicity": [38, 71, 74, 76, 90, 132], "\u0445\u0440\u0430\u0431\u0440\u043e\u0441\u0442": 38, "courage": 38, "goals": [38, 46, 51, 86], "conflict": [38, 76, 85], "social": [38, 75, 82, 85, 86, 88], "societies": 38, "developing": [38, 65, 72, 74, 76, 82, 86, 100], "sets": 38, "backed": 38, "rituals": [38, 75], "punishments": 38, "rewards": 38, "humans": [38, 65, 74, 90], "\u0441\u043f\u0443\u0441\u0442": [38, 70], "\u0443\u043f\u043e\u043c\u0438\u043d\u0443\u0432": 38, "puzzled": 38, "wild": 38, "heavily": [38, 75, 82], "tilted": 38, "towards": [38, 82], "geek": 38, "balanced": 38, "revenue": [38, 70], "struggle": 38, "personalities": 38, "sighted": 38, "visionary": 38, "thinking": [38, 40, 41, 62, 66, 72, 74, 76, 82, 85, 94], "economic": [38, 66, 74], "greed": 38, "wonder": [38, 70], "refactor": [38, 46, 47, 51, 70, 85], "tension": 38, "advancing": 38, "pressures": 38, "manufacturing": 38, "irregularities": 38, "evils": 38, "distractions": 38, "lie": [38, 80, 82], "sprint": [38, 51, 86], "stuff": [38, 74, 85], "smooth": 38, "postpone": [38, 68], "resolving": 38, "fixing": [38, 39, 73], "believe": [38, 86], "benefit": [38, 52, 74, 80, 86, 90], "worth": [38, 46, 66, 70, 74, 76, 85], "displace": 38, "generating": [38, 70, 82], "mcconnell": [38, 41, 60, 62, 65, 75, 76, 77, 82, 83, 86, 90, 95], "mcc96": 38, "stumbling": 38, "arounds": 38, "drag": 38, "impediments": 38, "steve": [38, 41, 60, 62, 75, 77, 82, 83, 86, 90, 95], "studies": 38, "38": [38, 82], "42": 38, "1996": [38, 74, 90], "august": [38, 82], "spirit": [38, 73], "game": [38, 68], "coplie": 38, "81": [38, 74, 90], "whack": 38, "mole": 38, "amongst": [38, 65], "perception": [38, 74], "sold": 38, "wasted": [38, 49], "occupying": 38, "months": [38, 46, 62, 65, 70, 74, 75, 82, 86, 95], "refactored": [38, 85], "shiny": 38, "sell": [38, 39, 46], "continue": [38, 74], "employ": 38, "aspects": [38, 70, 100], "firstly": 38, "justify": [38, 74], "secondly": 38, "justifying": [38, 46, 74], "ongoing": [38, 42, 46, 73], "\u0447\u0435\u0442\u044b\u0440\u0435\u0445": [38, 83, 86, 89], "\u0438\u043d\u043e\u0433\u0434": [38, 40, 41, 68, 70, 73, 74, 77, 83, 85, 90, 93], "\u0432\u0441\u0442\u0440\u0435\u0442": [38, 53], "iron": [38, 65], "triangle": [38, 65], "\u0442\u0440\u0435\u043c": 38, "barnes": 38, "phd": 38, "sketched": 38, "corners": 38, "began": [38, 73], "\u0442\u043e\u0436\u0434\u0435\u0441\u0442\u0432\u0435\u043d": 38, "\u0441\u043e\u0441\u0442\u0430\u0432\u043d": 38, "\u0437\u0430\u0440": [38, 92], "\u043d\u0435\u043b\u0438\u043d\u0435\u0439\u043d": 38, "\u043a\u0432\u0430\u0434\u0440\u0430\u0442": 38, "diamond": 38, "duncan": 38, "haughey": 38, "\u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a": [38, 65], "\u043e\u0441\u043d\u043e\u0432\u043e\u043f\u043e\u043b\u0430\u0433\u0430": 38, "\u0442\u0435\u0445\u043d\u0430\u0440": 38, "\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440": [38, 85], "\u0431\u0438\u0437\u043d\u0435\u0441\u043c": 38, "\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d": [38, 72, 83, 85, 93, 100], "\u0432\u043b\u0430\u0441\u0442": 38, "modes": 38, "suffers": 38, "splitting": [38, 76], "frederick": [38, 65, 82, 86], "brooks": [38, 65, 82, 86, 94], "\u0431\u0435\u0441\u0442\u0441\u0435\u043b\u043b\u0435\u0440": 38, "\u043c\u0438\u0444\u0438\u0447\u0435\u0441\u043a": [38, 65], "\u043c\u0435\u0441\u044f\u0446": [38, 40, 46, 65, 74, 86], "\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446": 38, "\u043e\u0442\u0434\u0435\u043b": 38, "\u043d\u0435\u0434\u043e\u0440\u043e\u0433": 38, "\u0441\u0434\u0435\u0440\u0436\u0430": 38, "\u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0442\u0435\u043b\u044c\u0441\u043a": 38, "\u044d\u043d\u0442\u0443\u0437\u0438\u0430\u0437\u043c": [38, 83], "discipline": [38, 64, 73, 76, 82, 86], "bounds": 38, "inventive": 38, "enthusiasm": 38, "mythical": [38, 65, 82, 86], "man": [38, 65, 75, 82, 86], "essays": [38, 65, 82, 86], "anniversary": [38, 65, 82, 86], "jr": [38, 65, 82, 86], "\u0447\u0440\u0435\u0437\u043c\u0435\u0440\u043d": 38, "\u0431\u0435\u043b": [38, 85], "\u0432\u043e\u0440\u043e\u0442\u043d\u0438\u0447\u043a": 38, "\u043f\u043e\u0434\u0433\u043e\u043d\u044f": [38, 46], "\u0441\u0443\u043f\u0435\u0440\u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d": 38, "\u043f\u043e\u043f\u0440\u043e\u0431\u0443": [38, 86], "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d": 38, "\u043f\u043e\u043b\u043d\u043e\u043c\u043e\u0447": [38, 40, 51, 86, 88], "\u043f\u0440\u0438\u043a\u043b\u0430\u0434\u044b\u0432\u0430": 38, "\u0433\u0435\u043d\u0435\u0440\u0438\u0440": [38, 85], "\u043e\u0442\u0434\u0430\u0447": [38, 42], "suits": [38, 76], "technologies": 38, "interesting": [38, 74, 76, 85, 86], "edge": 38, "haven": [38, 74, 75], "scenario": [38, 49, 52], "risks": [38, 47, 65, 70], "strains": 38, "cover": [38, 86], "release": [38, 49, 51, 65, 73, 74, 75, 82, 85, 86], "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442": [38, 40, 68, 74, 85, 86, 90, 93], "\u0441\u0435\u0440\u0434\u0446": 38, "\u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d": [38, 47, 86], "\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430": 38, "\u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442": [38, 93, 94], "\u0440\u0430\u0431\u043e\u0442\u043d\u0438\u043a": [38, 86], "\u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a": [38, 70, 74, 85], "\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d": 38, "\u043d\u0430\u0434\u043e\u0431\u043d": [38, 47], "programmers": [38, 68, 72, 73, 74, 75, 82, 85, 86, 90], "headed": 38, "roles": [38, 86], "\u043f\u043e\u0434\u0441\u043a\u0430\u0437\u0430": 38, "\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432": [38, 82, 90], "\u0440\u0435\u043c\u0435\u0441\u043b": 38, "\u043f\u043e\u0434\u0432\u043e\u0434": 38, "\u043c\u043d\u0435\u043d": [38, 51, 56, 72, 74, 75, 85, 94], "\u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d": [38, 82, 86, 95, 102], "\u0430\u0444\u043e\u0440\u0438\u0437\u043c": 38, "\u0445\u0443\u0434\u043e\u0436\u043d\u0438\u043a": [38, 73], "\u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430": [38, 52], "\u0443\u0436\u0430\u0441\u043d": 38, "\u0441\u0442\u0440\u043e\u0435\u043d": 38, "\u0431\u044e\u0434\u0436\u0435\u0442": 38, "\u0432\u0435\u043b\u0438\u043a": [38, 70, 83, 86, 100], "\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d": [38, 75], "\u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a": [38, 72, 73, 85, 86], "\u0430\u043a\u0442\u0438\u0432\u043d": [38, 56, 75, 76, 80, 85, 86, 92], "\u0431\u0430\u0445": 38, "\u0435\u0434\u0432": [38, 102], "\u0435\u0436\u0435\u043d\u0435\u0434\u0435\u043b\u044c\u043d": 38, "\u0438\u0437\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430": 38, "\u043a\u0430\u043d\u0442\u0430\u0442": 38, "\u0443\u0432\u0435\u0440": [38, 47, 74, 85], "\u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440": 38, "stretch": 38, "\u0436\u0435\u0441\u0442\u043a": [38, 85], "\u043d\u0430\u043b\u043e\u0436\u0435\u043d": 38, "360": [38, 86], "\u043f\u0440\u0438\u043d\u0435\u0441\u043b": 38, "\u0443\u0441\u0438\u043b\u0438\u0432\u0430": [38, 56, 92], "\u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b": 38, "\u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u0432\u0430": 38, "\u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0442\u0435\u043b\u044c\u043d": 38, "\u0431\u044c\u0435\u0442": 38, "\u043e\u0431\u0434\u0443\u043c\u044b\u0432\u0430\u043d": [38, 85], "arts": [38, 86], "crafts": 38, "art": [38, 73, 82, 86], "artist": 38, "aphorism": 38, "liberating": 38, "worst": [38, 76], "buildings": 38, "budget": [38, 62], "purposes": [38, 73], "served": [38, 51], "bach": 38, "creative": [38, 86], "hardly": 38, "squelched": 38, "necessity": 38, "cantata": 38, "constrained": [38, 51], "constraints": [38, 51, 52, 65, 76, 86], "imposed": [38, 76, 86], "beneficial": [38, 77], "similarly": [38, 85], "observe": 38, "provision": 38, "cramps": 38, "focus": [38, 49, 51, 73, 74, 85, 86, 90, 100], "inventions": 38, "unconstrained": 38, "thought": [38, 65, 72, 74, 76, 85, 86], "debate": 38, "shrift": 38, "englebart": 38, "augmenting": 38, "intellect": 38, "afips": 38, "conference": [38, 74, 76], "proceedings": [38, 74], "joint": 38, "san": [38, 74], "francisco": [38, 74], "dec": 38, "pp": 38, "395": 38, "410": 38, "resume": 38, "\u0431\u0435\u0437\u043e\u0431\u043e\u0441\u043d\u043e\u0432\u0430": 38, "\u043f\u0435\u0440\u0435\u0443\u0441\u043b\u043e\u0436\u043d\u044f": 38, "\u043e\u0442\u043c\u0435\u0442\u043a": [38, 85], "\u0443\u0449\u0435\u043c\u043b": 38, "\u0437\u0430\u0433\u043d\u0438\u0432\u0430": 38, "\u0434\u0435\u0433\u0440\u0430\u0434\u0438\u0440": 38, "\u0434\u0438\u043a\u0442\u043e\u0432\u0430": 38, "\u0442\u044b": [38, 56, 83, 92], "\u0442\u0435\u0431": 38, "\u0434\u0430\u0434\u0443\u0442": 38, "\u0440\u0430\u0431\u043e\u0447": [38, 40, 86, 100], "\u0441\u0442\u0430\u043d\u0446": 38, "\u043d\u0430\u0438\u0432\u044b\u0441\u0448": 38, "\u0441\u043a\u043e\u0442\u0438\u043d": 38, "\u043b\u0435\u043d\u0438\u0432": 38, "\u043f\u0440\u0435\u0434\u043f\u0438\u0441\u044b\u0432\u0430": 38, "\u0432\u043e\u0437\u0440\u0430\u0437": 38, "\u043f\u0440\u0438\u043d\u0443\u0434": 38, "\u043f\u043e\u043d\u0443\u0440": 38, "\u0433\u043e\u043b\u043e\u0432": [38, 82, 85, 94], "\u043d\u0435\u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c": [38, 82], "\u043f\u043e\u0441\u0442\u0430\u0432": [38, 86, 92], "\u043f\u0440\u0438\u0440\u043e\u0434": [38, 74], "\u043e\u0431\u0434\u0443\u043c\u044b\u0432\u0430": [38, 72, 85], "\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440": 38, "\u043e\u0441\u043c\u044b\u0441\u043b\u0438\u0432\u0430": 38, "\u043e\u043a\u0430\u0437\u044b\u0432\u0430": [38, 40, 72, 74, 75, 77, 80, 82, 85, 86, 88, 95, 102], "\u0440\u0438\u0441\u043a\u043e\u0432\u0430": 38, "feel": [38, 42, 46, 47, 65, 83, 85], "fit": [38, 65, 72, 74, 76, 85, 86, 100], "dictate": 38, "workstations": 38, "highest": [38, 49, 74, 90], "trouble": [38, 69, 70, 74, 76, 86, 131], "buster": [38, 89], "specifies": 38, "dutifully": 38, "heads": [38, 74, 100], "entail": 38, "poorest": 38, "somehow": 38, "riskier": [38, 51], "\u0432\u0430\u0439\u043d\u0431\u0435\u0440\u0433": 38, "\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440": [38, 40, 46], "\u043f\u043e\u0441\u0442\u0440\u0430\u0434\u0430": [38, 74], "weinberg": [38, 82], "gone": [38, 86], "awry": 38, "combined": [38, 75], "found": [38, 62, 65, 74, 82, 86, 90], "58": 38, "essence": [38, 65, 85, 94], "\u0438\u0441\u0442\u043e\u0440": [38, 64, 73, 75, 83, 88], "\u043d\u0435\u0443\u0434\u0430\u0447\u043d": [38, 82, 83], "\u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0437\u0438\u0440\u043e\u0432\u0430": 38, "backlog": [38, 51, 86], "\u0442\u0435\u043f\u043b": 38, "\u043d\u0435\u0441\u043e\u043c\u043d\u0435\u043d": 38, "\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446": [38, 76, 86], "\u0448\u0442\u0443\u043a": [38, 85], "\u0441\u043f\u0435\u0440\u0432": [38, 82], "\u0440\u0435\u0430\u043b\u0438\u0437\u0443": [38, 65, 70, 72, 85], "\u043a\u043e": [38, 70, 72, 77, 83, 85], "\u043f\u0440\u0438\u0431\u044b\u043b\u044c\u043d": 38, "\u043f\u0440\u0438\u043a\u0440\u0443\u0442": 38, "\u043a\u043e\u043d\u0444\u0435\u0442\u043a": 38, "\u043e\u043a": 38, "\u043a\u043e\u043c\u043f\u0435\u0442\u0435\u043d\u0442": 38, "\u0438\u0434\u0442": [38, 74], "experimented": 38, "stories": [38, 49, 51, 52, 53, 73, 77, 82, 85, 86], "tried": [38, 65], "treating": 38, "prioritized": [38, 62, 86], "apples": [38, 76], "oranges": 38, "yeah": 38, "guys": 38, "driving": 38, "shall": [38, 76], "candy": 38, "concluded": 38, "qualified": 38, "notice": [38, 46, 68], "groups": [38, 74, 77], "tackle": [38, 41, 60, 82, 90], "plenty": [38, 41, 85], "conflicting": 38, "negotiating": [38, 82], "relies": 38, "ensures": [38, 74, 100], "\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430": [38, 74, 75, 85, 86], "\u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0430": [38, 72], "\u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432": [38, 46, 72, 74, 77, 90], "\u0432\u0441\u0435\u043e\u0431\u0449": 38, "\u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430": 38, "\u043e\u0431\u0440\u0435\u0447": [38, 42], "\u043f\u0440\u043e\u0432\u0430": 38, "tricky": 38, "expound": 38, "pressure": 38, "mounts": 38, "discarded": [38, 62], "doomed": [38, 42, 76], "darkness": 38, "\u0432\u0437\u0430\u0438\u043c\u043e\u043a\u043e\u043c\u043f\u0435\u043d\u0441\u0438\u0440\u043e\u0432\u0430": 38, "\u043f\u0435\u0440\u0435\u043a\u043e\u0441": 38, "evolvability": [38, 40], "flexibility": [38, 40, 60, 70], "modularity": [38, 40, 74], "testabilty": [38, 40], "deployability": [38, 40], "\u0441\u0442\u0435\u0439\u043a\u0445\u043e\u043b\u0434\u0435\u0440": [38, 40, 51, 86], "\u0430\u043d\u0430\u043b\u0438\u0437": [38, 72, 76, 82, 85, 86, 100, 102], "identified": [38, 51, 86], "established": [38, 51], "consensus": 38, "stakeholders": [38, 39, 49, 51, 66, 75, 77, 80, 82], "medium": 38, "intended": [38, 49, 59, 60, 65, 100], "candidates": 38, "regarding": [38, 65], "alternatives": 38, "prioritization": 38, "facilitates": 38, "basis": [38, 86], "negotiation": 38, "allocation": 38, "requiring": [38, 51, 86], "mutually": [38, 77], "incompatible": 38, "desired": 38, "consult": 38, "reach": [38, 74, 85], "contractual": 38, "traceable": 38, "resolution": [38, 65], "subcategory": 38, "29148": [38, 52, 64, 65, 77, 82], "analyze": [38, 49], "\u0437\u0440\u0435\u043b": [38, 82, 83], "\u0441\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430": [38, 40], "4th": [38, 64, 77, 82, 86], "\u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430": [38, 76, 86], "\u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d": [38, 76, 86], "evaluation": [38, 70, 82], "lae": 38, "mini": 38, "qaw": [38, 51], "42030": [38, 82], "\u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d": [38, 102], "\u0440\u0430\u0437\u043e\u0431\u0440\u0430": 38, "\u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d": 38, "\u043d\u0435\u0438\u0437\u0431\u0435\u0436\u043d": [38, 92], "\u043a\u043e\u0440\u0440\u0435\u043b\u0438\u0440": 38, "\u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430": 38, "\u043f\u0440\u043e\u0442\u0438\u0432\u043d": [38, 41, 47], "\u0432\u043f\u043e\u043b\u043d": [38, 72, 77, 83, 85, 88], "\u043f\u0435\u0440\u0435\u0440\u0430\u0441\u0442": 38, "\u043d\u0435\u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d": 38, "\u043c\u0435\u0436\u043b\u0438\u0447\u043d\u043e\u0441\u0442\u043d": 38, "\u043f\u043e\u0442\u0435\u0440": [38, 56, 85], "\u043a\u0430\u0434\u0440": [38, 56], "\u0445\u0443\u0434\u0448": [38, 83], "\u043f\u043e\u043c\u0435\u0441\u0442": [38, 100], "\u043a\u043e\u043c\u043f\u0435\u0442\u0435\u043d\u0446": [38, 56], "\u043e\u0434\u043d\u043e\u0441\u0442\u043e\u0440\u043e\u043d": 38, "unilaterally": 38, "decide": [38, 41, 51, 65, 68, 72, 75, 85], "\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c": 38, "\u0438\u0433\u0440": [38, 40], "\u0442\u0440\u0435\u0445": [38, 46, 86], "\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440": 38, "\u043f\u043e\u043b\u0430\u0433\u0430": [38, 40, 85, 92], "\u0437\u0430\u0434\u0430\u043d": [38, 74, 86, 90], "\u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d": [38, 86, 94, 100], "\u0447\u0438\u0441\u043b\u0435\u043d": [38, 76, 86, 88], "\u043e\u0431\u0449\u0435\u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d": 38, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434": [38, 86, 92], "\u043d\u0435\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d": 38, "\u0443\u0441\u043f\u0435\u0432": 38, "\u0441\u0434\u0430\u0442": 38, "\u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d": [38, 100], "\u043d\u0435\u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c": 38, "\u0432\u0445\u043e\u0434\u043d": [38, 65], "played": [38, 74], "resultant": 38, "fourth": [38, 86], "exactly": [38, 51, 73, 75, 76, 100], "standards": [38, 42, 49, 51, 74, 92], "crappy": 38, "everyone": [38, 65, 73, 82, 88, 95], "inputs": [38, 85], "\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d": [38, 92], "\u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442": [38, 41, 85], "\u0431\u043e\u0440\u043e\u043b": 38, "slower": [38, 72, 85], "demanding": [38, 76], "lowering": 38, "biggest": [38, 74], "surprises": [38, 63], "measured": [38, 74], "defects": [38, 73, 74, 77, 85], "desirable": [38, 51, 76], "effectiveness": [38, 86], "apparent": [38, 86], "purely": [38, 72, 85, 93, 100], "proud": 38, "talking": [38, 74, 75, 85], "mediocre": [38, 86], "weekends": 38, "fancy": [38, 85], "ironwork": 38, "blacksmith": 38, "met": [38, 51], "controlling": 38, "chooses": 38, "steering": 38, "precisely": [38, 65], "advance": 38, "lever": 38, "weekly": [38, 82], "quarterly": 38, "choosing": [38, 88], "concern": [38, 60, 86, 90], "excuse": 38, "inaction": 38, "finish": 38, "evolution": [38, 59, 68, 85, 86], "solving": [38, 60, 62, 72, 85, 90, 100], "demonstration": 38, "efficiently": [38, 85], "safe": [38, 47, 49, 51, 52, 64, 65, 74, 76, 82, 83, 88, 90], "annotated": 38, "bibliography": 38, "reading": [38, 74, 76, 82, 85, 90, 94, 95], "adds": [38, 70, 76, 100], "richness": 38, "suggestions": [38, 86], "jane": [38, 77], "wood": 38, "denise": 38, "silver": [38, 86], "wiley": [38, 76], "sons": 38, "1995": 38, "isbn": [38, 82], "0471042994": 38, "jad": 38, "facilitators": 38, "directing": 38, "fade": [38, 46], "away": [38, 51, 73, 74, 85, 86], "document": [38, 49, 51, 52, 64, 76, 77], "facilitated": 38, "professionals": [38, 46, 73, 74], "neutral": 38, "hostile": 38, "atmosphere": 38, "specially": 38, "unbiased": 38, "facilitator": 38, "political": 38, "stake": 38, "stay": [38, 74], "psychologically": 38, "players": 38, "guardian": 38, "deliverables": [38, 64], "achieved": [38, 73, 74, 75, 86, 90], "leader": [38, 82], "ties": 38, "department": [38, 100], "training": [38, 52, 64, 74, 82, 86], "facilitation": 38, "attached": 38, "jennerich": 38, "\u0441\u0433\u043b\u0430\u0436\u0438\u0432\u0430\u043d": 38, "payoff": [38, 40, 66, 70, 75], "yagni": [38, 40, 46, 49, 66, 68, 69, 74, 75, 76, 85, 131], "\u043f\u0435\u0440\u0435\u0448\u0435\u043b": 38, "\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440": 38, "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0442\u043e\u0440": [38, 75], "profound": 38, "cut": [38, 76, 86], "ruin": 38, "reputations": 38, "ethics": 38, "dean": [38, 49, 51, 52, 64, 65, 82, 86], "leffingwell": [38, 49, 51, 52, 64, 65, 82, 86], "\u0432\u043e\u0437\u043b\u0430\u0433\u0430": [38, 75, 88], "vision": [38, 52, 64, 76, 86], "representative": [38, 86, 100], "challenge": [38, 73, 75, 86], "expectations": [38, 64, 86], "merge": [38, 73, 94], "diverse": 38, "voices": 38, "facilitating": 38, "leading": [38, 49, 51, 64, 74, 82, 86, 88, 90], "mix": [38, 85, 86], "programs": [38, 51, 52, 64, 65, 72, 73, 74, 82, 85, 90], "\u043d\u0435\u0439\u0442\u0440\u0430\u043b\u0438\u0442\u0435\u0442": 38, "\u0441\u0444\u0435\u0440": [38, 102], "\u0444\u0438\u043d\u0430\u043d\u0441\u043e\u0432": [38, 70, 90, 92], "\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d": [38, 52, 53, 86], "maximizing": [38, 73], "\u043f\u043e\u043b\u0438\u0441\u0435\u043c\u0430\u043d\u0442\u0438\u0447\u0435\u0441\u043a": 38, "\u0433\u0430\u0439\u0434": [38, 51, 75], "master": [38, 82, 89], "\u0432\u0435\u0441\u044c\u043c": [38, 70, 73, 74, 75, 92, 102], "\u043c\u0435\u043d\u044f": [38, 47, 74, 85, 88], "funding": 38, "maximizes": [38, 76, 86], "roi": [38, 82], "accountable": [38, 86], "measure": [38, 46, 62, 64, 74, 75], "twice": [38, 74], "half": [38, 74, 85], "jeffrey": [38, 82], "deciding": [38, 39, 65], "continually": [38, 41, 73], "prioritizing": [38, 86], "refining": [38, 62, 80], "loss": [38, 82], "assuming": [38, 85], "lowest": [38, 74, 75], "continuously": [38, 85, 86], "\u0448\u0438\u0440": [38, 94], "evidence": [38, 49], "organization": [38, 75, 76, 85, 86, 88, 100], "\u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f": [38, 70, 75, 80, 85, 92, 102], "innovate": 38, "hire": 38, "oversee": 38, "pressing": 38, "agendas": 38, "slows": [38, 74], "profitability": 38, "questions": [38, 72, 88], "awkward": 38, "organizationally": 38, "incentive": 38, "positive": [38, 42, 85], "\u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430": [38, 83], "\u043b\u0438\u0446": [38, 83, 86], "\u043f\u0440\u0435\u0434\u0432\u0437": 38, "\u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e\u0432\u0430": [38, 40], "2011": [38, 46, 52, 82, 88, 92], "\u043d\u0430\u0432\u044f\u0437\u044b\u0432\u0430": 38, "\u043e\u0441\u0442\u0430\u0432\u043b": [38, 47], "\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d": [38, 49], "xp1": 38, "organizing": [38, 51, 82, 86], "increments": [38, 60, 63], "releasable": 38, "\u0432\u044b\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043d": [38, 86, 102], "\u043f\u0443\u0442\u0430\u043d\u0438\u0446": 38, "led": [38, 86], "dev": 38, "objective": 38, "accountabilities": 38, "sm": 38, "guides": 38, "xp2": 38, "decrease": [38, 74, 86], "\u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d": [38, 89], "deviate": 38, "unacceptable": 38, "materials": [38, 86], "adjusted": 38, "adjustment": 38, "deviation": 38, "\u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0434": 38, "\u0434\u0438\u0441\u0431\u0430\u043b\u0430\u043d\u0441": [38, 40, 72], "empowered": [38, 40, 65], "transparency": 38, "regression": [38, 51, 85], "meet": [38, 59, 65, 74, 75], "reminded": 38, "review": [38, 49, 51, 57, 74, 82, 86, 88, 90, 100, 127], "viewing": 38, "presume": 38, "written": [38, 47, 49, 62, 72, 85, 100], "tested": [38, 47, 49, 86], "demonstrate": [38, 73, 82], "viewer": 38, "\u0443\u0441\u0442\u0440\u0430\u043d\u0435\u043d": [38, 83, 86, 88], "\u0446\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 38, "\u0438\u043d\u0441\u043f\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u043c": 38, "entireorganization": 38, "respect": [38, 42, 74, 85], "inspectable": 38, "increment": [38, 51], "\u0438\u043d\u0441\u043f\u0435\u043a\u0442\u0438\u0440": 38, "inspect": 38, "adjust": 38, "\u043c\u0430\u043b\u0435\u043d\u044c\u043a": [38, 86, 95], "\u0437\u0430\u0447": [38, 75, 92], "1993": [38, 65], "leadership": [38, 82, 88], "figuring": 38, "plotted": 38, "figured": 38, "daily": [38, 74, 86], "stand": [38, 47, 70], "400": [38, 74], "percent": [38, 74, 85, 95], "admittedly": 38, "qualities": 38, "inspiration": 38, "came": [38, 85], "toyota": 38, "chief": [38, 86], "engineer": [38, 85], "corolla": 38, "camry": 38, "draw": [38, 76], "talents": 38, "specializing": 38, "chassis": 38, "electrical": [38, 49, 82], "capable": 38, "car": 38, "thinks": [38, 76, 85], "legendary": [38, 85, 94], "shusas": 38, "leaders": [38, 82, 85, 86], "reports": [38, 73, 74], "report": [38, 74, 86], "anyone": [38, 62, 73, 74, 88, 90], "appraisals": 38, "promotions": 38, "persuasion": 38, "coercion": 38, "wanted": [38, 86], "embody": 38, "shook": 38, "quoting": 38, "marine": 38, "corps": 38, "rooted": 38, "organizational": [38, 49, 86, 88], "evil": 38, "misunderstanding": 38, "rampant": 38, "consciousness": 38, "remarkable": 38, "february": 38, "2009": [38, 73, 83, 86, 102], "vietnam": 38, "agreeing": 38, "servant": 38, "persuade": 38, "cajole": 38, "thirty": 38, "fill": 38, "skill": [38, 73, 85], "days": [38, 74, 76, 85], "knew": [38, 70, 73, 86], "deeply": [38, 85], "buying": [38, 39], "thoughts": [38, 72, 85], "valued": 38, "\u043d\u0435\u043f\u043e\u043d\u0438\u043c\u0430\u043d": [38, 70, 83], "\u043d\u0430\u0434\u043b\u0435\u0436\u0430": [38, 41], "\u0441\u043d\u0438\u043c\u0430": [38, 86, 95], "\u043f\u043e\u043b\u0430\u0433": [38, 83], "\u0434\u0435\u043b\u0435\u0433\u0438\u0440": 38, "\u0443\u0432": [38, 56], "\u043f\u0430\u0434\u0435\u043d": [38, 40, 86], "\u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0430": 38, "\u043f\u0435\u0440\u0435\u043b\u043e\u0436": 38, "\u0432\u0438\u043d": 38, "\u043a\u0430\u0434\u0440\u043e\u0432": 38, "\u0442\u0440\u0435\u0437\u0432": 38, "\u043d\u0435\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [38, 40, 51, 53], "nfr": [38, 51], "\u043f\u0440\u043e\u044f\u0432\u043b\u0435\u043d": [38, 73, 92, 94], "\u043b\u043e\u0432\u0443\u0448\u043a": [38, 40], "\u0438\u0441\u043f\u0440\u0430\u0432": [38, 46, 47, 92], "\u0432\u044b\u0433\u043e\u0434\u043d": [38, 68, 70, 92], "\u0441\u043c\u043e\u0442\u0440\u0435\u0442": 38, "\u0432\u0435\u043b\u0438\u0447\u0438\u043d": [38, 41, 47, 86, 93], "\u043f\u0430\u0434\u0430": [38, 40, 83], "\u0441\u043a\u043e\u0440\u043e\u0441\u0442": [38, 40, 72, 74, 82, 85, 86, 95, 100], "shoup": 38, "vp": [38, 74], "stitch": [38, 74, 75], "\u043e\u0442\u043b\u0438\u0447\u0430": [38, 40, 52, 70, 76, 85, 86, 92, 94], "\u0432\u043e\u0441\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d": 38, "\u0434\u043e\u0440\u043e\u0436": [38, 65, 70], "\u0441\u0433\u043b\u0430\u0434": [38, 40], "\u043f\u043e\u0434\u043c\u0435\u043d": 38, "\u043d\u0435\u0432\u0435\u0440\u043d": [38, 83], "\u043f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430": [38, 74], "\u0443\u0433\u043e\u0434": 38, "\u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u043e\u0432\u0430": [38, 76], "\u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440": [38, 75], "\u0436\u0435\u0440\u0442\u0432\u0443": [38, 70], "insights": [38, 77, 92], "stephany": 38, "bellomo": 38, "ian": [38, 82], "gorton": 38, "september": [38, 74], "october": [38, 46], "32": [38, 72, 85, 94], "45": [38, 74, 85], "longer": [38, 41, 62, 74, 75, 76, 85], "hit": [38, 73], "wall": [38, 82], "cumulative": [38, 74], "unplanned": [38, 77], "unreliable": 38, "consequently": [38, 85], "renewed": 38, "31": 38, "considerable": [38, 86], "relatively": [38, 65], "emerged": 38, "allocating": [38, 77], "iterations": [38, 51, 62, 65, 76, 77, 86], "checklists": 38, "retrospectives": 38, "major": [38, 49, 51, 65, 73, 86], "foundation": [38, 62, 65, 77, 82, 85], "qa": [38, 86], "ramifications": 38, "insecure": 38, "nord": [38, 82], "ozkaya": 38, "study": [38, 51, 74, 82, 86, 88], "fielding": 38, "speed": [38, 74, 86], "stability": 38, "international": [38, 82], "h": [38, 65, 82, 86, 90], "klein": 38, "discover": [38, 88], "elicitation": [38, 52, 82], "thijmen": 38, "gooijer": 38, "keeling": 38, "chaparro": 38, "participants": 38, "mario": 38, "barbacci": 38, "ellison": 38, "charles": [38, 82], "weinstock": 38, "william": [38, 46, 66, 70, 73, 82, 85, 92, 95], "ibm": [38, 74, 82, 86], "wish": [38, 74, 76, 80], "allowing": [38, 74], "amount": [38, 49, 73, 74, 86, 90], "\u0442\u0435\u0445\u043d\u0438\u043a": [38, 73, 82], "\u043c\u0435\u043b\u043a": [38, 86], "\u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430": 38, "\u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d": 38, "\u0431\u0435\u043a\u043b\u043e\u0433": 38, "\u0432\u0438\u0434\u0438\u043c": [38, 88], "\u0434\u043e\u0433\u043e\u0432\u0430\u0440\u0438\u0432\u0430": [38, 86], "\u043f\u0440\u0430\u0432\u0438\u043b": [38, 41, 47, 72, 83, 85], "\u043f\u0440\u0438\u0434\u0443\u043c\u044b\u0432\u0430": [38, 75], "\u0438\u043d\u0442\u0443\u0438\u0446": 38, "\u0441\u043f\u0440\u043e\u0441": [38, 74], "\u0440\u0435\u0442\u0440\u043e\u0441\u043f\u0435\u043a\u0442\u0438\u0432": 38, "\u0435\u043c\u043a\u043e\u0441\u0442": 38, "\u0441\u043f\u0440\u0438\u043d\u0442": [38, 46, 86], "\u0443\u0448\u043b": 38, "\u0438\u043d\u0432\u0435\u0441\u0442\u0438\u0446": 38, "embedded": [38, 85], "spent": [38, 72, 73, 74], "gut": 38, "retro": 38, "restructuring": [38, 46, 86], "strongly": [38, 46], "promote": [38, 46], "justification": [38, 46, 75], "codebase": [38, 46], "contrary": [38, 46, 75, 76], "whatsoever": [38, 46], "restructure": [38, 46], "opportunity": [38, 46, 85], "constitutes": [38, 46, 51], "documented": [38, 46, 49], "ries": [38, 46], "incumbent": [38, 46], "monetary": [38, 46], "seven": [38, 46, 74, 86, 90], "deploy": [38, 46, 52, 82, 86], "escalated": [38, 46], "pain": [38, 46, 85], "annual": [38, 46], "million": [38, 46, 74], "annum": [38, 46], "productive": [38, 46, 74, 86], "notoriously": [38, 46], "improving": [38, 46, 66, 70, 73, 74, 80, 82, 85, 86, 95], "january": [38, 46, 100], "addison": [38, 46, 74, 82, 90], "wesley": [38, 46, 74, 82, 90], "constant": [38, 46, 73, 82, 85, 90, 93], "radically": [38, 46], "businesses": [38, 46], "portfolio": [38, 46, 86], "penguin": [38, 46], "\u043f\u043e\u0441\u0432\u044f\u0442": 38, "\u0432\u0441\u0435\u043c\u0438\u0440\u043d": 38, "\u043e\u0431\u044a\u044f\u0441\u043d": [38, 82], "\u0444\u043e\u043d\u0434\u043e\u0432": [38, 39], "\u043e\u043f\u0446\u0438\u043e\u043d": [38, 39], "\u043c\u0435\u0442\u0430\u0444\u043e\u0440": [38, 40, 41, 74, 86], "\u043f\u0440\u043e\u0446\u0435\u043d\u0442": [38, 39, 43, 66, 82, 121], "technicaldebt": [38, 41], "\u0434\u0435\u0433\u0440\u0430\u0434\u0430\u0446": [38, 70], "\u0432\u043e\u0437\u043d\u0438\u043a": 38, "\u0441\u043c\u043e\u0433\u043b": 38, "\u0434\u043d\u044f": [38, 90], "\u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u043d": 38, "\u0434\u043d\u0435": [38, 76], "tracked": 38, "switched": 38, "confused": 38, "worked": 38, "politics": 38, "\u043a\u043e\u043c\u043f\u0430\u043d": [38, 40, 41, 73, 83, 86, 88, 92, 100], "\u043a\u043e\u043b\u044b\u0431\u0435\u043b": [38, 41], "\u043e\u0442\u043a\u0443\u0434": [38, 41, 90], "\u0432\u044b\u0448\u043b": [38, 41, 72, 75, 76, 86], "\u043e\u0442\u0441\u0442\u0430\u0438\u0432\u0430": 38, "\u0441\u043e\u0440\u0432\u0430": 38, "\u0432\u0438\u043d\u043e\u0432\u0430\u0442": 38, "\u043e\u0431\u0432\u0438\u043d": 38, "\u043a\u0430\u0440\u0430\u043d\u0434\u0430\u0448": 38, "\u0443\u0447\u0435\u0441\u0442": 38, "\u043d\u0430\u043a\u043e\u043d\u0435\u0446": [38, 46, 83], "\u0432\u044b\u0434\u0430": [38, 73], "\u0438\u043d\u0434\u0443\u043b\u044c\u0433\u0435\u043d\u0446": 38, "\u0441\u043d\u0438\u0436\u0435\u043d": [38, 52, 74, 75, 76, 83, 85, 88, 100], "\u043e\u0442\u043e\u0437\u0432\u0430": 38, "\u043e\u0441\u0442\u0430\u043d\u0443\u0442": 38, "\u043d\u0430\u0435\u0434\u0438\u043d": [38, 86], "\u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f": [38, 74, 94], "\u043e\u0442\u0437\u044b\u0432\u0430": 38, "\u0441\u0442\u0430\u0432": [38, 76, 85], "\u043f\u0435\u0440\u0441\u043e\u043d": 38, "\u0434\u043e\u043b\u0436\u043d\u043e\u0441\u0442": 38, "\u0432\u0435\u0447\u043d": [38, 83], "\u043d\u0430\u0441\u0442\u0430\u0438\u0432\u0430": [38, 85, 88, 92], "\u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0438\u0446\u0438\u0440": 38, "\u0441\u0430\u043c\u043e\u0437\u0432\u0430\u043d\u0446": [38, 83, 89, 95], "\u0445\u0432\u0430\u0442": [38, 92], "\u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0446": 38, "\u043d\u0435\u0443\u0432\u0435\u0440\u0435\u043d": 38, "\u043f\u043e\u0434\u043a\u0440\u0435\u043f\u043b": 38, "\u043e\u043f\u044b\u0442": [38, 46, 74, 82, 83, 85, 92, 94, 100], "\u043e\u0431\u043e\u0441\u043d\u043e\u0432\u0430": [38, 92], "\u0441\u043f\u043e\u0441\u043e\u0431\u043d": [38, 56, 60, 68, 70, 72, 74, 75, 83, 85, 88, 90, 92, 95], "\u0432\u044b\u0441\u043e\u043a\u043e\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d": [38, 75, 83], "\u0437\u0430\u043f\u0438\u043b": 38, "\u043e\u0441\u044f\u0437\u0430": 38, "\u0444\u0438\u0447": [38, 56], "\u043f\u0440\u0438\u0437\u0440\u0430\u0447\u043d": 38, "\u043d\u043e\u0431\u0435\u043b\u0435\u0432\u0441\u043a": [38, 94], "\u043b\u0430\u0443\u0440\u0435\u0430\u0442": [38, 94], "\u0434\u0430\u043d\u0438\u044d\u043b": [38, 94], "\u043a\u0430\u043d\u0435\u043c\u0430": [38, 94], "\u043f\u0438\u043a": [38, 94], "\u043a\u043e\u043d\u0435\u0446": [38, 94], "\u043d\u0435\u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d": [38, 94], "\u044d\u043c\u043e\u0446": [38, 94], "\u043d\u0435\u0434\u043e\u043e\u0446\u0435\u043d\u0438\u0432\u0430": 38, "unacknowledged": 38, "secures": 38, "inalienable": 38, "culture": [38, 75, 86], "courageous": 38, "huddle": 38, "fortress": 38, "walls": 38, "adopted": [38, 86], "cannonades": 38, "battlements": 38, "reviews": [38, 49, 82, 86, 94], "moats": 38, "crocodiles": 38, "torture": 38, "huge": [38, 85, 100], "pots": 38, "boiling": 38, "oil": 38, "tear": [38, 85], "impede": 38, "protecting": 38, "\u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d": [38, 89], "\u0432\u0435\u043b\u0438\u043a\u043e\u0432\u0430\u0442": 38, "nonfunctional": [38, 50, 52, 86, 125], "selling": [38, 41, 43, 66, 121], "\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d": [38, 43, 65, 66, 75, 76, 82, 83, 86, 89, 90, 91, 92, 93, 121, 138], "emacsway_log": [38, 92, 100], "488": 38, "techdebt": 38, "393": 38, "552": 38, "157": 38, "\u0443\u0432\u0438\u0434\u0435\u043b": 39, "\u0434\u043e\u043d\u0435\u0441\u0442": [39, 41, 56], "\u0442\u0435\u0440\u043c\u0438\u043d\u043e\u043b\u043e\u0433": 39, "\u0440\u0430\u0437\u044a\u044f\u0441\u043d\u044f": [39, 52, 66, 70], "obligation": 39, "buy": [39, 86], "instrument": 39, "american": [39, 75], "stock": [39, 82], "derivatives": 39, "doubt": 39, "cleared": 39, "fischer": [39, 82], "black": [39, 66, 74, 82], "myron": 39, "scholes": [39, 66], "compute": 39, "famous": 39, "formula": 39, "establishing": [39, 70, 86], "strike": 39, "purchased": 39, "tied": 39, "exercising": 39, "slightly": 39, "originates": 39, "deferring": [39, 66], "nobel": [39, 66], "prize": [39, 66], "economists": [39, 66], "surprisingly": [39, 66], "\u043f\u0440\u0438\u0445\u043e\u0434": [40, 70, 72, 73, 74, 85, 89, 90], "\u0441\u043a\u043b\u043e\u043d": [40, 68, 83], "\u043f\u043e\u0440\u044f\u0434\u043e\u043a": [40, 74, 82], "\u0443\u0434\u0435\u0448\u0435\u0432": [40, 65], "\u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043b\u044c\u043d": [40, 82], "\u0444\u043e\u043d": [40, 56, 88, 92, 102], "\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0447\u0435\u0441\u043a": [40, 41, 83], "\u0443\u0447\u0435\u0431\u043d\u0438\u043a": [40, 64, 82], "\u0432\u0443\u0437": [40, 41, 82], "\u0438\u0437\u0434": [40, 82, 88], "\u0433\u043b\u0443\u0445": [40, 82], "\u043e\u0441\u0432\u0435\u0449": 40, "\u0448\u0430\u0445\u043c\u0430\u0442": 40, "\u043e\u043f\u0440\u043e\u0432\u0435\u0440\u0436\u0435\u043d": 40, "\u0438\u0433\u0440\u043e\u043a": 40, "\u0444\u0438\u0433\u0443\u0440": 40, "\u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430": 40, "\u0434\u0432\u0438\u0433\u0430": [40, 74, 85], "\u0431\u0435\u0437\u0431\u043e\u043b\u0435\u0437\u043d\u0435\u043d": [40, 85], "\u0438\u0441\u043a\u043b\u044e\u0447\u0430": 40, "\u0432\u044b\u0440\u0430\u0441\u0442": 40, "\u043f\u0443\u043d\u043a\u0442": [40, 76], "\u0444\u043e\u0440\u043c\u0438\u0440": [40, 56, 86, 92, 100], "\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430": [40, 86, 92, 100], "\u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0430": 40, "\u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a": [40, 41, 85], "\u0441\u043f\u0438\u0440\u0430\u043b\u044c\u043d": [40, 65, 86], "\u043f\u043e\u0434\u043a\u0440\u0435\u043f\u043b\u044f": 40, "\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433": 40, "\u0438\u043d\u0434\u0438\u043a\u0430\u0442\u0438\u0432\u043d": 40, "\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b": [40, 75], "\u0437\u0434\u043e\u0440\u043e\u0432": [40, 77, 85], "\u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430": [40, 92], "\u043c\u043e\u0437\u0433": [40, 75, 85, 88, 95], "\u0441\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u043d": [40, 94], "\u043f\u0435\u0440\u0435\u0441\u0442\u0440\u0430\u0445\u043e\u0432\u043a": 40, "\u043e\u0442\u0447\u0430\u0441\u0442": 40, "\u0441\u043a\u0430\u0442": 40, "\u043d\u0435\u043e\u043f\u0440\u0430\u0432\u0434\u0430": [40, 72], "\u043e\u0432\u0435\u0440\u0438\u043d\u0436\u0438\u043d\u0438\u0440\u0438\u043d\u0433": 40, "\u0441\u043a\u043b\u043e\u043d\u044f": 40, "\u043e\u0440\u0433": 40, "\u043c\u0443\u0441\u043e\u0440\u043d\u0438\u043a": 40, "\u0443\u043f\u043e\u0434\u043e\u0431\u043b\u044f": 40, "\u0434\u0435\u043c\u043e\u0440\u0430\u043b\u0438\u0437": 40, "\u043a\u043e\u043c\u043f\u0435\u0442\u0435\u043d\u0442\u043d": [40, 92], "\u043e\u043f\u0440\u0430\u0432\u0434\u0430\u043d": 40, "\u043f\u043e\u043a\u0430\u0436": 40, "\u0441\u0442\u043e\u0440": 40, "\u0432\u044b\u0431\u0440\u043e\u0441": 40, "\u043f\u043b\u0430\u043d": [40, 60, 65, 70, 86, 90, 95], "\u043f\u043e\u0441\u0442\u043e\u044f\u043d\u0441\u0442\u0432": [40, 95], "\u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u0435\u043b\u044c\u043d": 40, "\u0432\u0430\u0440\u0438\u0430\u0442\u0438\u0432\u043d": 40, "\u0443\u0441\u043b\u043e\u0432\u043d": [40, 100], "\u043e\u0431\u043e\u0431\u0449\u0430": [40, 72, 92], "\u043f\u0435\u0440\u0435\u0444\u0440\u0430\u0437\u0438\u0440\u0443": 40, "\u0432\u044b\u043a\u0438\u043d\u0443\u0442": 40, "\u0447\u0443\u0432\u0441\u0442\u0432\u0443\u0435\u0442": 40, "\u0437\u0430\u043f\u0440\u044f\u0433\u0430": 40, "\u0435\u0445\u0430": 40, "\u043e\u0442\u043b\u0430\u0436\u0435\u043d": [40, 86], "\u0440\u0435\u0434\u043a": [40, 82, 92], "\u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430": [40, 85], "\u043e\u043a\u0443\u043f": 40, "\u0437\u0430\u0442\u044f\u0433\u0438\u0432\u0430": 40, "\u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d": [40, 74, 90], "\u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447": [40, 74, 85, 90], "\u043d\u0435\u0439\u0442\u0440\u0430\u043b\u044c\u043d": 40, "\u0432\u0441\u0442\u0430\u0435\u0442": [40, 75], "\u0440\u0430\u0437\u043e\u0433\u0440\u0435\u0432\u0430": 40, "\u043f\u0435\u0440\u0435\u0442\u044f\u0433\u0438\u0432\u0430\u043d": 40, "\u043e\u0434\u0435\u044f": 40, "\u043f\u0440\u0435\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d": 40, "\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d": 40, "\u0440\u0430\u0437\u043d\u043e\u0441": 40, "\u0434\u043e\u043b\u044c\u0448": 40, "\u043f\u043e\u0434\u0430\u0432\u043d": 40, "\u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0442\u0438\u0432\u043d": 41, "\u043a\u0430\u0441\u0430": 41, "\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d": 41, "\u0443\u043c\u0435\u0442": [41, 56, 76, 82, 83, 88, 90], "\u043f\u0440\u043e\u0434\u0430": 41, "\u043d\u0430\u0445\u043e\u0434\u044f": 41, "\u0431": [41, 77, 82, 88, 102], "\u0431\u0430\u043b\u0430\u043d\u0441": [41, 46, 65, 72, 73, 86, 100], "\u043e\u0441\u0442\u0440\u043e\u0442": 41, "\u0431\u044b\u0432\u0448": 41, "\u043d\u0430\u0440\u044f\u0434": [41, 85], "\u0432\u044b\u044f\u0432\u043b\u0435\u043d": 41, "\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0435\u043d": [41, 93], "\u043f\u043e\u0432\u0435\u0437\u043b": 41, "\u0437\u043d\u0430\u043a\u043e\u043c": [41, 51, 73, 82, 83, 85], "\u043f\u043e\u043c\u043e\u0447": 41, "\u043c\u0435\u043d\u0442\u0430\u043b\u0438\u0442\u0435\u0442": 41, "\u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u043d": [41, 52, 65], "\u043f\u043e\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430": 41, "cruft": 41, "loan": [41, 65], "burden": [41, 74, 86], "rush": 41, "analogy": 41, "borrowing": [41, 65, 69, 70, 76, 131], "credit": [41, 51], "card": [41, 46, 51, 74], "income": 41, "purchasing": 41, "zero": [41, 51], "reorganizing": 41, "contain": [41, 60, 65, 74, 75, 86, 90], "explains": [41, 65, 74], "coined": 41, "wycash": 41, "digitalk": 41, "smalltalk": [41, 72, 82, 85], "accumulate": 41, "learnings": 41, "along": [41, 70, 72, 75, 76, 85, 86], "explanation": 41, "gonna": [41, 49], "stumble": 41, "disagreement": 41, "\u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442": [41, 56, 85], "\u0442\u0435\u043b": [41, 83, 85], "\u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a": 41, "\u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441": 41, "n": [41, 53, 74, 75, 82, 86, 88, 102], "\u0441\u0442\u0435\u043f\u0435\u043d": [41, 68, 74, 85, 94], "\u0446\u0435\u043d": [41, 70, 77, 88], "\u043e\u0431\u043b\u0438\u0433\u0430\u0446": 41, "\u043f\u043e\u043a\u0443\u043f\u043a": 41, "\u0441\u043e\u0442": [41, 74], "\u0434\u043e\u043b": [41, 56, 73, 76, 92], "\u0432\u044b\u043f\u043b\u0430\u0442": 41, "\u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430": 41, "\u0434\u043e\u0445\u043e\u0434\u043d": 41, "bankiros": 41, "\u043d\u0430\u043a\u043e\u043f\u043b\u0435\u043d": 41, "\u0442\u0435\u0445\u0434\u043e\u043b\u0433": 41, "\u044d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0442": 41, "\u0431\u0435\u0437\u043e\u0431\u0438\u0434\u043d": 41, "\u0430\u0441\u0441\u043e\u0446\u0438\u0438\u0440": 41, "\u0430\u043a\u0430\u0434\u0435\u043c\u0438\u0447\u0435\u0441\u043a": 41, "\u0437\u0430\u0434\u043e\u043b\u0436\u0435\u043d": 41, "\u0446\u0435\u043d\u0442\u0440": 41, "\u043e\u0442\u0440\u0430\u0436\u0435\u043d": [41, 102], "\u0442\u0440\u0430\u0434\u0438\u0446": 41, "\u0431\u0435\u0437\u043f\u0440\u043e\u0446\u0435\u043d\u0442\u043d": 41, "\u0432\u0437\u0430\u0438\u043c\u043e\u0432\u044b\u0440\u0443\u0447\u043a": 41, "\u0437\u0430\u0440\u043f\u043b\u0430\u0442": 41, "\u044f\u0432\u043b\u0435\u043d": [41, 74, 75, 76, 77, 85, 94, 100], "\u0434\u0440\u0443\u0436\u0435\u0441\u043a": 41, "\u043d\u0435\u0441\u0435\u0442": [41, 73], "\u043d\u0435\u0434\u043e\u043f\u043e\u043d\u0438\u043c\u0430\u043d": [41, 75], "uninteresting": 41, "judge": 41, "1k": 41, "looking": [42, 72, 74, 75, 85], "henry": 42, "ford": [42, 82, 85, 92], "\u0447\u0443\u0432\u0441\u0442\u0432": [42, 56, 83, 88, 92], "\u0436\u0435\u0440\u0442\u0432\u0443\u0435\u0442": 42, "\u0432\u0441\u0442\u0443\u043f": 42, "\u0434\u0435\u043c\u043e\u0440\u0430\u043b\u0438\u0437\u0430\u0446": 42, "\u043d\u0430\u0447\u043d\u0435\u0442": [42, 47], "\u0434\u0430\u0432": 42, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432": [42, 80, 86, 92], "\u0431\u0440\u0430\u043a\u043e\u0432\u0430": 42, "\u043e\u0442\u043a\u0430\u0436\u0435\u0442": 42, "\u043f\u0435\u0440\u0435\u0441\u043c\u043e\u0442\u0440": 42, "\u0434\u043e\u0431\u044c\u0435\u0442": 42, "\u043f\u043e\u0442\u0435\u0440\u044f": 42, "deliberately": [42, 85], "downgrade": 42, "demoralization": 42, "crap": 42, "overwhelm": 42, "temporarily": [42, 74], "testing": [42, 46, 47, 51, 62, 65, 74, 76, 82, 85, 86], "reviewing": [42, 94], "sticking": 42, "\u0433\u043b\u0443\u0431\u0436": 42, "\u0437\u0430\u0431\u043e\u0442": 42, "\u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d": [42, 75], "\u0441\u043e\u0447\u0443\u0432\u0441\u0442\u0432": 42, "\u0442\u0440\u0435\u043d": 42, "\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432": 42, "\u0433\u043b\u0430\u0434\u043a": [42, 83], "\u0441\u043f\u0430\u0441\u0442": 42, "\u043f\u043e\u0437\u0438\u0442\u0438\u0432\u043d": [42, 85, 100], "\u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432": 42, "lies": [42, 85, 86], "surface": [42, 73], "sensitive": [42, 53], "compassion": 42, "lubrication": 42, "minimal": [42, 49, 73, 75], "passion": 42, "manipulative": 42, "enjoying": 42, "\u043c\u043e\u0442\u0438\u0432\u0430\u0446": [43, 72, 73, 75, 82], "\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u043d": [44, 46, 66, 70, 122], "\u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430": [46, 47], "\u0441\u043e\u0430\u0432\u0442\u043e\u0440": 46, "brant": [46, 66, 70, 73, 82, 85, 95], "opdyke": [46, 66, 70, 73, 82, 85, 95], "roberts": [46, 66, 70, 73, 82, 85, 95], "\u0441\u0442\u0438\u043b": [46, 72, 73, 85], "\u0441\u0442\u0430\u0440": [46, 47, 65, 74, 75, 76, 88], "\u0437\u0430\u0445\u043e\u0447\u0435\u0442": 46, "\u043c\u043e\u0434\u0435\u0440\u043d\u0438\u0437\u0430\u0446": 46, "\u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d": [46, 77, 92], "\u0431\u0443\u0434\u044c\u0442": [46, 73], "\u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": [46, 72, 74, 77, 82, 85, 86], "\u0437\u0430\u043f\u0443\u0442\u0430": [46, 93], "\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d": 46, "\u0440\u0430\u0437\u0431\u0440\u043e\u0441\u0430": 46, "\u0441\u043e\u0431\u0440\u0430": 46, "\u0432\u043e\u0435\u0434\u0438\u043d": 46, "\u0441\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440": 46, "\u0437\u0430\u043f\u0438\u0448": 46, "\u0440\u0430\u0437\u0432\u0435\u0441\u044c\u0442": 46, "\u0443\u0441\u0442\u0440\u043e": [46, 77, 83], "\u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d": 46, "\u0432\u0435\u0441\u0435\u043b": 46, "\u0432\u0435\u0447\u0435\u0440\u0438\u043d\u043a": 46, "\u0442\u043e\u0440\u0436\u0435\u0441\u0442\u0432\u0435\u043d": 46, "\u0441\u043e\u0436\u0433": 46, "\u0445\u043e\u0440\u043e\u0448\u0435\u043d\u044c\u043a": 46, "\u0432\u044b\u043f": 46, "\u0437\u0430\u043a\u0443\u0441": 46, "\u0440\u0430\u0441\u0442\u0432\u043e\u0440": 46, "\u0432\u043e\u0437\u0434\u0443\u0445": [46, 74, 85, 90], "tangled": 46, "inheritance": 46, "hierarchy": 46, "piece": [46, 74, 85, 90], "scattered": [46, 74], "unify": 46, "cards": 46, "display": 46, "prominently": 46, "nibbling": 46, "ceremoniously": 46, "burn": 46, "eat": [46, 82], "drink": 46, "demand": [46, 47], "visit": [46, 47], "activities": [46, 60, 62, 64, 74, 76, 77, 82, 85, 86], "\u0434\u043e\u043d": 46, "\u0440\u043e\u0431\u0435\u0440\u0442\u0441": 46, "\u043e\u0434\u043d\u0430\u0436\u0434": 46, "\u043c\u043e\u0440\u0449": 46, "\u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d": 46, "wince": 46, "duplication": [46, 76], "baseball": 46, "strikes": 46, "\u043a\u0440\u0430\u0441\u0438\u043a\u043e\u0432": [46, 74], "\u0442\u0440\u0438\u0433\u0443\u0431": [46, 74], "\u043f\u043e\u0434\u0440\u044b\u0432\u043d": 46, "\u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d": [46, 73, 85, 89, 92, 100], "\u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b": [46, 82, 83], "\u0441\u043d\u0430\u0447\u0430": [46, 47, 73, 74, 77, 83], "\u0443\u0434\u0430\u0441\u0442": [46, 74, 86], "advice": [46, 85, 92], "subversive": 46, "rapidly": [46, 74, 86], "suit": [46, 73, 86], "quicker": [46, 72, 85], "bug": [46, 47, 74], "fastest": [46, 74], "\u043c\u0430\u043a\u043a\u0430\u0432\u0435\u0435\u0432": [46, 70, 85], "\u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430": [46, 74, 95], "\u0440\u0435\u043b\u0438\u0437": [46, 86], "\u044e\u043d": 47, "\u0442\u0435\u0441\u0442": [47, 72, 74, 85], "xunit": [47, 73, 82, 85], "sunit": 47, "\u043f\u0440\u0438\u0441\u0442\u0443\u043f": [47, 74, 82], "\u0441\u0442\u0430\u043d\u0435\u0442": [47, 85], "\u0440\u0430\u0437\u043e\u0447\u0430\u0440\u043e\u0432\u044b\u0432\u0430": [47, 70], "\u043f\u0443\u0433\u0430": 47, "\u043e\u043f\u0430\u0441\u0435\u043d": [47, 85], "\u0448\u0430\u0433": [47, 83, 88, 90], "\u043a\u0430\u0440\u0442\u0438\u043d": [47, 74, 77, 85, 86, 88, 100], "\u0437\u0430\u0434\u0443\u043c\u044b\u0432\u0430": [47, 70, 74], "\u0432\u043d\u0435\u0441\u0442": [47, 56, 74], "\u043f\u0440\u0438\u044f\u0442\u043d": 47, "\u0442\u0435\u043c\u043d\u043e\u0442": [47, 83], "\u0441\u043e\u043b\u043d\u0435\u0447\u043d": 47, "\u043b\u043e\u0432": 47, "\u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u044f": 47, "\u043e\u0431\u0440\u0435\u0441\u0442": 47, "\u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u0438\u0432\u043d": [47, 93], "\u043d\u0430\u0447\u043d\u0443\u0442": [47, 92], "\u0441\u043a\u0430\u043f\u043b\u0438\u0432\u0430": 47, "\u0441\u0442\u0440\u0430\u0448\u043d": [47, 83], "\u0447\u0443\u0434\u043e\u0432\u0438\u0449": 47, "\u0432\u044b\u043f\u0440\u044b\u0433\u043d\u0443\u0442": 47, "\u043f\u0440\u0435\u0436\u043d": [47, 76, 85], "\u043e\u0446\u0435\u043d": [47, 70], "\u0441\u043e\u0431\u043b\u0430\u0437\u043d": 47, "\u043d\u0430\u043f\u0438\u0448": 47, "\u043d\u0430\u043c\u0435\u0440": [47, 74], "\u0443\u0447\u0430\u0441\u0442\u043e\u043a": [47, 95], "\u0437\u0430\u043c\u0435\u0434\u043b": [47, 72, 85], "\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442": 47, "\u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430": 47, "\u043e\u0431\u043e\u0437\u0440\u0438\u043c": [47, 102], "\u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430": [47, 85], "\u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442": [47, 74], "\u0431\u0443\u0434\u0442": 47, "frustrating": 47, "area": [47, 73, 100], "shifting": 47, "scary": 47, "picture": [47, 51, 74, 77, 85], "confidence": [47, 70, 74, 85], "night": 47, "avoiding": [47, 75, 82], "resist": 47, "tendency": [47, 85], "96in": 47, "dark": [47, 76, 82], "unknown": 47, "magnitude": 47, "untested": 47, "attract": 47, "thoroughly": [47, 65], "\u0441oncerns": [48, 124], "\u0438\u0441\u0447\u0435\u0440\u043f\u044b\u0432\u0430": 49, "\u0441\u0430\u043c\u043e\u043e\u0440\u0433\u0430\u043d\u0438\u0437": [49, 86, 88], "practitioners": 49, "discussions": [49, 76], "babok": [49, 52, 64, 82], "actual": [49, 52, 65, 75, 85], "bas": 49, "precision": 49, "conversations": 49, "iiba": 49, "encourage": 49, "minimum": 49, "accurately": [49, 73, 74, 80], "testers": [49, 82, 85, 86], "satisfy": [49, 64, 75, 76], "regulations": 49, "riskiest": [49, 63], "karl": [49, 52, 53, 82], "wiegers": [49, 51, 52, 53, 82], "emphatically": 49, "audience": 49, "ain": 49, "sufficient": [49, 70, 76, 86], "intent": [49, 73, 74], "obsolete": [49, 52, 86], "mechanical": [49, 72, 85], "property": 49, "knaster": [49, 51, 64, 82, 86], "preparation": 49, "artifacts": [49, 52, 73, 76, 82, 86], "transform": [49, 82], "narrative": 49, "preparing": 49, "packages": [49, 74, 90], "briefing": 49, "infrequent": 49, "milestone": 49, "meets": [49, 75, 86], "informal": 49, "completing": 49, "operator": 49, "baselines": 49, "versions": [49, 62, 65], "reuse": 49, "configuration": [49, 76, 86], "verification": [49, 59, 60, 85], "incident": 49, "bidirectional": 49, "automated": [49, 51, 85, 86], "measurement": 49, "atam": 51, "\u043f\u043e\u0439\u043c\u0435\u0442": 51, "k": [51, 74, 82], "wigers": 51, "\u0442\u043e\u043f\u043e\u0432": 51, "\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a": [51, 53, 86], "alongside": 51, "desk": 51, "technician": 51, "respond": [51, 60], "frustrated": 51, "hang": 51, "implications": 51, "efficiency": [51, 74, 85, 86], "deteriorate": 51, "corrective": 51, "quantify": 51, "stated": [51, 85], "keyword": 51, "preferably": 51, "pertinent": 51, "satisfied": 51, "satisfying": 51, "distinguish": [51, 82, 85, 95], "delight": 51, "disappointment": 51, "\u043f\u043e\u0434\u0440\u0430\u0437\u0434\u0435\u043b": 51, "beatty": 51, "\u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0437\u0430\u0446": 51, "\u0432\u044b\u0431\u0438\u0432\u0430": [51, 94], "\u043f\u043e\u0447\u0432": [51, 72, 82, 88, 91, 94, 138], "\u043e\u0442\u043e\u0440\u0432\u0430": [51, 75], "\u043b\u043e\u0431\u0431\u0438\u0440\u043e\u0432\u0430\u043d": 51, "nfrs": [51, 86], "\u043e\u0444\u0444": 51, "\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430": [51, 77], "\u0434\u0435\u043b\u0435\u0433\u0438\u0440\u043e\u0432\u0430": 51, "\u043f\u043e\u0441\u043c\u043e\u0442\u0440": [51, 56, 72, 73, 86, 88, 90], "enlist": 51, "assistance": [51, 86], "smes": 51, "incomplete": [51, 59, 65], "existence": [51, 64], "checklist": [51, 53], "browsers": 51, "prime": 51, "inclusion": 51, "browser": 51, "listed": 51, "recommend": 51, "waiting": [51, 70], "defers": 51, "critical": [51, 74, 76, 82], "relate": [51, 75, 82], "usability": 51, "maintainability": [51, 66, 75], "portability": 51, "\u0441\u043e\u0448\u043b": 51, "illustrated": 51, "appears": 51, "relevant": [51, 53, 76, 100], "affected": 51, "persisting": 51, "details": [51, 60, 65, 74, 77, 90], "throw": 51, "memorialized": 51, "1000": [51, 74], "simulated": 51, "suite": [51, 85], "excellent": 51, "accidentally": 51, "bottleneck": 51, "discovered": [51, 72, 85, 86], "forget": [51, 68], "fi": [51, 85], "remembers": 51, "treated": 51, "pci": 51, "compliance": [51, 77, 86], "security": [51, 86], "localize": 51, "supported": 51, "cfo": 51, "surely": [51, 85], "organized": [51, 82, 86, 100], "enterprises": [51, 64, 82, 86], "tooling": [51, 86], "central": 51, "scheduling": [51, 82, 86], "burndown": 51, "reporting": 51, "privileges": [51, 75], "granted": 51, "visibility": 51, "fosters": 51, "comments": 51, "interaction": [51, 52, 72, 73], "supplementary": 51, "auxiliary": 51, "rup": [51, 52, 65, 76, 86], "agilists": 51, "favor": [51, 85], "comprehensive": [51, 76], "supplemental": 51, "specif": 51, "cation": 51, "amounts": 51, "shippable": 51, "milestones": 51, "mandatory": [51, 52], "cations": 51, "epic": [51, 52, 82], "juha": [51, 52, 82, 86], "markus": [51, 52, 82, 86], "aalto": [51, 52, 82, 86], "syrs": 52, "15288": [52, 64, 82], "translates": 52, "expresses": 52, "lists": [52, 82, 85], "convey": [52, 100], "\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d": [52, 85, 92], "gathering": [52, 75], "alistair": 52, "compiling": 52, "inventory": 52, "placeholders": 52, "pbis": 52, "currency": 52, "expressing": [52, 85], "traditionally": 52, "statements": [52, 77], "uml": [52, 75, 82], "workhorses": 52, "\u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d": [52, 75, 82], "express": 52, "emphasizing": 52, "verbal": 52, "cohn": [52, 76, 82, 83, 88, 92], "advantages": [52, 76, 85], "\u0441\u0435\u043c\u0430\u043d\u0442\u0438\u0447\u0435\u0441\u043a": [52, 65, 102], "\u043d\u0435\u0434\u043e\u0441\u0442\u0438\u0436\u0438\u043c": 52, "steered": 52, "dictionary": [52, 75], "obligatory": 52, "carries": 52, "connotation": 52, "absolutism": 52, "permanence": 52, "inhibitors": 52, "thousand": 52, "envisioned": 52, "80": [52, 74, 85], "weren": 52, "estimation": [52, 80, 82], "perspectives": [52, 82], "interact": [52, 72, 74, 86], "combine": 52, "extend": [52, 75], "\u0430\u043a\u0446\u0435\u043d\u0442": [52, 100], "\u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0430": 52, "accepts": 52, "determined": [52, 65, 86], "emerge": [52, 86], "develops": [52, 86], "intermediate": [52, 85], "releases": [52, 73, 82, 86], "phone": 52, "dials": 52, "covers": 52, "variants": 52, "obtained": 52, "differs": 52, "lay": 52, "claim": 52, "achieving": [52, 74, 76, 86], "collected": 52, "progresses": [52, 65], "absolute": 52, "literature": [52, 82], "suggests": [52, 73, 85, 86], "blasts": 52, "presents": 52, "imagination": 52, "authors": [52, 86], "constantly": [52, 74, 76], "criticism": 52, "\u0443\u0442\u043e\u0447\u043d\u044f": 52, "ireb": [52, 64, 82], "certified": [52, 64, 82], "advanced": [52, 64, 82], "\u0430\u043a\u0440\u043e\u043d\u0438\u043c": 53, "invest": [53, 85], "independent": [53, 72, 74, 86, 90], "negotiable": 53, "estimable": 53, "acronym": 53, "alliance": 53, "\u0430\u043a\u0440\u043e\u043d": 53, "\u0437\u043d\u0430\u043a": [53, 76, 93], "mnemonic": 53, "measurable": 53, "attainable": [53, 75], "\u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446": 53, "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442": [56, 65, 76, 80, 86, 94], "\u043a\u043e\u043d\u0435\u0441\u0435\u043d\u0441\u0443\u0441": 56, "\u043e\u0431\u043e\u044e\u0434\u043d": 56, "\u0443\u0449\u0435\u0440\u0431\u043d": [56, 88, 92], "\u0433\u0440\u0430\u043c\u043e\u0442\u043d": [56, 64, 74, 75, 76, 83, 86, 90], "\u0441\u043f\u0438\u043a\u0435\u0440": [56, 92, 95], "\u0437\u043e\u043d": [56, 92, 100], "\u043a\u043e\u043c\u0444\u043e\u0440\u0442": [56, 85, 92], "\u0430\u0433\u0440\u0435\u0441\u0441\u0438\u0432\u043d": 56, "\u043f\u043e\u043f\u044b\u0442\u043e\u043a": [56, 88, 92], "\u0434\u0438\u0441\u043a\u0440\u0435\u0434\u0438\u0442\u0430\u0446": 56, "\u043d\u0435\u0443\u0434\u043e\u0431\u043d": 56, "\u043c\u0430\u043b": [56, 74, 82, 83, 85, 100], "\u043d\u0435\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0438\u0432": [56, 92], "\u043f\u0443\u0441\u0442": [56, 82, 83, 92, 102], "\u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a": [56, 70], "\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u0446": [56, 82], "\u0441\u043e\u043f\u0435\u0440\u043d\u0438\u0447\u0435\u0441\u0442\u0432": 56, "\u043b\u0438\u0434\u0435\u0440\u0441\u0442\u0432": 56, "\u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430": [56, 92], "\u044d\u043d\u0446\u0438\u043a\u043b\u043e\u043f\u0435\u0434\u0438\u0447\u0435\u0441\u043a": [56, 92], "\u0441\u043b\u043e\u0432\u0430\u0440": [56, 75, 92, 100], "\u0433\u0430\u0440\u0434\u0430\u0440\u0438\u043a": [56, 92], "\u0438\u0432\u0438\u043d": [56, 92], "\u043a\u043e\u043d\u0444\u043e\u0440\u043c\u0438\u0437\u043c": [56, 88], "\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430": 56, "\u043f\u043e\u044f\u0441\u043d": [56, 70], "\u043f\u0440\u0435\u043a\u0440\u0430\u0442": 56, "\u043f\u0440\u0435\u043d": 56, "\u043d\u0435\u0441\u043e\u0433\u043b\u0430\u0441\u043d": 56, "\u0438\u0440\u0440\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [56, 88, 89, 94], "\u0443\u0441\u0438\u043b\u0435\u043d": [56, 88, 89, 94], "\u0440\u0430\u0441\u0441\u0442\u0430": 56, "\u043f\u0440\u043e\u0434\u0435\u043b\u0430": 56, "\u0434\u0435\u043c\u043e\u0442\u0438\u0432\u0430\u0446": 56, "\u0442\u0435\u043a\u0443\u0447\u043a": 56, "\u0443\u043f\u0443\u0449\u0435\u043d": [56, 70], "\u0441\u0434\u0432\u0438\u0433": 56, "\u0440\u044b\u043d\u043e\u043a": [56, 75, 86], "\u043f\u0440\u043e\u0441\u0442\u0430\u0438\u0432\u0430\u043d": 56, "\u043d\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d": 56, "\u0432\u0430\u043a\u0430\u043d\u0441": 56, "\u043e\u0442\u0432\u043b\u0435\u043a\u0430\u043d": 56, "\u043e\u043f\u044b\u0442\u043d": [56, 65, 76, 80, 85, 100], "\u043e\u0431\u0443\u0447\u0435\u043d": [56, 75, 86, 88, 89, 91, 93, 138], "\u043e\u0441\u0432\u043e\u0435\u043d": [56, 82, 94, 95], "\u0441\u043e\u0438\u0441\u043a\u0430\u0442\u0435\u043b": [56, 94], "\u0440\u0435\u0432\u044c\u044e\u0435\u0440": 56, "\u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430": [56, 73], "\u0438\u043d\u0441\u043f\u0435\u043a\u0446": 56, "\u043f\u0440\u043e\u0432\u0435\u0441\u0442": [56, 85, 88, 92], "\u0430\u043d\u0430\u043b\u043e\u0433": [56, 85, 90, 100, 102], "\u044d\u043c\u043f\u0438\u0440\u0438\u0447\u0435\u0441\u043a": [56, 65, 76, 80, 92], "\u0441\u0440\u043e\u0434\u043d": 56, "\u0445\u043e\u0436\u0434\u0435\u043d": [56, 94], "\u043e\u0449\u0443\u043f": 56, "\u043a\u0443\u0434": [56, 92], "\u0434\u043e\u0431\u0440\u0430": 56, "\u043f\u0440\u043e\u0438\u0441\u043f\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430": 56, "\u043f\u043e\u0442\u0440\u043e\u0433\u0430": 56, "\u0440\u0430\u0441\u0448\u0438\u0440": [56, 92], "\u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442": [56, 65, 73, 76, 95], "\u0440\u0443\u043b": [56, 92], "\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446": [56, 74], "\u0432\u043e\u0436\u0434\u0435\u043d": [56, 92], "\u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442": [56, 92], "\u0431\u0443\u0441\u0438\u043d\u043a": 56, "dr": [56, 82], "deming": 56, "red": [56, 85], "bead": 56, "experiment": [56, 86], "\u043d\u0430\u0440\u043e\u0434\u043d": [56, 65, 83, 85, 89, 92], "\u043f\u043e\u0441\u043b\u043e\u0432\u0438\u0446": [56, 65, 85, 89], "\u0443\u0441\u043b\u044b\u0448\u0430": [56, 74, 75, 82], "mobbing": [56, 94], "\u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d": [56, 85], "\u0436\u0430\u043b\u043a": 56, "\u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430": 56, "allocates": [59, 60], "reworked": 59, "portion": 60, "inaccurate": [60, 65], "patton": [60, 62], "associates": [60, 62], "\u0432\u043b\u0430\u0441\u0442\u0432": [60, 90], "\u044d\u0434\u0441\u0433\u0435\u0440": [60, 90], "\u0434\u0435\u0439\u043a\u0441\u0442\u0440": [60, 74, 90, 92], "\u043f\u0440\u043e\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c": [60, 90], "\u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440": [60, 90], "\u043f\u043e\u043f\u0430\u0434\u0435\u0442": [60, 90], "\u0442\u0443\u043f\u0438\u043a": [60, 90], "\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u043d": [60, 90], "\u0443\u043b\u0443\u0447\u0448\u0435\u043d": [60, 74, 75, 85, 86, 90], "\u043c\u043e\u0449\u043d": [60, 85, 86, 90], "\u0441\u043e\u0432\u0435\u0442\u043e\u0432\u0430": [60, 83, 90], "\u043f\u043e\u0439\u043c": [60, 90], "\u0441\u043e\u0441\u0442\u0430\u0432\u044c\u0442": [60, 90], "\u043e\u0433\u043b\u044f\u043d": [60, 90], "polya": [60, 62, 90], "conquer": [60, 86, 90], "edsger": [60, 90, 92], "dijkstra": [60, 74, 90, 92], "pointed": [60, 74, 76, 90], "skull": [60, 73, 74, 90, 92], "applies": [60, 77, 90, 100], "areas": [60, 62, 90, 100], "individually": [60, 90], "iterate": [60, 62, 77, 86, 90], "refinement": [60, 62, 65, 90], "devise": [60, 62, 90], "2d": [60, 75, 82, 90], "ed": [60, 75, 90], "nj": [60, 75, 90], "press": [60, 74, 75, 82, 88, 90], "\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u043a": [60, 73, 74, 77, 90], "\u0442\u043e\u0440\u0433\u043e\u0432": [60, 73, 74, 77, 90], "\u0434\u043e\u043c": [60, 73, 74, 77, 90], "spiral": [61, 65, 129], "cyclic": 62, "prototyping": [62, 65], "repeatedly": 62, "refined": [62, 86], "ronald": [62, 65, 82, 85], "graham": [62, 65, 82, 85], "donald": [62, 65, 82, 85, 88], "knuth": [62, 65, 82, 85], "oren": [62, 65, 82, 85], "patashnik": [62, 65, 82, 85], "\u0432\u0445\u043e\u0434": [62, 82], "final": [62, 75, 77, 86, 100], "subset": [62, 65, 74], "fluid": 62, "firm": [62, 82, 95], "clarify": [62, 65], "shift": [62, 65, 75], "dividing": [62, 74, 90], "ten": [62, 65, 73, 74, 76, 86], "expecting": [62, 72, 85], "closely": [62, 75], "regardless": [62, 86], "regularly": 62, "agilealliance": 62, "variation": 63, "developmental": [63, 77], "proposes": [63, 86], "protection": 63, "occurring": [63, 74], "traits": 64, "fashion": 64, "observed": 64, "virtually": [64, 74], "encountered": 64, "noticeably": 64, "absent": 64, "strong": [64, 75, 85, 86], "maksimchuk": [64, 82], "engle": [64, 82], "bobbi": [64, 82], "ph": [64, 68, 82], "jim": [64, 82, 85, 86], "conallen": [64, 82], "kelli": [64, 82], "houston": [64, 82], "\u043e\u0442\u043b\u0430\u0436": 64, "4cio": [64, 82], "sebok": [64, 75, 82], "mellarius": [64, 82, 92], "\u0441\u0430\u043c\u043e\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d": [64, 82, 86], "quick": [64, 74, 76], "itabok": [64, 82], "incose": [64, 82], "pmbok": [64, 82, 86], "pmi": [64, 82], "15289": [64, 82], "24765": [64, 82], "vocabulary": [64, 82], "9000": [64, 82], "2005": [64, 82, 83], "33001": [64, 82], "\u0433\u043e\u0441\u0442": 64, "\u0440": [64, 82], "\u0438\u0441": [64, 82], "\u043c\u044d\u043a": [64, 82], "2010": [64, 76, 82, 83, 88], "\u0438\u043d\u0436\u0435\u043d\u0435\u0440": [64, 73, 82, 86], "57193": [64, 82], "2016": [64, 80, 82, 88, 100], "perplexed": [64, 82], "barry": [64, 82], "boehm": [64, 82], "turner": [64, 82], "\u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 64, "\u0430\u0441\u043f\u0435\u043a\u0442": [64, 74, 77, 82, 90, 94, 100], "pediction": 64, "disciplined": [64, 82, 85], "scaled": [64, 76], "situations": [64, 76], "harmonized": 64, "identical": [64, 85], "specialization": 64, "products": [64, 65, 85], "crystal": [65, 76], "balls": [65, 74, 85, 90], "predict": [65, 70], "competition": 65, "announcement": 65, "unanticipated": [65, 74], "crop": [65, 74], "direction": [65, 70, 73, 86], "furthermore": 65, "uncertain": [65, 76], "guessing": [65, 68], "spending": [65, 74, 86], "eight": 65, "fantasy": 65, "constructed": 65, "\u0433\u043b\u0430\u0437": [65, 74, 86, 88, 95], "\u0431\u043e": [65, 83, 85, 90, 93], "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0432\u0435\u0441": 65, "\u043d\u0430\u0443\u0447\u043d": [65, 75, 89, 92], "\u0442\u044b\u043a": 65, "\u0433\u0438\u043f\u043e\u0442\u0435\u0437": [65, 74], "\u0438\u043d\u0441\u043f\u0435\u043a\u0442\u0438\u0440\u0443": 65, "\u0430\u0434\u0430\u043f\u0442\u0438\u0440\u0443": 65, "\u0442\u043e\u043c\u0430\u0441": 65, "\u044d\u0434\u0438\u0441\u043e\u043d": 65, "\u0442\u0435\u0440\u043f\u0435\u043b": 65, "\u043f\u043e\u0440\u0430\u0436\u0435\u043d": [65, 83], "\u043d\u0430\u0448\u0435\u043b": [65, 85], "000": [65, 74, 85], "\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d": [65, 85, 86], "\u0438\u043d\u043a\u0440\u0435\u043c": 65, "\u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u0442": 65, "\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d": 65, "\u0438\u0441\u0447\u0435\u0437\u0430": 65, "\u043f\u043e\u043d\u0438\u0436\u0430": 65, "\u0441\u043c\u0435\u0449\u0430": 65, "irreversible": 65, "acquire": [65, 85], "declines": 65, "likelihood": 65, "increasing": [65, 70], "certainty": [65, 100], "\u043d\u0435\u043e\u0442\u044a\u0435\u043c\u043b\u0435\u043c": 65, "\u0433\u0438\u0431\u0440\u0438\u0434\u043d": 65, "\u0441\u043e\u043e\u0442\u043d\u043e\u0448\u0435\u043d": [65, 74, 85], "\u0441\u0438\u0442\u0443\u0430\u0442\u0438\u0432\u043d": 65, "builders": 65, "extraction": 65, "assert": [65, 85], "exact": [65, 85], "promising": 65, "technological": 65, "attacks": 65, "accidents": 65, "deliverable": 65, "vast": [65, 74], "majority": [65, 74], "glibly": 65, "\u0437\u0430\u0440\u0430\u043d": [65, 70, 74], "\u043a\u0430\u0440\u0442\u0438\u043d\u043a": [65, 74], "\u0432\u0435\u0440\u0448\u0438\u043d": [65, 73, 77], "\u0432\u0432\u0435\u0440\u0445": [65, 77, 83], "fixes": 65, "varies": [65, 86], "friend": [65, 76], "foe": [65, 76], "alone": [65, 85], "sufficiently": 65, "needing": [65, 74], "tbs": 65, "tbr": 65, "clauses": 65, "tbx": 65, "designations": 65, "timeframe": 65, "incompletely": 65, "\u043d\u0435\u043f\u043e\u043b\u043d\u043e\u0442": 65, "srs": 65, "revisions": 65, "foreseen": 65, "inevitable": 65, "std": 65, "830": 65, "1998": [65, 75], "\u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a": [65, 102], "\u043d\u0438\u043a\u043e": 65, "annex": 65, "mode": [65, 73, 85, 86, 95], "iterating": [65, 76], "pivoting": 65, "till": 65, "verifiably": 65, "pilot": 65, "unsound": 65, "approving": 65, "roadmaps": 65, "overinvesting": 65, "projected": 65, "analytics": 65, "surveys": 65, "capability": [65, 76, 82], "chunks": [65, 85], "delta": 65, "adoption": 65, "conversion": [65, 82], "assessing": 65, "upfront": [65, 76], "incurring": 65, "approve": 65, "roadmap": [65, 82], "miss": 65, "sriram": 65, "narayan": 65, "rushing": 65, "repay": 65, "acquired": 65, "pendulum": [65, 76], "swung": [65, 76], "lduf": [65, 76], "enuf": [65, 76], "strawman": [65, 76], "retrofitting": [66, 70], "9th": [66, 82], "roger": [66, 82], "pressman": [66, 82], "bruce": [66, 82], "swebok": [66, 82], "draft": [66, 82], "delay": [66, 70], "repair": [66, 70], "removing": [66, 70], "quadrant": [66, 70, 74, 85], "stamina": [66, 74], "hypothesis": [66, 74], "\u0442\u0435\u043f\u043b\u044f\u043a": [66, 70, 75, 82, 94], "\u0442\u0438": [66, 75], "\u043c\u0438\u043d\u0443\u0442\u043d": 66, "sig": 66, "sqale": 66, "identification": 66, "strecansky": 66, "stanislav": [66, 100, 102], "chren": 66, "bruno": 66, "rossi": 66, "\u043b\u0435\u0434\u043e\u043a\u043e\u043b": [66, 73, 74, 88, 91, 93, 95, 138], "\u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442": [68, 74, 90, 92, 94], "\u043f\u0440\u043e\u0434\u0443\u043c\u044b\u0432\u0430": 68, "\u0440\u044f\u0434\u043e\u0432": 68, "\u0443\u043c\u043d": [68, 70, 92], "\u043e\u0432\u043b\u0430\u0434\u0435\u0432\u0430": 68, "\u043f\u043e\u043c\u0435\u043d\u044f": 68, "\u0443\u043c\u0435\u043d": [68, 73, 82, 83], "\u0434\u0430\u043b\u044c\u043d\u043e\u0432\u0438\u0434\u043d": [68, 73], "\u0442\u0435\u0441\u043d": [68, 85, 86], "hardest": 68, "\u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u043d": [68, 74, 90], "\u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430": [68, 82], "\u0447\u0430\u0441\u0442\u0435\u043d\u044c\u043a": [68, 82], "\u0441\u0435\u0440\u044c\u0435\u0437\u043d": [68, 75], "\u043c\u0435\u0448\u0430": [68, 75, 85, 100], "contribute": 68, "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0441\u043a": [68, 74], "\u0438\u043d\u0441\u0442\u0438\u043d\u043a\u0442": 68, "\u043f\u0440\u0438\u0432\u044b\u043a\u043b": [68, 85], "\u0441\u0447\u0430\u0441\u0442\u043b\u0438\u0432": [68, 88], "\u0443\u0432\u0435\u0441\u0442": 68, "\u0440\u0430\u0437\u043c\u044b\u0448\u043b\u0435\u043d": [68, 72, 74, 85, 86], "\u043e\u0442\u0443\u0447": 68, "\u043d\u0435\u043f\u0440\u0438\u044f\u0442\u043d": 68, "\u0432\u0437\u0430\u0439\u043c": 68, "\u0431\u0430\u0431\u0443\u0448\u043a": 68, "instincts": 68, "habit": [68, 73], "anticipating": 68, "sideways": 68, "fortunately": 68, "folks": 68, "unlearn": 68, "grandmother": 68, "smarter": [68, 85], "lazy": [68, 82], "irresponsible": 68, "lets": [68, 72, 73, 85], "premature": [68, 74], "suboptimal": 68, "mental": [68, 74, 90], "craftsmanship": [68, 73, 74, 82, 85], "\u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430": [70, 72, 85, 89], "\u043f\u043e\u0447\u0442": [70, 72, 73, 75, 85], "\u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d": 70, "\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u043d": [70, 86], "\u043d\u0435\u043f\u0440\u0435\u043e\u0434\u043e\u043b\u0438\u043c": 70, "\u0432\u043f\u0440\u043e\u043a": 70, "\u043d\u0435\u0432\u043e\u0441\u0442\u0440\u0435\u0431\u043e\u0432\u0430": 70, "\u043f\u0440\u0438\u0447\u0438\u043d\u044f": 70, "\u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d": 70, "\u0442\u0438\u043c\u043b\u0438\u0434": 70, "\u043e\u0431\u0440\u0430\u0437\u043d": 70, "\u043f\u043e\u043b\u043a\u043e\u0432\u043e\u0434\u0446": 70, "\u0433\u0440\u043e\u0448": 70, "\u0441\u043e\u043b\u0434\u0430\u0442": 70, "\u0443\u043c\u0435\u044e\u0442": 70, "\u0441\u0442\u0440\u0435\u043b\u044f": 70, "\u0432\u044b\u0440\u043e\u0441\u043b": 70, "emergent": [70, 76, 85], "\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433": [70, 72, 74, 75, 85], "\u0438\u0441\u043a\u0430": [70, 75, 82], "\u0434\u043e\u0440\u043e\u0433\u043e\u0441\u0442\u043e\u044f": 70, "\u0432\u044b\u0434\u0435\u0440\u0436\u0430": [70, 83], "\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u0442": [70, 85], "\u043f\u043b\u0430\u0442": 70, "\u043f\u0435\u0440\u0435\u043d\u0430\u0446\u0435\u043b\u0438\u0432\u0430": 70, "\u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430": [70, 85], "\u0434\u043e\u0441\u0442\u0438\u0447": [70, 74, 100], "\u043d\u0430\u0443\u0447": [70, 83], "\u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430": [70, 90], "\u043f\u043e\u0434\u0434\u0430": 70, "\u043f\u0435\u0440\u0435\u0441\u0442\u0430": [70, 85], "\u0443\u0432\u0435\u0440\u0435\u043d": [70, 85], "foresee": 70, "flex": 70, "forced": [70, 77], "designs": [70, 77, 85, 86], "stressful": [70, 85], "\u043b\u0430\u043a\u043c\u0443\u0441\u043e\u0432": 70, "\u0431\u0443\u043c\u0430\u0436\u043a": 70, "\u043b\u0438\u043d\u0435\u0439\u043d": [70, 74, 86], "\u0443\u0441\u043b\u043e\u0436\u0435\u043d": 70, "\u0438\u0437\u043b\u0438\u0448\u043d": [70, 85], "\u043a\u043e\u0441\u0432\u0435\u043d": [70, 72], "\u043e\u0434\u0438\u043d\u043e\u0447\u043a": [70, 74, 92], "\u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d": [70, 100], "npv": 70, "\u043a\u0430\u043a\u043e\u0432": 70, "\u0433\u043e\u0442": [70, 83, 95], "\u0437\u0430\u043f\u043b\u0430\u0442": 70, "\u0441\u043e\u0431\u0435\u0440\u0435\u0442": 70, "\u043f\u043e\u0434\u043e\u0436\u0434\u0435\u0442": 70, "\u0441\u0440\u0435\u0434\u043d": [70, 76, 85, 86], "\u043f\u0440\u043e\u0446\u0435\u043d\u0442\u043d": 70, "\u0441\u0442\u0430\u0432\u043a": 70, "\u043e\u043a\u043e\u043b": [70, 85, 93, 100], "\u0433\u043e\u0434\u043e\u0432": 70, "\u0443\u0447\u0435\u0442": [70, 82], "\u0438\u0441\u043a\u043e\u043c": 70, "87": 70, "\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d": [70, 85], "\u0433\u043e\u0434\u0438\u0447\u043d": 70, "\u043e\u0436\u0438\u0434\u0430\u043d": 70, "\u043e\u0436\u0438\u0434": [70, 72, 85], "\u0438\u043d\u0432\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430": 70, "\u0434\u0435\u043d\u044c\u0433": 70, "nvp": 70, "\u0437\u0430\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": 70, "\u043f\u0440\u0438\u0431\u044b\u043b": 70, "\u0441\u044d\u043a\u043e\u043d\u043e\u043c": [70, 74, 76, 85], "\u0438\u0437\u0431\u0430\u0432": [70, 82, 85], "\u043d\u0435\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d": 70, "merrily": 70, "wasn": [70, 85, 86], "vary": [70, 72, 73, 86], "calculator": 70, "cranks": 70, "investing": 70, "uncertainy": 70, "zilch": 70, "worthless": 70, "jargon": [70, 76], "\u043f\u043b\u044e\u0441": [70, 85], "expending": 70, "piracy": 70, "pricing": 70, "sales": [70, 100], "weather": 70, "storm": 70, "presumptive": 70, "insurance": 70, "imposes": 70, "debug": 70, "delayed": 70, "difficulties": 70, "\u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d": 70, "\u0442\u0440\u0438\u0430\u0436": 70, "podcast": 70, "talks": [70, 76], "\u044d\u043f\u0438\u0437\u043e\u0434": [70, 92], "\u0430\u043b\u0435\u043a\u0441": [70, 92], "\u0446\u044b\u0431\u0443\u043b\u044c\u043d\u0438\u043a": 70, "everyday": 70, "turbocharge": 70, "anna": 70, "radzikowska": 70, "anderson": 70, "agreements": 70, "\u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d": [70, 90], "\u043d\u0430\u0439\u0434\u0435\u0442": [70, 77], "\u0440\u043e\u0432\u043d": [70, 85, 90], "\u0441\u0442\u0435\u0440\u0435\u0442": 70, "\u043f\u043e\u0440\u043e\u0448\u043e\u043a": 70, "\u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442": 70, "\u043f\u0440\u0438\u043d\u044f": [70, 72, 83, 85, 92], "\u043e\u043a\u0430\u0436": 70, "\u0438\u043d\u0435\u0440\u0446": [70, 83], "\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c": 70, "\u043f\u0440\u043e\u0432\u0438\u0434\u0435\u0446": 70, "\u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430": [70, 73, 77], "\u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430": [70, 74, 82], "\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430": 70, "probability": 70, "knowing": [70, 85], "conclude": 70, "concludes": 70, "troubles": 70, "thereof": 70, "inertia": 70, "guesser": 70, "\u043f\u0440\u0438\u043d\u043e\u0441": 72, "\u0437\u043b\u043e\u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f": [72, 92], "\u043c\u043e\u043b\u043e\u0442\u043a": 72, "\u0433\u0432\u043e\u0437\u0434": 72, "\u0437\u0430\u0431": 72, "\u043f\u0430\u043b\u044c\u0446": [72, 85], "\u043e\u0442\u0431": 72, "\u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430": [72, 75, 86], "promotes": [72, 73, 86], "keeping": [72, 73, 74, 85, 86, 90], "independently": [72, 73, 86], "\u043b\u0435\u043a\u0430\u0440\u0441\u0442\u0432": 72, "\u0445\u0443\u0436": [72, 75, 83, 86], "\u0431\u043e\u043b\u0435\u0437\u043d": 72, "\u043e\u043f\u0440\u0430\u0432\u0434\u044b\u0432\u0430": 72, "\u0432\u043d\u043e": 72, "\u043f\u0440\u0438\u0432\u043d\u043e\u0441\u0438\u043c": 72, "\u0437\u043b\u043e\u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d": 72, "\u043f\u0435\u0440\u0435\u0443\u0441\u043b\u043e\u0436\u0435\u043d": 72, "\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0437\u0430\u0446": [72, 82, 92], "\u0432\u044b\u0434\u0443\u043c\u044b\u0432\u0430": 72, "\u043d\u0435\u0437\u043d\u0430\u043d": 72, "\u043d\u0435\u043e\u0441\u043e\u0437\u043d\u0430": [72, 85], "\u0443\u043b\u0443\u0447\u0448": [72, 74, 85, 86], "\u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430": 72, "\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440": [72, 85, 86], "\u0432\u043f\u0438\u0441\u044b\u0432\u0430": [72, 85], "\u044d\u043d\u0435\u0440\u0433": [72, 85, 90], "\u043c\u043d\u043e": [72, 74, 85], "\u043f\u0440\u043e\u0448\u0435\u0441\u0442\u0432": [72, 76, 85], "\u043d\u0435\u0434\u0435\u043b": [72, 74, 85], "\u0441\u043b\u0435\u0442\u0430": [72, 85], "\u0440\u0430\u0437\u043c\u044b\u0448\u043b\u044f": [72, 85], "\u043f\u0440\u0438\u0434": [72, 85], "\u0440\u043e\u0431\u0435\u0440\u0442": [72, 85], "\u043c\u0430\u0440\u0442\u0438\u043d": [72, 75, 85, 92], "\u0443\u0434\u0438\u0432\u043b\u044f": [72, 85], "\u043a\u0430\u0436\u0443\u0442": [72, 85], "\u0434\u043e\u0432\u0435\u0440\u044f": [72, 85], "\u043f\u0440\u0435\u0434\u0447\u0443\u0432\u0441\u0442\u0432": [72, 85], "\u043e\u0444\u043e\u0440\u043c": [72, 85], "hope": [72, 85], "rote": [72, 75, 85], "redebating": [72, 85], "exception": [72, 85], "creativity": [72, 85], "stopping": [72, 85], "ripping": [72, 85], "fingertips": [72, 85], "pause": [72, 85], "bigger": [72, 73, 77, 85], "variant": [72, 85], "drive": [72, 85], "surprising": [72, 85, 86], "sensible": [72, 85], "\u0430\u043d\u0434\u0436\u0430": [72, 85], "\u043f\u0435\u0447\u0430": [72, 86], "heinemeier": 72, "hansson": 72, "\u043f\u0440\u043e\u0447\u0438\u0442\u0430": [72, 74, 82], "rails": 72, "ror": 72, "\u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442": 72, "\u0444\u043e\u043a\u0443\u0441": [72, 74, 76], "\u043f\u0440\u0438\u0440\u043e\u0441\u0442": [72, 85, 94], "\u0432\u0438\u0440\u0443\u0441\u043d": 72, "\u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d": 72, "\u0442\u0438\u043f\u043e\u0432": 72, "\u043f\u043e\u0443\u0447\u0438\u0442\u0435\u043b\u044c\u043d": 72, "\u0441\u0435\u0440\u0438\u0430": [72, 85], "badri": 72, "janakiraman": 72, "\u043e\u0447\u0435\u0432\u0438\u0434": 72, "mundane": 72, "repetitive": [72, 74], "truly": [72, 74], "unique": [72, 76, 100], "structured": [72, 74, 75, 76, 82, 86], "readers": 72, "commonality": 72, "verify": [72, 85], "\u043f\u0435\u0440\u0444\u0435\u043a\u0446\u0438\u043e\u043d\u0438\u0437\u043c": 73, "overengineering": 73, "imperative": [73, 76, 90], "\u043f\u0440\u0438\u0432\u043d\u0435\u0441\u0435\u043d": 73, "\u0433\u0435\u0440\u043e\u0438\u0447\u0435\u0441\u043a": 73, "\u0430\u0432\u0438\u0430\u0446\u0438\u043e\u043d": 73, "\u043f\u043e\u0436\u0430\u043b": [73, 88], "\u0441\u0430\u043c\u043e\u043b\u0435\u0442": 73, "62": 73, "skyships": 73, "\u043e\u0433\u0440\u043e\u043c\u043d": [73, 75, 82, 95], "\u043c\u0435\u0436\u043a\u043e\u043d\u0442\u0438\u043d\u0435\u043d\u0442\u0430\u043b\u044c\u043d": 73, "\u043b\u0430\u0439\u043d\u0435\u0440": 73, "\u043c\u0443\u0441\u043a\u0443\u043b\u044c\u043d": 73, "\u043f\u0438\u043b\u043e\u0442": [73, 86], "\u0431\u0435\u0437\u0431\u0443\u0441\u0442\u0435\u0440\u043d": 73, "\u0443\u0441\u0438\u043b\u0438\u0442\u0435\u043b": 73, "\u043f\u0440\u0438\u0432\u043d\u0435\u0441\u0442": 73, "\u0437\u0430\u0434\u043d": [73, 92], "\u0448\u0442\u0430\u043d\u0433": [73, 90], "kiss": [73, 82], "\u043f\u0440\u0435\u0434\u043a\u0440\u044b\u043b\u043a": 73, "\u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a": 73, "\u0437\u0443\u0431": 73, "\u043f\u0435\u0440\u0435\u0434\u043d": 73, "\u043a\u0440\u043e\u043c\u043a": 73, "\u043a\u0440\u044b\u043b": [73, 92], "\u044f\u0440\u043a": [73, 92], "\u0432\u043e\u0431\u0440\u0430": 73, "\u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 73, "\u043d\u0430\u0440\u0430\u0431\u043e\u0442\u043a": 73, "\u0438\u0434\u0435\u043e\u043b\u043e\u0433": [73, 82], "\u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d": 73, "\u043c\u0430\u0433\u0438\u0441\u0442\u0440\u0430\u043b\u044c\u043d": 73, "\u043f\u0435\u0440\u0435\u0432\u043e\u0437\u043e\u043a": 73, "\u0441\u0441\u0441\u0440": 73, "\u0438\u043b\u044c\u044e\u0448\u0438\u043d": 73, "\u043f\u0430\u0441\u0441\u0430\u0436\u0438\u0440\u0441\u043a": 73, "\u0442\u0440\u0430\u043d\u0441\u043a\u043e\u043d\u0442\u0438\u043d\u0435\u043d\u0442\u0430\u043b\u044c\u043d": 73, "\u0432\u044b\u0448\u0435\u0434\u0448": 73, "\u0432\u043e\u0437\u0434\u0443\u0448\u043d": [73, 86], "1967": 73, "62\u043c": 73, "\u0441\u0442\u0430\u0432\u0448": [73, 83], "\u0444\u043b\u0430\u0433\u043c\u0430\u043d": 73, "\u0430\u044d\u0440\u043e\u0444\u043b\u043e\u0442": 73, "\u043f\u0440\u0438\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d": 73, "\u043f\u0440\u0438\u0441\u0443\u0449": 73, "\u0443\u043f\u043e\u0440\u0441\u0442\u0432": 73, "\u043d\u0430\u0434\u0435\u0436\u043d": 73, "\u0441\u043e\u0447\u0435\u0442\u0430\u043d": [73, 82, 85], "\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0447\u043d": [73, 76], "\u0431\u043e\u0435\u0432": [73, 83, 93], "\u0432\u043e\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u043d": 73, "\u0433\u0435\u043d\u0435\u0440\u0430\u043b\u044c\u043d": 73, "\u0430\u043a\u0430\u0434\u0435\u043c\u0438\u043a": 73, "\u044f\u043a\u043e\u0432\u043b": 73, "\u043e\u0442\u043c\u0435\u0447\u0430": 73, "\u043c\u0430\u0441\u0442\u0435\u0440": [73, 93], "\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u043e\u043d": 73, "\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u043c": 73, "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0441\u043a": 73, "\u0431\u044e\u0440": 73, "\u0432\u043e\u043f\u043b\u043e\u0449": 73, "\u0442\u0432\u043e\u0440\u0446": 73, "\u043c\u0430\u0448\u0438\u043d": [73, 82], "\u0441\u044b\u0433\u0440\u0430": 73, "\u0432\u043e\u0435\u043d": [73, 83], "\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0441\u043a": 73, "\u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442": 73, "\u0437\u0430\u043d\u044f": [73, 83], "\u0434\u043e\u0441\u0442\u043e\u0439\u043d": [73, 82, 83], "\u043e\u0442\u0435\u0447\u0435\u0441\u0442\u0432\u0435\u043d": 73, "\u0430\u0432\u0438\u0430\u0446": 73, "\u043f\u043b\u0430\u043d\u0435\u0440": 73, "\u043f\u043e\u043b\u0435\u0442\u043d": 73, "\u043a\u0433": [73, 83], "160": 73, "\u0438\u0441\u043f\u044b\u0442\u0430": 73, "\u043f\u043e\u043b\u0435\u0442": [73, 86, 92], "\u0434\u0435\u0441\u044f\u0442\u043a": [73, 82], "\u043d\u0435\u043f\u0440\u0435\u0432\u0437\u043e\u0439\u0434\u0435\u043d": 73, "\u043b\u0435\u0442\u043d": 73, "\u0431\u0438\u043e\u0433\u0440\u0430\u0444": [73, 83], "\u043f\u0430": 73, "\u043e\u0430\u043a": 73, "\u043f\u043e\u0441\u043b\u0443\u0448": 73, "\u043e\u0440\u0443\u0436\u0435\u0439\u043d": 73, "\u0430\u0432\u0442\u043e\u043c\u0430\u0442": 73, "\u043a\u0430\u043b\u0430\u0448\u043d\u0438\u043a": 73, "\u0436\u0443\u0440\u043d\u0430\u043b\u0438\u0441\u0442": 73, "\u0433\u0430\u0437\u0435\u0442": 73, "metro": 73, "\u043c\u043e\u0441\u043a\u0432": 73, "\u043f\u043e\u0441\u043b\u0443\u0448\u0430": 73, "\u0435\u0444\u0438\u043c\u043e\u0432\u0438\u0447": 73, "\u0440\u0435\u043f\u0438\u043d": 73, "ultimate": 73, "sophistication": 73, "leonardo": 73, "da": 73, "vinci": 73, "\u0438\u0441\u0447\u0438\u0441\u043b\u044f": 73, "\u0441\u0438\u043c\u0432\u043e\u043b": [73, 74, 85], "\u043f\u043e\u043f\u0440\u043e\u0431": [73, 86], "echo": 73, "perl": 73, "\u0432\u0437\u0434\u0443\u043c\u0430": 73, "rm": 73, "rf": 73, "\u0430\u0431\u0437\u0430\u0446": 73, "battle": [73, 90], "elegance": [73, 85], "unpopular": 73, "appreciated": 73, "prerequisite": 73, "virtue": 73, "appreciate": 73, "sells": 73, "1984": 73, "ewd896": 73, "\u043e\u0441\u043e\u0437\u043d\u0430": [73, 82, 88, 92, 100], "\u0447\u0435\u0440\u0435\u043f": [73, 92], "\u0441\u043a\u0440\u043e\u043c\u043d\u043e\u0441\u0442": 73, "competent": [73, 82, 92, 95], "strictly": [73, 92], "humility": [73, 92], "1972": [73, 74, 86, 90, 92], "\u0438\u043c\u043f\u0435\u0440\u0430\u0442\u0438\u0432": [73, 74, 90], "\u043f\u043e\u0434\u0430\u0432\u043b\u0435\u043d": [73, 74, 90], "\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d": [73, 74, 82, 90], "greatly": [73, 74, 90], "aided": [73, 74, 90], "brain": [73, 74, 85, 88, 89, 90], "accidental": [73, 74, 75, 90], "proliferating": [73, 74, 90], "needlessly": [73, 74, 90], "disciplines": 73, "beneath": 73, "understands": 73, "coherent": 73, "reflects": 73, "perfection": 73, "afford": [73, 77, 82], "remains": [73, 76, 86], "toolbox": 73, "fewer": [73, 74, 85, 90], "handful": 73, "mastery": [73, 82], "annals": 73, "owed": 73, "lines": [73, 74, 75, 85, 86, 94], "gotten": 73, "complicated": [73, 74, 75, 90, 100], "taste": [73, 76], "rolling": 73, "travel": 73, "light": [73, 76], "intellectual": 73, "nomads": 73, "tents": 73, "herd": 73, "anticipated": 73, "hot": 73, "climate": 73, "shifts": 73, "traveling": 73, "meetings": [73, 88], "lengthy": 73, "fulfill": 73, "refine": [73, 77, 85, 86], "impressed": 73, "dissatisfied": 73, "habits": [73, 82, 88, 95], "proportion": 73, "stop": [73, 76], "struggling": 73, "defect": [73, 74, 85], "improved": 73, "hours": [73, 74, 82, 86, 95], "dedicated": [73, 86], "lots": [73, 86], "intervention": 73, "hour": [73, 74, 82, 95], "steady": 73, "60": 73, "seventy": 73, "twenty": [73, 74], "66": 73, "minor": 73, "stopped": [73, 85], "digging": 73, "climb": 73, "eliminating": [73, 74], "excess": 73, "chip": [73, 88], "brighten": 73, "corner": 73, "objection": 73, "cleanup": 73, "wasting": 73, "interruptions": 73, "cleaning": 73, "saying": [73, 80], "vested": 73, "abandon": 73, "coder": [73, 74, 82, 85], "conduct": [73, 85], "destination": 73, "enquiry": 73, "frozen": 73, "straightforward": 73, "ease": [73, 85, 86], "articulated": 73, "optimal": 73, "tempt": 73, "messy": 73, "unprincipled": 73, "inventor": 73, "author": [73, 74, 76, 85, 88], "eventlet": 73, "readability": [73, 74], "excessively": 73, "clever": 73, "\u0441\u0443\u043f\u0435\u0440\u0433\u0435\u043d": 73, "\u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0435\u0442": 73, "\u0433\u0435\u043d": 73, "super": 73, "genius": 73, "mistake": [73, 75], "\u043f\u0440\u0438\u0432\u044f\u0437\u0430": 73, "\u0441\u0442\u043e\u043b\u0431": 73, "\u0437\u0430\u0431\u043b\u0443\u0434": 73, "\u0434\u0443\u0445\u043e\u0432\u043d": 73, "\u043b\u044e\u0441": 73, "\u043c\u0430\u043b\u043e\u0440": 73, "\u043d\u0435\u043a\u043e\u0433\u0434": 74, "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u043e\u0432\u0430\u043d": [74, 75, 85], "91": [74, 85], "\u0431\u043e\u0440\u044c\u0431": [74, 83, 85, 88, 92], "\u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440": [74, 85], "\u0443\u0445\u043e\u0434": [74, 83], "\u0434\u043e\u0432\u043e\u0434": [74, 75], "\u0437\u0430\u043f": 74, "\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 74, "90": [74, 76, 95], "\u043d\u0430\u0436\u0430\u0442": 74, "\u043a\u043b\u0430\u0432\u0438\u0448": 74, "\u043f\u0440\u043e\u0440\u0430\u0431\u043e\u0442\u0430": 74, "\u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442": [74, 92, 100], "\u0432\u0435": [74, 82, 85, 92], "\u0441\u043b\u043e\u0432\u043d": 74, "\u0443\u0441\u043a\u043e\u0440\u0435\u043d": [74, 85], "\u043a\u0438\u043d": 74, "\u043f\u043e\u0442\u0440\u044f\u0441\u0430": 74, "\u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a": 74, "\u0431\u043e\u0431": [74, 75], "\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446": 74, "\u0441\u043d\u043e\u0432": 74, "\u0441\u0442\u0438\u0440\u0430": 74, "\u0437\u0430\u043d\u043e\u0432": [74, 77], "\u043f\u043e\u043b\u043e\u0432\u0438\u043d": [74, 92], "\u043f\u0440\u043e\u043a\u0440\u0443\u0447\u0438\u0432\u0430": 74, "\u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430": [74, 86], "\u0441\u0442\u0435\u0440\u0442": 74, "\u0441\u0443\u0431\u043a\u043b\u0430\u0441\u0441": 74, "\u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f": 74, "\u0441\u0442\u043e\u043b": [74, 75, 94], "\u0443\u0439\u0442": 74, "\u043e\u043a\u0440\u0443\u0436\u0430": [74, 83, 100], "\u0441\u043e\u0431\u0438\u0440\u0430": [74, 86, 92, 93], "\u0441\u043f\u0440\u0430\u0432": [74, 83, 85, 94, 100], "\u043f\u043e\u0437\u0430\u0431\u043e\u0442\u044c\u0442": 74, "80s": 74, "track": 74, "keystroke": 74, "movie": 74, "fascinating": 74, "playback": 74, "scrolling": 74, "navigating": 74, "enters": 74, "scrolls": 74, "pauses": 74, "check": [74, 85], "initialization": 74, "begins": [74, 77], "ooops": 74, "erasing": 74, "typed": 74, "erases": 74, "erased": 74, "pops": 74, "subclass": 74, "overridden": 74, "drift": 74, "ratio": 74, "escape": 74, "surrounding": 74, "\u043c\u0430\u0442\u0432\u0435": [74, 85], "constructing": 74, "deficiencies": 74, "hoare": 74, "\u043e\u0445\u0432\u0430\u0442": [74, 90, 92, 94], "\u0432\u0441\u044e": [74, 77, 83, 90], "\u0441\u0432\u043e\u0435\u043e\u0431\u0440\u0430\u0437\u043d": [74, 90], "\u0443\u043c\u0441\u0442\u0432\u0435\u043d": [74, 85, 90], "\u0436\u043e\u043d\u0433\u043b\u0438\u0440\u043e\u0432\u0430\u043d": [74, 90], "\u0443\u0440\u043e\u043d": [74, 90], "\u0434\u043e\u043f\u0443\u0441\u0442": [74, 85, 86, 90, 100], "\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d": [74, 90], "\u043f\u043e\u0434\u0441\u0438\u0441\u0442\u0435\u043c": [74, 90], "\u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c": [74, 85, 86, 90, 93, 100], "\u0430\u0433\u0440\u0435\u0433\u0430\u0446": [74, 90], "\u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0442": [74, 90], "\u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432": [74, 77, 82, 90], "cram": [74, 90], "skulls": [74, 90], "organize": [74, 90], "juggling": [74, 90], "air": [74, 85, 90], "drop": [74, 76, 90], "comprehending": [74, 90], "workload": [74, 75, 90], "bottom": [74, 78, 90, 133], "compensate": [74, 90], "limitations": [74, 90], "\u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430": [74, 90], "\u0434\u0438\u0441\u043a\u0440\u0435\u0442\u043d": [74, 90], "miller": [74, 90], "1956": [74, 90], "\u0441\u0435\u043c": [74, 82, 85, 86, 90, 92], "\u043f\u043e\u0434\u0443\u043c\u0430": [74, 76, 90], "riel": [74, 90], "decomposed": [74, 86, 90], "magical": [74, 86, 90], "plus": [74, 90], "minus": [74, 90], "psychological": [74, 85, 90], "63": [74, 90], "97": [74, 90], "arthur": [74, 82, 90], "heuristics": [74, 82, 90], "ma": [74, 90], "\u0438\u0437\u0440\u0435\u0447\u0435\u043d": 74, "ninio": 74, "extinction": 74, "illusion": [74, 86], "dots": 74, "stevens": 74, "variations": 74, "hermann": 74, "grid": 74, "29": [74, 100], "1209": 74, "1217": 74, "akiyoshi": 74, "kitaoka": 74, "\u043c\u0438\u043b\u043b\u0435\u0440": [74, 85], "\u0440\u0435\u0446\u0435\u043f\u0442\u043e\u0440": 74, "\u0441\u0435\u0442\u0447\u0430\u0442\u043a": 74, "\u043d\u0435\u0441\u043f\u043e\u0441\u043e\u0431\u043d": 74, "\u043f\u0435\u0440\u0435\u043d\u043e\u0441\u043d": 74, "eye": 74, "receptors": 74, "stimulated": 74, "influenced": [74, 75], "neighboring": 74, "receptor": 74, "perceiving": 74, "stimulation": 74, "nearby": 74, "\u0438\u0437\u0431\u0438\u0440\u0430\u0442\u0435\u043b\u044c\u043d": 74, "\u0432\u043e\u0441\u043f\u0440\u0438\u044f\u0442": [74, 83, 88, 89], "\u043f\u0435\u0440\u0438\u0444\u0435\u0440\u0438\u0439\u043d": 74, "\u0432\u0438\u0434\u0435\u0442": [74, 90], "\u0441\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430": [74, 75, 76, 85, 86], "\u043e\u043f\u0442\u0438\u0447\u0435\u0441\u043a": 74, "\u0441\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440\u043e\u0432\u0430": [74, 85, 95], "\u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446": [74, 77, 85, 86], "\u043f\u0435\u0440\u0435\u0432\u0435\u0441": 74, "\u0432\u043c\u0435\u0449\u0430": 74, "elucidated": [74, 75], "mid": [74, 75], "70s": [74, 75], "yourdon": [74, 75], "constantine": [74, 75], "cascading": 74, "propensity": 74, "transitively": 74, "skips": 74, "loads": [74, 86], "decomposition": [74, 77, 82, 85], "monolith": [74, 75, 76, 82, 86, 89, 93], "micro": [74, 82], "adapted": [74, 76, 85], "blind": 74, "sided": 74, "novel": 74, "article": [74, 76, 82], "coded": 74, "protocol": [74, 82, 85], "navigate": 74, "manure": 74, "pile": 74, "aromatically": 74, "\u043d\u0435\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a": 74, "cheaper": [74, 85], "tradable": 74, "graph": [74, 82], "plots": 74, "imaginary": 74, "stereotypical": 74, "enabler": 74, "perceive": 74, "reduces": [74, 85], "lowers": 74, "sadly": 74, "countless": 74, "talked": 74, "professionalism": 74, "moralistic": 74, "dooming": 74, "annoying": 74, "crufty": 74, "misses": 74, "negative": [74, 86], "crafted": [74, 100], "unusual": 74, "absorb": [74, 86], "maximum": 74, "\u0443\u0434\u043e\u0431\u043e\u0447\u0438\u0442\u0430\u0435\u043c": 74, "\u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d": [74, 86, 100], "\u043e\u0431\u0449\u0430": [74, 86], "\u0441\u043b\u044b\u0448": [74, 85], "\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442": 74, "\u0432\u043f\u0435\u0440\u0435\u0434": [74, 85], "\u0432\u043f\u0438\u0441\u0430": 74, "\u043a\u043e\u0434\u043e\u0432": [74, 82, 83, 88], "\u0441\u0435\u0440": [74, 83, 85], "\u043d\u0430\u0432\u044b\u043a": [74, 83, 95], "\u0430\u0440\u0445\u0435\u043e\u043b\u043e\u0433": 74, "\u0437\u0430\u043c\u0435\u0434\u043b\u044f": [74, 76, 85], "\u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430": [74, 85], "\u043f\u0441\u0435\u0432\u0434\u043e\u0433\u0440\u0430\u0444\u0438\u043a": 74, "\u043e\u043f\u0438\u0440": [74, 77], "\u043c\u043e\u0434\u0443\u043b\u044c\u043d": 74, "\u043f\u043e\u043d\u044f\u0442": [74, 75, 83, 93, 100, 102], "\u043e\u0442\u043b\u0430\u0434\u043a": [74, 85, 86], "\u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430": [74, 75, 88], "\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c": [74, 86], "\u0441\u0442\u043e\u0439\u043a\u043e\u0441\u0442": 74, "\u0441\u043e\u0437\u0434\u0430\u0432": 74, "\u0434\u043e\u043a\u0430\u0437\u0430": [74, 75, 86, 88, 102], "\u043f\u043e\u0434\u0441\u043a\u0430\u0437\u044b\u0432\u0430": 74, "\u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c": 74, "\u043a\u0430\u0440\u044c\u0435\u0440": [74, 83], "\u0434\u0432\u0430\u0434\u0446\u0430": 74, "\u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442": 74, "\u0443\u043f\u0430\u0434\u043a": 74, "\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430": [74, 75, 83, 85], "\u0443\u043b\u0443\u0447\u0448\u0430": [74, 85, 94], "sounds": [74, 76], "counterintuitive": 74, "talk": [74, 86], "improves": [74, 85], "theseimprove": 74, "hear": [74, 75], "patches": 74, "covering": 74, "archaeology": 74, "blank": 74, "slate": 74, "visualize": 74, "affairs": 74, "pseudograph": 74, "leverage": [74, 86], "debugging": [74, 85, 86], "conventional": 74, "wrote": [74, 92], "decay": 74, "virtuous": 74, "earliest": [74, 76], "misconception": [74, 76], "manifests": [74, 76], "becoming": [74, 76, 82], "kills": [74, 75], "\u0441\u0442\u0440\u0430\u043d": [74, 75, 88], "\u043d\u0430\u0441\u0442\u0430\u0438\u0432": 74, "\u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430": 74, "\u0438\u043d\u0442\u0435\u0440\u0432\u0430": 74, "\u043b\u0438\u043f\u0448": 74, "\u0441\u043e\u043c\u043d\u0435\u043d": 74, "\u043f\u043e\u0434\u0447\u0438\u0441\u0442": 74, "\u0438\u0437\u043c\u0435\u0440\u0435\u043d": [74, 86], "\u043d\u0430\u0434\u0435\u0435\u0442": 74, "\u0437\u0430\u043a\u0440": 74, "\u043e\u0442\u0434\u0435\u043b\u043a": 74, "\u0443\u0432\u0435\u043b\u0438\u0447": [74, 76, 85, 86, 100], "\u0447\u0440\u0435\u0437\u0432\u044b\u0447\u0430\u0439\u043d": 74, "insisting": [74, 85], "episode": 74, "mess": 74, "prohibitively": 74, "unable": [74, 76], "listen": [74, 88], "indefinitely": 74, "forgiving": 74, "victim": 74, "organizes": 74, "operates": [74, 86], "deadline": 74, "bay": 74, "succumb": 74, "temptation": 74, "oxymoron": 74, "utopian": 74, "lifetime": [74, 75], "\u043f\u043e\u043c\u0435\u0448\u0430": 74, "\u043f\u0440\u0435\u0436\u0434\u0435\u0432\u0440\u0435\u043c\u0435\u043d": 74, "recall": 74, "saps": 74, "peoplepower": 74, "average": 74, "50": [74, 93], "noncoding": 74, "seemingly": 74, "nonprogrammer": 74, "tester": 74, "administrative": 74, "factored": [74, 85], "correcting": [74, 86], "naive": [74, 85], "importance": 74, "prerequisites": 74, "shortening": 74, "confirmed": 74, "involving": [74, 75], "nasa": 74, "laboratory": 74, "increased": 74, "assurance": 74, "decreased": 74, "rate": [74, 77, 86], "overalldevelopment": 74, "1987": 74, "findings": 74, "shortest": 74, "schedules": 74, "jones": [74, 75, 76, 82], "capers": 74, "assessments": 74, "benchmarks": 74, "holds": 74, "1985": [74, 88], "166": 74, "averaged": 74, "220": 74, "median": 74, "demarco": [74, 75, 76], "lister": 74, "slowest": 74, "shows": [74, 76, 86], "watts": 74, "humphrey": 74, "tsp": 74, "06": 74, "focuses": [74, 82], "weber": 74, "2003": 74, "morales": 74, "alexandra": 74, "consummate": 74, "coach": 74, "father": 74, "cmm": 74, "sd": 74, "cleanroom": 74, "confirm": 74, "checked": 74, "740": 74, "closer": 74, "250": 74, "300": 74, "cusumano": 74, "worldwide": 74, "november": [74, 88], "december": 74, "34": 74, "savings": 74, "devoted": 74, "worthy": 74, "conducted": 74, "fjelstad": 74, "hamlen": 74, "1979": [74, 75, 88], "respondents": 74, "48": 74, "philadelphia": 74, "reprinted": 74, "parikh": 74, "zvegintzov": 74, "eds": 74, "los": 74, "alamitos": 74, "ca": [74, 76], "cs": 74, "1983": [74, 92], "\u0430\u043d\u0435\u043a\u0434\u043e\u0442": 74, "\u043c\u0443\u0436\u0438\u043a": 74, "\u043b\u0435\u0441": [74, 75], "\u0440\u0443\u0431": [74, 90], "\u043f\u0440\u0438\u0432\u0435\u0442": 74, "\u0440\u0443\u0431\u043b": 74, "\u0431\u0435\u043d\u0437\u043e\u043f": 74, "\u043f\u0440\u043e\u0447\u0442": 74, "\u0438\u0441\u0441\u043b\u0435\u0434\u0443": 75, "\u0441\u043e\u0436\u0430\u043b\u0435\u0435\u0442": 75, "historically": 75, "rephrase": 75, "cohesive": [75, 100], "binds": [75, 100], "symptoms": 75, "\u043d\u0435\u043d\u0430\u043c\u043d": 75, "heard": [75, 85], "unworkable": 75, "impractical": 75, "utter": 75, "nonsense": 75, "2002": [75, 76, 83], "\u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d": 75, "tom": [75, 76], "meilir": 75, "relatedness": 75, "demarco79": 75, "310": 75, "jones88": 75, "englewood": 75, "cliff": 75, "1988": 75, "newkirk": [75, 82], "koss": [75, 82], "\u0432\u0435\u0434\u0435\u0442": [75, 86], "\u0442\u0430\u043a\u043e\u0432": 75, "\u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d": [75, 86, 89], "\u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a": [75, 95, 102], "\u0441\u043e\u0435\u0434\u0438\u043d\u044f": 75, "\u0440\u0430\u0441\u0447\u043b\u0435\u043d\u044f": 75, "\u043e\u0441\u043c\u044b\u0441\u043b\u0435\u043d": [75, 92], "partitioning": [75, 86], "conventions": 75, "apart": 75, "conceptual": [75, 86], "reveals": 75, "lose": [75, 85, 86], "chunk": 75, "\u043f\u0435\u0440\u0435\u0443\u0441\u043b\u043e\u0436\u043d": [75, 100], "\u043a\u0440\u0438\u0442\u0438\u043a": [75, 83, 94], "\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 75, "\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0441\u0442\u0432": 75, "\u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u0438\u0432\u043d": 75, "\u0442\u0435\u0440\u0440\u0438\u0442\u043e\u0440\u0438\u0430\u043b\u044c\u043d": 75, "\u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432": 75, "\u0433\u0440\u0430\u0436\u0434\u0430\u043d": 75, "\u0434\u0432\u043e\u0439\u043d": [75, 83], "\u043d\u0435\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430": 75, "\u0432\u043e\u0441\u0445\u043e\u0434": 75, "inline": 75, "\u043e\u0442\u0431\u0438\u0440\u0430": [75, 100], "\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430": 75, "\u043f\u043e\u043d\u0438\u0436": 75, "\u043c\u043d\u043e\u0433\u043e\u0447\u0438\u0441\u043b\u0435\u043d": [75, 95], "\u0434\u0438\u0441\u0442\u0438\u043b\u043b\u0438\u0440\u043e\u0432\u0430": 75, "\u043a\u0443\u0441\u043e\u0447\u043a": 75, "\u043f\u0440\u0438\u043c\u0435\u0441": 75, "\u0441\u0438\u0445": 75, "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u043b\u043e\u0436\u043d": [75, 92], "active": 75, "corollary": 75, "gather": 75, "restated": 75, "multiples": 75, "reusability": 75, "confined": 75, "redeploy": 75, "revalidated": 75, "redeployed": 75, "prompts": 75, "bound": [75, 86], "physically": 75, "belong": 75, "minimizes": 75, "releasing": 75, "revalidating": 75, "redeploying": 75, "experienced": [75, 85], "amplifies": 75, "lesson": 75, "restricted": 75, "kitty": 75, "smallest": 75, "jar": 75, "gem": 75, "dlls": 75, "aggregations": [75, 77], "binary": [75, 82], "interpreted": [75, 100], "granule": 75, "\u043c\u043d\u043e\u0433\u043e\u043e\u0431\u0440\u0430\u0437\u043d": 75, "\u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442": [75, 83], "\u0437\u0430\u043f\u0443\u0442\u0430\u043d": 75, "\u0430\u0441\u0442": 75, "\u0445\u0430\u0440\u0432\u0435\u0441\u0442": 75, "\u044e": 75, "\u0433\u043e\u043b\u043e\u0432\u0438\u043d": 75, "\u043f\u0435\u0440": [75, 82, 88], "\u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0437": [75, 92], "\u043f\u0435\u0440\u0435\u043f\u043b\u0435\u0442\u0430": 75, "\u0441\u0432\u043e\u0439\u0441\u0442\u0432": [75, 100, 102], "\u0442\u043e\u043b\u043a\u043e\u0432": [75, 92], "\u0435\u0444\u0440\u0435\u043c\u043e\u0432": 75, "\u0444": [75, 82, 92, 100], "plex": 75, "k\u014fm": 75, "pl\u0115ks": 75, "complexus": 75, "complecti": 75, "entwine": 75, "comprise": 75, "plectere": 75, "twist": 75, "akin": 75, "plicare": 75, "plait": 75, "composite": 75, "gratitude": 75, "army": 75, "universe": 75, "locke": 75, "intricate": 75, "motions": 75, "heavens": 75, "calculated": 75, "whewell": 75, "fraction": 75, "ordinary": 75, "integers": 75, "syn": 75, "assemblage": 75, "complication": 75, "parable": [75, 76], "wedding": 75, "supper": 75, "comprehends": 75, "blessings": 75, "exhibited": 75, "gospel": 75, "geom": 75, "straight": 75, "relation": 75, "constitute": 75, "congruency": 75, "surfaces": 75, "webster": 75, "1913": 75, "connoisseur": 75, "wordsmiths": 75, "\u0432\u043d\u043e\u0441\u044f": 75, "\u043e\u043a\u0443\u043f\u0430": [75, 86], "\u0444\u043e\u0440\u043c\u0438\u0440\u0443": 75, "structural": [75, 85, 86], "\u0442\u0435\u043e\u0440\u0435\u0442\u0438\u043a": [75, 95], "\u0438\u043b\u043b\u044e\u0437\u043e\u0440\u043d": 75, "\u043c\u0438\u0440\u043a": 75, "\u043d\u0435\u0436\u0438\u0437\u043d\u0435\u0441\u043f\u043e\u0441\u043e\u0431\u043d": 75, "\u043e\u0431\u043e\u0441\u043d\u043e\u0432\u0430\u043d": [75, 89, 92], "\u0441\u043a\u0440\u044b\u0432\u0430": 75, "\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440\u0441\u043a": 75, "\u0435\u0434\u0438\u043d\u043e\u0434\u0443\u0448\u043d": 75, "\u0443\u0432\u0430\u0436\u0438\u0442\u0435\u043b\u044c\u043d": 75, "\u043c\u0430\u043d\u0435\u0440": 75, "\u0434\u043e\u043d\u0435\u0441\u0435\u043d": [75, 92], "\u043f\u0440\u0438\u043d": [75, 83, 88], "\u0430\u0434\u0430\u043f\u0442\u0438\u0432\u043d": 75, "\u0432\u044b\u043f\u0443\u0441\u0442": [75, 86], "\u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430": [75, 85, 86], "\u0435\u0434\u0438\u043d\u043e\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a": 75, "\u043f\u0440\u043e\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430": 75, "\u043f\u0440\u0438\u0437\u0432\u0430": [75, 76], "\u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432": 75, "\u0441\u0438\u0442\u0443\u0430\u0446\u0438\u043e\u043d": 75, "\u0431\u0435\u0441\u043f\u0435\u0447\u043d": 75, "\u043e\u0442\u0440\u044b\u0432\u0430": 75, "\u043d\u0430\u0432\u044f\u0437\u044b\u0432\u0430\u043d": 75, "\u0443\u0431\u0438\u0432\u0430": 75, "\u043a\u0443\u043b\u044c\u0442\u0443\u0440": [75, 83, 93], "\u0437\u0430\u0434\u0430\u0432\u0430\u043d": 75, "\u0432\u043e\u0432\u043b\u0435\u0447\u0435\u043d": 75, "\u043f\u0440\u0438\u0434\u0443\u043c\u0430": [75, 85], "\u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432": [75, 82], "adequate": 75, "situational": 75, "blithely": 75, "claiming": 75, "disconnects": 75, "questioning": 75, "engagement": 75, "\u043e\u0441\u043e\u0437\u043d\u0430\u0432\u0430": 75, "\u0444\u0438\u0434\u0431\u044d\u043a": 75, "\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430": 75, "\u043a\u0430\u0440\u0433": [75, 92], "\u043a\u0443\u043b\u044c\u0442": [75, 92], "\u0438\u0441\u043a\u0430\u0437": 75, "\u043e\u0448\u0438\u0431": 75, "\u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430": 75, "\u043f\u0440\u0438\u0432\u043b\u0435\u043a": 75, "\u043a\u043e\u043b\u043b\u0435\u0433": 75, "\u043e\u0440\u0438\u0433\u0438\u043d\u0430": [75, 100], "\u0438\u0437\u043b\u043e\u0436\u0435\u043d": [75, 82], "gym": 75, "lift": 75, "interpretations": 75, "backward": 75, "compatibility": 75, "ripple": 75, "1970s": 75, "1980s": [75, 76], "fertile": 75, "rage": 75, "notions": 75, "amplified": 75, "\u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442": [75, 92], "\u0430\u0431\u0431\u0440\u0435\u0432\u0438\u0430\u0442\u0443\u0440": 75, "grasp": [75, 82, 95], "\u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d": [75, 82, 100], "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d": [75, 85], "\u0434\u043e\u0441\u0442\u0438\u0433": 75, "\u0441\u0435\u0440\u0435\u0431\u0440\u044f\u043d": 75, "\u043f\u0443\u043b": [75, 94], "\u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a": [75, 85], "\u043f\u044f\u0442": [75, 76, 82], "\u0431\u0443\u043a\u0432": [75, 82, 92], "\u0432\u043e\u043b\u0448\u0435\u0431\u043d": [75, 95], "\u0437\u0430\u0439\u0434": 75, "\u043c\u043d\u043e\u0433\u043e\u043e\u0431\u0440\u0430\u0437": 75, "\u0432\u0437\u0430\u0438\u043c\u043d": 75, "\u043f\u0440\u0435\u0442\u0435\u043d\u0434": 75, "\u044d\u0442\u0430\u043b\u043e\u043d": 75, "\u0434\u0440\u043e\u0432": [75, 90], "\u043f\u0430\u0440\u043d": [75, 88, 94], "\u043a\u0440\u0443\u0433\u043e\u0437\u043e\u0440": 75, "\u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d": 75, "\u0431\u044d\u043a\u0433\u0440\u0430\u0443\u043d\u0434": 75, "kamil": [75, 82], "grzybek": [75, 82], "\u043f\u0440\u0435\u0442\u0435\u043d\u0434\u043e\u0432\u0430": [75, 102], "modular": [75, 76, 82], "\u0443\u0447\u0430\u0441\u0442": [75, 82], "\u0430\u0432\u0442\u043e\u0440\u0438\u0442\u0435\u0442": [75, 86, 88, 89, 92], "injection": 75, "paint": 75, "teach": 75, "judgement": 75, "arbitrary": 75, "relevance": 75, "liskov": 75, "substitution": 75, "lsp": 75, "isp": 75, "inversion": 75, "dip": 75, "repeated": 76, "intentional": 76, "guided": [76, 82], "deliberate": 76, "conscious": [76, 89], "thrown": [76, 86], "finding": 76, "anticipation": 76, "highsmith": 76, "influence": 76, "redone": 76, "forgo": 76, "jump": 76, "positioned": 76, "medical": 76, "safety": 76, "website": 76, "kayak": 76, "racing": 76, "foretelling": 76, "speaker": [76, 86], "expansion": 76, "bogged": 76, "materialize": 76, "breakfast": 76, "food": 76, "cooker": 76, "ridgecrest": 76, "do_while": 76, "toaster": 76, "htm": 76, "bogging": 76, "realizing": 76, "worrying": 76, "succeeding": [76, 82], "involves": 76, "in\ufb02uence": 76, "solely": 76, "emergence": 76, "argues": [76, 85, 86], "saves": 76, "waste": 76, "accelerates": 76, "emerging": [76, 82], "assumptions": [76, 86], "verified": [76, 86], "july": 76, "axiom": 76, "bias": [76, 89], "waterfalls": 76, "nest": 76, "consist": 76, "projecta": 76, "contrast": [76, 85], "middle": 76, "ground": 76, "classify": 76, "predominates": 76, "overlooked": 76, "wanting": 76, "unnecessary": 76, "excessive": 76, "punishment": 76, "ralf": 76, "2021": [76, 86], "\u043d\u0430\u0437\u0440\u0435\u0432\u0448": 76, "ages": 76, "laszczak": [76, 82], "\u0442\u0435\u043c\u043d": 76, "\u0432\u0435\u043a": 76, "\u043f\u0435\u0448\u043a\u043e\u0432": 76, "\u043a\u0430\u0447\u043d\u0443\u043b": 76, "\u043f\u0440\u0435\u043e\u0431\u043b\u0430\u0434\u0430": [76, 86], "ipu5hps1c4": 76, "camden": 76, "maine": 76, "war": 76, "von": 76, "clausewitz": 76, "military": 76, "swinging": 76, "forth": 76, "relative": 76, "armor": 76, "mobility": 76, "knights": 76, "shining": 76, "dominate": 76, "knight": 76, "nearly": [76, 82, 95], "naked": 76, "pony": 76, "warriors": 76, "swept": 76, "plains": 76, "genghis": 76, "kahn": 76, "mongols": 76, "cavalry": 76, "tanks": 76, "fleet": 76, "footed": 76, "palestinian": 76, "teenagers": 76, "sagger": 76, "missiles": 76, "maginot": 76, "french": 76, "gambling": 76, "hadn": 76, "germans": 76, "laudable": 76, "obsessed": 76, "tended": 76, "reacted": 76, "imperatives": 76, "thrust": 76, "foreword": 76, "\u0440\u0443\u0431\u0435\u0436": 76, "\u043e\u0442\u043a\u043b\u043e\u043d": 76, "\u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u0443": [76, 90], "pbr": [76, 80, 86], "spike": [76, 80, 86], "\u0440\u0430\u0434\u0438\u043a\u0430\u043b\u044c\u043d": 76, "\u043e\u0442\u043a\u0440": [76, 85], "\u0441\u043c\u0435\u0441\u0442": 76, "pretends": 76, "ah": 76, "mostly": 76, "lived": [76, 86], "addressing": 76, "angles": 76, "sustain": 76, "unexpected": 76, "attitude": [76, 85], "quote": 76, "msf": [76, 86], "rad": [76, 86], "fdd": [76, 86], "switch": [76, 85, 88], "\u0434\u0430\u0431": [76, 92], "\u0441\u0442\u0438\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430": 76, "\u043f\u0440\u043e\u0434\u0432\u0438\u0436\u0435\u043d": 76, "\u043f\u0440\u0438\u0437\u043d\u0430": [76, 85], "\u043f\u0440\u0438\u043d\u0435\u0431\u0440\u0435\u0433\u0430": 76, "arms": 76, "beliefs": 76, "\u043f\u043e\u0448\u0435\u043b": 76, "\u043a\u043e\u0434\u0438\u043d\u0433": 76, "\u0432\u044f\u043b": 76, "\u0432\u0441\u043a\u043e\u043b\u044c\u0437": 76, "\u0431\u0443\u043d\u0442": 76, "\u0437\u0430\u0432\u0435\u0442": 76, "c\u0440\u0435\u0434\u043d": 76, "\u043d\u0430\u0440\u0430\u0441\u0442\u0430": [76, 88], "\u043e\u043f\u0435\u0440\u0435\u0436\u0435\u043d": 76, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c": [76, 86], "\u0432\u043e\u0441\u043a\u0440\u0435\u0448\u0435\u043d": 76, "dad": [76, 88], "\u043d\u0435\u043c\u043d\u043e\u0433\u043e\u0447\u0438\u0441\u043b\u0435\u043d": 76, "\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0446": 76, "\u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b": 76, "\u0432\u0430": 76, "\u0441\u043e\u0432\u043f\u0430": 76, "\u0445\u0440\u043e\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 76, "\u0432\u0437\u0440\u044b\u0432\u043d": 76, "storytelling": 76, "\u0434\u0435\u0448\u0435\u0432\u043b": 76, "\u0440\u0435\u0438\u043d\u043a\u0430\u0440\u043d\u0438\u0440\u043e\u0432\u0430": 76, "nexus": 76, "\u0445\u0438\u0440\u0443\u0440\u0433": [76, 85, 86], "\u0445\u0430\u0440\u043b\u0430": 76, "\u043c\u0438\u043b\u043b\u0437": 76, "\u043c\u043b\u0430\u0434\u0448": 76, "\u043a\u043e\u043d\u0432\u0435": 76, "\u0432\u044b\u0434\u0432\u0438\u043d\u0443\u043b": 76, "despite": [76, 85], "amended": 76, "signers": 76, "living": [76, 82], "u": 76, "rewrite": 76, "lessons": [76, 82], "individuals": 76, "\u043e\u0442\u0440\u0430\u0441\u043b": [76, 83, 92], "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d": [76, 102], "chaotic": 76, "secondary": [76, 85], "strips": 76, "determination": 76, "totally": 76, "un": 76, "strawberries": 76, "personally": [76, 85], "chose": 76, "introduces": [76, 86], "underlie": 76, "\u0430\u043d\u0434\u0440": 76, "\u0433\u0430\u043d\u0438\u0447": 76, "contributor": 76, "\u0431\u0440\u0430\u043d\u0434\u043e\u043b\u0438\u043d": 76, "collective": [76, 94], "\u043d\u0435\u0434\u043e\u043f\u0438\u0441\u0430": 76, "pretending": 76, "domains": [76, 86], "tuning": 76, "renaming": [76, 85], "reasonable": 76, "recalls": 76, "memories": 76, "infamous": 76, "banned": 76, "blasphemy": 76, "typing": 76, "firs": 76, "implicitly": 77, "executable": 77, "emerges": [77, 86], "numerous": 77, "shorterterm": 77, "elicit": 77, "architecturally": [77, 85], "peaks": 77, "cleland": 77, "huang": 77, "depaul": 77, "hanmer": 77, "alcatel": 77, "lucent": 77, "supakkul": 77, "sabre": [77, 86], "mehdi": [77, 82], "mirakhorli": 77, "progression": 77, "recursion": 77, "differing": [77, 86], "accomplishes": 77, "proceeds": 77, "purposeful": 77, "predicted": 77, "genuine": 77, "feasibility": 77, "arising": 77, "obsolescence": 77, "reverse": 77, "regulatory": 77, "nor": 77, "\u0444\u0435\u043d\u043e\u043c": 77, "\u043a\u043e\u0440\u043e\u0447": 77, "\u0432\u044b\u0439\u0434": 77, "\u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0432": 77, "\u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430": 77, "\u043f\u043e\u043c\u043e\u0436\u0435\u0442": 77, "\u043f\u043e\u043c\u043e\u0433\u0443\u0442": 77, "\u043f\u0440\u043e\u0447\u043d": 77, "\u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442": 77, "\u0441\u0432\u0435\u0440\u0445": [77, 88, 90], "wished": 77, "armed": 77, "gained": [77, 86], "shorter": 77, "whirl": 77, "tug": 77, "considerations": 77, "healthy": 77, "dynamic": [77, 82], "stressed": 77, "wholly": 77, "\u043d\u0438\u0441\u0445\u043e\u0434\u044f": 77, "\u0432\u043e\u0441\u0445\u043e\u0434\u044f": 77, "\u043a\u0430\u0437\u0430": 77, "\u043d\u0435\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a": 77, "\u0445\u043e\u0434": [77, 83, 88, 90, 92], "\u0434\u0435\u0442\u0430\u043b\u044c\u043d": 77, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d": [77, 82], "\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a": 77, "\u043e\u0431\u0449\u043d\u043e\u0441\u0442": 77, "\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446": 77, "\u0440\u0430\u0437\u0431\u0438\u0432": 77, "\u0441\u043e\u0441\u0442\u0430\u0432\u043b": 77, "\u043f\u0440\u043e\u0440\u044b\u0432\u0430": 77, "\u043f\u043e\u0442\u043e\u043f": 77, "\u044d\u0432\u0440\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": 77, "fashioned": 77, "nonspecific": 77, "derived": [77, 86], "collaborating": [77, 88], "specifics": 77, "generalities": 77, "generalizes": 77, "strategies": [77, 86, 88], "composition": [77, 85], "builds": [77, 85], "strengths": 77, "weaknesses": 77, "tends": [77, 85], "ripples": 77, "torpedo": 77, "trial": 77, "establish": [77, 86], "selecting": 77, "complained": 80, "\u043c\u0430\u043a\u0435\u0442": [80, 83], "ux": [80, 83, 86], "dor": [80, 86], "reveal": 80, "\u0431\u043b\u0438\u0437\u043e\u043a": 80, "\u0432\u044b\u0447\u0442": 80, "breakdown": 80, "logarithmically": 80, "yow": [80, 82], "33": 80, "\u0443\u043f\u043e\u043c\u044f\u043d\u0443\u043b": 80, "\u043d\u0430\u0441\u0442\u0443\u043f\u0430": [80, 83, 88], "\u043f\u043e\u0441\u043e\u0432\u0435\u0442": 82, "\u0438\u0437\u043b\u043e\u0436": 82, "\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 82, "\u043d\u043e\u0432\u0438\u0447\u043a": 82, "\u0436\u0430\u0436\u0434": 82, "\u043d\u0435\u0442\u0435\u0440\u043f\u0435\u043b\u0438\u0432": 82, "\u043f\u043e\u0433\u043e\u043d": 82, "\u043d\u0430\u0434\u0440\u044b\u0432\u0430": 82, "\u0432\u043f\u0430\u0434\u0430": 82, "\u0434\u0435\u043f\u0440\u0435\u0441\u0441": [82, 95], "\u043c\u043e\u043b": 82, "\u0430\u043a\u0430\u0434\u0435\u043c\u0438\u0447\u043d": 82, "\u043d\u0435\u0443\u043c\u0435\u0441\u0442\u043d": 82, "\u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0430": 82, "\u043e\u0431\u0440\u0435\u0442\u0435\u043d": [82, 83, 92, 95], "\u043c\u0430\u0442": 82, "\u043f\u043e\u0431\u0435\u0434": [82, 83, 90], "\u0441\u0443\u0432\u043e\u0440": 82, "\u0433\u043d\u0430\u0442": 82, "advancement": [82, 95], "35": [82, 95], "authorities": [82, 95], "scientific": [82, 95], "spheres": [82, 95], "acts": [82, 95], "faithfully": [82, 95], "busy": [82, 95], "waking": [82, 95], "morning": [82, 95], "cited": 82, "\u0442\u0435\u043c\u0430\u0442\u0438\u043a": 82, "\u043b\u0435\u0433\u043b": 82, "\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b": 82, "\u043f\u043b\u0430\u043d\u043e\u0432": 82, "\u0448\u0442\u0430\u043c\u043f": 82, "\u043f\u0430\u0440\u0435\u0442": 82, "\u0434\u0438\u0441\u043a\u0443\u0441\u0441": [82, 83], "\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0437\u0438\u0440": 82, "\u043e\u0448\u0438\u0431\u0430": [82, 83, 88, 92], "\u043a\u0440\u0438\u0441\u0442\u0430\u043b\u0438\u0437\u0430\u0446": 82, "\u0441\u0434\u0435\u0440\u0436\u0430\u043d": 82, "\u0437\u0430\u0432\u0435\u0441\u0442": 82, "\u043a\u043e\u043c\u044c\u044e\u043d\u0438\u0442": 82, "\u0437\u0430\u043a\u0440\u0435\u043f\u043b\u0435\u043d": 82, "\u043f\u0440\u0435\u0434\u0448\u0435\u0441\u0442\u0432\u043e\u0432\u0430": 82, "\u043b\u0435\u0447": [82, 93, 94], "\u0440\u0438\u0441\u043a\u0443\u0435\u0448": [82, 93], "\u0443\u043c\u0435\u0440\u0435\u0442": [82, 93], "\u043e\u043f\u0435\u0447\u0430\u0442\u043a": [82, 93], "\u043c\u0430\u0440\u043a": [82, 83, 93], "\u0442\u0432\u0435\u043d": [82, 83, 93], "\u043d\u0430\u0437\u0440\u0435\u0442": 82, "\u043d\u0430\u043a\u043e\u043f\u043b": 82, "\u0441\u043e\u043b\u0438\u0434\u043d": 82, "\u0431\u0430\u0433\u0430\u0436": 82, "bridge": 82, "\u043f\u0440\u043e\u043c\u0435\u043b\u044c\u043a\u043d\u0443\u043b": 82, "smells": 82, "\u0432\u0441\u043f\u043e\u043c\u0438\u043d\u0430": [82, 83], "\u043d\u0430\u0432\u0435\u0447\u043d": 82, "\u0437\u0430\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043b": 82, "\u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d": [82, 100], "\u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446": [82, 85], "\u0444\u0430\u043d\u0430\u0442\u0438\u0437\u043c": 82, "\u0437\u0430\u0441\u0430\u0441\u044b\u0432\u0430": 82, "\u0443\u0440\u0430\u0432\u043d\u043e\u0432\u0435\u0448\u0438\u0432\u0430": 82, "\u0441\u043f\u043e\u0440\u0442": [82, 92, 93], "\u0444\u0438\u0437\u043a\u0443\u043b\u044c\u0442\u0443\u0440": 82, "\u0448\u0430\u0448\u043b\u044b\u043a": [82, 90], "\u043f\u0443\u0442\u0435\u0448\u0435\u0441\u0442\u0432": 82, "\u043d\u0435\u043f\u0440\u0435\u0434\u0432\u0437\u044f\u0442": 82, "\u0438\u0437\u043e\u0431\u0438\u043b": [82, 93], "\u0441\u0430\u043c\u043e\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446": 82, "\u0441\u0442\u0440\u0435\u0441\u0441": [82, 85, 92], "\u043e\u0446\u0435\u0432\u0430\u043d": 82, "\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043d": [82, 94], "\u043f\u0440\u0430\u0432\u0434\u0438\u0432": 82, "\u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430": 82, "\u043a\u043e\u0434\u0435\u0440": 82, "\u0438\u0437\u044b\u0441\u043a\u0430": [82, 92], "\u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a": 82, "5th": 82, "lutz": 82, "jyotiswarup": 82, "raiturkar": 82, "alan": 82, "donovan": 82, "inc": 82, "brian": 82, "kernighan": 82, "erlang": 82, "pragmatic": [82, 85], "joe": 82, "armstrong": 82, "frontend": 82, "angular": 82, "ng": 82, "book2": 82, "nate": 82, "murray": 82, "felipe": 82, "coury": 82, "ari": 82, "lerner": 82, "carlos": 82, "taborda": 82, "\u043f\u0440\u0438\u0432\u043e\u0436": 82, "\u0438\u0437\u043e\u043b\u044f\u0446": 82, "\u043e\u0441\u0442\u0430\u043d\u0435\u0442": 82, "\u043c\u0435\u0447\u0442\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432": 82, "\u043d\u0430\u0441\u0442\u0430\u0432\u043d\u0438\u043a": 82, "\u043f\u043e\u0441\u043e\u0432\u0435\u0442\u043e\u0432\u0430": 82, "\u0440\u0435\u0433\u0438\u0441\u0442\u0440": 82, "\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440": 82, "\u0443\u0441\u0442\u0430\u0440\u0435\u043b": 82, "kernel": 82, "primer": 82, "x86": 82, "powerpc": 82, "claudia": 82, "salzberg": 82, "rodriguez": 82, "gordon": 82, "smolski": 82, "computers": 82, "microprocessors": 82, "aliyev": 82, "\u0446\u0438\u0444\u0440\u043e\u0432": 82, "\u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d": 82, "\u043c\u0438\u043a\u0440\u043e\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440": 82, "\u0430\u043b": [82, 83], "administration": 82, "evi": 82, "nemeth": 82, "garth": 82, "snyder": 82, "hein": 82, "ben": [82, 89], "whaley": 82, "mackin": 82, "\u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d": [82, 85, 100], "\u0443\u0442\u0438\u043b\u0438\u0442": 82, "\u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446": 82, "\u0431\u0438\u0440\u0436\u0435\u0432": 82, "\u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440": 82, "\u0434\u0432\u0435\u0441\u0442": 82, "algorithms": [82, 90], "unlocked": [82, 90], "cormen": [82, 90], "\u0430\u043a\u0446\u0435\u043d\u0442\u0438\u0440": 82, "\u043d\u0435\u0432\u043e\u0441\u043f\u043e\u043b\u043d\u0435\u043d": 82, "levitin": 82, "appendix": [82, 85], "formulas": 82, "recurrence": 82, "\u0433\u0443\u0441\u0430\u043a": 82, "viii": 82, "background": 82, "leiserson": 82, "rivest": 82, "clifford": 82, "stein": 82, "\u043b\u0438\u043a\u0431\u0435\u0437": 82, "\u043f\u043e\u0434\u043e\u0439\u0442": 82, "wladston": 82, "ferreira": 82, "filho": 82, "\u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0442\u043e\u0440\u0438\u043a": 82, "\u0436\u0435\u043b\u0435\u0437": 82, "\u0444\u0430\u043c\u0438\u043b": 82, "\u0442\u043e\u0440\u043c\u043e\u0437": 82, "\u043e\u0441\u0432\u0435\u0436\u0430": 82, "volume": [82, 88], "\u0445\u043e\u0442\u0435\u043b": [82, 86, 95], "\u0441\u0442\u0443\u0434\u0435\u043d\u0447\u0435\u0441\u0442\u0432": 82, "\u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d": 82, "\u0441\u043b\u0435\u0433\u043a": 82, "\u0432\u043d\u0438\u043a\u0430": 82, "polyglot": 82, "pramod": 82, "sadalage": 82, "newman": [82, 86, 92], "russian": 82, "crdt": 82, "\u0436\u0434\u0430\u0442": 82, "\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432": 82, "microsoftarchive": 82, "sagas": 82, "garcia": 82, "molina": 82, "salem": 82, "\u043a\u043b\u0430\u0441\u0441\u0438\u043a": 82, "isolation": 82, "uniqueness": 82, "link": [82, 100], "smith": 82, "overselling": 82, "streams": 82, "savvas": 82, "kleanthous": 82, "dennis": 82, "doomen": 82, "michiel": 82, "overeem": 82, "marten": 82, "spoor": 82, "slinger": 82, "jansen": 82, "jimmy": 82, "bogard": 82, "ddddd": 82, "subdomain": [82, 100], "tl": 82, "macro": 82, "zhamak": 82, "dehghani": 82, "crew": 82, "sheet": [82, 89], "quiz": 82, "contextmapper": 82, "mapper": 82, "servicecutter": 82, "domoroboto": 82, "topo": 82, "visualizing": 82, "sociotechnical": 82, "maps": 82, "apis": 82, "odata": 82, "apigee": 82, "crafting": 82, "love": 82, "urls": 82, "w3c": 82, "graphql": 82, "openapis": 82, "asyncapi": 82, "rql": 82, "jsonpath": 82, "xpath": 82, "falcor": 82, "prakash": 82, "subramaniam": 82, "whoughtworks": 82, "crud": 82, "mullender": 82, "sergey": 82, "konstantinov": 82, "discovering": 82, "covid": 82, "acceleration": 82, "trader": 82, "kevin": 82, "webber": 82, "dana": 82, "harrington": 82, "shipment": 82, "refarch": 82, "kc": 82, "awesome": 82, "c4": 82, "starter": 82, "modernisation": 82, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d": [82, 85], "scott": 82, "berkun": 82, "\u043e\u0440\u0433\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0447\u0435\u0441\u043a": 82, "\u0449\u0435\u0434\u0440\u043e\u0432\u0438\u0446\u043a": 82, "\u0433\u0435\u043e\u0440\u0433": 82, "\u043f\u0435\u0442\u0440\u043e\u0432\u0438\u0447": 82, "7th": [82, 88], "daft": [82, 88], "013": [82, 88], "journeyman": 82, "hunt": [82, 94], "20th": 82, "york": 82, "dorset": 82, "house": 82, "gerald": 82, "1992": [82, 88], "0932633226": 82, "harvard": [82, 88], "school": 82, "elevator": 82, "redefining": 82, "richards": 82, "neal": [82, 85, 92], "analyses": 82, "37": 82, "eaten": 82, "jungle": 82, "warfare": 82, "politician": 82, "phil": 82, "porter": 82, "presentations": 82, "mccullough": 82, "nathaniel": 82, "schutta": 82, "eben": 82, "donella": 82, "meadows": 82, "diana": 82, "wright": 82, "psychology": [82, 88], "13th": [82, 88], "myers": [82, 88], "\u043c\u0430\u0439\u0435\u0440\u0441": [82, 88], "\u0430\u043d\u0433\u043b": [82, 88], "\u0437": [82, 86, 88], "\u0437\u0430\u043c\u0447\u0443\u043a": [82, 88], "\u0437\u0430\u0432": [82, 88], "\u0440\u0435\u0434": [82, 88], "\u043a\u043e\u043b": [82, 88], "\u0432\u0438\u043d\u043e\u043a\u0443\u0440": [82, 88], "2006": [82, 88], "depended": 82, "voss": 82, "\u0434\u043e\u0433\u043e\u0432\u043e\u0440": 82, "\u0443\u0441\u0442\u0443\u043f\u043e\u043a": 82, "\u043a\u0440\u0438\u0441": 82, "\u0432\u043e\u0441\u0441": 82, "\u0441\u043f\u043e\u0440": 82, "\u044d\u0440\u0438\u0441\u0442\u0438\u043a": 82, "\u043f\u043e\u0431\u0435\u0436\u0434\u0430": [82, 88], "\u0448\u043e\u043f\u0435\u043d\u0433\u0430\u0443\u044d\u0440": 82, "\u0430\u0440\u0442\u0443\u0440": 82, "win": [82, 86], "schopenhauer": 82, "\u043e\u0431\u0443\u0447\u0430": 82, "\u0440\u0438\u0442\u043e\u0440\u0438\u043a": 82, "\u0434\u043e\u0445\u043e\u0434\u0447\u0438\u0432": [82, 89], "\u0432\u0438\u0434\u0435\u043e\u043a\u0443\u0440\u0441": [82, 89], "softskills": [82, 89], "pro": [82, 89], "mastering": 82, "dimitri": 82, "fontaine": 82, "antipatterns": 82, "karwin": 82, "ambler": 82, "ibrar": 82, "ahmed": 82, "gregory": 82, "enrico": 82, "pirozzi": 82, "\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d": 82, "\u043d\u0435\u043e\u0441\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d": 82, "\u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d": 82, "\u043b\u0443\u0437\u0430\u043d": 82, "\u0440\u043e\u0433": 82, "\u043b\u0435\u0432\u0448\u0438\u043d": 82, "\u0438\u0437\u043d\u0443\u0442\u0440": [82, 92], "\u0434\u043c\u043a": 82, "\u043f\u0440\u0435\u0441\u0441": 82, "2022": 82, "660": 82, "\u0443\u0447\u0435\u0431": [82, 88], "\u043f\u043e\u0441\u043e\u0431": [82, 88], "\u043c\u043e\u0440\u0433\u0443\u043d": 82, "\u0440\u043e\u0433\u043e\u0432": 82, "\u043b\u0443\u0437\u0430\u043d\u043e\u0432": 82, "\u043d\u043e\u0432\u0438\u043a": 82, "\u0433\u043e\u0440\u0448\u043a\u043e\u0432": 82, "\u0433\u0440\u0430\u0444\u0435\u0435\u0432": 82, "\u0441\u043b\u0430\u0439\u0434": 82, "\u0430\u0440\u0445\u0438\u0432": 82, "\u0432\u0438\u0434\u0435\u043e\u0437\u0430\u043f\u0438\u0441": 82, "mvcc": 82, "wal": 82, "\u0431\u0443\u0444\u0435\u0440\u043d": 82, "\u043a\u0435\u0448": 82, "dozen": 82, "replica": 82, "divergence": 82, "reads": 82, "skew": 82, "tagged": 82, "\u0440\u0435\u0439\u0442\u0438\u043d\u0433": 82, "ranking": 82, "soap": 82, "wsdl": 82, "restful": 82, "daigneau": 82, "architecting": 82, "dino": 82, "esposito": 82, "andrea": 82, "saltarello": 82, "nygard": [82, 86], "edited": 82, "betsy": 82, "beyer": 82, "jennifer": 82, "petoff": 82, "niall": 82, "murphy": 82, "workbook": 82, "sre": 82, "rensin": 82, "kawahara": 82, "stephen": [82, 88], "thorne": 82, "maintaining": [82, 86], "heather": 82, "adkins": 82, "blankinship": 82, "ana": 82, "oprea": 82, "piotr": 82, "lewandowski": 82, "stubblefield": 82, "erl": 82, "definitive": 82, "aalst": 82, "wil": 82, "der": 82, "russell": 82, "ter": 82, "hofstede": 82, "bpmn": 82, "dmn": 82, "jakob": 82, "freund": 82, "bernd": 82, "r\u00fccker": 82, "ruecker": 82, "hypermedia": 82, "savas": 82, "parastatidis": 82, "robinson": 82, "leonard": 82, "amundsen": 82, "mulloy": 82, "rulebook": 82, "mass\u00e9": 82, "higginbotham": 82, "medjaoui": 82, "erik": 82, "wilde": 82, "ronnie": 82, "mitra": 82, "psaltis": 82, "realtime": 82, "nathan": 82, "marz": 82, "warren": [82, 88], "bejeck": 82, "lake": 82, "promise": 82, "gorelik": 82, "millett": 82, "signature": 82, "rebecca": [82, 85], "parsons": [82, 85], "hatching": 82, "meier": 82, "hill": 82, "jason": [82, 85, 88], "taylor": 82, "prashant": 82, "bansode": 82, "lonnie": 82, "rob": 82, "boucher": 82, "akshay": 82, "bogawat": 82, "joshua": [82, 85], "kerievsky": [82, 85], "interpretation": [82, 85, 100], "sicp": 82, "harold": 82, "abelson": 82, "jay": 82, "sussman": 82, "julie": 82, "matthias": 82, "felleisen": 82, "findler": 82, "flatt": 82, "shriram": 82, "krishnamurthi": 82, "ivar": 82, "jacobson": 82, "frank": 82, "buschmann": 82, "regine": 82, "meunier": 82, "hans": 82, "rohnert": 82, "sommerlad": 82, "stal": 82, "networked": 82, "douglas": 82, "kircher": 82, "jain": 82, "henney": 82, "oberon": [82, 93], "wirth": 82, "fascicle": 82, "mmix": 82, "risc": 82, "millennium": 82, "seminumerical": 82, "sorting": 82, "searching": 82, "combinatorial": 82, "boolean": [82, 85], "bitwise": 82, "tricks": [82, 85, 94], "tuples": 82, "permutations": 82, "combinations": 82, "partitions": 82, "paperback": 82, "trees": 82, "preliminaries": 82, "backtracking": 82, "dancing": 82, "links": 82, "satisfiability": 82, "4a": 82, "maxx": 82, "bookz": 82, "gerard": [82, 85], "meszaros": [82, 85], "mocking": [82, 85], "growing": 82, "freeman": 82, "nat": 82, "pryce": 82, "lisa": 82, "crispin": 82, "janet": 82, "journeys": 82, "atdd": 82, "g\u00e4rtner": 82, "jez": 82, "farley": 82, "duvall": 82, "matyas": 82, "glover": 82, "istqb": 82, "referenced": 82, "syllabi": 82, "interpreters": 82, "craftinginterpreters": 82, "nystrom": 82, "compiler": [82, 85], "compilers": 82, "alfred": 82, "aho": 82, "monica": 82, "lam": 82, "ravi": 82, "sethi": 82, "ullman": 82, "documenting": 82, "felix": 82, "bachmann": 82, "garlan": 82, "ivers": 82, "reed": 82, "paulo": 82, "merson": 82, "judith": 82, "viewpoints": 82, "rozanski": 82, "e\u00f3in": 82, "woods": 82, "sei": 82, "humberto": [82, 86], "cervantes": [82, 86], "mcsweeney": 82, "haley": 82, "wixom": 82, "roberta": 82, "roth": [82, 88], "scientist": [82, 92], "sharing": 82, "cyrille": 82, "martraire": 82, "george": [82, 88], "fairbanks": 82, "migration": 82, "michele": 82, "danieli": 82, "francois": 82, "landreau": 82, "tahir": 82, "hashmi": 82, "lee": 82, "atchison": 82, "skelton": [82, 86], "manuel": [82, 86], "pais": [82, 86], "patrick": 82, "kua": 82, "muhammad": 82, "babar": 82, "kai": 82, "koskimies": 82, "mistr\u00edk": 82, "centric": 82, "murat": 82, "erder": 82, "pierre": 82, "pureur": 82, "architected": [82, 86], "reliant": 82, "jo": 82, "lane": 82, "quantitative": 82, "ricardo": 82, "valerdi": 82, "42010": 82, "42020": 82, "25010": 82, "square": [82, 86], "57100": 82, "\u0443\u043f\u0440\u0430\u043b\u0435\u043d": 82, "gartner": 82, "markets": 82, "unified": 82, "widrig": 82, "exam": 82, "compliant": 82, "klaus": 82, "pohl": 82, "rupp": 82, "\u0442\u0430\u0440\u0430\u0441\u0435\u043d\u043a": 82, "cpre": 82, "qualification": 82, "caution": 82, "syllabus": 82, "whitepaper": 82, "volere": 82, "estimating": [82, 83, 86], "demystifying": 82, "pert": 82, "\u043e\u0446\u0435\u043d\u043a": [82, 83], "\u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u043d": 82, "mauvisoft": 82, "bartosz": 82, "milewski": 82, "latex": 82, "wlaschin": 82, "marick": 82, "haskell": 82, "sergei": 82, "winitzki": 82, "monitoring": 82, "anuj": 82, "kumar": 82, "lex": 82, "sheehan": 82, "tucker": 82, "teofilo": 82, "gonzalez": 82, "jorge": 82, "diaz": 82, "herrera": 82, "eabok": 82, "mitre": 82, "bizbok": 82, "dama": 82, "dmbok": 82, "\u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043d": 82, "4cdto": 82, "\u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446": [82, 92], "competency": [82, 86], "sfia": 82, "bodies": 82, "allgosts": 82, "\u043a\u043e\u043d\u0442\u043e\u0440\u0441\u043a": 82, "standartgost": 82, "\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d": 82, "\u043c\u0430\u0433\u0430\u0437\u0438\u043d": 82, "catalog": 82, "dsl": 82, "overview": 82, "soapatterns": 82, "cloudpatterns": 82, "bigdatapatterns": 82, "clickable": 82, "subway": 82, "arcitura": 82, "playbook": 82, "selection": 82, "supporting": [82, 86], "chapters": [82, 86], "prep": 82, "interview": 82, "courses": 82, "maximal": 82, "luxoft": 82, "pratices": 82, "toolkits": 82, "decade": 82, "anemic": 82, "xoom": 82, "vlingo": 82, "demonstrating": 82, "goa": 82, "holistic": 82, "j\u00e9r\u00e9mie": 82, "chassaing": 82, "contributors": 82, "serverless": 82, "shop": 82, "showcase": 82, "zhang": 82, "xiaolong": 82, "dci": 82, "sys": [82, 86], "grpc": 82, "cockroachdb": 82, "shiju": 82, "varghese": 82, "displays": 82, "positions": 82, "transport": 82, "vehicles": 82, "helsinki": 82, "proto": 82, "ultra": 82, "kotlin": 82, "realtimemap": 82, "demo": 82, "taxi": 82, "bank": 82, "cargo": 82, "shipping": 82, "ftgo": 82, "eventuate": 82, "tram": 82, "packt": 82, "eventuous": 82, "extended": 82, "idris": 82, "redelastic": 82, "contosouniversitydotnetcore": 82, "lagom": 82, "lightbend": 82, "native": 82, "witn": 82, "hybrid": 82, "mission": 83, "geeks": 83, "linkedin": 83, "profile": 83, "\u043e\u0448\u0438\u0431\u043e\u0447\u043d": [83, 93, 100], "\u0431\u0435\u0441\u043f\u043e\u043a\u043e": [83, 85], "\u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b": 83, "\u043d\u0435\u0434\u043e\u043e\u0446\u0435\u043d\u043a": [83, 92], "\u043f\u0440\u043e\u0432\u043e\u0446\u0438\u0440": 83, "\u0445\u0440\u043e\u043d\u0438\u0447\u0435\u0441\u043a": 83, "\u043d\u0435\u0443\u0441\u043f\u0435\u0432\u0430\u0435\u043c": 83, "\u043f\u043e\u0439\u0434\u0435\u0442": 83, "\u0434\u043e\u043b\u0438\u043d": 83, "\u043e\u0442\u0447\u0430\u044f\u043d": 83, "\u0434\u0430\u043d\u043d\u0438\u043d\u0433": [83, 88, 89], "\u043a\u0440\u044e\u0433\u0435\u0440": [83, 88, 89], "\u0438\u0441\u043a\u0430\u0436\u0430": 83, "\u043b\u0435\u0433\u0435\u043d\u0434\u0430\u0440\u043d": 83, "\u043b\u0435\u0442\u0447\u0438\u043a": 83, "\u0430\u0441": 83, "\u0438\u0432\u0430": [83, 96], "\u043a\u043e\u0436\u0435\u0434\u0443\u0431": 83, "\u043d\u0438\u043a\u0438\u0442\u043e\u0432\u0438\u0447": 83, "\u043f\u0440\u0435\u0441\u043b\u0435\u0434\u043e\u0432\u0430": 83, "\u043f\u0435\u0440\u0435\u0432\u0435\u043b": 83, "\u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d": 83, "\u0437\u0430\u0441\u0442\u0443\u043f\u043d\u0438\u0447\u0435\u0441\u0442\u0432": 83, "\u043a\u043e\u043c\u0430\u043d\u0434\u0438\u0440": 83, "\u043f\u043e\u043b\u043a": 83, "\u043c\u0430\u0439\u043e\u0440": 83, "\u0441\u043e\u043b\u0434\u0430\u0442\u0435\u043d\u043a": 83, "\u043f\u043e\u043c\u043e\u0433\u043b": 83, "\u043e\u0434\u0435\u0440\u0436\u0430": [83, 90], "\u0432\u044b\u043b\u0435\u0442": 83, "\u0441\u0431\u0438\u0432": 83, "\u043f\u0438\u043a\u0438\u0440\u043e\u0432\u0449\u0438\u043a": 83, "\u043a\u0438\u0441\u0435\u043b": 83, "\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440": [83, 94], "\u043d\u0435\u0432\u0430\u0436\u043d": 83, "\u043d\u0430\u0437\u0438\u0434\u0430\u0442\u0435\u043b\u044c\u043d": 83, "\u043a\u0443\u0431\u0438\u043d\u0435\u0446": 83, "\u043b\u043e\u043f\u0435\u0441": 83, "\u0447\u0435\u0442\u044b\u0440\u0435\u0445\u043a\u0440\u0430\u0442\u043d": 83, "\u043e\u043b\u0438\u043c\u043f\u0438\u0439\u0441\u043a": 83, "\u0447\u0435\u043c\u043f\u0438\u043e\u043d": 83, "\u0433\u0440\u0435\u043a": 83, "\u0440\u0438\u043c\u0441\u043a": 83, "\u043f\u0440\u0435\u0432\u0437\u043e\u0439\u0434": 83, "\u0430\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440": [83, 88], "\u043a\u0430\u0440\u0435\u043b\u0438\u043d": 83, "\u0434\u043e\u0441\u0440\u043e\u0447\u043d": 83, "\u043f\u0435\u0440\u0435\u043b": 83, "\u043d\u043e\u0433": [83, 90], "\u043f\u043e\u043f\u0430": 83, "\u0441\u0431\u043e\u0440\u043d": 83, "\u043a\u0443\u0431": 83, "\u0448\u043b\u043e": 83, "\u0441\u043e\u0440\u0435\u0432\u043d\u043e\u0432\u0430\u043d": 83, "\u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442": 83, "\u0442\u0440\u0435\u0441\u043a": 83, "\u043f\u0440\u043e\u0432\u0430\u043b": [83, 85], "\u0444\u0438\u043d\u0438\u0448\u0438\u0440\u043e\u0432\u0430": 83, "\u0432\u0435\u0441\u043e\u0432": 83, "\u0432\u044b\u0441\u0442\u0443\u043f": [83, 88], "\u0437\u0430\u043b\u0430\u0434": 83, "\u043e\u043b\u0438\u043c\u043f\u0438\u0430\u0434": 83, "\u0430\u0444\u0438\u043d": 83, "\u0447\u0435\u0442\u0432\u0435\u0440\u0442\u044c\u0444\u0438\u043d\u0430\u043b": 83, "\u043a\u0443\u0431\u0438\u043d\u0446": 83, "\u0440\u043e\u0441\u0441\u0438\u044f\u043d\u0438\u043d": 83, "\u0445\u0430\u0441\u0430": 83, "\u0431\u0430\u0440\u043e": 83, "\u0432\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432": 83, "\u043b\u0438\u0448\u0435\u043d": [83, 102], "\u043c\u0435\u0434\u0430": 83, "\u0437\u0430\u0440\u044f\u0436": 83, "\u0448\u043b\u0438": 83, "\u043d\u0430\u0447\u0438\u043d": 83, "\u0443\u043f\u043e\u0440\u043d": [83, 94], "\u0443\u043f\u0440\u044f\u043c": 83, "\u043f\u043e\u0448\u043b": 83, "2007": 83, "\u043a\u0443\u0431\u0438\u043d\u0441\u043a": 83, "\u0433\u0438\u0433\u0430\u043d\u0442": 83, "\u043f\u043e\u0431": 83, "\u0440\u0435\u043a\u043e\u0440\u0434": 83, "\u043b\u0430\u0437\u043e\u0440\u0438\u043d": 83, "\u0438\u0433\u043e\u0440": 83, "\u0442\u0430\u0441\u0441": 83, "\u0442\u0440\u0443\u0434\u043e\u043b\u044e\u0431": 83, "\u0437\u0430\u0445\u043e\u0442\u0435\u0442": 83, "\u0431\u043e\u044f": 83, "\u043f\u0440\u0435\u043e\u0434\u043e\u043b\u0435\u0432\u0430": 83, "\u043b\u0435\u043d\u043e\u0441\u0442": 83, "\u0442\u0440\u0443\u0441\u043e\u0441\u0442": 83, "\u0441\u0430\u043c\u043e\u0432\u043e\u0441\u043f\u0440\u0438\u044f\u0442": 83, "\u0432\u0441\u0442\u0430\u0442": 83, "\u0434\u0438\u0432\u0430": 83, "\u043f\u043e\u0434\u043d\u044f": 83, "\u0442\u0443\u0448": 83, "\u0441\u043e\u043f\u0435\u0440\u043d\u0438\u043a": 83, "\u043a\u043e\u0432\u0440": 83, "\u0438\u043c\u043f\u0443\u043b\u044c\u0441": 83, "\u0432\u043e\u043b\u0435\u0432": [83, 95], "\u043f\u043e\u043c\u043e\u0433": 83, "\u0432\u044b\u0441\u043e\u043a\u043e\u043a\u043b\u0430\u0441\u0441\u043d": 83, "\u043d\u0435\u043c\u0430": [83, 85], "\u044e\u0440": 83, "\u043d\u0438\u043a\u0443\u043b\u0438\u043d": 83, "\u0432\u0433\u0438\u043a": 83, "\u0430\u043a\u0442\u0435\u0440\u0441\u043a": 83, "\u0433\u0438\u0442\u0438\u0441": 83, "\u0448\u043a\u043e\u043b": [83, 95], "\u0441\u0442\u0443\u0434": 83, "\u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440\u043d": [83, 100], "\u0436\u0430\u043d\u0440": 83, "\u043c\u043e\u0441\u043a\u043e\u0432\u0441\u043a": 83, "\u0446\u0438\u0440\u043a": 83, "\u0446\u0432\u0435\u0442\u043d": 83, "\u0431\u0443\u043b\u044c\u0432\u0430\u0440": 83, "\u0442\u0430\u043b\u0430\u043d\u0442\u043b\u0438\u0432": 83, "sylvester": 83, "stallone": 83, "\u0443\u0441\u043f\u0435\u0432\u0430\u0435\u043c": [83, 95], "\u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d": [83, 85], "\u0432\u043b\u0430\u0434\u0435\u043d": [83, 86, 89], "\u0441\u0442\u0440\u0443": 83, "\u043a\u043e\u043c\u0430\u043d\u0434\u043d": 83, "\u0444\u0430\u043d\u0442\u0430\u0441\u0442\u0438\u0447\u0435\u0441\u043a": 83, "\u043e\u0431\u043b\u0430\u0434\u0430\u043d": 83, "\u0443\u043c\u0435\u043b": [83, 90, 94], "\u0434\u0435\u043c\u043e\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430": 83, "\u0440\u0430\u0437\u043d\u043e\u0433\u043b\u0430\u0441": 83, "\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u043d\u0442": 83, "\u043f\u0440\u043e\u0434\u0430\u043a\u0442": 83, "\u043e\u0446\u0435\u043d\u0438\u0432\u0430\u043d": [83, 86], "\u043d\u0430\u043f\u0440\u043e\u0447": 83, "\u0443\u0431": 83, "\u0432\u0437\u0430\u0438\u043c\u043e\u043f\u043e\u043c\u043e\u0449": 83, "\u0440\u0430\u0437\u043e\u0433\u043d\u0430": 83, "\u043d\u0435\u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d": 83, "\u043f\u0443\u0442\u0430": 83, "\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432": 83, "\u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440": 83, "\u043f\u043e\u0442\u043e\u043f\u0430": 83, "\u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d": [83, 86, 88], "\u0443\u0432\u043e\u043b\u044c\u043d\u0435\u043d": 83, "\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430": 83, "\u043f\u043e\u0441\u0442\u0430\u0432\u043b": 83, "\u043f\u043e\u043b\u0443\u0447\u0448": 83, "\u0432\u043b\u0438": [83, 85], "\u043a\u0430\u0440\u044c\u0435\u0440\u043d": 83, "\u0436\u0438\u0442": 83, "\u0447\u0435\u0441\u0442\u043d": 83, "\u0440\u0432\u0430\u0442": 83, "\u0431\u0440\u043e\u0441\u0430": 83, "\u0431\u043e\u0440\u043e\u0442": 83, "\u0441\u043f\u043e\u043a\u043e\u0439\u0441\u0442\u0432": [83, 95], "\u0434\u0443\u0448\u0435\u0432\u043d": 83, "\u043f\u043e\u0434\u043b\u043e\u0441\u0442": 83, "\u043b\u0435\u0432": 83, "\u043d\u0438\u043a\u043e\u043b\u0430\u0435\u0432\u0438\u0447": 83, "\u0442\u043e\u043b\u0441\u0442": 83, "\u043e\u0441\u043c\u0435\u043b\u0438\u0432\u0430": 83, "\u043c\u043e\u0433\u0443\u0447": 83, "\u0441\u043b\u0430\u0432\u043d": 83, "\u0442\u0440\u0438\u0443\u043c\u0444": 83, "\u043f\u0435\u0440\u0435\u043c\u0435\u0436\u0430": 83, "\u0441\u043b\u0430\u0431": [83, 90], "\u0434\u0443\u0445": 83, "\u043d\u0430\u0441\u043b\u0430\u0436\u0434\u0430": 83, "\u0434\u0443\u0448": 83, "\u0436\u0438\u0432\u0443\u0442": 83, "\u0441\u0443\u043c\u0435\u0440\u043a": 83, "\u043c\u0443\u0436\u0435\u0441\u0442\u0432": 83, "\u0441\u043f\u043e\u0442\u043a\u043d\u0443\u043b": 83, "\u0434\u043e\u0441\u0442\u043e\u0438\u043d": 83, "\u0430\u0440\u0435\u043d": 83, "\u043f\u043e\u043a\u0440\u044b\u0442": [83, 85], "\u043a\u0440\u043e\u0432": 83, "\u0433\u0440\u044f\u0437": 83, "\u043e\u0442\u0432\u0430\u0436\u043d": 83, "\u0431\u043e\u0440\u0435\u0442": 83, "\u0441\u043e\u0432\u0435\u0440\u0448\u0430": 83, "\u043f\u0440\u043e\u043c\u0430\u0445": 83, "\u043f\u043e\u0437\u043d\u0430": 83, "\u043f\u0440\u0435\u0434\u0430\u043d": 83, "\u0432\u044b\u0441\u043e\u0447\u0430\u0439\u0448": 83, "\u043f\u043e\u0441\u0442\u0438\u0433\u0430": 83, "\u0434\u0435\u0440\u0437\u043d\u043e\u0432\u0435\u043d": 83, "\u0445\u043e\u043b\u043e\u0434\u043d": 83, "\u0440\u043e\u0431\u043a": 83, "\u043f\u0430\u0440\u0438\u0436": 83, "\u0441\u043e\u0440\u0431\u043e\u043d": 83, "1910": 83, "\u0442\u0435\u043e\u0434\u043e\u0440": [83, 89], "\u0440\u0443\u0437\u0432\u0435\u043b\u044c\u0442": [83, 89], "\u043b\u0435\u0442\u0430": 83, "\u0443\u043c\u0435\u0435\u0448": 83, "\u043a\u043e\u0432\u0447\u0435\u0433": 83, "\u043b\u044e\u0431\u0438\u0442\u0435\u043b": 83, "\u0442\u0438\u0442\u0430\u043d\u0438\u043a": 83, "\u0441\u043f\u043e\u0442\u044b\u043a\u0430": 83, "\u043c\u0443\u0434\u0440\u043e\u0441\u0442": [83, 92], "\u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442": [83, 92, 100], "\u0437\u0430\u0436\u0435\u0447": 83, "\u0441\u0432\u0435\u0447": 83, "\u043f\u0440\u043e\u043a\u043b\u0438\u043d\u0430": 83, "\u043c\u0430\u0445\u0430\u0442\u043c": 83, "\u0433\u0430\u043d\u0434": 83, "\u0441\u043e\u043b\u043d\u0446": 83, "\u0431\u0435\u0437\u0440\u0430\u0437\u043b\u0438\u0447\u043d": 83, "\u043f\u043e\u0447\u0438\u0442\u0430": [83, 93], "\u0441\u0432\u0435\u0442\u043b\u044f\u0447\u043e\u043a": 83, "\u043f\u043e\u0434\u043e\u0440\u0432\u0430": 83, "\u0432\u043d\u0443\u0448\u0430": 83, "\u0441\u043c\u0435\u043b\u043e\u0441\u0442": [83, 88], "\u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d": [83, 88, 89, 90], "\u0433\u043e\u0441\u043f\u043e\u0434\u0441\u0442\u0432": [83, 90], "\u043c\u043e\u0436\u0435\u0448": 83, "\u0442\u043e\u0431": 83, "\u0432\u043e\u043a\u0440\u0443\u0433": [85, 86], "\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0435\u043b\u044c\u043d": 85, "\u0440\u043e\u043d": 85, "\u0434\u0436\u0435\u0444\u0444\u0440\u0438\u0437": 85, "seeming": 85, "contradiction": 85, "replies": 85, "paradox": 85, "\u0438\u0440\u043e\u043d": 85, "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d": 85, "ironies": 85, "koan": 85, "structuring": 85, "\u0434\u0435\u0444\u0435\u043a\u0442": 85, "\u0438\u0437\u044f\u0449\u0435\u0441\u0442\u0432": 85, "cleaner": 85, "souls": 85, "healed": 85, "balm": 85, "\u0431\u0430\u0437\u0438\u0440": 85, "\u043e\u0447\u0430\u0440\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d": 85, "\u043d\u0430\u0438\u0432\u043d": 85, "\u043f\u043e\u0434\u0445\u043e\u0434\u044f": 85, "\u0447\u0438\u0449": 85, "\u0432\u0441\u0442\u0430\u044e\u0442": 85, "rests": 85, "charmingly": 85, "geekoid": 85, "\u0437\u0430\u043a\u043e\u043d\u043e\u043c\u0435\u0440\u043d": [85, 92], "\u043c\u0438\u043d\u0443\u0441": 85, "\u0430\u043c\u0435\u0440\u0438\u043a\u0430\u043d\u0441\u043a": 85, "\u0434\u0436\u043e\u0440\u0434\u0436": 85, "\u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d": 85, "\u043f\u0440\u0435\u043e\u0434\u043e\u043b\u0435\u0442": [85, 90], "\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0430\u0446": [85, 86, 90, 100], "\u0432\u0435\u043d\u0438\u043a": 85, "\u043f\u043e\u043b\u043e\u043c\u0430": 85, "\u0440\u0430\u0437\u0432\u044f\u0437\u0430": 85, "\u043f\u0440\u0443\u0442\u0438\u043a": 85, "\u043f\u0435\u0440\u0435\u043b\u043e\u043c\u0430": 85, "\u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0440": 85, "\u043f\u0435\u0440\u0435\u043c\u0430\u043b\u044b\u0432\u0430": 85, "\u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d\u0438\u0440\u043e\u0432\u0430": 85, "\u043f\u043e\u044d\u0442\u0430\u043f\u043d": 85, "\u0432\u044b\u0441\u043e\u0442": [85, 90], "\u0444\u0443\u0442": 85, "feet": 85, "\u043d\u0435\u043e\u0431\u044a\u0435\u043c\u043b\u0435\u043c": 85, "\u0437\u0435\u043b\u0435\u043d": 85, "\u043c\u0430\u043d\u0442\u0440": 85, "mantra": 85, "factoring": 85, "\u0434\u043e\u0441\u043b\u043e\u0432\u043d": 85, "\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u0437\u0430\u0446": 85, "5x": 85, "broken": 85, "etymology": 85, "reorganization": 85, "equivalence": 85, "functionally": 85, "whatisreworking": 85, "practically": 85, "rewriting": 85, "grokable": 85, "operators": 85, "arguably": 85, "\u043d\u0430\u0441\u0442\u0430\u0432\u043d\u0438\u0447\u0435\u0441\u0442\u0432": 85, "\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0435\u0441\u0442\u0432": 85, "\u0443\u043e\u0440\u0434": 85, "\u043a\u0430\u043d\u043d\u0438\u043d\u0433\u044d\u043c": 85, "\u0434\u0440\u0443\u0436\u0431": 85, "\u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d": 85, "patient": 85, "mentoring": 85, "comfort": 85, "intimacy": 85, "factorization": 85, "decompositions": 85, "surjective": 85, "injective": 85, "conceive": 85, "\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u0437": 85, "\u0446\u0438": 85, "\u0444\u0430": 85, "\u043a\u0442\u043e\u0440\u0438\u043d\u0433": 85, "\u043f\u043e\u043b\u0438\u043d\u043e\u043c": 85, "\u043c\u0430\u0442\u0440\u0438\u0446": 85, "\u0431\u0443\u0434\u0443\u0447": 85, "\u043f\u0435\u0440\u0435\u043c\u043d\u043e\u0436\u0435\u043d": 85, "\u043f\u043e\u043b\u0438\u043d": 85, "x2": 85, "\u043f\u043e\u0434\u043e\u0431": [85, 92, 94], "\u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d": [85, 102], "\u0440\u0430\u0441\u0449\u0435\u043f\u043b\u044f": 85, "\u043f\u0435\u0441\u043e\u0447\u043d": [85, 95], "\u043f\u0435\u0441\u0447\u0438\u043d\u043a": [85, 95], "\u0438\u0437\u043e\u043b\u0438\u0440": 85, "\u0445\u0438\u0440\u0443\u0440\u0433\u0438\u0447\u0435\u0441\u043a": 85, "\u043e\u043f\u0435\u0440\u0438\u0440\u0443\u0435\u043c": 85, "\u043f\u0430\u0446\u0438\u0435\u043d\u0442": 85, "\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d": [85, 93, 100], "\u043f\u0440\u043e\u0441\u0442\u044b\u043d": 85, "\u0432\u0440\u0430\u0447": 85, "\u0441\u043a\u043e\u043b": 85, "\u043e\u0431\u0441\u0443\u0436\u0434\u0430": 85, "\u043e\u0440\u0433\u0430": 85, "isolate": 85, "operated": 85, "draped": 85, "draping": 85, "surgeon": 85, "abdomen": 85, "health": 85, "glad": 85, "\u0448\u043e\u0440": 85, "\u043e\u0449\u0443\u0449\u0430": 85, "\u0436\u043e\u043d\u0433\u043b\u0438\u0440": 85, "\u0448\u0430\u0440\u0438\u043a": 85, "\u0441\u044b\u043f\u0435\u0442": 85, "\u0434\u043e\u0431": 85, "\u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d": 85, "\u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430": 85, "\u0440\u0435\u0436": [85, 92], "\u0431\u0435\u0441\u043f\u043e\u043a": 85, "\u0440\u0430\u0441\u043f\u044b\u043b\u044f": 85, "lapse": 85, "concentration": 85, "tumbling": 85, "unhurriedness": 85, "ball": 85, "concentrate": 85, "worried": 85, "afterword": 85, "\u0432\u0442\u043e\u0440\u0438\u0447\u043d": 85, "\u043d\u0435\u0440\u0432\u043d": 85, "\u0437\u0430\u0441\u0442\u0430\u0432": 85, "pa\u0431\u043e\u0442\u0430": 85, "\u043f\u0430\u0440\u0442\u043d\u0435\u0440": 85, "\u0441\u0431\u043e": 85, "\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d": 85, "\u0432\u044b\u043f\u0443\u0441\u043a": 85, "mars": 85, "lander": 85, "teammates": 85, "andpeople": 85, "host": 85, "\u0443\u0434\u0435\u0440\u0436\u0430": 85, "\u0431\u0435\u0440\u0435\u0442": [85, 89], "\u043b\u0438\u0441\u0442\u043e\u0447\u0435\u043a": 85, "\u0440\u0443\u0447\u043a": 85, "\u043b\u0438\u0441\u0442\u043e\u0447\u043a": 85, "\u043f\u0435\u0440\u0435\u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [85, 92], "\u043f\u0440\u0430\u043a\u0442\u0438\u043a\u043e\u0432\u0430\u043d": 85, "\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c": [85, 90, 94], "\u0442\u0440\u0438\u0430\u043d\u0433\u0443\u043b\u044f\u0446": [85, 93], "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u044f": [85, 86], "\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430": 85, "\u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d": 85, "\u0432\u044b\u0432\u0435\u0434\u0435\u043d": [85, 92], "\u0444\u0438\u0431\u043e\u043d\u0430\u0447": 85, "fibonacci": 85, "\u043e\u0431\u043e\u0431\u0449": [85, 92], "\u0437\u0430\u043c\u0435\u043d\u044f": [85, 100], "\u0443\u043c\u043e\u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d": 85, "generalize": [85, 93], "replacing": [85, 93], "constants": [85, 93], "hardwired": [85, 93], "reasoning": [85, 93], "\u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d": 85, "\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440\u0443\u0435\u0442": 85, "imagining": 85, "sorts": 85, "generalizing": 85, "prevents": 85, "prematurely": 85, "confusing": 85, "extraneous": [85, 100], "recurrent": 85, "tower": [85, 86], "hanoi": 85, "\u043d\u0438\u0442\u043e\u0447\u043a": 85, "\u0440\u0430\u0441\u043f\u0443\u0442\u0430": 85, "\u043a\u043b\u0443\u0431\u043e\u043a": 85, "\u043f\u043e\u0434\u0441\u0442\u0443\u043f": 85, "\u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430": 85, "\u0432\u0434\u0432\u043e": 85, "83": 85, "\u0441\u0432\u0435\u0445": 85, "\u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442": 85, "\u0437\u0430\u0432\u044b\u0448": 85, "gorman": 85, "\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430": 85, "\u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d": 85, "\u043a\u0430\u0442": 85, "\u043f\u0435\u0440\u0435\u043f\u0440\u043e\u0432\u0435\u0440\u044f": 85, "\u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0438\u0440\u043e\u0432\u0430": 85, "decouple": 85, "untestable": 85, "mass": 85, "outputs": 85, "\u043f\u0440\u0435\u0443\u0432\u0435\u043b\u0438\u0447": [85, 88], "\u0431\u0435\u0437\u0443\u0441\u043b\u043e\u0432\u043d": 85, "overstating": 85, "sink": 85, "\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f": 85, "\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d": 85, "\u043d\u0435\u043f\u043e\u043b\u043d": 85, "shore": 85, "\u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f": [85, 88, 92], "opportunities": 85, "\u0442\u0435\u0441\u0442\u0438\u0440\u0443": 85, "\u043f\u043e\u0434\u043c\u0435\u043d\u044f": 85, "\u0433\u043b\u0443\u0431": 85, "\u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d": [85, 86, 88], "\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430": 85, "\u043e\u043a\u043e\u0432": 85, "\u043a\u0440\u0435\u0441\u0442": 85, "personal": 85, "mock": 85, "mocks": 85, "couldn": 85, "streets": 85, "piecemeal": 85, "assertequals": 85, "\u0431\u0443\u043b\u0435\u0432\u0441\u043a": 85, "\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442": 85, "startdate": 85, "\u0440\u0430\u0432": 85, "\u043f\u043b\u044b\u0442": 85, "\u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b": 85, "jxunit": 85, "junit": 85, "\u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d": 85, "\u043f\u043e\u0434\u0435\u043b\u0430": 85, "\u0441\u043c\u0430\u0445\u0438\u0432\u0430": 85, "\u043d\u0435\u043f\u0440\u043e\u0448\u0435\u043d": 85, "\u0441\u043b\u0435\u0437": 85, "\u0432\u043d\u043e\u0448": 85, "\u043d\u0430\u0434\u0435": 85, "\u043d\u0430\u0441\u0442\u0443\u043f": 85, "boxes": 85, "throws": 85, "swimming": 85, "tide": 85, "extends": 85, "wishing": 85, "anytime": 85, "checking": 85, "ran": 85, "shed": 85, "\u043f\u0440\u0430\u0433\u043c\u0430\u0442\u0438\u0447": 85, "\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443": [85, 92], "heavy": 85, "parse": 85, "pollute": 85, "speculation": 85, "providing": 85, "rip": 85, "\u043a\u043e\u0432\u0430\u0440\u043d": 85, "\u043f\u043e\u0432\u043b\u0435\u0447": 85, "\u0445\u0440\u0443\u043f\u043a": 85, "\u043d\u0430\u043f\u0440\u043e\u0442": 85, "strongest": 85, "insidious": 85, "fragile": 85, "rigid": 85, "increasingly": 85, "impedes": 85, "\u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430": 85, "\u0434\u0443\u0431\u043b\u0435\u0440": 85, "criticized": 85, "mockist": 85, "mockists": 85, "insist": 85, "classicists": 85, "stayed": 85, "pyramid": 85, "ham": 85, "vocke": 85, "testdrivendevelopment": 85, "implicates": 85, "recent": 85, "reverting": 85, "stubs": 85, "\u043c\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d": 85, "\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0438\u0440": 85, "monkey": 85, "patch": 85, "\u043d\u0438\u0437\u043a\u043e\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d": 85, "\u043c\u043e\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 85, "\u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d": 85, "\u043e\u0431\u043e\u043b\u043e\u0447\u043a": 85, "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430": 85, "\u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430": 85, "\u043f\u043e\u043b\u0443\u0444\u0430\u0431\u0440\u0438\u043a\u0430\u0442": 85, "\u0437\u0430\u0434\u0443\u043c\u044b\u0432": 85, "\u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430": 85, "\u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": 85, "\u0441\u043c\u0435\u0441": 85, "\u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d": [85, 94], "\u043f\u0440\u0438\u0432\u0435\u0440\u0436\u0435\u043d\u0446": 85, "\u043b\u0438\u0434\u0435\u0440": [85, 88], "\u043e\u043f\u0430\u0441\u043d": [85, 86], "\u043c\u043e\u0449": 85, "monological": 85, "flavors": 85, "stint": 85, "keyboard": 85, "pulled": 85, "programmed": 85, "fair": 85, "manipulating": 85, "baked": 85, "oven": 85, "blindly": 85, "struggled": 85, "intersection": 85, "advocates": 85, "dangerous": [85, 86], "concert": 85, "inevitably": 85, "emphasized": 85, "eloquently": 85, "repeat": 85, "bearing": [85, 86], "fresh": [85, 86, 94], "sixteen": [85, 94], "evening": [85, 94], "fueled": [85, 94], "malt": [85, 94], "joke": [85, 94], "overused": [85, 94], "invent": 85, "gradually": 85, "treats": 85, "mailing": 85, "discouraging": 85, "irony": 85, "vitally": 85, "backbone": 85, "evolving": 85, "xpers": 85, "pulling": 85, "emphasize": 85, "objectclub": 85, "jp": 85, "xp_relate": 85, "xp_patterns": 85, "industriallogic": 85, "patternsandxp": 85, "\u0443\u0431\u0435\u0436\u0434\u0435\u043d": 85, "\u0443\u043c\u0430\u043b\u0447\u0438\u0432\u0430": 85, "contentious": 85, "insistence": 85, "testcase": 85, "fixture": 85, "verifying": 85, "awaitingapprovalflight": 85, "validapproverrequestshouldbeapproved": 85, "elds": 85, "comply": 85, "extracting": 85, "474": 85, "readable": 85, "dogmatic": 85, "\u043b\u0438\u0441\u0442\u0438\u043d\u0433": 85, "\u0434\u0438\u0440\u0435\u043a\u0442": 85, "\u0441\u0432\u0435\u0434": 85, "\u043c\u0438\u043d\u0438\u043c\u0443\u043c": 85, "domainspeci\ufb01c": 85, "supports": 85, "ought": 85, "minimized": 85, "astels": 85, "\u0443\u043a\u043b\u0430\u0434\u044b\u0432\u0430": 86, "\u0437\u0430\u0434\u0435\u0440\u0436": 86, "manpower": 86, "communications": 86, "cotton": 86, "partitionable": 86, "nine": 86, "women": 86, "baby": 86, "woman": 86, "picking": 86, "staff": 86, "brought": 86, "train": 86, "repealed": 86, "\u0432\u0437\u0430\u0438\u043c\u043e\u0437\u0430\u043c\u0435\u043d\u044f": 86, "\u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b": [86, 95], "interchangeable": 86, "commodities": 86, "workers": 86, "fig": 86, "stefan": 86, "tilkov": 86, "consultant": 86, "innoq": 86, "\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u044b\u0432\u0430": 86, "\u0438\u0437\u0434\u0435\u0440\u0436\u0435\u043a": 86, "\u043e\u0431\u0449\u0435\u043d": [86, 92, 102], "\u0440\u0430\u0437\u043e\u0431\u0449\u0435\u043d": 86, "\u0432\u043b\u0435\u0447\u0435\u0442": 86, "\u0443\u0434\u043e\u0440\u043e\u0436\u0430\u043d": 86, "\u0437\u0430\u043c\u0435\u0434\u043b\u0435\u043d": 86, "\u043d\u0435\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d": 86, "\u0446\u0435\u043b\u043e\u0441\u0442\u043d": [86, 93], "\u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0438\u0440": 86, "\u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447": 86, "os": 86, "exec": 86, "scop": 86, "6600": 86, "multics": 86, "tss": 86, "sage": 86, "argued": 86, "sheer": 86, "minds": 86, "coordinated": 86, "affects": 86, "miscommunication": 86, "brute": 86, "costly": 86, "inefficient": 86, "codebases": 86, "\u043f\u043e\u043b\u043e\u0436": 86, "\u043c\u0430\u043b\u043e\u0447\u0438\u0441\u043b\u0435\u043d": 86, "\u043f\u0440\u043e\u0442\u044f\u0436\u0435\u043d": [86, 88], "5000": 86, "\u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442": 86, "tackled": 86, "postulate": 86, "\u0434\u0438\u043b\u0435\u043c\u043c": 86, "\u0436\u0435\u0441\u0442\u043e\u043a": 86, "\u0441\u0432\u0435\u0442\u043b": 86, "\u0433\u043e\u043b": 86, "\u0440\u0443\u0436": 86, "\u043a\u043e\u043d\u0442\u0438\u043d\u0433\u0435\u043d\u0442": 86, "\u0432\u043e\u0432\u0440\u0435\u043c": 86, "\u043f\u0440\u0438\u043c\u0438\u0440": 86, "dilemma": 86, "cruel": 86, "prefers": 86, "bear": 86, "appearance": 86, "reconciled": 86, "\u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0435\u043d": [86, 102], "\u0437\u0430\u043a\u043b\u044e\u0447": 86, "\u0438\u0437\u043c\u0435\u0440\u044f": 86, "\u0437\u0430\u0442\u0440\u0430\u0447\u0435\u043d": 86, "\u0436\u043d\u0443\u0442": 86, "\u043f\u0448\u0435\u043d\u0438\u0446": 86, "\u0445\u043b\u043e\u043f\u043e\u043a": 86, "\u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c": 86, "\u0440\u0430\u0437\u0431": 86, "\u0440\u0435\u0431\u0435\u043d\u043a": 86, "\u0434\u0435\u0432\u044f": 86, "\u0436\u0435\u043d\u0449\u0438\u043d": 86, "\u043f\u0440\u0438\u0432\u043b\u0435\u0447": 86, "\u043d\u043e\u0441": [86, 100, 102], "\u043d\u0435\u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c": 86, "unpartitionable": 86, "\u0440\u0430\u0437\u0431\u0438\u0442": [86, 89, 94], "\u043f\u043e\u0434\u0437\u0430\u0434\u0430\u0447": 86, "\u0434\u043e\u0431\u0430\u0432\u043b": 86, "\u0434\u043e\u0441\u0442\u0438\u0436\u0438\u043c": 86, "\u043e\u0431\u0443\u0447": 86, "\u043e\u0431\u043c\u0435\u043d": 86, "\u0441\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u043e\u0432\u0430": 86, "\u0432\u0442\u0440\u043e": 86, "\u043f\u043e\u043f\u0430\u0440\u043d": 86, "\u0432\u0448\u0435\u0441\u0442\u0435\u0440": 86, "\u0441\u043e\u0432\u0435\u0449\u0430\u043d": [86, 92], "\u043e\u0431\u0435\u0441\u0446\u0435\u043d": 86, "\u0434\u0440\u043e\u0431\u043b\u0435\u043d": 86, "\u0440\u0438\u0441\u0443\u043d\u043a": [86, 100], "interrelationships": [86, 100], "\u043f\u0440\u0438\u0432\u043b\u0435\u0447\u0435\u043d": [86, 102], "\u0441\u043e\u043a\u0440\u0430\u0449\u0430": [86, 93], "\u0443\u0434\u043b\u0438\u043d\u044f": 86, "fallacious": 86, "deceptive": 86, "reaping": 86, "wheat": 86, "child": 86, "subtasks": 86, "poorer": 86, "intercommunication": 86, "worker": 86, "linearly": 86, "increases": 86, "pairwise": 86, "moreover": 86, "conferences": 86, "jointly": 86, "communicating": 86, "counteract": 86, "division": 86, "inherently": 86, "dominates": 86, "lengthens": 86, "shortens": 86, "\u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430": 86, "\u0432\u044b\u0439\u0442": 86, "\u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443": 86, "\u0441\u043f\u0440\u0430\u0432\u043b\u044f": 86, "\u0431\u043b\u0430": 86, "blaauw": 86, "\u0446\u0438\u0444\u0435\u0440\u0431\u043b\u0430\u0442": 86, "\u0441\u0442\u0440\u0435\u043b\u043e\u043a": 86, "\u0437\u0430\u0432\u043e\u0434\u043d": 86, "\u0433\u043e\u043b\u043e\u0432\u043a": 86, "\u0440\u0435\u0431\u0435\u043d\u043e\u043a": 86, "\u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432": 86, "\u0440\u0443\u0447\u043d": 86, "\u043a\u043e\u043b\u043e\u043a\u043e\u043b\u044c\u043d": 86, "distinguished": 86, "winding": 86, "knob": 86, "wristwatch": 86, "church": 86, "realization": 86, "powering": 86, "accuracy": 86, "harlan": 86, "proposal": 86, "federal": 86, "fsc": 86, "71": 86, "5108": 86, "gaithersburg": 86, "1971": 86, "baker": 86, "\u0441\u0432\u0435\u0436": 86, "\u0443\u0447\u0430\u0441\u0442\u043a": [86, 90], "\u043d\u0430\u043f\u043e\u0434\u043e\u0431": 86, "\u0431\u0440\u0438\u0433\u0430\u0434": 86, "\u043c\u044f\u0441\u043d\u0438\u043a": 86, "\u0432\u0440\u0435\u0437\u0430": 86, "\u0440\u0435\u0437\u0430": 86, "\u0432\u0441\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d": 86, "\u043f\u043e\u0432\u044b\u0448": 86, "\u043f\u043b\u043e\u0434\u043e\u0442\u0432\u043e\u0440\u043d": 86, "\u043f\u043e\u0434\u0445\u0432\u0430\u0442": 86, "\u0430\u043d\u0435\u0441\u0442\u0435\u0437\u0438\u043e\u043b\u043e\u0433": 86, "\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d": 86, "\u0441\u0435\u0441\u0442\u0435\u0440": 86, "\u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430": [86, 92], "\u043c\u044b\u0441\u043b\u0438\u043c": 86, "\u0432\u043e\u043b\u044c\u043d": 86, "surgical": 86, "hog": 86, "butchering": 86, "enhance": 86, "desiderata": 86, "anesthesiologists": 86, "nurses": 86, "freely": 86, "metaphors": 86, "enlarged": 86, "conceivable": 86, "aim": 86, "pace": 86, "premium": 86, "rescued": 86, "helpful": 86, "influx": 86, "accelerated": 86, "ramp": 86, "netflix": 86, "\u043f\u0440\u043e\u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430": 86, "\u0432\u0441\u0435\u0446\u0435\u043b": 86, "\u0440\u0430\u0441\u043f\u043e\u0440\u044f\u0436\u0430": 86, "\u0443\u043f\u0440\u0430\u0432\u043b": 86, "\u0437\u043d\u0430\u043b": [86, 95], "\u043d\u0430\u043a\u043e\u0440\u043c": 86, "\u043f\u0438\u0446\u0446": 86, "\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440": 86, "\u0432\u043e\u043e\u0440\u0443\u0436\u0435\u043d": 86, "\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c": 86, "\u043f\u0440\u0438\u0446\u0435\u043b": 86, "poster": 86, "children": 86, "owning": 86, "famously": 86, "pizza": 86, "fed": 86, "pizzas": 86, "ensured": 86, "optimized": 86, "kit": 86, "\u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d": 86, "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b": 86, "\u0430\u0432\u0442\u043e\u043d\u043e\u043c": 86, "contemporary": 86, "singular": 86, "elegantly": 86, "friction": 86, "ship": 86, "toolkit": 86, "\u0430\u0440\u043c\u0435\u0439\u0441\u043a": 86, "\u0443\u043a\u0440\u0435\u043f\u043b\u044f": 86, "\u043c\u0438\u043a\u043e\u0440\u0441\u0435\u0440\u0432\u0438\u0441": 86, "\u0430\u043c": 86, "monolithic": 86, "creeping": 86, "leak": 86, "\u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u043d": 86, "\u0443\u043f\u0440\u043e\u0447": 86, "\u043e\u0431\u043e\u0441\u043e\u0431\u043b\u0435\u043d": 86, "\u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d": [86, 100], "perils": 86, "\u0447\u0435\u0440\u0432\u044f\u043a": 86, "\u0431\u0435\u0441\u043f\u043e\u0437\u0432\u043e\u043d\u043e\u0447\u043d": 86, "\u0436\u0438\u0432\u043e\u0442\u043d": 86, "\u0442\u044f\u0436\u0435\u0441\u0442": [86, 90, 95], "\u043f\u0440\u043e\u0447\u043d\u043e\u0441\u0442": [86, 90], "\u043e\u043f\u0435\u0440\u0435\u0436\u0430": 86, "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043c": 86, "\u043e\u043f\u043e\u0440\u043d": 86, "\u043a\u043e\u0440\u0430\u0431\u043b\u0438\u043a": 86, "\u0434\u0435\u0440\u0436": [86, 90], "\u043f\u0440\u043e\u043f\u043e\u0440\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": [86, 93], "\u0440\u0443\u0445\u043d\u0435\u0442": 86, "\u0444\u0435\u0440\u043c": 86, "\u0436\u0435\u0441\u0442\u043a\u043e\u0441\u0442": 86, "\u0441\u0435\u043b": 86, "\u0433\u043e\u0440\u043e\u0434": [86, 89], "\u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d": 86, "\u043c\u0430\u0433\u0438\u0441\u0442\u0440\u0430": 86, "galileo": 86, "galilei": 86, "beam": 86, "bending": 86, "discorsi": 86, "dimostrazioni": 86, "matematiche": 86, "intorno": 86, "\u00e0": 86, "nuoue": 86, "scienze": 86, "leiden": 86, "appresso": 86, "gli": 86, "elsevirii": 86, "1638": 86, "mathematicians": 86, "statics": 86, "strength": 86, "transmit": 86, "length": 86, "decreases": 86, "thickness": 86, "breadth": 86, "triple": 86, "dimensions": 86, "animal": 86, "branches": 86, "limbs": 86, "illustration": 86, "cantilever": 86, "\u0431\u0430\u043b\u043a": 86, "\u043a\u0443\u0431\u0430\u0442\u0443\u0440": 86, "\u0441\u0435\u0447\u0435\u043d": 86, "\u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0443\u0440": 86, "\u0440\u0430\u0432\u043d\u043e\u0441\u0438\u043b\u044c\u043d": 86, "\u0434\u0438\u043d\u043e\u0437\u0430\u0432\u0440": 86, "\u0440\u0443\u0448": 86, "\u043d\u0435\u0443\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044c\u043d": 86, "\u0434\u0432\u0438\u0436\u0435\u043d": 86, "\u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440": 86, "\u044d\u043a\u0438\u043f\u0430\u0436": 86, "\u0440\u0430\u0441\u0445\u043e\u0434": 86, "\u044d\u0448\u0435\u043b\u043e\u043d": 86, "\u043f\u043e\u0441\u0430\u0434\u043a": 86, "\u0432\u0437\u043b\u0435\u0442": 86, "\u0433\u0438\u043f\u043e\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a": 86, "\u0440\u0430\u0439\u043e\u043d": 86, "\u043c\u0430\u043b\u043e\u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d": 86, "\u0430\u044d\u0440\u043e\u043f\u043e\u0440\u0442": 86, "\u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0435\u0442": [86, 100], "\u0441\u0443\u0434\u043d": [86, 90, 92, 100], "\u0448\u0435\u0440\u0435\u043c\u0435\u0442\u044c\u0435\u0432": 86, "\u0442\u0435\u0440\u043f": 86, "\u0431\u0435\u0434\u0441\u0442\u0432": 86, "squads": 86, "road": 86, "coordinates": 86, "input": 86, "squad": 86, "tribes": 86, "guilds": 86, "anders": 86, "ivarsson": 86, "oct": 86, "2012": [86, 88], "\u043e\u0442\u0447\u0435\u0442\u043b\u0438\u0432": 86, "\u0440\u0435\u0433\u043b\u0430\u043c\u0435\u043d\u0442\u0438\u0440": 86, "\u043e\u0431\u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430": 86, "titles": 86, "analysts": 86, "personnel": 86, "assure": 86, "conformance": 86, "specialists": 86, "designers": 86, "administrators": 86, "whomever": 86, "\u043d\u0435\u0441\u0438\u043d\u0445\u0440\u043e\u043d": 86, "\u043e\u043f\u0435\u0440\u0435\u0436": 86, "\u0434\u043e\u0432\u0435\u0434\u0435\u043d": 86, "\u043e\u0442\u0432\u043b\u0435\u043a\u0430": 86, "\u043d\u0430\u043b\u0438\u0446": 86, "\u043d\u0430\u043a\u043b\u0430\u0434\u043d": 86, "\u043f\u043e\u0433\u0440\u0443\u0436\u0430": 86, "\u0434\u0443\u0431\u043b\u0438\u0440\u0443": 86, "\u0441\u043c\u0435\u0449\u0435\u043d": 86, "pridiction": 86, "backlogs": 86, "\u043c\u044f": 86, "runway": 86, "dimension": 86, "assist": 86, "devops": [86, 88], "staging": 86, "readily": 86, "dbas": 86, "\u043e\u0440\u0443\u0436": 86, "\u043d\u0435\u043e\u0441\u043f\u043e\u0440\u0438\u043c": 86, "\u043e\u0441\u0442\u0440": 86, "\u0443\u0441\u043b\u044b\u0448": 86, "\u0432\u043e\u0437\u0440\u0430\u0436\u0435\u043d": 86, "analogous": 86, "similarities": 86, "synergies": 86, "yuval": 86, "yeret": 86, "\u0443\u0437\u043a": [86, 93], "\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440": 86, "\u043f\u0440\u0435\u0434\u043b\u0430\u0433": 86, "\u0434\u0435\u043b\u0435\u0433\u0430\u0446": [86, 88], "\u0433\u043e\u0440\u043b\u044b\u0448\u043a": 86, "delegate": 86, "subordinate": 86, "kanbans": 86, "enablers": 86, "epics": 86, "\u043f\u0440\u043e\u0447": 86, "\u043b\u0435\u0441\u0442\u043d": 86, "\u043e\u0442\u0437\u044b\u0432": 86, "complementary": 86, "ranging": 86, "\u0432\u044b\u0441\u0442\u0440\u043e": 86, "\u0434\u0435\u043b\u0438\u043a\u0430\u0442\u043d": [86, 88, 92], "\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0435\u043b": 86, "sized": 86, "director": 86, "qentinel": 86, "awareness": 86, "adaptations": 86, "augmented": 86, "scales": 86, "hundred": 86, "solvable": 86, "fracture": 86, "reconcile": 86, "airline": 86, "profiled": 86, "extensively": 86, "occasional": 86, "exceptions": 86, "norm": 86, "coordinating": 86, "fails": 86, "faced": 86, "senior": 86, "commitment": [86, 88], "remediation": 86, "branding": 86, "sos": 86, "factory": 86, "amogh": 86, "founders": 86, "experiences": 86, "proving": 86, "peppered": 86, "canadian": 86, "rasmusson": 86, "mcdonald": 86, "achievement": 86, "\u0432\u044b\u0437\u044b\u0432\u0430\u0442": 86, "selected": 86, "vetted": 86, "workable": 86, "continues": 86, "\u0437\u0430\u0432\u043e\u0434": 86, "\u0444\u0430\u0437": [86, 89, 91, 92, 138], "powerhouse": 86, "kyle": 86, "foreman": 86, "\u0445\u0440\u0435\u0431\u0442": 86, "\u0441\u0432\u043e\u0435\u0432\u0440\u0435\u043c\u0435\u043d": 86, "\u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u0430\u0446": 86, "\u043a\u0430\u0440\u0442": [86, 92, 94, 100], "\u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u043e\u043d": [86, 100], "supplier": 86, "\u043a\u043e\u043d\u0442\u0440\u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0438\u0432\u043d": 86, "cdc": 86, "obstacles": 86, "118": 86, "jyri": 86, "lehv\u00e4": 86, "niko": 86, "m\u00e4kitalo": 86, "tommi": 86, "mikkonen": 86, "pact": 86, "provider": 86, "pathways": 86, "bullet": 86, "caves": 86, "toss": 86, "invested": 86, "organisation": 86, "cd": 86, "setup": 86, "\u043c\u0438\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430": 86, "maccormack": 86, "participation": 86, "contribution": 86, "exploring": 86, "remit": 86, "kelly": 86, "conway": 86, "modernization": [86, 88], "weak": 86, "evan": 86, "bottcher": 86, "audit": 86, "\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a": 88, "\u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 88, "\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d": 88, "\u0440\u0430\u0437\u0440": 88, "\u0441\u043c\u0438\u0440\u044f": 88, "\u043f\u0440\u043e\u044f\u0432": 88, "\u043e\u043f\u0430\u0441": 88, "\u043f\u043e\u0434\u0430\u0432": 88, "\u0434\u0438\u0441\u0441\u043e\u043d\u0430\u043d\u0441": [88, 89], "\u043f\u0440\u0438\u0443\u043c\u0435\u043d\u044c\u0448": 88, "\u043e\u0442\u0432\u0435\u0440\u0433\u043d\u0443\u0442": 88, "\u0432\u0441\u043b\u0435\u0434\u0441\u0442\u0432": 88, "\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043a": 88, "\u0440\u0435\u0430\u043a\u0446\u0438\u043e\u043d\u0438\u0441\u0442": 88, "\u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a": [88, 94], "\u044e\u043d\u043e\u0448\u0435\u0441\u043a": 88, "\u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u0438\u0437\u043c": 88, "\u043a\u0435\u043c": 88, "\u0444\u0430\u0442\u0430\u043b\u0438\u0437\u043c": 88, "\u0442\u0440\u0443\u0441": 88, "\u0443\u0447": [88, 92], "\u0441\u043e\u043a\u0440\u0443\u0448\u0430": 88, "\u0434\u043e\u0440\u043e\u0433": 88, "\u0448\u0430\u0440\u043b": 88, "\u0434\u0435": 88, "\u0433\u043e\u043b\u043b": 88, "\u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d": 88, "\u0440\u0430\u0437\u0440\u044b\u0432": 88, "\u0440\u0438\u0433\u0438\u0434\u043d": 88, "\u043e\u0431\u0443\u0447\u0430\u0435\u043c": [88, 89], "\u0432\u043e\u0437\u0432\u0435\u0441\u0442": 88, "\u043f\u0440\u0435\u0441\u0442\u0438\u0436": [88, 94], "\u0448\u0435": 88, "\u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a": 88, "\u043d\u0435\u043f\u0440\u0430\u0432\u043e\u0442": 88, "\u0441\u0435\u043b\u0435\u043a\u0442\u0438\u0432\u043d": [88, 89], "\u0441\u043a\u043b\u043e\u043d\u043d\u043e\u0441\u0442": [88, 89, 94], "\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430": 88, "\u0442\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a": 88, "\u0440\u0430\u0441\u0441\u0435\u044f": 88, "\u0432\u043e\u0434": [88, 90], "\u043a\u0430\u043c\u0435\u043d": [88, 90], "\u0442\u043e\u0447": [88, 90], "\u043c\u043e\u0440": [88, 90], "\u0440\u0435\u0436\u0435\u0442": [88, 90], "\u0441\u043a\u0430\u043b": [88, 90], "\u0432\u0434\u043e\u0445\u043d\u043e\u0432\u043b\u044f": [88, 90], "\u0441\u0442\u0435\u043a\u0430": [88, 90], "\u043a\u0430\u043f\u0435\u043b\u044c\u043a": [88, 90], "\u043f\u0440\u043e\u0440\u0435\u0437\u0430": [88, 90], "\u043a\u0430\u043c\u043d": [88, 90], "\u0431\u043e\u0440\u043e\u0437\u0434\u043a": [88, 90], "\u0443\u0433\u043b\u0443\u0431\u043b\u044f": [88, 90], "\u0433\u043b\u044b\u0431": [88, 90, 93], "\u043e\u0431\u0440\u0443\u0448": [88, 90], "\u043a\u0430\u043f\u043b": [88, 90], "\u0442\u0435\u0440\u043f\u0435\u043d": 88, "\u0433\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d": 88, "\u0441\u0438\u043b\u043e\u0432": [88, 90], "\u0443\u0434\u0435\u043b\u044c\u043d": [88, 90], "\u043f\u043b\u043e\u0449\u0430\u0434": [88, 90, 100], "\u0441\u0440\u0430\u0431\u043e\u0442\u0430": 88, "\u043a\u0430\u0441\u043a\u0430\u0434": [88, 89], "\u0433\u0435\u043d\u0440": 88, "\u0444\u043e\u0440\u0434": 88, "\u043f\u0440\u043e\u043b\u0438\u0432\u0430\u043d": 88, "\u043d\u0435\u0434\u043e\u0441\u0442\u0430": [88, 92, 95], "\u0441\u043f\u0443\u0441\u043a\u0430": 88, "\u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u043d": 88, "\u0432\u043d\u0435\u0434\u0440": 88, "\u043f\u043e\u0434\u043f\u0438\u0442\u044b\u0432\u0430": 88, "\u0441\u043b\u0443\u0448\u0430": 88, "\u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430": [88, 92, 93], "\u0442\u0430\u043a\u0442\u0438\u043a": 88, "\u043a\u043e\u043d\u043a\u0440\u0435\u0442\u0438\u0437\u0438\u0440": 88, "\u0437\u0430\u0434\u0430\u0432\u0430": 88, "\u043d\u0430\u0448\u0443\u043c\u0435\u0432\u0448": 88, "\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d": 88, "\u0441\u0438\u043d\u044c\u043e\u0440": 88, "\u0434\u0435\u0440\u0436\u0430": 88, "\u043f\u0440\u0438\u0448\u0435\u043b": 88, "\u0441\u0430\u0431\u043e\u0442\u0438\u0440\u043e\u0432\u0430": 88, "\u0440\u0430\u0441\u043a\u043e\u043b": [88, 92], "\u043c\u043d\u043e\u0433\u043e\u043b\u0435\u0442\u043d": 88, "\u0432\u043a\u043b\u0430\u0434": 88, "\u043d\u0435\u0434\u043e\u0432\u0435\u0440": 88, "\u043d\u0430\u043d\u044f\u0442": 88, "\u043f\u043e\u0434\u0447\u0438\u043d\u044f": 88, "\u043a\u0430\u0442\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440": 88, "forming": 88, "\u043f\u0440\u0438\u043d\u0443\u0436\u0434\u0435\u043d": [88, 92], "\u043a\u043e\u043d\u0441\u043e\u043b\u0438\u0434\u0430\u0446": [88, 92], "\u0440\u0430\u0441\u043f\u0430": 88, "\u043f\u0440\u0438\u043d\u0443\u0436\u0434\u0430": 88, "\u043d\u0435\u0434\u043e\u043e\u0446\u0435\u043d\u0435\u043d": 88, "\u043d\u0435\u0434\u043e\u043e\u0446\u0435\u043d\u043d\u0435\u043d": 88, "\u043f\u043e\u0447\u0443\u0432\u0441\u0442\u0432\u043e\u0432\u0430": 88, "\u043e\u043a\u0430\u0437\u0430\u043d": 88, "\u0434\u043e\u0432\u0435\u0440": 88, "\u0432\u044b\u0431": 88, "\u0432\u043e\u0437\u0432\u0435\u0434\u0435\u043d": 88, "\u043f\u0430\u0440\u0435\u043d": 88, "\u0437\u0430\u043c\u043a\u043d\u0443\u0442": 88, "\u043f\u043e\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a": 88, "\u0443\u0432\u043e\u043b": 88, "\u043e\u0431\u043b\u0430\u0434": 88, "\u043e\u0447\u0430\u0433": 88, "\u0448\u043b\u0430": 88, "\u0444\u0440\u043e\u043d\u0442": [88, 90, 95], "\u043e\u0441\u043b\u0430\u0431": 88, "\u0432\u044b\u043d\u0443\u0436\u0434\u0435\u043d": 88, "speak": 88, "\u0432\u043d\u0435\u0434\u0440\u044f": 88, "\u043f\u043b\u0430\u0446\u0434\u0430\u0440\u043c": [88, 90], "\u0440\u0430\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043a": 88, "\u0438\u0437\u0433\u043e": 88, "\u0432\u043e\u0437\u0434\u0435\u0440\u0436\u0430": 88, "\u0441\u0430\u0431\u043e\u0442\u0430\u0436": 88, "\u0432\u044b\u043d\u043e\u0441": 88, "\u043e\u043f\u0440\u043e\u043c\u0435\u0442\u0447\u0438\u0432": 88, "\u043e\u0442\u043e\u0436\u0434\u0435\u0441\u0442\u0432\u043b\u0435\u043d": [88, 92], "\u0443\u0433\u0440\u043e\u0437": [88, 92, 94], "reversing": 88, "disablement": 88, "reinforcing": 88, "preface": 88, "kotter": 88, "dance": 88, "sustaining": 88, "momentum": 88, "senge": 88, "march": 88, "1999": 88, "innovative": 88, "\u043a\u0430\u0440\u043b\u043e\u0444": 88, "\u0441\u0435\u0434\u0435\u0440\u0431\u0435\u0440\u0433": 88, "huse": 88, "1975": 88, "masters": 88, "kanter": 88, "schlesinger": 88, "transformational": 88, "initiatives": 88, "mayner": 88, "proquest": 88, "employees": 88, "herold": 88, "fedor": 88, "caldwell": 88, "yi": 88, "liu": 88, "93": 88, "heath": 88, "crown": 88, "inquiry": 88, "spark": 88, "breakthrough": 88, "berger": 88, "goulston": 88, "\u0431\u0440\u0430\u0436\u043d\u0438\u043a": 88, "\u0445\u043e\u0440\u0438\u043d": 88, "\u0441\u0430\u043c\u0430\u0440": 88, "\u0433\u043e\u0441": 88, "\u0442\u0435\u0445\u043d": 88, "\u0443\u043d": 88, "238": 88, "\u0434\u0430\u043d\u0438\u043b\u044e\u043a": 88, "\u0442\u044e\u043c\u0435\u043d": 88, "\u0442\u044e\u043c\u0435\u043d\u0441\u043a": 88, "\u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432\u0435\u043d": 88, "\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442": 88, "288": 88, "\u0438\u0432\u0430\u043d\u043e\u0432": [88, 96], "\u043c\u0433\u0443\u043f\u0441": 88, "\u043c\u0438": 88, "167": 88, "\u043a\u0443\u0436\u0435\u0432": 88, "\u043e\u043c\u0441\u043a": 88, "\u043e\u043c": 88, "140": 88, "\u043c\u0435\u0434\u0432\u0435\u0434\u0435\u0432": 88, "\u0441\u0430\u0440\u0430\u0442": 88, "\u0441\u0433\u0443": 88, "119": 88, "\u043a\u043e\u043b\u0435\u043c\u0430": 88, "\u0444\u0430\u0440\u043c\u0435\u0440": 88, "\u0436\u0443\u043a\u043e\u0432\u0441\u043a": 88, "\u0442\u0438\u0447": 88, "\u0434\u0435\u0432\u0430\u043d": 88, "\u0440\u0435\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446": 88, "\u0440\u043e\u0441\u0441": 88, "\u0434\u0435\u043c\u044c\u044f\u043d\u0435\u043d\u043a": 88, "\u0432\u0430\u0441\u0438\u043b": 88, "scarf": 88, "influencing": 88, "vol": 88, "rock": 88, "\u0434\u044d\u0432\u0438\u0434": 88, "\u0440\u043e\u043a": 88, "\u043a\u043d\u0443\u0442": 88, "\u043f\u0440\u044f\u043d\u0438\u043a": 88, "\u0441\u043c\u0430\u0440\u0430\u043a\u043e\u0432": 88, "\u043b\u044e\u0434\u044c\u043c": 89, "\u0432\u0435\u0436\u043b\u0438\u0432": 89, "\u0441\u0438\u043d\u0434\u0440": 89, "\u043d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d": [89, 91, 138], "\u0441\u043f\u0438\u0440\u0430\u043b": [89, 91, 138], "\u043f\u0440\u0438\u0432\u044f\u0437\u043a": 89, "\u044f\u043a\u043e\u0440": 89, "\u0441\u0442\u0430\u0442\u0443\u0441": [89, 102], "\u043a\u0432\u043e": 89, "\u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d": 89, "\u043d\u0443\u043b\u0435\u0432": 89, "sunk": 89, "\u043a\u043e\u043d\u0444\u043e\u0440\u043c\u043d": 89, "\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 89, "\u0432\u044b\u0436": 89, "\u043e\u043a\u043e\u043d": [89, 94], "\u0430\u043f\u0435\u043b\u043b\u044f\u0446": 89, "\u043b\u0438\u0447\u043d\u043e\u0441\u0442": 89, "\u0445\u043e\u0442\u043e\u0440\u043d\u0441\u043a": 89, "\u043d\u043e\u0432\u0438\u0437\u043d": 89, "\u0434\u0435\u0444\u043e\u0440\u043c\u0430\u0446": 89, "\u043f\u0440\u043e\u0436\u0435\u043a\u0442\u043e\u0440": 89, "\u043f\u0440\u043e\u043a\u0440\u0430\u0441\u0442\u0438\u043d\u0430\u0446": 89, "\u044d\u043c\u043e\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 89, "\u0432\u044b\u0433\u043e\u0440\u0430\u043d": 89, "\u0442\u0435\u043b\u0435\u0441\u043a\u043e\u043f": 89, "\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d": 89, "\u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u043d": 89, "\u0441\u0430\u0440": 89, "\u043f\u0430\u0440\u043a\u0438\u043d\u0441\u043e\u043d": 89, "\u0437\u0430\u043f\u043e\u043b\u043d\u044f": 89, "\u043e\u0442\u043f\u0443\u0449\u0435\u043d": 89, "\u043d\u0435\u043f\u0440\u0438\u044f\u0442": 89, "\u0433\u0440\u0443\u043f\u043f\u043e\u0432": [89, 100], "\u0437\u0430\u0431\u044b\u0432\u0430\u043d": 89, "\u043a\u0440\u0430": 89, "\u0430\u0433\u0440\u0435\u0433\u0438\u0440\u043e\u0432\u0430": 89, "cognitive": 89, "crothers": 89, "\u0431\u0438\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 89, "crunching": 89, "\u043d\u0435\u0438\u0437\u0431\u0435\u0436": 89, "\u0432\u044b\u0437\u0440\u0435\u0432\u0430\u043d": 89, "plastic": 89, "temporal": 89, "\u0445\u0430\u0431\u0440": 89, "\u043c\u043e\u0431\u0438\u043b\u044c\u043d": 89, "dropbox": 89, "8l49rx8ig9i4za3": 89, "ezh": 89, "li": 89, "cbcs": 89, "busterbenson": 89, "blob": 89, "benson": 89, "\u043f\u0430\u043c\u044f\u0442\u043a": 89, "ezhikov": 89, "\u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434": [90, 95], "\u043b\u0435\u0434": 90, "\u043a\u043e\u0440\u0430\u0431\u043b": 90, "\u0430\u0442\u0430\u043a": 90, "\u043b\u044c\u0434\u0430": 90, "\u0442\u043e\u0440\u0446": 90, "\u043b\u044c\u0434\u043e\u043c": 90, "\u0442\u043e\u043b\u0449": 90, "\u043f\u0440\u043e\u0441\u0442\u0438\u0440\u0430": 90, "\u0441\u043e\u0442\u043d": [90, 100], "\u043a\u0438\u043b\u043e\u043c\u0435\u0442\u0440": 90, "\u043f\u0440\u043e\u043b\u043e\u0436": 90, "\u043a\u043e\u043b\u0435\u0442": 90, "\u0437\u0438\u043c\u043d": 90, "\u043f\u0440\u043e\u0435\u0446\u0438\u0440\u0443": 90, "\u0432\u043e\u0438\u043d\u0441\u043a": 90, "\u043c\u043d\u043e\u0433\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432": 90, "taming": 90, "\u0432\u0438\u0441\u044f\u0447\u043a": 90, "\u0441\u0430\u043c\u0431": [90, 92], "\u043e\u0434\u0435\u0440\u0436\u0430\u043d": 90, "\u043f\u0440\u043e\u0442\u0438\u0432\u043d\u0438\u043a": 90, "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u0441\u0442\u0430\u0432": 90, "\u043c\u044b\u0448\u0446": [90, 95], "\u0444\u043e\u0442": 90, "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b": 90, "\u0441\u043f\u0438\u043d": 90, "\u0431\u0438\u0446\u0435\u043f\u0441": 90, "\u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434\u044f": 90, "\u0431\u043e\u043b\u0435\u0432": 90, "\u043f\u0440\u0438\u0435\u043c": [90, 93], "\u0432\u0435\u0434\u043e\u043c\u0441\u0442\u0432": 90, "\u0444\u0438\u043b\u044c\u043c": 90, "\u0432\u043e\u0435\u0432\u0430": 90, "\u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d": 90, "\u0442\u044f\u0433\u043e\u0442\u0435\u043d": 90, "\u0437\u0435\u043c\u043b": [90, 92, 100], "\u043f\u043e\u0432\u0430\u043b": 90, "\u043e\u043a\u0440\u0443\u0436\u0435\u043d": 90, "\u0436\u0443\u043a": 90, "\u0441\u0443\u0445": 90, "\u043f\u0435\u0440\u0435\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a": [90, 95], "\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a": 90, "\u043a\u043b\u0435\u0449": 90, "\u043e\u0441\u043b\u0430\u0431\u043b\u0435\u043d": 90, "\u0442\u044b\u043b\u043e\u0432": 90, "\u0444\u043e\u0440\u0441\u0438\u0440\u043e\u0432\u0430\u043d": 90, "\u0432\u043e\u0434\u043d": 90, "\u043f\u0440\u0435\u0433\u0440\u0430\u0434": 90, "\u043d\u0430\u0441\u0442\u0443\u043f\u043b\u0435\u043d": 90, "\u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430": 90, "\u043f\u0440\u0438\u0441\u0435\u0434": 90, "\u043f\u043b\u0435\u0447": 90, "\u043f\u043e\u0437\u0432\u043e\u043d\u043e\u0447\u043d\u0438\u043a": 90, "\u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d": 90, "\u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f": 90, "\u043a\u043e\u043d\u0442\u0430\u043a\u0442\u043d": 90, "\u043f\u043e\u0432\u0435\u0440\u0445\u043d": [90, 100], "\u043f\u043e\u0437\u0432\u043e\u043d\u043a": 90, "\u0438\u043d\u0432\u0435\u0441\u0442\u043e\u0440": 90, "\u0434\u0438\u0432\u0435\u0440\u0441\u0438\u0444\u0438\u043a\u0430\u0446": 90, "\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c": [90, 92], "\u0440\u0430\u0432\u043d\u043e\u0432\u0435\u0441": 90, "\u043f\u043b\u0430\u0432\u0443\u0447\u0435\u0441\u0442": 90, "\u0432\u043e\u0434\u043e\u043d\u0435\u043f\u0440\u043e\u043d\u0438\u0446\u0430": 90, "\u043f\u0435\u0440\u0435\u0433\u043e\u0440\u043e\u0434\u043a": 90, "\u0433\u0438\u0434\u0440\u043e\u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 90, "\u043f\u043e\u0434\u044a\u0435\u043c\u043d": 90, "\u043f\u0440\u043e\u0431\u043e\u0438\u043d": 90, "\u0434\u0435\u0439\u043b": [90, 92, 95], "\u043a\u0430\u0440\u043d\u0435\u0433": [90, 92, 95], "\u043e\u0442\u0441\u0435\u043a": 90, "\u0431\u0438\u0442\u0432": 90, "\u0440\u0430\u0437\u0436\u0438\u0433": 90, "\u043c\u0430\u043d\u0433\u0430\u043b": 90, "\u0448\u0435\u043f\u043a": 90, "\u0432\u0435\u0442\u043a": 90, "\u0431\u0443\u043c\u0430\u0433": 90, "\u0433\u043e\u0440\u044e\u0447": 90, "\u0436\u0438\u0434\u043a\u043e\u0441\u0442": 90, "\u043f\u043b\u0430\u043c\u0435\u043d": 90, "\u0441\u043f\u0438\u0447\u043a": 90, "\u0442\u0435\u043f\u043b\u043e\u0435\u043c\u043a": 90, "\u0432\u043e\u0441\u043f\u043b\u0430\u043c\u0435\u043d\u044f": 90, "\u0432\u043e\u0441\u043f\u043b\u0430\u043c\u0435\u043d": 90, "\u043d\u0430\u043f\u0440\u044f\u043c": 90, "\u0448\u0438\u0440\u043e\u0442": [92, 102], "\u043f\u0440\u0438\u0440\u043e\u0434\u043d": 92, "\u043c\u043b\u043d": 92, "\u043c\u0430\u0441\u0442\u0435\u0440\u0441\u0442\u0432": 92, "\u043f\u043e\u043b\u0438\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a": 92, "\u044d\u043d\u0446\u0438\u043a\u043b\u043e\u043f\u0435\u0434": [92, 102], "\u0440\u044f\u0437\u0430\u043d\u0446": 92, "lucky": 92, "\u044d\u043b\u0435\u0430\u0442": 92, "\u0430\u0442\u043e\u043c\u0438\u0441\u0442": 92, "\u043f\u043b\u0430\u0442\u043e\u043d": 92, "\u0444\u0438\u043b\u043e\u0441\u043e\u0444\u0441\u043a": [92, 100, 102], "\u0442\u0442": 92, "\u0441\u0442\u0435\u043f\u0438\u043d": 92, "\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c": 92, "\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u0435\u043b\u044c\u043d": 92, "\u043d\u0435\u043f\u0440\u0435\u0445\u043e\u0434\u044f": 92, "3\u043d\u0430\u043d": 92, "\u044f\u0432\u043b": [92, 100], "\u0441\u043e\u0432\u0435\u0442\u0441\u043a": 92, "\u0433\u043b": 92, "\u0438\u043b\u044c\u0438\u0447": 92, "\u0444\u0435\u0434\u043e\u0441\u0435": 92, "\u043a\u043e\u0432\u0430\u043b": 92, "\u043f\u0430\u043d": 92, "\u0441\u043e\u0437\u043d\u0430\u043d": [92, 102], "\u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d": 92, "\u0437\u043d\u0430\u043a\u043e\u0432": 92, "\u043f\u0440\u0438\u0434\u0430\u043d": 92, "\u0441\u043e\u0432\u0440": 92, "\u043e\u0441\u043d": [92, 100], "\u044d\u043c\u043f\u0438\u0440\u0438\u0447": 92, "\u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447": 92, "\u043f\u043e\u0441\u0442\u0443\u043b\u0430\u0442": 92, "\u0430\u043a\u0441": 92, "\u0438\u0434\u0435\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430": 92, "\u043b\u043e": 92, "\u0433\u0438\u0447": 92, "\u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d": 92, "\u043f\u0440\u0438\u0437\u0432\u0435\u0434": 92, "\u043d\u0435\u0441\u043e\u0433\u043b\u0430\u0441": 92, "\u0443\u0449\u0435\u043c\u043b\u0435\u043d": 92, "\u043a\u043e\u0433\u043d\u0438\u0442\u0438\u0432": 92, "\u0442\u043e\u043a\u0441\u0438\u0447\u043d": 92, "\u043e\u0442\u043e\u0436\u0434\u0435\u0441\u0442\u0432\u043b\u044f": 92, "\u043c\u043e\u043f\u0435\u0434": 92, "issac": 92, "newton": 92, "standing": 92, "shoulders": 92, "giants": 92, "isaac": 92, "1675": 92, "letter": 92, "fellow": 92, "hooke": 92, "\u0432\u043e\u0441\u043f\u043e\u043b\u043d": 92, "\u0432\u0430\u043a\u0443\u0443\u043c": 92, "\u0432\u043e\u0437\u043d\u0438\u043a\u0448": 92, "\u0437\u0430\u0432\u0435\u0434\u043e\u043c": 92, "\u043e\u0442\u0442\u043e\u0440\u0433\u043d\u0443\u0442": 92, "\u043f\u0440\u043e\u043b": 92, "\u0440\u0430\u0437\u0434\u0432\u0438\u0433\u0430": 92, "\u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430": [92, 93], "\u043f\u0435\u0440\u0435\u043e\u0441\u043c\u044b\u0441\u043b": 92, "\u043d\u0435\u043f\u0440\u0438\u0441\u0442\u0443\u043f\u043d": 92, "\u043a\u0440\u0435\u043f\u043e\u0441\u0442": 92, "\u0431\u0435\u0440\u0443\u0442": 92, "\u043e\u0431\u0449\u0435\u043f\u0440\u0438\u0437\u043d\u0430": 92, "\u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0446": 92, "\u043e\u0442\u0441": 92, "\u0434\u043e\u0431\u044b\u0432\u0430\u043d": [92, 100], "\u0441\u043e\u0438\u0437\u043c\u0435\u0440\u0438\u043c": 92, "\u0434\u0438\u0432\u0435\u0440\u0433\u0435\u043d\u0442\u043d": 92, "\u0433\u043b\u0443\u0431\u0438\u043d": 92, "\u043a\u043e\u043d\u0432\u0435\u0440\u0433\u0435\u043d\u0442\u043d": 92, "\u0442\u0432\u043e": 92, "\u043e\u0442\u043c\u0435\u043d\u044f": 92, "ch": 92, "\u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0430": 92, "\u043f\u0435\u0440\u0435\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430": 92, "\u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440": 92, "\u0432\u043e\u0437\u043e\u0431\u043b\u0430\u0434\u0430": 92, "\u043f\u043e\u0439\u043c\u0443\u0442": 92, "\u044d": 92, "\u0431\u043e\u043b\u043e\u0442": 92, "\u043f\u0440\u043e\u0439\u0442": 92, "\u0441\u043e\u0432\u0435\u0440\u0448": 92, "\u043f\u043e\u0445\u043e\u0434": 92, "\u0432\u043b\u044f\u043f\u0430": 92, "\u0441\u0430\u043c\u043e\u043b\u0438\u0447\u043d": 92, "\u043a\u043e\u0440\u043c\u0447": 92, "\u0432\u0441\u0442\u0443\u043f\u0430": 92, "\u043a\u043e\u043c\u043f\u0430\u0441": [92, 100], "\u043f\u043b\u044b\u0432\u0435\u0442": 92, "\u043e\u043f\u0438\u0440\u0430": 92, "\u0442\u0432\u0435\u0440\u0434": 92, "\u043e\u0441\u043d\u043e\u0432\u0430\u043d": 92, "\u043b\u0435\u043e\u043d\u0430\u0440\u0434": 92, "\u0432\u0438\u043d\u0447": 92, "\u043c\u0443\u0434\u0440": 92, "\u0434\u0443\u0440\u0430\u043a": 92, "\u0440\u0435\u0431": 92, "\u0441\u0440\u0435\u0434\u043d\u0435\u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": 92, "\u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a": 92, "\u0441\u043b\u0443\u0436": [92, 100], "\u0441\u0430\u043c\u043e\u043d\u0430\u0434\u0435\u044f": 92, "\u0438\u0437\u043e\u0431\u0440\u0435\u0441\u0442": 92, "\u043a\u043e\u043b\u0435\u0441": 92, "\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430": 92, "\u044d\u0440\u0438\u0445": 92, "\u0433\u0430\u043c\u043c": 92, "\u0444\u0430\u0443\u043b\u0435\u0440": 92, "\u0437\u0430\u043c\u043a\u043d\u0443\u043b": 92, "\u0441\u043c\u043e\u0442\u0440\u0435\u043b": 92, "\u043f\u043e\u0434\u043d\u043e\u0436\u043a": 92, "\u0443\u044f\u0437\u0432\u0438\u043c": 92, "\u043a\u043e\u043d\u0442\u0440\u0430\u0442\u0430\u043a\u043e\u0432\u0430": 92, "\u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a": 92, "\u0441\u043d\u0430\u0440\u0443\u0436": 92, "\u043f\u0440\u043e\u0436\u0438\u0432\u0430": 92, "\u043f\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442": 92, "\u043f\u0435\u0440\u043f\u0435\u043d\u0434\u0438\u043a\u0443\u043b\u044f\u0440\u043d": [92, 102], "\u0433\u0435\u043e\u043c\u0435\u0442\u0440": 92, "\u043a\u043e\u0440\u043e\u0442\u043a\u043e\u043c\u0435\u0442\u0440\u0430\u0436\u043a": 92, "\u0431\u0435\u0440\u0435\u0437\u0438\u043d": 92, "\u0431\u043b\u0430\u0433": 92, "\u0437\u043b\u043e": 92, "\u043d\u0435\u0432\u0435\u0436\u0435\u0441\u0442\u0432": 92, "\u043a\u0430\u043f\u0438\u0442\u0430": 92, "\u0443\u043c\u0440\u0443\u0442": 92, "\u043f\u043e\u0433\u0443\u0431": 92, "\u043b\u0430\u0440\u0440": 92, "\u043f\u0440\u0443\u0441\u0430\u043a": 92, "\u0433\u043b\u0443\u043f\u043e\u0441\u0442": 92, "\u0434\u0430\u0440": 92, "\u0431\u043e\u0436": 92, "\u043e\u0442\u0442": 92, "\u0431\u0438\u0441\u043c\u0430\u0440\u043a": 92, "shakespeare": 92, "lear": 92, "\u0438\u0449\u0443\u0442": 92, "\u0441\u0430\u043c\u043e\u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d": 92, "\u0441\u0445\u043e\u0434": [92, 94], "\u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c": 92, "\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442": [92, 100], "\u0432\u044b\u0432\u0435\u0441\u0442": 92, "\u043f\u0440\u0438\u043b\u0430\u0433\u0430": 92, "\u043f\u0440\u0438\u0441\u0430\u0434": 92, "\u043e\u043f\u043f\u043e\u043d\u0435\u043d\u0442": 92, "\u043f\u043e\u0441\u0442\u0438\u0436\u0435\u043d": 92, "\u043c\u0430\u043b\u043e\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d": 92, "boiled": 92, "carrot": 92, "\u043c\u0430\u0440\u0442\u044b\u0448\u043a": 92, "\u043e\u0447\u043a": 92, "113": 92, "\u043e\u0442\u0441\u0435\u0447\u0435\u043d": 93, "\u0441\u043a\u0443\u043b\u044c\u043f\u0442\u043e\u0440": 93, "\u0431\u0435\u0441\u0444\u043e\u0440\u043c\u0435\u043d": 93, "\u0432\u044b\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430": 93, "\u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b": 93, "\u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437": 93, "\u0434\u0435\u0442\u0441\u0442\u0432": 93, "\u043e\u0444\u0438\u0446\u0435\u0440": 93, "\u0441\u043f\u0435\u0446\u0441\u043b\u0443\u0436\u0431": 93, "\u0441\u043e\u0441\u043b\u0443\u0436\u0438\u0432\u0446": 93, "\u043e\u0442\u0446": 93, "\u0440\u0443\u043a\u043e\u043f\u0430\u0448\u043d": 93, "\u0432\u0440\u0435\u0434\u043d": 93, "\u043d\u0440\u0430\u0432": 93, "\u043d\u0438\u043a\u043b\u0430\u0443\u0441": 93, "\u0432\u0438\u0440\u0442": 93, "\u0431\u043e\u0433\u0430\u0442\u0441\u0442\u0432": 93, "\u043a\u043e\u043b\u043e\u043a\u043e\u043b\u044c\u0447\u0438\u043a": 93, "\u0441\u0432\u0438\u0441\u0442\u043a": 93, "\u0431\u0430\u0437\u0438\u0441\u043d": 93, "\u043d\u0435\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d": 93, "\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0430\u043d": 93, "pascal": 93, "modula": 93, "\u043f\u0440\u0430\u043a\u0442\u0438\u0447\u043d": 93, "\u0437\u0430\u043c\u0435\u0449\u0430": 93, "\u0431\u0438\u0442": 93, "\u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c": 93, "\u0430\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u0447\u0435\u0441\u043a": 93, "\u0431\u0438\u0442\u043e\u0432": 93, "\u0431\u0435\u0441\u043f\u043e\u0434\u043e\u0431\u043d": 93, "\u0432\u0435\u0447\u0435\u0440": 93, "\u0441\u043f\u0438\u0440\u0430": 94, "\u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d": [94, 100], "\u0443\u0432\u043b\u0435\u0447\u0435\u043d": 94, "\u0437\u0430\u043d\u043e\u0441": 94, "\u044d\u0439\u0444\u043e\u0440": 94, "\u0440\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 94, "\u0432\u0437\u0430\u0438\u043c\u043e\u043f\u043e\u043d\u0438\u043c\u0430\u043d": 94, "\u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430": 94, "\u0434\u0435\u0432\u0438\u0430\u0446": 94, "\u0438\u043d\u0442\u0435\u0440\u0432\u044c\u044e\u0435\u0440": 94, "\u043f\u043e\u0433\u043e\u0432\u043e\u0440": 94, "\u0432\u043e\u0437\u0432\u0435\u0434": 94, "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0441\u0442\u043e\u044f\u043d": 94, "\u0430\u0441\u0441\u043e\u0446\u0438\u0438\u0440\u043e\u0432\u0430": 94, "\u0433\u0435\u043d\u0438\u0430\u043b\u044c\u043d": 94, "\u0438\u043c\u0438\u0434\u0436": 94, "\u043e\u0431\u0438\u0436\u0430": 94, "\u043e\u0442\u0432\u0435\u0440\u0433\u0430\u043d": 94, "\u043d\u044c\u044e\u0442\u043e\u043d": 94, "\u0441\u0435\u0440\u0435\u0431\u0440\u044f": 94, "\u0432\u043f\u0440\u0438\u043d\u0446\u0438\u043f": 94, "\u043d\u0430\u043e\u0449\u0443\u043f": 94, "\u0432\u044b\u044f\u0432\u043b": 94, "frederic": 94, "\u0441\u0430\u0434\u043e\u0432\u043d\u0438\u043a": 94, "\u0432\u044b\u0440\u0430\u0449\u0438\u0432\u0430": 94, "\u0441\u0442\u0440\u043e": 94, "\u043d\u0435\u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043d": 94, "\u043d\u0430\u0447\u0430\u043b\u044c\u043d": 94, "\u043c\u0435\u043d\u0442\u043e\u0440\u0438\u043d\u0433": 94, "matias": 94, "pre": 94, "intention": 94, "\u0431\u0435\u0441\u043f\u043e\u043a\u043e\u0439\u0441\u0442\u0432": 95, "\u043e\u0442\u0440\u0435\u0437\u043a": 95, "\u0441\u043f\u0435\u0448\u043a": 95, "remaining": 95, "\u043f\u0430\u043d\u0438\u043a": 95, "\u043d\u0430\u0443\u043a\u043e\u0435\u043c\u043a": 95, "\u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0436\u0430": 95, "\u043f\u0441\u0438\u0445\u0438\u043a": 95, "\u043e\u0431\u043e\u0441\u0442\u0440": 95, "\u0433\u0440\u0443\u0437": [95, 100], "\u0443\u0441\u043f\u0435\u0432\u0430": 95, "\u0444\u043e\u043a\u0443\u0441\u0438\u0440": 95, "\u043e\u0441\u0432\u0430\u0438\u0432\u0430": 95, "\u0441\u043b\u043e\u043c\u0430": 95, "\u0441\u043f\u0430\u0437\u043c": 95, "\u043d\u0435\u0437\u0430\u0449\u0438\u0449\u0435\u043d": 95, "\u0445\u0440\u0443\u0441\u0442\u0430\u043b\u0438\u043a": 95, "\u0430\u043a\u043a\u043e\u043c\u043e\u0434\u0430\u0446": 95, "\u043c\u0438\u043e\u043f": 95, "\u043d\u0435\u0441\u043b\u0443\u0447\u0430\u0439\u043d": 95, "\u043f\u0438\u043b\u044e\u043b": 95, "\u0440\u0438\u0441\u043e\u0432\u0430": 95, "\u0442\u0430\u0431\u043b\u0438\u0447\u043a": 95, "timelines": 95, "trello": 95, "\u043e\u0432\u043b\u0430\u0434\u0435\u0442": 95, "\u043e\u0441\u043e\u0437\u043d\u0430\u043d": 95, "\u043f\u0430\u0431\u043b\u0438\u043a": 95, "\u0434\u043d\u044f\u0445": 95, "\u0441\u0442\u0430\u043d\u0438\u0441\u043b\u0430\u0432": 96, "\u0431\u043e\u043b\u0441\u0443\u043d": 96, "rss": 96, "\u0432\u044b\u043c\u044b\u0448\u043b\u0435\u043d": 97, "bolsun": [100, 102], "simplification": 100, "abstracts": 100, "ignores": 100, "\u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446": 100, "\u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442": 100, "\u0438\u0433\u043d\u043e\u0440\u0438\u0440": 100, "\u0441\u043c\u043e\u0436": 100, "\u0441\u043b\u0443\u0436\u0430": 100, "\u0437\u0438\u043c\u0430\u0440": 100, "rough": 100, "stage": 100, "intend": 100, "replicate": 100, "literal": 100, "subsystem": 100, "practicing": 100, "smallish": 100, "phew": 100, "\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430": 100, "head": 100, "rigorously": 100, "selective": 100, "sentence": 100, "intimate": 100, "binding": 100, "inclusive": 100, "opposite": 100, "moderately": 100, "encompassing": 100, "vigorously": 100, "brussels": 100, "\u043c\u043e\u0440\u0441\u043a": 100, "\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 100, "\u0446\u0438\u043b\u0438\u043d\u0434\u0440\u0438\u0447\u0435\u0441\u043a": 100, "\u043c\u0435\u0440\u043a\u0430\u0442\u043e\u0440": 100, "\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f": 100, "\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u0442": 100, "\u0441\u0442\u0440\u0435\u043b\u043a": 100, "\u0430\u0444\u0440\u0438\u043a": 100, "\u0433\u0440\u0435\u043d\u043b\u0430\u043d\u0434": 100, "\u043a\u0430\u0440\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a": 100, "\u0437\u0435\u043c\u043d": 100, "\u043c\u043d\u043e\u0433\u043e\u0433\u0440\u0430\u043d\u043d\u0438\u043a": 100, "\u0434\u0438\u043c\u0430\u043a\u0441\u0438\u043e\u043d": 100, "\u0444\u0443\u043b\u043b\u0435\u0440": 100, "painful": 100, "\u0432\u0441\u0435\u043e\u0431\u044a\u0435\u043c\u043b\u044e\u0449": 100, "\u0434\u043e\u043f\u043e\u043b\u043d": 100, "\u043e\u0431\u0449\u0435\u0441\u0438\u0441\u0442\u0435\u043c\u043d": 100, "\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u0443\u0435\u043c": 100, "\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b": 100, "\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d": 100, "\u043a\u043e\u043d\u043a\u0440\u0435\u0442\u0438\u0437\u0430\u0446": 100, "\u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0430": 100, "\u0441\u043e\u0447\u0442\u0435\u043d": 100, "\u043d\u0435\u0432\u043a\u043b\u044e\u0447\u0435\u043d": 100, "\u043d\u0435\u0447\u0442": [100, 102], "\u043d\u0435\u043f\u043e\u0437\u043d\u0430": 100, "\u043c\u043e\u0433\u0443\u0449": 100, "\u0437\u0430\u043c\u0435\u043d\u0438\u0442\u0435\u043b": 100, "\u0440\u0430\u043a\u0443\u0440\u0441": 100, "\u043e\u0433\u0443\u0440\u0446": 100, "\u043b\u0435\u043a\u0441\u0438\u043a\u043e\u043d": 100, "6000": 100, "\u043a\u043e\u043b\u0438\u0447\u0441\u0442\u0432": 100, "\u0431\u0435\u0437\u0433\u0440\u0430\u043d\u0438\u0447\u043d": 100, "\u043b\u0438\u043d\u0433\u0432\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": [100, 102], "\u0441\u043b\u043e\u0432\u0430\u0440\u043d": 100, "\u0437\u0430\u043f\u0430\u0441": 100, "\u043c\u0430\u0440\u043a\u0435\u0440": 100, "\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d": 100, "\u044f\u0437\u044b\u043a\u043e\u0432": 100, "\u0441\u0438\u0433\u043d\u0430": 100, "\u0443\u0434\u043e\u0440\u043e\u0436\u0430": 100, "semantics": 100, "tailored": 100, "precise": 100, "cord": 100, "weaves": 100, "\u043e\u0431\u044b\u043a\u043d\u043e\u0432\u0435\u043d": 100, "\u043e\u0433\u0443\u0440\u0435\u0446": 100, "\u0442\u043e\u043b\u043a\u043e\u0432\u0430\u043d": 100, "\u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442": 100, "\u0440\u0430\u0441\u043f\u043b\u044b\u0432\u0447\u0430\u0442": 100, "\u0441\u043b\u043e\u0432\u0435\u0441\u043d": [100, 102], "\u0432\u043e\u0448\u0435\u043b": 100, "\u0441\u0432\u0435\u0440\u0442\u043e\u043a": 100, "\u043e\u0431\u043b\u0430\u043a": 100, "\u043e\u043f\u0438\u0441\u044b\u0432": 100, "\u043e\u0431\u0432\u043e\u043b\u0430\u043a\u0438\u0432\u0430": 100, "\u0433\u0434\u0435\u0442": 100, "\u0441\u0435\u0440\u0435\u0434\u0438\u043d": 100, "\u0441\u043a\u043e\u043f\u043b\u0435\u043d": 100, "\u043f\u043e\u044d\u0437": 100, "\u044e\u043c\u043e\u0440": 100, "\u0434\u0438\u043f\u043b\u043e\u043c\u0430\u0442": 100, "\u043c\u043e\u0448\u0435\u043d\u043d\u0438\u0447\u0435\u0441\u0442\u0432": 100, "\u0431\u044b\u0442\u043e\u0432": 100, "\u0438\u0437\u0436\u0438\u0432\u0430": 100, "\u0432\u044b\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430": 100, "\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a": 100, "\u0441\u043a\u043e\u0442\u043e\u0432\u043e\u0434\u0447\u0435\u0441\u043a": 100, "\u0430\u0444\u0440\u0438\u043a\u0430\u043d\u0441\u043a": 100, "\u043f\u043b\u0435\u043c\u0435\u043d": 100, "\u043c\u0430\u0441\u0430": 100, "\u043a\u043e\u0440": 100, "\u0441\u0435\u0432\u0435\u0440\u043d": 100, "\u043d\u0430\u0440\u043e\u0434": 100, "\u0441\u043d\u0435\u0433": 100, "\u0440\u0430\u0437\u0433\u043e\u0432\u0430\u0440\u0438\u0432\u0430": 100, "\u0444\u0438\u0437\u0438\u043a": 100, "\u043c\u0435\u0434\u0438\u043a": 100, "\u044e\u0440\u0438\u0441\u0442": 100, "\u0443\u0433\u043e\u043b\u043e\u0432\u043d\u0438\u043a": 100, "\u0431\u043e\u0442\u0430": 100, "\u0444\u0435\u043d": 100, "\u043c\u043e\u043b\u043e\u0434\u0435\u0436": 100, "\u0441\u043b\u044d\u043d\u0433": 100, "\u0432\u0437\u0440\u043e\u0441\u043b": 100, "\u043b\u043e\u043d\u0434\u043e\u043d\u0441\u043a": 100, "\u043d\u0438\u0437": 100, "\u043a\u043e\u043a\u043d": 100, "\u043d\u0430\u0437\u043e\u0432": 100, "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b": 100, "\u0438\u0437\u0436": 100, "\u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d": 100, "\u043d\u0430\u0431\u043e\u043b\u044c\u0448": 100, "\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430": 100, "\u0441\u0432\u044f\u0437\u0430\u043d": 100, "\u0440\u0430\u0437\u0440\u0435\u0437\u0430": 100, "\u0441\u0432\u0430\u043b": 100, "\u043d\u0435\u0440\u0435\u043b\u0435\u0432\u0430\u0442\u043d": 100, "\u043e\u0442\u043d\u0438\u043c": 100, "\u0437\u0430\u043f\u0438\u0445\u043d\u0443\u0442": 100, "\u043a\u0440\u043e\u0439\u043a": 100, "\u0431\u043b\u044e\u0434": 100, "\u0434\u043e\u0434\u0435\u043a": 100, "\u044d\u0434\u0440": 100, "\u043f\u0430\u0437\u043b": 100, "\u043f\u043e\u043b\u043e\u0442\u043d": 100, "\u043f\u043e\u0441\u0435\u0442\u0438\u0442\u0435\u043b": 100, "\u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b": 100, "\u043f\u043b\u0430\u0442\u0435\u043b\u044c\u0449\u0438\u043a": 100, "\u0430\u0434\u0440\u0435\u0441\u0430\u0442": 100, "\u0432\u043b\u0430\u0434\u0438\u043a": 100, "divergent": 100, "cope": 100, "ambiguity": 100, "optimizing": 100, "advertising": 100, "campaigns": 100, "simplify": 100, "simplistic": 100, "overengineered": 100, "engineered": 100, "zakrevskii": 100, "\u0442\u0433": 100, "ru_arc": 100, "chat": 100, "tg": 100, "idddqd": 100, "topology": 100, "\u0438\u0437\u0431\u0440\u0430": 102, "\u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d": 102, "\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c": 102, "\u044d\u043b\u0438\u043c\u0438\u043d\u0438\u0440": 102, "\u043c\u043d\u043e\u0433\u043e\u0437\u043d\u0430\u0447\u043d": 102, "\u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0438\u0440": 102, "\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0443\u0430\u043b\u044c\u043d": 102, "\u043d\u0430\u043f\u0440": 102, "\u0441\u0438\u043d\u043e\u043d\u0438\u043c": 102, "\u0430\u043d\u0442\u043e\u043d\u0438\u043c": 102, "\u0440\u0430\u0437\u043b\u0438\u0447\u0435\u043d": 102, "\u044d\u043a\u0441\u0442\u0435\u043d\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 102, "\u0438\u043d\u0442\u0435\u043d\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 102, "\u0441\u0438\u043d\u043e\u043d\u0438\u043c\u0438\u0447\u043d": 102, "\u044d\u043a\u0441\u0442\u0435\u043d\u0441\u0438\u043e\u043d\u0430\u043b": 102, "\u0434\u0438\u0430\u0433\u043e\u043d\u0430": 102, "\u0440\u043e\u043c\u0431": 102, "\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u043e\u0433\u0440\u0430\u043c\u043c": 102, "\u0441\u043c\u0435\u0436\u043d": 102, "\u044d\u043f\u0438\u0441\u0442\u0435\u043c\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": 102, "\u0432\u0437\u0430\u0438\u043c\u043e\u0437\u0430\u043c\u0435\u043d\u0438\u043c": 102, "\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d": 102, "\u0437\u0430\u043c\u0435\u043d\u0438\u043c": 102, "\u0432\u044b\u0442\u0435\u043a\u0430": 102, "\u0442\u043e\u0436\u0434\u0435\u0441\u0442\u0432": 102, "\u0438\u043d\u0442\u0435\u043d\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 102, "\u043d\u043e\u044d\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 102, "\u0444\u0440\u0435\u0433": 102, "\u043f\u0440\u043e\u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 102, "\u0430\u043a\u0442": 102, "\u0444\u0438\u0433\u0443\u0440\u0438\u0440": 102, "\u043e\u0431\u044b\u0434\u0435\u043d": 102, "\u0435\u0441\u0442\u0435\u0441\u0442\u0432\u043e\u0437\u043d\u0430\u043d": 102, "\u0444\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446": 102, "\u0444\u043e\u0440\u043c\u0430\u043b\u044c\u043d": 102, "\u0433\u0443\u043c\u0430\u043d\u0438\u0442\u0430\u0440\u043d": 102, "\u043c\u0430\u0442\u0435\u0440": 102, "\u0430\u0440\u0438\u0441\u0442\u043e\u0442\u0435\u043b": 102, "\u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d": 102, "\u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 102, "\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u043a": 102, "\u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c": 102, "\u0440\u0430\u0441\u043a\u0440\u044b\u0442": 102, "\u0434\u043b\u0438\u043d": 102, "\u043b\u0438\u043d\u0433\u0432\u0438\u0441\u0442\u0438\u043a": 102, "\u044d\u043a\u0441\u0442\u0440\u0430\u043b\u0438\u043d\u0433\u0432\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a": 102, "\u0438\u043c\u043f\u043b\u0438\u0446\u0438\u0442\u043d": 102, "\u043d\u0435\u044f\u0437\u044b\u043a\u043e\u0432": 102, "\u043e\u0431\u0441\u0442\u0430\u043d\u043e\u0432\u043a": 102, "\u043f\u0441\u0438\u0445\u0438\u0447\u0435\u0441\u043a": 102, "\u044d\u043a\u0441\u043f\u043b\u0438\u0446\u0438\u0442\u043d": 102, "\u043f\u0440\u0435\u0441\u0443\u043f\u043f\u043e\u0437\u0438\u0446": 102, "\u0434\u0438\u0441\u043a\u0443\u0440\u0441": 102, "\u0433\u0443\u0442\u043d\u0435\u0440": 102, "\u044d\u043f\u0438\u0441\u0442\u0435\u043c\u043e\u043b\u043e\u0433": 102, "\u043a\u0430\u043d\u043e\u043d": 102, "\u0440\u043e\u043e": 102, "\u0440\u0435\u0430\u0431\u0438\u043b\u0438\u0442\u0430\u0446": 102, "\u043a\u0430\u0441\u0430\u0432\u0438\u043d": 102}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"\u043a\u0430\u043a": [0, 9, 40, 70, 83, 88, 93], "\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": 0, "\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d": [0, 5, 8, 9, 10, 11, 21, 23, 30, 34, 37, 38, 39, 40, 41, 46, 52, 56, 65, 68, 70, 72, 73, 74, 75, 76, 77, 82, 83, 85, 86, 88, 90, 92, 94, 95, 100], "\u043f\u043e\u0447": [0, 11, 23, 52, 85], "\u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432\u043d": [0, 72], "\u0441\u0443\u0431\u044a\u0435\u043a\u0442\u043d": 0, "\u043f\u0441\u0438\u0445\u043e\u043b\u043e\u0433": [0, 90], "\u044d\u043a\u043e\u043d\u043e\u043c": 0, "\u0432\u0440\u0435\u043c\u0435\u043d": [0, 40], "\u043d\u0430\u0432\u0438\u0433\u0430\u0446": 0, "\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446": [0, 5], "\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446": [0, 8, 70], "\u0432\u043b\u0438\u044f\u043d": [0, 77, 85, 95], "\u043d\u0430": [0, 30, 38, 46, 77, 82, 85, 90, 92, 95], "\u043a\u0430\u0447\u0435\u0441\u0442\u0432": [0, 40, 53, 74, 82], "\u043e\u0431\u0443\u0447\u0435\u043d": [0, 82, 94, 95], "\u043b\u0435\u0433\u043a\u043e\u0441\u0442": 0, "\u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d": 0, "\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442": [0, 30, 100, 102], "\u043f\u043e\u0440\u044f\u0434\u043e\u043a": 0, "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d": 0, "\u0441\u043e\u0431\u0440\u0430": 0, "html": 0, "\u043e": [0, 21, 34, 37, 65, 70, 85, 92], "zettelkasten": 0, "\u0444\u0438\u043b\u043e\u0441\u043e\u0444": 0, "\u0431\u043b\u0438\u0437\u043a": 0, "\u043f\u043e": [0, 40, 66, 82, 86, 88, 100], "\u0434\u0443\u0445": 0, "\u0441\u0438\u0441\u0442\u0435\u043c": [0, 82], "obsidian": 0, "neuron": 0, "antora": 0, "gitjournal": 0, "\u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a": 0, "\u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440": 0, "\u0441\u0430\u0439\u0442": 0, "\u0434\u0440\u0443\u0433": [0, 73, 82, 86], "\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d": 0, "\u043f\u0440\u043e\u0435\u043a\u0442": [0, 15], "markdown": 0, "\u0440\u0430\u0431\u043e\u0442\u0430": 0, "\u043c\u043e\u0431\u0438\u043b\u044c\u043d": 0, "\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432": 0, "android": 0, "iphone": 0, "\u0441": [0, 21], "notion": 0, "evernote": 0, "rss": 0, "\u0438\u043d\u0442\u0435\u0433\u0430\u0446": 0, "mattermost": 0, "telegram": 0, "sitemap": 0, "\u043f\u043e\u043b\u0435\u0437\u043d": 0, "\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d": 0, "\u043f\u043e\u0441\u043b\u0435\u0441\u043b\u043e\u0432": [0, 23], "\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432": [1, 96, 97, 98, 99, 105], "emacsway": 1, "\u043e\u0433\u043b\u0430\u0432\u043b\u0435\u043d": [1, 2, 6, 7, 12, 16, 17, 19, 22, 24, 25, 27, 28, 31, 32, 33, 35, 36, 43, 44, 45, 48, 50, 54, 57, 58, 61, 67, 69, 71, 78, 79, 81, 84, 87, 91, 99, 101, 103, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138], "concurrency": [2, 106], "saga": 3, "transaction": 4, "event": [5, 6, 10, 16, 23, 82, 107], "storming": [5, 6, 82, 107], "with": 5, "archi": 5, "\u043e\u0431\u0437\u043e\u0440": 5, "\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442": 5, "\u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432": 5, "\u0434\u043b\u044f": [5, 11, 21, 82], "\u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a": [5, 92], "\u0441\u0440\u0435\u0434\u0441\u0442\u0432": 5, "git": 5, "\u0448\u0442\u0430\u0442\u043d": 5, "\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c": 5, "\u0441\u043b\u0438\u044f\u043d": 5, "\u043c\u043e\u0434\u0435\u043b": [5, 8, 11, 100], "\u0438\u0437\u0431\u0435\u0433\u0430\u043d": 5, "\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442": [5, 92], "\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a": 5, "\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [5, 37, 75, 102], "\u0433\u0440\u0430\u043d\u0438\u0446": [5, 8], "\u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441": [5, 86], "\u0433\u0435\u043d\u0435\u0440\u0430\u0446": 5, "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446": 5, "\u0441\u0442\u0438\u043a\u0435\u0440": 5, "c4": 5, "model": [5, 25, 100, 101, 113], "archimatetool": 5, "troubleshooting": 5, "ddd": [7, 16, 19, 23, 82, 86, 103, 108, 109], "in": [7, 14, 18, 23, 38, 44, 48, 50, 72, 73, 74, 75, 108, 122, 124, 125], "practice": [7, 86, 108], "\u043f\u043e\u0438\u0441\u043a": [8, 38], "\u0430\u0433\u0440\u0435\u0433\u0430\u0442": [8, 9, 11], "\u0431\u0438\u0437\u043d\u0435\u0441": [8, 23, 38, 43, 46, 121], "\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d": [8, 52, 77], "strong": [8, 23], "consistency": [8, 23, 30], "rdbms": 8, "eventual": [8, 23], "\u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d": 8, "\u0443\u043f\u0440\u043e\u0449\u0435\u043d": 8, "\u043f\u0440\u043e\u0431\u043b\u0435\u043c": [8, 23], "\u0434\u0430\u043d": [8, 82], "\u0432\u0435\u0440\u043e\u044f\u0442\u043d": 8, "\u0443\u0442\u0440\u0430\u0442": 8, "\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d": 8, "\u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d": 8, "\u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442": 8, "\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d": 8, "endorsement": 8, "\u0432": [8, 9, 11, 15, 21, 34, 40, 46, 47, 70, 76, 86, 88, 90, 92, 93, 95], "\u0441\u0443\u0449\u043d\u043e\u0441\u0442": [8, 11], "\u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d": 8, "data": 8, "context": [8, 11, 30, 82, 102], "and": [8, 23, 29, 30, 75, 82, 86, 96], "interaction": 8, "dci": 8, "process": [8, 23], "manager": 8, "pattern": [8, 9, 15], "pessimistic": 8, "offline": 8, "lock": 8, "\u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u043d": 8, "\u0438\u0442\u043e\u0433\u043e\u0432": 8, "missing": 8, "chapter": 8, "\u0441\u043e\u0445\u0440\u0430\u043d": 9, "\u0431\u0434": 9, "\u043d\u0435": [9, 21, 23, 26, 46, 52, 70, 93], "\u0440\u0430\u0437\u0440\u0443\u0448": 9, "\u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u044f\u0446": 9, "memento": 9, "walker": 9, "valuer": 9, "scanner": 9, "reflection": 9, "exporter": 9, "1": [9, 83], "accepting": 9, "interface": 9, "mediator": 9, "2": [9, 83], "returning": 9, "structure": 9, "sourcing": [10, 16, 82], "\u0444\u0430\u0439\u043b\u043e\u0432": 11, "\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440": [11, 82, 86], "\u0434\u043e\u043c\u0435\u043d": [11, 100], "\u0437\u0430\u0447": 11, "\u043a\u0430\u0436\u0434": 11, "bounded": [11, 30, 82], "\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440": 11, "internal": [11, 23], "\u0440\u0435\u0437\u043c\u0435\u0449": 11, "\u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d": 11, "\u0432\u044b\u0434\u0435\u043b": 11, "\u043e\u0442\u0434\u0435\u043b\u044c\u043d": [11, 30], "\u043d\u0435\u0442": 11, "\u0435\u0433": 11, "\u043e\u0431\u044a\u0435\u043a\u0442": [11, 23], "\u0437\u043d\u0430\u0447\u0435\u043d": [11, 21, 95], "\u0441\u043e\u0431\u044b\u0442": [11, 23, 30, 34], "\u0440\u0430\u0437\u043c\u0435\u0449": 11, "\u0438": [11, 21, 23, 41, 52, 75, 82, 85, 86, 93, 100], "domain": [12, 23, 24, 25, 82, 100, 101, 112, 113], "layer": [12, 29], "shotgun": 13, "surgery": 13, "specification": 14, "golang": [14, 16, 18], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430": 15, "\u043b\u0438": [15, 21, 23, 74, 92], "canexecute": 15, "cqrs": [16, 21, 22, 23, 82, 111], "reference": [16, 21, 64], "application": 16, "grade": 16, "infrastructure": 17, "repository": [18, 29, 30, 31, 116], "strategic": [20, 110], "design": [20, 28, 71, 72, 74, 77, 82, 85, 110, 115, 132], "\u043c\u043e\u0436\u0435\u0442": [21, 23], "\u043a\u043e\u043c\u0430\u043d\u0434": [21, 23, 82, 83, 86, 100], "\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430": [21, 23], "\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442": [21, 23, 56], "transparency": 21, "\u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [21, 82], "\u0441\u0440\u0435\u0434": 21, "\u0447\u0435\u043c": 21, "\u043e\u0442\u043b\u0438\u0447\u0430": 21, "\u043e\u0442": [21, 23, 70, 75], "cqs": 21, "\u0430": [21, 23, 52, 100], "\u0435\u0441\u0442": 21, "\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447": [21, 86], "\u0430\u0432\u0442\u043e\u0440\u0438\u0442\u0435\u0442\u043d": 21, "\u0442\u043e\u0447\u043a": 21, "\u0437\u0440\u0435\u043d": 21, "\u044d\u0442": [21, 23, 85, 92], "\u0431\u043e\u043b\u044c\u0448": 21, "referential": 21, "query": 21, "command": 21, "\u0441\u043b\u0443\u0436\u0435\u0431\u043d": 21, "\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446": [21, 82, 93, 100], "\u043a\u043e\u0434": [21, 40, 46, 73, 74, 83], "\u043e\u0448\u0438\u0431\u043a": [21, 40, 100], "\u0438\u043b": 21, "\u0443\u0441\u043f\u0435\u0448\u043d": [21, 83], "\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d": 21, "\u043a\u0440\u043e\u043c": 21, "\u0441\u0443\u0449\u0435\u0441\u0442\u0432": 21, "\u0435\u0449": 21, "\u0444\u0443\u043d\u043a\u0446": 21, "\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440": 21, "\u0434\u043e\u043b\u0436": 21, "\u0438\u043c\u0435\u0442": 21, "abstract": 21, "side": 21, "effect": 21, "\u043d\u043e": 21, "concrete": 21, "\u0447\u0442\u043e": [21, 26, 37, 40, 46, 52, 65, 80, 85, 100], "\u0434\u0435\u043b\u0430": [21, 26, 46, 82], "\u0430\u0442\u043e\u043c\u0430\u0440\u043d": 21, "\u043e\u043f\u0435\u0440\u0430\u0446": 21, "\u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440": 21, "\u0438\u0437\u043c\u0435\u043d": 21, "\u0441\u0441\u044b\u043b\u043e\u0447\u043d": 21, "\u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442": 21, "\u043a\u043e\u043d\u0446\u0435\u043f\u0446": 21, "\u0431\u0443\u0444\u0435\u0440": 21, "\u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d": 21, "\u0435\u0441\u043b": [21, 26, 46, 83, 100], "\u0434\u043e\u043b\u0436\u043d": 21, "\u0432\u0435\u0440\u043d\u0443\u0442": 21, "\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440": 21, "\u0441\u043e\u0437\u0434\u0430": 21, "\u0440\u0435\u0441\u0443\u0440\u0441": [21, 46], "\u043e\u0434\u043d\u043e\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d": 21, "\u043f\u043e\u0442\u043e\u043a": 21, "\u0438\u0437\u043c\u0435\u043d\u0435\u043d": [21, 88], "jimmy": [21, 23], "bogard": [21, 23], "\u0432\u044b\u0432\u043e\u0434": [21, 30, 95], "events": [23, 24, 82, 112], "\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d": [23, 65], "vs": [23, 56], "transactional": 23, "\u0441\u043b\u0435\u0434\u0441\u0442\u0432": 23, "\u043f\u0440\u0438\u0447\u0438\u043d": [23, 34], "\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d": 23, "\u0432\u0441\u0435": [23, 83], "\u0440\u0435\u0448\u0430": 23, "\u043f\u0440\u0430\u0432": 23, "\u043f\u0440\u0438\u043d\u0446\u0438\u043f": [23, 90], "ask": 23, "whose": 23, "job": 23, "it": [23, 32, 104, 117], "is": [23, 75], "\u043d\u043e\u0432\u0438\u0447\u043a": 23, "\u0438\u043d\u0442\u0435\u0440\u0435\u0441": [23, 38, 43, 45, 75, 121, 123], "performance": 23, "\u043e\u0431\u0440\u0430\u0442\u043d": 23, "\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c": 23, "\u0444\u043e\u0440\u043c\u0430\u0442": 23, "\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446": 23, "net": 23, "microservices": [23, 82], "\u043c\u043d\u0435\u043d": [23, 92], "scott": 23, "millett": 23, "nick": 23, "tune": 23, "kamil": 23, "grzybek": 23, "udi": 23, "dahan": 23, "cesar": 23, "de": 23, "la": 23, "torre": 23, "out": 23, "of": [23, 72, 73, 74, 75, 82, 86], "external": 23, "one": [23, 75, 85], "phase": 23, "two": 23, "\u043a\u0442\u043e": [23, 74], "\u0438\u0437\u0434\u0430\u0432\u0430": 23, "\u043e\u0442\u043c\u0435\u043d": 23, "\u0441\u0432\u043e": 23, "\u0440\u0435\u0448\u0435\u043d": [23, 30, 38, 70, 92], "\u0431\u0430\u043b\u0430\u043d\u0441": [23, 38, 75, 76], "\u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442": [23, 40, 76], "\u043e\u0431\u0440\u0435\u0442\u0430": 23, "\u0432\u044b\u0433\u043e\u0434": 23, "atomicity": 23, "resiliency": 23, "integration": [23, 35, 119], "\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d": 23, "\u043e\u0447\u0435\u0440\u0435\u0434\u043d": [23, 34], "\u0433\u0434\u0435": 23, "\u0441\u043e\u0437\u0434\u0430\u0432\u0430": 23, "\u043e\u0431": 23, "\u0443\u0434\u0430\u043b\u0435\u043d": 23, "\u0432\u0430\u0436\u043d": [23, 100], "\u0447\u0438\u0442\u0430": [23, 74, 93], "\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b": 23, "\u0432\u043c\u0435\u0441\u0442": 23, "\u043f\u0435\u0440\u0435\u0432\u043e\u0434": 23, "immutability": 26, "\u044f\u043f": 26, "\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430": 26, "\u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c": 26, "value": [27, 114], "objects": [27, 114], "tactical": [28, 115], "anticorruption": 29, "causal": 30, "\u0432\u0430\u0440\u0438\u0430\u043d\u0442": 30, "\u0432\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d": 30, "\u0441\u043e\u0441\u0442\u043e\u044f\u043d": 30, "\u0432\u0435\u0440\u0441": [30, 38], "asynchronous": [33, 118], "communication": [33, 118], "\u0433\u043e\u043d\u043a": 34, "\u0441\u043e\u043e\u0431\u0449\u0435\u043d": 34, "\u0443\u0441\u043b\u043e\u0432": 34, "\u043a\u043e\u043d\u043a\u0443\u0440\u0438\u0440": 34, "\u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a": 34, "\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a": 34, "\u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0442\u0438\u0432\u043d": [34, 40], "\u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d": 34, "\u043d\u0430\u0440\u0443\u0448\u0435\u043d": 34, "\u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d": 34, "\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a": 34, "sdlc": [36, 61, 64, 82, 120, 129], "\u0442\u0430\u043a": [37, 52, 65, 80, 85], "agile": [37, 38, 44, 48, 49, 50, 51, 52, 53, 54, 55, 58, 72, 73, 74, 75, 76, 82, 86, 122, 124, 125, 126, 128], "development": [37, 57, 59, 60, 62, 63, 64, 127], "\u0438\u0441\u0442\u043e\u0440": 37, "\u0441\u0443\u0442": [37, 38, 65, 90], "\u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442": [37, 85], "\u043f\u0440\u0438\u043c\u0435\u0440": [37, 83, 88], "\u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u043d": 38, "\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a": [38, 40, 45, 123], "\u043f\u0440\u0435\u043e\u0431\u043b\u0430\u0434\u0430\u043d": 38, "extreme": [38, 86], "programming": [38, 86], "\u043f\u0435\u0440\u0432": 38, "xp": 38, "\u0432\u0442\u043e\u0440": [38, 82], "scrum": [38, 86], "the": [38, 76, 86], "guide": [38, 86], "\u043a": [38, 76], "\u043f\u0435\u0440\u0432\u043e\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a": [38, 75], "\u0437\u0430": 38, "atam": 38, "\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430": 38, "\u0447\u0430\u0441\u0442": [38, 40, 82], "\u0438\u0442\u0435\u0440\u0430\u0446": 38, "\u0437\u0430\u0434\u0430\u0447": [38, 40, 82], "open": [38, 76], "architecture": [38, 39, 76, 96], "\u0441\u0438\u0441\u0442\u0435\u043c\u043d": 38, "\u043c\u044b\u0448\u043b\u0435\u043d": 38, "\u043f\u0441\u0438\u0445\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a": [38, 89, 95], "\u0441\u0442\u043e\u0440\u043e\u043d": [38, 76], "\u0432\u043e\u043f\u0440\u043e\u0441": [38, 82], "\u043f\u043b\u0430\u043d": [38, 92], "selling": 39, "options": 39, "\u043d\u0430\u0438\u0431\u043e\u043b": 40, "\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d": [40, 95], "\u0441\u043f\u0438\u0441\u043e\u043a": [40, 82, 89], "\u043e\u0448\u0438\u0431\u043e\u043a": 40, "\u043b\u043e\u0436\u043d": 40, "\u0432\u0435\u0440": 40, "\u0442\u043e": 40, "\u0442\u0435\u0445\u0434\u043e\u043b\u0433": 40, "\u044f\u0432\u043b\u044f": 40, "\u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u043d": 40, "\u0432\u0435\u043b\u0438\u0447\u0438\u043d": 40, "\u043e\u0442\u043d\u043e\u0448\u0435\u043d": 40, "\u043a\u043e": 40, "\u043d\u0430\u043a\u043e\u043f\u043b\u0435\u043d": 40, "\u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430": 40, "\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a": [40, 66, 85, 100], "\u043b\u0438\u043d\u0435\u0439\u043d": 40, "\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a": [40, 42, 82, 83], "\u0431\u0435\u0437\u0440\u0430\u0437\u043b\u0438\u0447\u043d": 40, "\u0432\u0437\u044f\u0442": 40, "\u0440\u0435\u043b\u0438\u0437": 40, "technical": [41, 74], "debt": 41, "\u0441\u043b\u043e\u0436\u043d": 41, "\u043f\u0440\u043e\u0446\u0435\u043d\u0442": 41, "\u043c\u043e\u0442\u0438\u0432\u0430\u0446": 42, "\u0441oncerns": [44, 122], "\u043a\u043e\u0433\u0434": [46, 47, 70], "refactoring": [46, 65], "legacy": [46, 47], "\u0432\u044b\u0434\u0435\u043b\u044f": 46, "\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433": 46, "\u043f\u0438\u0441\u0430": [47, 83], "unit": 47, "tests": 47, "analysis": [48, 124], "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 49, "requirements": [49, 50, 51, 52, 53, 86, 125], "nonfunctional": 51, "product": 52, "backlog": 52, "item": 52, "user": 52, "story": 52, "\u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440": [52, 70, 82, 86, 88], "\u043f\u0440\u043e": 52, "\u043a\u0440\u0438\u0442\u0435\u0440": 53, "particular": 55, "models": [55, 61, 129], "code": [56, 82, 85, 94], "review": [56, 94], "\u0432\u043e\u0437\u043c\u043e\u0436\u043d": 56, "apaptation": 56, "prediction": [56, 76, 79, 80, 134], "continuous": 56, "collaborative": [57, 127], "practices": [58, 86, 128], "evolutionary": 59, "incremental": 60, "iterative": 62, "spiral": 63, "systems": 64, "life": 64, "cycle": 64, "adaptation": [65, 67, 76, 130], "\u0430\u0434\u0430\u043f\u0442\u0430\u0446": 65, "\u043d\u0435\u043c\u043d\u043e\u0436\u043a": 65, "\u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432": 65, "\u043f\u043e\u0434\u0445\u043e\u0434": 65, "\u043f\u0440\u0438\u0447": 65, "\u0437\u0434\u0435": 65, "\u043a\u0440\u0430\u0442\u043a": 66, "\u043a\u0443\u0440\u0441": 66, "\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u043a": 66, "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d": [66, 82], "\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d": [66, 82], "borrowing": 68, "trouble": 68, "software": [69, 71, 74, 85, 86, 131, 132], "construction": [69, 131], "yagni": 70, "\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430": 70, "\u043f\u0440\u043e\u0435\u043a\u0442\u043d": 70, "\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0447\u0435\u0441\u043a": [70, 72, 83], "\u0443\u0449\u0435\u0440\u0431": 70, "\u043f\u0440\u0435\u0436\u0434\u0435\u0432\u0440\u0435\u043c\u0435\u043d": 70, "\u0441\u043b\u0443\u0447\u0430": 70, "\u043c\u043e\u043c\u0435\u043d\u0442": 70, "\u0441\u0442\u043e": 70, "\u043e\u0442\u043a\u043b\u0430\u0434\u044b\u0432\u0430": 70, "role": [72, 73, 74, 75], "patterns": [72, 85], "\u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f": 72, "\u044d\u0444\u0444\u0435\u043a\u0442": [72, 89], "\u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d": 72, "\u043f\u0430\u0442\u0442\u0435\u0440\u043d": 72, "\u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d": 72, "simplicity": 73, "\u0435\u0434\u0438\u043d\u0438\u0446": 73, "\u0438\u0437\u043c\u0435\u0440\u0435\u043d": 73, "\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d": 73, "\u0432\u0441\u0435\u0433\u0434": 73, "\u043f\u0440\u043e\u0441\u0442": 73, "eric": 73, "evans": 73, "edsger": 73, "w": 73, "dijkstra": 73, "steve": [73, 74], "mcconnell": [73, 74], "kent": [73, 74], "beck": [73, 74], "martin": [73, 74], "fowler": [73, 74], "robert": [73, 74], "c": 73, "bjarne": 73, "stroustrup": 73, "primary": 74, "imperative": 74, "\u043e\u043f\u0440\u0430\u0432\u0434\u0430": 74, "manifesto": 74, "ralph": 74, "johnson": 74, "\u0441\u0435\u0440\u0433": 74, "\u0442\u0435\u043f\u043b\u044f\u043a": 74, "\u043d\u0430\u0440\u043e\u0434\u043d": 74, "\u0442\u0432\u043e\u0440\u0447\u0435\u0441\u0442\u0432": 74, "randy": 74, "shoup": 74, "solid": 75, "principles": 75, "\u043e\u0448\u0438\u0431\u043e\u0447\u043d": 75, "\u0442\u0440\u0430\u043a\u0442\u043e\u0432\u043a": 75, "srp": 75, "not": 75, "to": 75, "do": 75, "just": 75, "thing": 75, "about": [75, 76], "cohesion": 75, "conway": 75, "s": 75, "law": 75, "common": 75, "closure": 75, "principle": 75, "ccp": 75, "complexity": 75, "ad": 75, "hominem": 75, "\u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0440\u043e\u0447\u043d": 75, "\u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d": 75, "ocp": 75, "no": 75, "silver": 75, "bullet": 75, "\u043f\u043e\u0441\u043b\u0435\u0434\u043d": 75, "2022": 75, "07": 75, "06": 75, "balancing": [76, 77], "\u0433\u0438\u0431\u043a\u043e\u0441\u0442": 76, "standard": 76, "by": [76, 86], "group": 76, "\u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d": 76, "\u043c\u0430\u044f\u0442\u043d\u0438\u043a": 76, "\u0437\u0430\u043d\u043e\u0441": 76, "\u043e\u0442\u0441\u043a\u043e\u043a": 76, "\u043d\u0430\u0437\u0430\u0434": 76, "alberto": 76, "brandolini": 76, "top": 77, "down": 77, "bottom": 77, "up": 77, "approaches": 77, "\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440": [77, 82, 86], "\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d": [78, 85, 95, 133], "\u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d": [78, 133], "\u0441\u0430\u043c\u043e\u043e\u0431\u0443\u0447\u0435\u043d": [81, 82, 135], "\u043f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432": 82, "\u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u0441\u043a": 82, "\u043c\u0438\u043d\u0438\u043c\u0443\u043c": 82, "\u0443\u0447": [82, 83], "\u0438\u0437\u0443\u0447\u0430": 82, "\u043e\u0441\u043d\u043e\u0432\u043d": [82, 85], "\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c": 82, "\u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433": 82, "\u0430\u0437\u0431\u0443\u043a": 82, "\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d": [82, 90], "\u0431\u044b\u0442": [82, 90], "\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d": [82, 83, 86], "\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d": 82, "\u0441\u0438\u0441\u0442": 82, "\u043e\u0441\u043d\u043e\u0432": 82, "\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c": 82, "\u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a": 82, "\u0443\u0433\u043b\u0443\u0431\u043b\u044f": 82, "\u043d\u0430\u0432\u044b\u043a": 82, "\u0441\u0442\u0430\u0442": [82, 83], "aggregate": 82, "modeling": 82, "api": 82, "modelling": 82, "\u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d": 82, "\u0432\u044b\u0431\u043e\u0440": 82, "single": 82, "team": [82, 87, 137], "scaled": [82, 86], "\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442": 82, "\u043c\u0435\u043d\u0435\u0434\u0436\u043c\u0435\u043d\u0442": 82, "\u0440\u0430\u0437\u0432\u0438\u0442": 82, "\u043b\u0438\u0447\u043d\u043e\u0441\u0442\u043d": 82, "\u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 82, "\u0431\u0430\u0437": 82, "\u0442\u0440\u0435\u0442": 82, "\u0437\u0430\u0445\u043e\u0434": 82, "streaming": 82, "processing": 82, "\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d": 82, "posa": 82, "\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d": [82, 85], "\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440": 82, "\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a": 82, "\u043e\u0446\u0435\u043d\u0438\u0432\u0430\u043d": 82, "\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d": 82, "\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a": 82, "\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d": 82, "body": 82, "knowledge": 82, "\u0433\u043e\u0441\u0442": 82, "online": 82, "\u043a\u0430\u0442\u0430\u043b\u043e\u0433": 82, "smell": 82, "catalogs": 82, "\u043f\u043e\u0434\u0431\u043e\u0440\u043a": 82, "\u043f\u043e\u0447\u0442\u043e\u0432": 82, "\u0440\u0430\u0441\u0441\u044b\u043b\u043a": 82, "\u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432": 82, "\u044d\u0442\u0430\u043b\u043e\u043d": 82, "\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d": 82, "\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d": 82, "\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a": 83, "\u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a": 83, "\u0434\u043e\u0440\u043e\u0436\u043d": 83, "\u043a\u0430\u0440\u0442": 83, "\u043e\u0431\u0443\u0447\u0430": 83, "3": 83, "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430": 83, "\u043f\u0440\u043e\u0446\u0435\u0441\u0441": 83, "4": 83, "\u0438\u0437\u043c\u0435\u043d\u044f": 83, "\u043a\u043e\u043b\u043b\u0435\u043a\u0442": 83, "\u0445\u043e\u0447\u0435\u0442": 83, "\u0431\u0440\u043e\u0441": 83, "tdd": [84, 85, 136], "\u0447\u0435\u0440\u0435\u0437": 85, "\u0441\u043f\u043e\u0441\u043e\u0431": 85, "\u0431\u044b\u0441\u0442\u0440": 85, "\u043a\u0430\u0442\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440": 85, "clean": 85, "\u0442\u0435\u043c\u043f": 85, "black": 85, "box": 85, "or": 85, "white": 85, "sociable": 85, "solitary": 85, "assertion": 85, "per": 85, "test": 85, "\u0440\u043e\u043b": [86, 92], "\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d": 86, "\u0437\u0430\u043a\u043e\u043d": 86, "\u0431\u0440\u0443\u043a\u0441": 86, "\u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d": 86, "\u043c\u0435\u0436\u0434": 86, "\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d": 86, "\u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d": 86, "\u0445\u0430\u0440\u043b\u0430": 86, "\u043c\u0438\u043b\u043b\u0437": 86, "program": 86, "management": 86, "spotify": 86, "lean": 86, "for": 86, "teams": 86, "programs": 86, "enterprise": 86, "framework": 86, "safe": 86, "pmi": 86, "disciplined": 86, "delivery": 86, "dad": 86, "iso": 86, "iec": 86, "ieee": 86, "12207": 86, "2017": 86, "nexus": 86, "scrums": 86, "early": 86, "\u0444\u0440\u0430\u043a\u0442\u0430\u043b\u044c\u043d": 86, "\u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d": 86, "\u0441\u0441\u044b\u043b\u043a": 86, "\u0442\u0435\u043c": [86, 88], "topologies": [87, 137], "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f": 88, "\u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432": 88, "\u043e\u0434\u0438\u043d": 88, "\u0438\u0437": 88, "\u0440\u0435\u0430\u043b\u044c\u043d": 88, "\u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u0435\u043d": 88, "\u043b\u0435\u0434\u043e\u043a\u043e\u043b": 90, "\u0431\u043e\u0440\u044c\u0431": 90, "\u0432\u043e\u0435\u043d": 90, "\u0434\u0435\u043b": 90, "\u0441\u043f\u043e\u0440\u0442": 90, "\u0442\u043e\u0440\u0433\u043e\u0432\u043b": 90, "\u0444\u043e\u043d\u0434\u043e\u0432": 90, "\u0440\u044b\u043d\u043a": 90, "\u0442\u0435\u0445\u043d\u0438\u043a": 90, "\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0447\u0435\u0441\u043a": 90, "\u043f\u0440\u0438\u0440\u043e\u0434": 90, "soft": [91, 138], "skills": [91, 138], "\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d": 92, "\u043f\u043e\u0447\u0432": 92, "\u0437\u043d\u0430\u043d": [92, 93], "\u0442\u0435\u043e\u0440": 92, "\u043e\u0431\u043e\u0431\u0449\u0435\u043d": 92, "\u043f\u0440\u0430\u043a\u0442\u0438\u043a": 92, "\u0440\u043e\u0436\u0434\u0430": 92, "\u0441\u043f\u043e\u0440": 92, "\u0438\u0441\u0442\u0438\u043d": 92, "\u043a\u0440\u0438\u0441\u0442\u0430\u043b\u043b\u0438\u0437\u0430\u0446": 93, "\u043f\u0440\u0435\u0432\u0440\u0430\u0442": 93, "\u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u043e\u043d\u0435\u0440": 93, "\u043d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d": 94, "\u0444\u0430\u0437": 94, "\u0441\u043f\u0438\u0440\u0430\u043b": 94, "\u043d\u0430\u043f\u0440\u044f\u0436\u0435\u043d": 95, "\u0437\u0434\u043e\u0440\u043e\u0432": 95, "system": 96, "\u043e\u0431\u0449": [96, 105], "\u0430\u0432\u0442\u043e\u0440\u0441\u043a": 96, "\u043f\u0440\u0438\u0432\u0430\u0442\u043d": [96, 98], "\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432o": 96, "\u043f\u0440\u043e\u0447": 96, "indices": 96, "tables": 96, "\u0438\u0432\u0430": 97, "\u0438\u0432\u0430\u043d\u043e\u0432": 97, "\u0441\u0442\u0430\u043d\u0438\u0441\u043b\u0430\u0432": 99, "\u0431\u043e\u043b\u0441\u0443\u043d": 99, "definition": [100, 102], "\u043f\u043e\u043f\u044b\u0442\u0430": 100, "\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430": 100, "\u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d": 100, "\u0432\u0441\u0435\u043e\u0431\u044a\u0435\u043c\u043b\u0438\u0432\u0430": 100, "\u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d": 100, "\u043e\u0431\u043b\u0430\u0441\u0442": 100, "\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d": 100, "\u0442\u0430\u0440\u0430\u0441\u0435\u043d\u043a": 100, "\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d": 100, "\u0435\u0434\u0438\u043d": 100, "\u044f\u0437\u044b\u043a": 100, "\u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a": 100, "\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d": 100, "\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a": 100, "language": 102, "\u044f\u0437\u044b\u043a\u043e\u0432": 102}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.todo": 2, "sphinx": 56}}) \ No newline at end of file