پروژه چابکیشماره ۲۰ - بخش اول
یکی بود یکی نبود. زیر گنبد کبود یک شهر خیلی خیلی بزرگ با نام تهران بود. تهران هزارها رستوران و مطبخ مختلف داشت. اجایل کوچ مهربان قصه ما هم مشتری دهها جای گونهگونش بود.
اما جالب بود که یک مورد خاص در ذهنش ماندگار شده بود: تجربه «سیبزمینی آتیشی» که نیمهشب زمستانی در پارک لاله به قیمت فقط دو هزارتومن خریده بود.
آن جوانی که در بساط سادهاش «چایی و سیبزمینی آتیشی» میفروخت قطعن قابلیت رقابت با امکانات رستوران مجلل آجودانیه بانک ملی را نداشت.اما زیرک بود و یک «تجربه کاربری» خاص میفروخت. «قصه» دورهمیهای کودکی را میفروخت. چیزی برای روایت داشت و در حد خودش کسبوکار پر رونقی هم داشت.
بله رفقا، همه ما آدمها در بند قدرت قصهایم. با قصه درباره مشکلاتمان حرف میزنیم. با قصه راهحل پیدا میکنیم و رابطههایی برپا میکنیم که به سادگی فراموش نمیشوند
بعله، «بله»ی بندِ دل ما ممکن هستش که به اندازه تلگرام محتوا نداشته باشد، به اندازه کافهبازار کاربر نداشته باشد و ... اما میتواند «قصه»ی خاص خودش را داشته باشد. قصهای که «موجب معرکه شدن همه افراد بشود» و در عین حال موجب متمایز شدن ما بشود .
یکی بود یکی نبود. زیر گنبد کبود یک شهر خیلی خیلی بزرگ با نام تهران بود. تهران هزارها رستوران و مطبخ مختلف داشت. اجایل کوچ مهربان قصه ما هم مشتری دهها جای گونهگونش بود.
اما جالب بود که یک مورد خاص در ذهنش ماندگار شده بود: تجربه «سیبزمینی آتیشی» که نیمهشب زمستانی در پارک لاله به قیمت فقط دو هزارتومن خریده بود.
آن جوانی که در بساط سادهاش «چایی و سیبزمینی آتیشی» میفروخت قطعن قابلیت رقابت با امکانات رستوران مجلل آجودانیه بانک ملی را نداشت.اما زیرک بود و یک «تجربه کاربری» خاص میفروخت. «قصه» دورهمیهای کودکی را میفروخت. چیزی برای روایت داشت و در حد خودش کسبوکار پر رونقی هم داشت.
بله رفقا، همه ما آدمها در بند قدرت قصهایم. با قصه درباره مشکلاتمان حرف میزنیم. با قصه راهحل پیدا میکنیم و رابطههایی برپا میکنیم که به سادگی فراموش نمیشوند
بعله، «بله»ی بندِ دل ما ممکن هستش که به اندازه تلگرام محتوا نداشته باشد، به اندازه کافهبازار کاربر نداشته باشد و ... اما میتواند «قصه»ی خاص خودش را داشته باشد. قصهای که «موجب معرکه شدن همه افراد بشود» و در عین حال موجب متمایز شدن ما بشود .
۱۸:۴۲
پروژه چابکیشماره ۲۰ - بخش دوم (ادامه پست قبلی)
یکی از مشکلاتی که ما با اسکرام داشتیم کمک به توهم «کار کردن» بود. بکلاگی داشتیم با هشتاد ایشوی مختلف. هر اسپرینت چندتایش را دان و دمو میکردیم و با برپایی همه مناسک آیینی اسکرام ، خرسند میشدیم ازینکه داریم «کار میکنیم». و خیلی فکر نمیکردیم که آیا ارزش واقعی برای مشتری خلق کردهایم یا نه.
در تلاشی که برای بازگشت به عصاره چابکی داشتیم روی مفهوم «ارزش» و «دلیور» کردن آن تاکید زیادی کردیم: «Deliver Value Continuously»گفتیم که ما اینجا جمع نشدیم که یک کارگاه تولید کشکولی از فیچر راه بیاندازیم. بلکه رویای خلق و تحویل یک «محصول عالی ارزشمند برای مردم» را داریم .
گاهی اوقات لازم است که همه بکلاگ را پاک کنیم . یک کاغذ سرخ بچسبانیم رووی بورد با این عبارت: «Make people Awesome in top-up»(تاپآپ: شاٰرژ موبایل) دیگر فقط یک ابزار ساده فروش شارژ مثل همه نباشیم. بلکه یک تجربه کاربری برایش خلق کنیم . شارژ اتومات بخریم. گزارش تماسهایش را تحلیل کنیم و برچسب بزنیم. بهش یادآوری کنیم این هفته به مادرشوهرش زنگ بزند. بسته «دکای» رایتل را بهش پیشنهاد کنیم. جوری باشیم که با ما «اُخت بگیرد و به بقیه توصیه کند» . خلاصه بگویم: ما باید برایش قصه گفتوگو را تعریف کنیم .
و البته حواسمان همیشه به ارزش بنیادین «Experiment & Learn Rapidly» هست. قرار نیست یهو و در دو روز به این کیفیت رویایی برسیم. پلهپله و پیوسته باید بهتر بشویم ، مدام آزمایش کنیم، مدام تحویل بدهیم و مدام یاد بگیریم و مدام «معرکه بشویم»
یکی از مشکلاتی که ما با اسکرام داشتیم کمک به توهم «کار کردن» بود. بکلاگی داشتیم با هشتاد ایشوی مختلف. هر اسپرینت چندتایش را دان و دمو میکردیم و با برپایی همه مناسک آیینی اسکرام ، خرسند میشدیم ازینکه داریم «کار میکنیم». و خیلی فکر نمیکردیم که آیا ارزش واقعی برای مشتری خلق کردهایم یا نه.
در تلاشی که برای بازگشت به عصاره چابکی داشتیم روی مفهوم «ارزش» و «دلیور» کردن آن تاکید زیادی کردیم: «Deliver Value Continuously»گفتیم که ما اینجا جمع نشدیم که یک کارگاه تولید کشکولی از فیچر راه بیاندازیم. بلکه رویای خلق و تحویل یک «محصول عالی ارزشمند برای مردم» را داریم .
گاهی اوقات لازم است که همه بکلاگ را پاک کنیم . یک کاغذ سرخ بچسبانیم رووی بورد با این عبارت: «Make people Awesome in top-up»(تاپآپ: شاٰرژ موبایل) دیگر فقط یک ابزار ساده فروش شارژ مثل همه نباشیم. بلکه یک تجربه کاربری برایش خلق کنیم . شارژ اتومات بخریم. گزارش تماسهایش را تحلیل کنیم و برچسب بزنیم. بهش یادآوری کنیم این هفته به مادرشوهرش زنگ بزند. بسته «دکای» رایتل را بهش پیشنهاد کنیم. جوری باشیم که با ما «اُخت بگیرد و به بقیه توصیه کند» . خلاصه بگویم: ما باید برایش قصه گفتوگو را تعریف کنیم .
و البته حواسمان همیشه به ارزش بنیادین «Experiment & Learn Rapidly» هست. قرار نیست یهو و در دو روز به این کیفیت رویایی برسیم. پلهپله و پیوسته باید بهتر بشویم ، مدام آزمایش کنیم، مدام تحویل بدهیم و مدام یاد بگیریم و مدام «معرکه بشویم»
۱۸:۴۲
پروژه چابکیشماره ۲۱
بنیانگذار برند «نایکی» کتاب «خاطرات کفشباز» را برای بازگویی داستان شکلگیری شرکتش نوشته است. قصه پاگرفتن این شراکت دونفره در زمان یکهتازی و عظمت «آدیداس»!این شما و این بخشی از کتاب با ترجمه «شورش بشیری» که برای من به شدت یادآور این ارزش بنیادین است: «سریع بیآزمایید و سریع یاد بگیرید» :
«...در جوابش نوشتم: «بلندپروازانه است. اما ارزش تلاش کردن رو داره» این خط آخر را با ایمان کامل نوشتم! واقعن ارزش تلاش کردن داشت.همیشه امید من این بود که اگر قرار است شکست بخورم، سریع شکست بخورم تا وقت کافی برای دوباره برخواستن و استفاده از درسهایی که آموختهام را داشته باشم.خیلی دربند تعریف هدف برای خودم نبودم. اما این هدف آنقدر هر روز در ذهنم تکرار شد که به زمزمهی درونیام تبدیل شد:
سریع شکست بخور! »
بنیانگذار برند «نایکی» کتاب «خاطرات کفشباز» را برای بازگویی داستان شکلگیری شرکتش نوشته است. قصه پاگرفتن این شراکت دونفره در زمان یکهتازی و عظمت «آدیداس»!این شما و این بخشی از کتاب با ترجمه «شورش بشیری» که برای من به شدت یادآور این ارزش بنیادین است: «سریع بیآزمایید و سریع یاد بگیرید» :
«...در جوابش نوشتم: «بلندپروازانه است. اما ارزش تلاش کردن رو داره» این خط آخر را با ایمان کامل نوشتم! واقعن ارزش تلاش کردن داشت.همیشه امید من این بود که اگر قرار است شکست بخورم، سریع شکست بخورم تا وقت کافی برای دوباره برخواستن و استفاده از درسهایی که آموختهام را داشته باشم.خیلی دربند تعریف هدف برای خودم نبودم. اما این هدف آنقدر هر روز در ذهنم تکرار شد که به زمزمهی درونیام تبدیل شد:
سریع شکست بخور! »
۱۲:۴۸
پروژه چابکی شماره ۲۲بخش اول
و باز هم بخشی از کتاب عالی «خاطرات کفشباز» ، نوشته «فیل نایت»، بنیانگذار برند «نایکی» :
«از اوضاع خسته بودیم تا وقتی سرانجام در اواخر ۷۸ محصول «تیلویند» را عرضه کردیم. یک اختراع عالی از تیم طراحی خوبمان که در ژاپن ساخته شد.تیلویند چیزی بیش از یک کفش بود . این محصول یک اثر هنری پستمدرن بود. بزرگ، نقرهای روشن با کفی هوای انحصاری.مشخصن «دوازده نوآوری مختلف درین محصول بود.»...تیلیوند بعد از آغاز به کار بسیار موفقش یک غول فروش شد. و اما اندکی بعد گزارشات باگ و خرابی شروع به سرازیر شدن کردند. ما یک فراخوان بازگردانی صادر کردیم و پیشنهاد برگشت همهی پول مشتریان را دادیم. همه روانه سطل زباله شدند....ما درس ارزشمندی گرفتیم: «دوازده نوآوری را نباید در یک کفش قرار داد. این کار انتظار زیادی از یک کفش است. و همینطور از تیم طراحی»
و باز هم بخشی از کتاب عالی «خاطرات کفشباز» ، نوشته «فیل نایت»، بنیانگذار برند «نایکی» :
«از اوضاع خسته بودیم تا وقتی سرانجام در اواخر ۷۸ محصول «تیلویند» را عرضه کردیم. یک اختراع عالی از تیم طراحی خوبمان که در ژاپن ساخته شد.تیلویند چیزی بیش از یک کفش بود . این محصول یک اثر هنری پستمدرن بود. بزرگ، نقرهای روشن با کفی هوای انحصاری.مشخصن «دوازده نوآوری مختلف درین محصول بود.»...تیلیوند بعد از آغاز به کار بسیار موفقش یک غول فروش شد. و اما اندکی بعد گزارشات باگ و خرابی شروع به سرازیر شدن کردند. ما یک فراخوان بازگردانی صادر کردیم و پیشنهاد برگشت همهی پول مشتریان را دادیم. همه روانه سطل زباله شدند....ما درس ارزشمندی گرفتیم: «دوازده نوآوری را نباید در یک کفش قرار داد. این کار انتظار زیادی از یک کفش است. و همینطور از تیم طراحی»
۱۱:۵۶
پروژه چابکی شماره ۲۲بخش دوم
خب رفقا، پست قبل شما را یاد چه اصلی میاندازد؟ بله: «به صورت پیوسته ارزشآفرینی کنید»کدهاتان، محصولتان، پیشرفتتان را در گامهای کوچک و پیوسته پیش ببرید. سعی نکنید یک فیچر خیلی بزرگ را در فقط یک کامیت یا pull request یا اسپرینت بزرگ ارایه بدهید. خورد خورد انجامش دهید. و خب زود زود هم بازخورد بگیرید و بهترش کنید!
در پست بعدی تجربهمان در مبحث «Continuous Delivery» و پترنهای مرتبط با آن را به اشتراک میگذارم. یک بحث کاملن فنی با این خلاصه که: CD برای ما فقط راهاندازی یک ابزار مانند Jenkins و Ansible و ... نبود .بلکه اشتراک تنگاتنگی با این سه پترن حیاتی داشت:
- Trunk Based Development - Branch By Abstraction - Feature Toggles
برایتان خواهم گفت که چگونه توانستیم اینها را تمرین کنیم! و چقدر برایمان مفید بودند.
خب رفقا، پست قبل شما را یاد چه اصلی میاندازد؟ بله: «به صورت پیوسته ارزشآفرینی کنید»کدهاتان، محصولتان، پیشرفتتان را در گامهای کوچک و پیوسته پیش ببرید. سعی نکنید یک فیچر خیلی بزرگ را در فقط یک کامیت یا pull request یا اسپرینت بزرگ ارایه بدهید. خورد خورد انجامش دهید. و خب زود زود هم بازخورد بگیرید و بهترش کنید!
در پست بعدی تجربهمان در مبحث «Continuous Delivery» و پترنهای مرتبط با آن را به اشتراک میگذارم. یک بحث کاملن فنی با این خلاصه که: CD برای ما فقط راهاندازی یک ابزار مانند Jenkins و Ansible و ... نبود .بلکه اشتراک تنگاتنگی با این سه پترن حیاتی داشت:
- Trunk Based Development - Branch By Abstraction - Feature Toggles
برایتان خواهم گفت که چگونه توانستیم اینها را تمرین کنیم! و چقدر برایمان مفید بودند.
۱۱:۵۶
پروژه چابکیشماره ۲۲. بخش اول
به نام خدا. سلام.
چشم کفشها به راهبا خدای خویش، مناجات میکنند:«سرنوشت را به مهر سوی ما روانه کنجان عاشقان بیقرار را، مست گامهای عاشقانه کن»
باز هم از خاطرات کفشباز میخواهیم بگوییم؟ :) نه برای این شماره. این شماره برای کیبوردبازهاست. تیمهای چابکی که قهوه و شکلات را به عنوان ورودی میگیرند و «کد» تحویل میدهند!
بارها گفتیم: «چابکی به معنای اسکرام نیست». چابکی «ابزار» نیست، فریمورک نیست که یکیش را دانلود کنی و فقط مناسکش را به جا بیاوری و حالش را ببری و تامام.
بلکه چابکی یک «فرایند» است. یک طرز نگرش است.که از قضا دو بخش خیلی مهم و مرتبط دارد:
- نحوه تعریف هدف، شکل همکاری، برنامهریزی، بازنگری و دیگر فرایندهای اجرایی - نحوه DESIGN . معماری نرمافزار. جایی که «خروجی» نهایی را میبینیم. کدی که تبدیل به محصول و ارزش میشود.
نمیشود که شما کدهای آشغال بنویسید. کدهای پر از بدهی فنی. کدهای با معماری up-front. پر از RIGIDITY. کدهایی که برای «تغییر» کردن آماده نیست.و فقط با تنقیه اسکرام و کانبان و مدرن اجایل و ... بخواهی یک تیم چابک درست کنی.با یک گاو گوشتی نمیشود در مسابقه اسبسواری شرکت کرد. حتا اگر «خوزه مورینیو»ی بزرگ را به عنوان مربی داشته باشی.
ادامه دارد...
به نام خدا. سلام.
چشم کفشها به راهبا خدای خویش، مناجات میکنند:«سرنوشت را به مهر سوی ما روانه کنجان عاشقان بیقرار را، مست گامهای عاشقانه کن»
باز هم از خاطرات کفشباز میخواهیم بگوییم؟ :) نه برای این شماره. این شماره برای کیبوردبازهاست. تیمهای چابکی که قهوه و شکلات را به عنوان ورودی میگیرند و «کد» تحویل میدهند!
بارها گفتیم: «چابکی به معنای اسکرام نیست». چابکی «ابزار» نیست، فریمورک نیست که یکیش را دانلود کنی و فقط مناسکش را به جا بیاوری و حالش را ببری و تامام.
بلکه چابکی یک «فرایند» است. یک طرز نگرش است.که از قضا دو بخش خیلی مهم و مرتبط دارد:
- نحوه تعریف هدف، شکل همکاری، برنامهریزی، بازنگری و دیگر فرایندهای اجرایی - نحوه DESIGN . معماری نرمافزار. جایی که «خروجی» نهایی را میبینیم. کدی که تبدیل به محصول و ارزش میشود.
نمیشود که شما کدهای آشغال بنویسید. کدهای پر از بدهی فنی. کدهای با معماری up-front. پر از RIGIDITY. کدهایی که برای «تغییر» کردن آماده نیست.و فقط با تنقیه اسکرام و کانبان و مدرن اجایل و ... بخواهی یک تیم چابک درست کنی.با یک گاو گوشتی نمیشود در مسابقه اسبسواری شرکت کرد. حتا اگر «خوزه مورینیو»ی بزرگ را به عنوان مربی داشته باشی.
ادامه دارد...
۱۱:۵۵
پروژه چابکیشماره ۲۲. بخش دوم (ادامه از پست قبل)
و اما بعد تغییر در نیازمندیهای محصول ذات توسعه نرمافزار است. چیزی است که حتمن اتفاق میافتد. و ما باید برایش آماده باشیم.ما باید کدهایی بنویسیم که اصول حیاتی SOLID را تا حد مرگ رعایت کرده باشد. خصوصن Dependency Inversion خیلی خیلی خیلی مهم است. چیزی که پیشنیاز موضوع این پست است: Trunk Based Development .
اول از همه بگویم: TBD اینها نیست: - هر کسی به صورت مستقیم در برنچ مستر کد بنویسد. - هر کسی هرجای کد را بخواهد به راحتی و بدون آزمایش کافی عوض کند و در نسخه اصلی مرج هم بکند. - کلن شل بگیریم و code review نداشته باشیم. - تستنوشتن را رها کنیم چون زمان زیادی میبرد.
بلکه TBD این است: ما میخواهیم تا حد امکان زود شکست بخوریم . ما میخواهیم از فرایندهای پیچیده و رفتوبرگشتی و کارهای مستلزم Context-Switching .. بپرهیزیم. نمیخواهیم کد بیات داشته باشیم. کدی که بیشتر از یک روز فقط دست ما باشد. ما نمیخواهیم برای نسخه دادن درد بکشیم . بلکه در نظر داریم نسخه دادن را به یک امر خیلی راحت و پرتکرار تبدیل کنیم . ما میخواهیم روزی سه مرتبه و بعد از هر وعده نسخه بدهیم و عملیاتیش هم بکنیم! اما با همه اینها حواسمان به ارزش «امنیت خاطر را پیشنیاز همه چیز قرار دهید» هست. نمیخواهیم باگ ایجاد کنیم. تجربه کاربری را خراب کنیم. پایداری سیستم را پایین بیاوریم. و ...خب چطور؟با استفاده صحیح از Branch By Abstraction و Feature Toggles در عین پیادهسازی Trunk Based Development .میشود با ذکر مثال توضیح بدهی؟ بله در پست بعد!
و اما بعد تغییر در نیازمندیهای محصول ذات توسعه نرمافزار است. چیزی است که حتمن اتفاق میافتد. و ما باید برایش آماده باشیم.ما باید کدهایی بنویسیم که اصول حیاتی SOLID را تا حد مرگ رعایت کرده باشد. خصوصن Dependency Inversion خیلی خیلی خیلی مهم است. چیزی که پیشنیاز موضوع این پست است: Trunk Based Development .
اول از همه بگویم: TBD اینها نیست: - هر کسی به صورت مستقیم در برنچ مستر کد بنویسد. - هر کسی هرجای کد را بخواهد به راحتی و بدون آزمایش کافی عوض کند و در نسخه اصلی مرج هم بکند. - کلن شل بگیریم و code review نداشته باشیم. - تستنوشتن را رها کنیم چون زمان زیادی میبرد.
بلکه TBD این است: ما میخواهیم تا حد امکان زود شکست بخوریم . ما میخواهیم از فرایندهای پیچیده و رفتوبرگشتی و کارهای مستلزم Context-Switching .. بپرهیزیم. نمیخواهیم کد بیات داشته باشیم. کدی که بیشتر از یک روز فقط دست ما باشد. ما نمیخواهیم برای نسخه دادن درد بکشیم . بلکه در نظر داریم نسخه دادن را به یک امر خیلی راحت و پرتکرار تبدیل کنیم . ما میخواهیم روزی سه مرتبه و بعد از هر وعده نسخه بدهیم و عملیاتیش هم بکنیم! اما با همه اینها حواسمان به ارزش «امنیت خاطر را پیشنیاز همه چیز قرار دهید» هست. نمیخواهیم باگ ایجاد کنیم. تجربه کاربری را خراب کنیم. پایداری سیستم را پایین بیاوریم. و ...خب چطور؟با استفاده صحیح از Branch By Abstraction و Feature Toggles در عین پیادهسازی Trunk Based Development .میشود با ذکر مثال توضیح بدهی؟ بله در پست بعد!
۱۱:۵۸
پروژه چابکیشماره ۲۲. بخش سوم (ادامه از پست قبل)
ما یک نسخه بله اندروید داریم. تبهای مختلفی دارد. «بانک من»، «تنظیمات» و ... میخواهیم یک تب جدید «ویترین» هم اضافه کنیم. که کلی چیز جدید دارد.طبعن توسعه این ویژگی کاملن جدید روزها و بلکه هفتهها زمان میبرد. چه کنیم؟یک راهش این است که مدل Github flow رفتار کنیم.
- یک برنچ جدید از برنچ اصلی مستر بگیریم. - کدهای جدیدمان را در آنجا با خیال راحت بنویسیم. ممکن است چند هفته هم برای خودمان با خیال آسوده کار کنیم. - تمام که شد حالا یک pull-request میدهیم و منتظر merge میشویم و تمام!
ظاهرش قشنگ است. اما معمولن خیلی دردناک میشود .
- اول از همه وقتی پول ریکویست میدهیم هزار و شونصد تا confilct میخوریم. یکی یکی برطرف میکنیم و مدام خونریزی میکنیم.
- ازین بدترش اینجاست که یک همکار میآید و میگوید که کدت کلن آشغال است . معماریش حال آدم را به هم میزند و فلان کار احمقانه را حق نداشتی انجام بدهی. تو باز به آشیانه تنهایی خودت برمیگردی. زخمهایت را لیس میزنی و باز برمیگردی و ...
چه کنیم که زودتر شکست بخوریم؟ چه کنیم که چابکتر باشیم؟ برای مشکل اول یک راهحل به نظر میرسد: - هر روز برنچ خودمان را با برنچ اصلی merge همزمان کنیم. (یعنی در کامپیوتر خودمان هر روز برنچ مستر را بگیریم. تغییراتش را به برنچ شخصی خودمان اضافه کنیم که وقتی در نهایت درخواست مرج میدهیم کانفلیکتی نخوریم)
آفرین. خوب بود. اما هنوز مشکل دوم حل نشده! به نظر میرسد اصل «به صورت پیوسته ارزشآفرینی کنید» را رعایت نمیکنیم.
راه حلش این است که من خیلی زود زود pull-request بدهم. که همه سریع ببینند. و سریع بازخورد بدهند. که من زوود یاد بگیرم. و درستش کنم. اصل «سریع بیآزمایید و سریع یاد بگیرید» را رعایت کنم.
خب خب پس من اول فقط در روز اول یک تب خالی اضافه میکنم. داخلش فقط سه تا کانال رسمی پیشفرض (هارد کد) میگذارم. و درخواست ادغام میدهم. بقیه از لحاظ فنی و بیزینسی بررسی میکنند. چون حجم تغییرات کم است سریع نظرشان را میدهند. درستشان میکنم و کد در کمتر از ۲۴ ساعت وارد برنچ اصلی میشود. هوورااا! و بعد باز میروم سراغ اضافه کردن بقیه جزییات. داینامیک کردن لیست کانالها و ...زندگی شیرین میشود :)
اما داستان ادامه دارد...
ما یک نسخه بله اندروید داریم. تبهای مختلفی دارد. «بانک من»، «تنظیمات» و ... میخواهیم یک تب جدید «ویترین» هم اضافه کنیم. که کلی چیز جدید دارد.طبعن توسعه این ویژگی کاملن جدید روزها و بلکه هفتهها زمان میبرد. چه کنیم؟یک راهش این است که مدل Github flow رفتار کنیم.
- یک برنچ جدید از برنچ اصلی مستر بگیریم. - کدهای جدیدمان را در آنجا با خیال راحت بنویسیم. ممکن است چند هفته هم برای خودمان با خیال آسوده کار کنیم. - تمام که شد حالا یک pull-request میدهیم و منتظر merge میشویم و تمام!
ظاهرش قشنگ است. اما معمولن خیلی دردناک میشود .
- اول از همه وقتی پول ریکویست میدهیم هزار و شونصد تا confilct میخوریم. یکی یکی برطرف میکنیم و مدام خونریزی میکنیم.
- ازین بدترش اینجاست که یک همکار میآید و میگوید که کدت کلن آشغال است . معماریش حال آدم را به هم میزند و فلان کار احمقانه را حق نداشتی انجام بدهی. تو باز به آشیانه تنهایی خودت برمیگردی. زخمهایت را لیس میزنی و باز برمیگردی و ...
چه کنیم که زودتر شکست بخوریم؟ چه کنیم که چابکتر باشیم؟ برای مشکل اول یک راهحل به نظر میرسد: - هر روز برنچ خودمان را با برنچ اصلی merge همزمان کنیم. (یعنی در کامپیوتر خودمان هر روز برنچ مستر را بگیریم. تغییراتش را به برنچ شخصی خودمان اضافه کنیم که وقتی در نهایت درخواست مرج میدهیم کانفلیکتی نخوریم)
آفرین. خوب بود. اما هنوز مشکل دوم حل نشده! به نظر میرسد اصل «به صورت پیوسته ارزشآفرینی کنید» را رعایت نمیکنیم.
راه حلش این است که من خیلی زود زود pull-request بدهم. که همه سریع ببینند. و سریع بازخورد بدهند. که من زوود یاد بگیرم. و درستش کنم. اصل «سریع بیآزمایید و سریع یاد بگیرید» را رعایت کنم.
خب خب پس من اول فقط در روز اول یک تب خالی اضافه میکنم. داخلش فقط سه تا کانال رسمی پیشفرض (هارد کد) میگذارم. و درخواست ادغام میدهم. بقیه از لحاظ فنی و بیزینسی بررسی میکنند. چون حجم تغییرات کم است سریع نظرشان را میدهند. درستشان میکنم و کد در کمتر از ۲۴ ساعت وارد برنچ اصلی میشود. هوورااا! و بعد باز میروم سراغ اضافه کردن بقیه جزییات. داینامیک کردن لیست کانالها و ...زندگی شیرین میشود :)
اما داستان ادامه دارد...
۱۲:۱۴
پروژه چابکیشماره ۲۲. بخش چهارم (ادامه از پست قبل)
داستان ما تا اینجا یک اشکال اساسی وجود دارد! ما قرار گذاشتیم که «نسخه مستر یک ماشین در حال حرکت است» . ما هر لحظه ممکن است بخواهیم یک نسخه ازش بدهیم و در کافهبازار بگذاریم. تیم «پول» یک ویژگی جدید تسهیلات بانک مسکن اضافه کرده و همین الآن میخواهد یک نسخه بدهد. اما تب ویترین خالی است. زشت است. آماده انتشار برای همه کاربران نیست. چه کنیم؟
اولین راه حل این است که تیم پول یک برنچ رلیز درست کند. که شامل همه تغییرات به جز ویترین است. و با آن برود نسخه بدهد. آفرین. اما این کار سرانجامی جز آشوب ندارد! بعد از شش ماه ده تا برنچ داریم که اصلن خر توو خر است. ما قرار گذاشتهایم که «فقط و فقط از برنچ مستر نسخه عملیاتی بدهیم. و هر زمان که دلمان خواست باید بتوانیم این کار را بکنیم»
راهحل چیست؟ استفاده از پترن Feature-Toggles . به طور خلاصه اینکه ما بتوانیم به صورت دلخواه فیچر صفحه ویترینمان را «فعال-غیرفعال» بکنیم . این toggle کردن میتواند در زمان کامپایل یا در هنگام انتشار یا حتا بعد از انتشار اتفاق بیفتد.طبعن روشهای مختلفی هم برای پیادهسازیش وجود دارد و باید بسیار به دقت انجام شود. چرا که به راحتی موجب کثیف شدن و درهمبرهم شدن کد میشود.
حالا ما برنچ با عمر کوتاه کد ویترین را به همان شکل ساده اولیه در برنچ اصلی ادغام میکنیم. منتها فقط برای اعضای تیم توسعه دهنده فیچرش را روشن میکنیم.بقیه کاربران هیچ اثری ازش نمیبینند. و ما میتوانیم یک نسخه اندروید (با فیچرهای جدید بقیه تیمها) در مارکت داشته باشیم. خود برنچ با عمر کوتاه مان را هم پاک میکنیم.
ما به هدفمان رسیدیم: - کامل نبودن ویترین مانع انتشار نسخههای اندروید از برنچ اصلی نمیشود. - کد ناکامل هم در برنچ شخصی ما بیات نمیشود. بلکه به صورت پیوسته با کد اصلی ادغام میشود. بازخوانی میشود و ...
بعد ازین به کار روی ویترین ادامه میدهیم. همینجور به صورت پیوسته امکانات ویترین را زیاد میکنیم. و کد هم مدام مرج میشود و نسخه هم میدهیم و با تکنیکهای A/B Testing و به صورت تدریجی برای کاربران مختلف بیشتر (کل تیم بله، سداد، ...) فعالش میکنیم.اگر جایی باگ خاصی هم گزارش شد به سرعت میتوانیم فیچرش را غیرفعال کنیم .در ضمن حواسمان هم هست که تیم BI به صورت پیوسته آمارهای کامل و مفصل از میزان و نحوه استفاده کاربران ازین فیچر را بررسی میکند.و مدام بازخورد میدهد و ما مدام معماری این فیچر را بهبود میدهیم.
اما داستان ادامه دارد...
داستان ما تا اینجا یک اشکال اساسی وجود دارد! ما قرار گذاشتیم که «نسخه مستر یک ماشین در حال حرکت است» . ما هر لحظه ممکن است بخواهیم یک نسخه ازش بدهیم و در کافهبازار بگذاریم. تیم «پول» یک ویژگی جدید تسهیلات بانک مسکن اضافه کرده و همین الآن میخواهد یک نسخه بدهد. اما تب ویترین خالی است. زشت است. آماده انتشار برای همه کاربران نیست. چه کنیم؟
اولین راه حل این است که تیم پول یک برنچ رلیز درست کند. که شامل همه تغییرات به جز ویترین است. و با آن برود نسخه بدهد. آفرین. اما این کار سرانجامی جز آشوب ندارد! بعد از شش ماه ده تا برنچ داریم که اصلن خر توو خر است. ما قرار گذاشتهایم که «فقط و فقط از برنچ مستر نسخه عملیاتی بدهیم. و هر زمان که دلمان خواست باید بتوانیم این کار را بکنیم»
راهحل چیست؟ استفاده از پترن Feature-Toggles . به طور خلاصه اینکه ما بتوانیم به صورت دلخواه فیچر صفحه ویترینمان را «فعال-غیرفعال» بکنیم . این toggle کردن میتواند در زمان کامپایل یا در هنگام انتشار یا حتا بعد از انتشار اتفاق بیفتد.طبعن روشهای مختلفی هم برای پیادهسازیش وجود دارد و باید بسیار به دقت انجام شود. چرا که به راحتی موجب کثیف شدن و درهمبرهم شدن کد میشود.
حالا ما برنچ با عمر کوتاه کد ویترین را به همان شکل ساده اولیه در برنچ اصلی ادغام میکنیم. منتها فقط برای اعضای تیم توسعه دهنده فیچرش را روشن میکنیم.بقیه کاربران هیچ اثری ازش نمیبینند. و ما میتوانیم یک نسخه اندروید (با فیچرهای جدید بقیه تیمها) در مارکت داشته باشیم. خود برنچ با عمر کوتاه مان را هم پاک میکنیم.
ما به هدفمان رسیدیم: - کامل نبودن ویترین مانع انتشار نسخههای اندروید از برنچ اصلی نمیشود. - کد ناکامل هم در برنچ شخصی ما بیات نمیشود. بلکه به صورت پیوسته با کد اصلی ادغام میشود. بازخوانی میشود و ...
بعد ازین به کار روی ویترین ادامه میدهیم. همینجور به صورت پیوسته امکانات ویترین را زیاد میکنیم. و کد هم مدام مرج میشود و نسخه هم میدهیم و با تکنیکهای A/B Testing و به صورت تدریجی برای کاربران مختلف بیشتر (کل تیم بله، سداد، ...) فعالش میکنیم.اگر جایی باگ خاصی هم گزارش شد به سرعت میتوانیم فیچرش را غیرفعال کنیم .در ضمن حواسمان هم هست که تیم BI به صورت پیوسته آمارهای کامل و مفصل از میزان و نحوه استفاده کاربران ازین فیچر را بررسی میکند.و مدام بازخورد میدهد و ما مدام معماری این فیچر را بهبود میدهیم.
اما داستان ادامه دارد...
۱۷:۵۸
پروژه چابکیشماره ۲۲. بخش پنجم و آخر (ادامه از پست قبل)
خب وقتی میخواهیم یک ویژگی کاملن جدید مثل «صفحه ویترین» را به برنامه اندروید اضافه کنیم کارمان راحت بود.از پترن Feature-Toggles استفاده کردیم. حواسمان به معماری بود و ...
اما اگر بخواهیم یک ویژگی فعلی را تغییر بدهیم چه ؟ مثلن صفحه کارت به کارت را بازطراحی گرافیکی کنیم؟خب راهحل معمول را توضیح دادیم که - یا کد بیات میشود - و یا در صورت ادغام به خاطر ناکامل بودن مانع انتشار نسخه از روی برنچ مستر میشود. کلن خون و خونریزی!
اما مثل قبل هم نمیشود فیچر کارتبهکارت را هم خاموش و روشن کنیم! ملت دارند استفاده میکنند!راهحل چیست؟ استفاده همزمان از پترن Feature-Toggles و پترن عالی Branch By Abstraction
حالا این BBA چیست؟ ببنید وضعیت چیست؟ نیاز به کار بلند مدت برای یک تغییر بزرگ در یک فیچر موجود داریمراه حل معمول: ایجاد یک برنچ مجزای مستقل با عمر طولانی چند هفتهای و در نهایت درخواست ادغام راه حل BBA : - یک برنچ مجزای مستقل میسازیم که قرار است کمتر از یک روز عمر کند و سریع ادغام بشود و برنچ هم پاک بشود. - یک Abstraction (در جاوا همان Interface) از کاری که انجام میشود را درست میکنیم. (مثلن با توابع «نمایش کارتهای فعال»، «اضافه کردن کارت»، ...) - کلاس فعلی (صفحه کارت به کارت موجود) را جوری re-factor میکنیم که از اینترفیس قبلی ارث ببرد. (طبعن اگر کدهامان MVVM هم باشد خیلی راحتتر هست کارمان) - کلاس جدید (بازطراحی صفحه) را هم از اینترفیس ارث میبریم. (که فعلن هیچ عملیات واقعی انجام نمیدهد) - با استفاده از پترن Feature-Toggle (و استراتژی و رعایت Dependency Inversion) صفحه جدید را فقط برای تیم توسعه خودمان روشن میکنیم و بقیه کاربران همان صفحه قبلی را میبینند. - به صورت پیوسته رووی صفحه جدید کار میکنیم و کدش را هم با رعایت TBD در برنچ اصلی در هر روز ادغام میکنیم. - با تکنیکهای A/B صفحه جدید را به تدریج برای همه کاربران باز میکنیم و اگر همه چیز از دید تیم BI اوکی بود صفحه قبلی را پاک میکنیم.
و تامام! تا حد خووبی از شر پیچیدگیهای برنچهای مختلف و درد و خونریزی نسخهدادن و ... رها میشویم!بازدهی همه افزایش پیدا میکند. و حالا تازه وقت استفاده واقعی از ابزارهای CI/CD مثل Jenkins هستش!
خب وقتی میخواهیم یک ویژگی کاملن جدید مثل «صفحه ویترین» را به برنامه اندروید اضافه کنیم کارمان راحت بود.از پترن Feature-Toggles استفاده کردیم. حواسمان به معماری بود و ...
اما اگر بخواهیم یک ویژگی فعلی را تغییر بدهیم چه ؟ مثلن صفحه کارت به کارت را بازطراحی گرافیکی کنیم؟خب راهحل معمول را توضیح دادیم که - یا کد بیات میشود - و یا در صورت ادغام به خاطر ناکامل بودن مانع انتشار نسخه از روی برنچ مستر میشود. کلن خون و خونریزی!
اما مثل قبل هم نمیشود فیچر کارتبهکارت را هم خاموش و روشن کنیم! ملت دارند استفاده میکنند!راهحل چیست؟ استفاده همزمان از پترن Feature-Toggles و پترن عالی Branch By Abstraction
حالا این BBA چیست؟ ببنید وضعیت چیست؟ نیاز به کار بلند مدت برای یک تغییر بزرگ در یک فیچر موجود داریمراه حل معمول: ایجاد یک برنچ مجزای مستقل با عمر طولانی چند هفتهای و در نهایت درخواست ادغام راه حل BBA : - یک برنچ مجزای مستقل میسازیم که قرار است کمتر از یک روز عمر کند و سریع ادغام بشود و برنچ هم پاک بشود. - یک Abstraction (در جاوا همان Interface) از کاری که انجام میشود را درست میکنیم. (مثلن با توابع «نمایش کارتهای فعال»، «اضافه کردن کارت»، ...) - کلاس فعلی (صفحه کارت به کارت موجود) را جوری re-factor میکنیم که از اینترفیس قبلی ارث ببرد. (طبعن اگر کدهامان MVVM هم باشد خیلی راحتتر هست کارمان) - کلاس جدید (بازطراحی صفحه) را هم از اینترفیس ارث میبریم. (که فعلن هیچ عملیات واقعی انجام نمیدهد) - با استفاده از پترن Feature-Toggle (و استراتژی و رعایت Dependency Inversion) صفحه جدید را فقط برای تیم توسعه خودمان روشن میکنیم و بقیه کاربران همان صفحه قبلی را میبینند. - به صورت پیوسته رووی صفحه جدید کار میکنیم و کدش را هم با رعایت TBD در برنچ اصلی در هر روز ادغام میکنیم. - با تکنیکهای A/B صفحه جدید را به تدریج برای همه کاربران باز میکنیم و اگر همه چیز از دید تیم BI اوکی بود صفحه قبلی را پاک میکنیم.
و تامام! تا حد خووبی از شر پیچیدگیهای برنچهای مختلف و درد و خونریزی نسخهدادن و ... رها میشویم!بازدهی همه افزایش پیدا میکند. و حالا تازه وقت استفاده واقعی از ابزارهای CI/CD مثل Jenkins هستش!
۱۸:۱۷
به نام خدا
طربنامه چابکی (خبرنامه داخلی چابکی بله)شماره ۱۱
به مجمعی که درآیند شاهدان دو عالم
به گفتوپول تو خیزم، به جستوجوی تو باشم
درود رفقا، ضمن پوزش از اعلام دیرهنگام و با طلب همدلی به خاطر زمان محدود اجایل کوچ مهربان
برنامه مجمع بیستویکم: از ساعت ۱۵:۳۰ تا ۱۷ امروز یکشنبه ۱۴ بهمن ۱۳۹۷ خورشیدیدر محل سالن اجتماعات طبقه همکفامید که با همکاری شما در خور دوستان بسازیمش.
1549195200-1549195500: Revolutionary Anthem 1549195500-1549196100: Money & Said Teams1549196100-1549196400: Employee Referrals1549196400-1549197000: Infra & Humans Teams1549197000-1549198800: Bale Development1549198800-1549199400: Agile Coach1549199400-1549200000: BeKhatereTeam
چهار تیم گفتهشده با انگلیس خفن به سه سوال اساسی پاسخ میدهند: - مهمترین «دستاورد تحویلشده» سه هفته اخیرشان چه بوده است؟ - چرا این مساله خاص را برای تمرکز انتخاب کردند؟ - چه آموزههایی ازین چالش را با بقیه به اشتراک میگذارند؟
و زیاده جسارت است!
طربنامه چابکی (خبرنامه داخلی چابکی بله)شماره ۱۱
به مجمعی که درآیند شاهدان دو عالم
به گفتوپول تو خیزم، به جستوجوی تو باشم
درود رفقا، ضمن پوزش از اعلام دیرهنگام و با طلب همدلی به خاطر زمان محدود اجایل کوچ مهربان
برنامه مجمع بیستویکم: از ساعت ۱۵:۳۰ تا ۱۷ امروز یکشنبه ۱۴ بهمن ۱۳۹۷ خورشیدیدر محل سالن اجتماعات طبقه همکفامید که با همکاری شما در خور دوستان بسازیمش.
1549195200-1549195500: Revolutionary Anthem 1549195500-1549196100: Money & Said Teams1549196100-1549196400: Employee Referrals1549196400-1549197000: Infra & Humans Teams1549197000-1549198800: Bale Development1549198800-1549199400: Agile Coach1549199400-1549200000: BeKhatereTeam
چهار تیم گفتهشده با انگلیس خفن به سه سوال اساسی پاسخ میدهند: - مهمترین «دستاورد تحویلشده» سه هفته اخیرشان چه بوده است؟ - چرا این مساله خاص را برای تمرکز انتخاب کردند؟ - چه آموزههایی ازین چالش را با بقیه به اشتراک میگذارند؟
و زیاده جسارت است!
۹:۲۵
پروژه چابکیشماره ۲۳. بخش اول
اسکرامفال!
«در آغاز کلمه بود، و کلمه خدا بود!»سلام! «اسکرامفال» دقیقن همان واژهای بود که دنبالش میگشتم.تیمهایی که میخواهند چابک باشند و دنبال یک میانبر هستند.و چه میانبری معروفتر از «اسکرام»! شبیه یک قرص ویتامین. راحتالحلقوم!
متاسفانه بسیاری از تیمها به دو دلیل در سطح «مناسک» اسکرام باقی میمانند: - توانایی ناکافی در مهارتهای فنی Agile Design و Evolutionary Design - اجرای محدود «اسکرام» فقط در سطح پیادهسازی و تیم توسعه (نه کل فرایند و سازمان)
اول درباره مساله دوم بگویم: (خواندن این مساله دوم چندان توصیه نمیشود! بروید به پست بعدی!)
خیلی اوقات ما یک مدیر با دید کاملن سنتی داریم. که دقیقن دنبال یک فرایند کاملن مشخص از پیش تعیینشده و قراردادی مبتنی بر Gant Chart و ... است. با یک Release Plan معلوم. با فیچرها و ... مشخص. شبیه ساختن یک پل توسط مهندسان عمران . یک ذهنیت کاملن واترفال .
حالا ایشان با همان ابزارهای «مدیریت پروژه» معمول از یک تیم توسعه انتظار تحویل محصول را دارد. فریمورک اسکرام را هم چون مد روز است به ایّ نحو ممکن در تیم تنقیه میکند و انتظار «سرعت» (نه لزومن چابکی) در اجرا را دارد!
بدیش اینجاست که خیلی وقتها تیم توسعه هم با خوشنودی به همین تراژدی تن میدهد و تند تند اسپرینت برگزار میکند و دمو میکند و همه شادان که ما چابکیم!
چند اسپرینت اول همهش صرف طراحی میشود. اسپرینت سوم فقط لاگین (با همه انواعش) را مینویسند. اسپرینت بعدی تمام رابط کاربری و ... تا اسپرینت هشتم هنوز هیچ نرمافزار واقعی قابل اجرایی وجود ندارد! و قس علی هذا!
نمیشود آقا. نمیشود! با یک گاو گوشتی نمیشود در مسابقه اسبدوانی شرکت کرد! حتا اگر خوزه مورینیوی بزرگ مربیت باشد!
حالا چه کنیم و چه بپوشیم؟ در پست بعد...
اسکرامفال!
«در آغاز کلمه بود، و کلمه خدا بود!»سلام! «اسکرامفال» دقیقن همان واژهای بود که دنبالش میگشتم.تیمهایی که میخواهند چابک باشند و دنبال یک میانبر هستند.و چه میانبری معروفتر از «اسکرام»! شبیه یک قرص ویتامین. راحتالحلقوم!
متاسفانه بسیاری از تیمها به دو دلیل در سطح «مناسک» اسکرام باقی میمانند: - توانایی ناکافی در مهارتهای فنی Agile Design و Evolutionary Design - اجرای محدود «اسکرام» فقط در سطح پیادهسازی و تیم توسعه (نه کل فرایند و سازمان)
اول درباره مساله دوم بگویم: (خواندن این مساله دوم چندان توصیه نمیشود! بروید به پست بعدی!)
خیلی اوقات ما یک مدیر با دید کاملن سنتی داریم. که دقیقن دنبال یک فرایند کاملن مشخص از پیش تعیینشده و قراردادی مبتنی بر Gant Chart و ... است. با یک Release Plan معلوم. با فیچرها و ... مشخص. شبیه ساختن یک پل توسط مهندسان عمران . یک ذهنیت کاملن واترفال .
حالا ایشان با همان ابزارهای «مدیریت پروژه» معمول از یک تیم توسعه انتظار تحویل محصول را دارد. فریمورک اسکرام را هم چون مد روز است به ایّ نحو ممکن در تیم تنقیه میکند و انتظار «سرعت» (نه لزومن چابکی) در اجرا را دارد!
بدیش اینجاست که خیلی وقتها تیم توسعه هم با خوشنودی به همین تراژدی تن میدهد و تند تند اسپرینت برگزار میکند و دمو میکند و همه شادان که ما چابکیم!
چند اسپرینت اول همهش صرف طراحی میشود. اسپرینت سوم فقط لاگین (با همه انواعش) را مینویسند. اسپرینت بعدی تمام رابط کاربری و ... تا اسپرینت هشتم هنوز هیچ نرمافزار واقعی قابل اجرایی وجود ندارد! و قس علی هذا!
نمیشود آقا. نمیشود! با یک گاو گوشتی نمیشود در مسابقه اسبدوانی شرکت کرد! حتا اگر خوزه مورینیوی بزرگ مربیت باشد!
حالا چه کنیم و چه بپوشیم؟ در پست بعد...
۷:۴۲
پروژه چابکیشماره ۲۳. بخش دوم (ادامه از پست قبل)
دوم درباره مساله اول:تعریف مختصر Agile Design : «تعهد و توانایی نوشتن کدهایی که آماده تغییر هستند» .
اما باید بگویم که Agile Design یک مناسباتی دارد. تامل و دقت فنی میخواهد. متاسفانه متاسفانه ما (برنامهنویسان معمول ایرانی) خیلی کم پی رعایت کردن best practice های موجود هستیم. خیلیهامان یک ترکیب «بیست درصد یادگیری سینتکس یک زبان» + «هشتاد درصد مشکل خوردن و جستجو در استکاورفلو و پیدا کردن یک تکه کد از گیتهاب » هستیم. خوبترهامان کمی با «دیزاین پترن»ها هم آشنایی داریم.
در حالی که در زمانهی «نوآوری باز» دو تا کتاب خیلی خیلی عالی و معروف از عمو باب هست که اندازه سه تا مدرک لیسانس نرمافزار به دانش و بهرهوری برنامهنویسی ما میافزاید:
- کتاب Clean Code - کتاب Agile Principles, Patterns, and Practices
منتها دقت کنیم که خود «کتابخوانی» تبدیل به یک دام نشود . آدم فقط با خواندن «آییننامه راهنمایی» راننده خوبی نمیشود. همه مفاهیمش نیاز به تامل، تعهد و تمرین و تمرین و تمرین دارد!
در پست کاملن فنی بعدی میخواهم یک مثال واقعی از تجربه بله در رعایت اصول SOLID و خصوصن Dependency Inversion و Open-Closed و فواید حاصل از آن را تعریف کنم.
و این که چطور طراحی چابک و تکاملی به جلوگیری از افتادن در دام اسکرامفال کمک میکند!چگونه SOLID جلوی Bad Smell های اساسی مهندسی نرمافزار خصوصن Rigidity و Fragility را میگیرد!
و زیاده جسارت است!
دوم درباره مساله اول:تعریف مختصر Agile Design : «تعهد و توانایی نوشتن کدهایی که آماده تغییر هستند» .
اما باید بگویم که Agile Design یک مناسباتی دارد. تامل و دقت فنی میخواهد. متاسفانه متاسفانه ما (برنامهنویسان معمول ایرانی) خیلی کم پی رعایت کردن best practice های موجود هستیم. خیلیهامان یک ترکیب «بیست درصد یادگیری سینتکس یک زبان» + «هشتاد درصد مشکل خوردن و جستجو در استکاورفلو و پیدا کردن یک تکه کد از گیتهاب » هستیم. خوبترهامان کمی با «دیزاین پترن»ها هم آشنایی داریم.
در حالی که در زمانهی «نوآوری باز» دو تا کتاب خیلی خیلی عالی و معروف از عمو باب هست که اندازه سه تا مدرک لیسانس نرمافزار به دانش و بهرهوری برنامهنویسی ما میافزاید:
- کتاب Clean Code - کتاب Agile Principles, Patterns, and Practices
منتها دقت کنیم که خود «کتابخوانی» تبدیل به یک دام نشود . آدم فقط با خواندن «آییننامه راهنمایی» راننده خوبی نمیشود. همه مفاهیمش نیاز به تامل، تعهد و تمرین و تمرین و تمرین دارد!
در پست کاملن فنی بعدی میخواهم یک مثال واقعی از تجربه بله در رعایت اصول SOLID و خصوصن Dependency Inversion و Open-Closed و فواید حاصل از آن را تعریف کنم.
و این که چطور طراحی چابک و تکاملی به جلوگیری از افتادن در دام اسکرامفال کمک میکند!چگونه SOLID جلوی Bad Smell های اساسی مهندسی نرمافزار خصوصن Rigidity و Fragility را میگیرد!
و زیاده جسارت است!
۹:۲۸
پروژه چابکیشماره ۲۴. بخش اول
سلام. امروز یک پست چند قسمتی طولانی فنی درباره تجربه نوشتن فیچر «کارت به کارت» در «بله»ی بند دل مان داریم! تجربه اصول Open-Closed، DI و پترن MVP !
یکی بود یکی نبود. اولین بار سال ۹۵ بود که تحت فشار زیاد کاری و زمانی این فیچر کارت به کارت را رساندیم.کد تقریبن اینجور چیزی بود:
نسخه یک : یک صفحه اکتیویتی اندروید داشتیم که داخلش یک «ویجت» کارت نمایش میدادیم. بعد با توجه به ورودیهای کاربر یک سری «لاجیک» داشتیم و همانجا هم API بکس باحال بام را صدا میزدیم:
منتها بعد از مدتی خواستیم یک ویژگی «ذخیره کردن» کارت را هم اضافه کنیم. دیگر دفعات بعد فقط رمز دوم را بزنیم.
نسخه دو اینجوری شد:
یعنی مجبور شدیم قبل از نمایش ویجت برویم و در همان «اکتویتی» اندروید یه سری چک بکنیم که آیا کارتی از قبل ذخیره داریم یا نه و ...
خب! این ویژگی را هم رفتیم و دمو کردیم و همه کف و احسنت!
بعد از مدتی خواستیم که آن کتابخانه/ماژولی که برای صدا زدن API استفاده میکردیم را ریفکتور کنیم. چون یه سری کدهای سمت سرور عوض شده بود. اینجوری شد:
نسخه سه :
خب دیگر پیش نمیروم! بگذارید کمی روضه بخوانم:تا همینجا هم یک کد ما انواع و اقسام Bad Smellهای ممکن را دارد :
یک اکتویتی اندروید چند صد خطی داریم. که از لحاظ Clean Code واویلاست. کدها درهم. بدون نامگذاری صحیح. تابعهای طولانی با پارامترهای فراوان! ...
از لحاظ معماری هم:
کد به شدت Rigidiy دارد. همه بخشهای مختلف به شدت «وابسته» به هماند. Coupling شدیدی همه جا هستش. اگر بخواهی کد لاجیک را عوض کنی مجبوری همه کدهای قبل و بعدش را هم عوض کنی. ماستا قاتی قیمهها و لاجیک قاتی یوآی هستش!
کد به شدت Fragility دارد. یعنی مثلن میخواهی فقط رنگ بکگراند صفحه را عوض کنی و یهو میبینی دیگر کارتهای بانک تجارت کار نمیکند و باگهای منطقن نامرتبط دیگر!
کد به شدت Viscosity دارد. یعنی همهمان میدانیم که ادامه این مسیر اشتباه است و کار درست چیز دیگری است. اما «انجام کار درست» خیلی سختتر از «راه معمول و اشتباه» است. خصوصن در فشار زمانی و بیزینسی!
طبعن کد هیچ گونه قابلیت آزمون اتومات ندارد (TDD و از قبل آزمون نوشتن را فراموش کنید تازه). بماند که حتا دیباگ دستیش هم بسیار دشوار است.
خب چه کنیم؟ چه میبایستی میکردیم؟ خصوصن که حجم درخواستهای بیزینس همیشه بالاست و فشار بیامانی برای ویژگیهای جدید وجود دارد!
و البته برایشان (و حتا برای خود ما) سوال شده که کوچکترین درخواستشان (در حد ویرایش جملات رابط کاربری و خطاها) هم خیلی زیاااد زمان میبرد.چرا که کد نوشته میشود، به تیم تست داده میشود. شونصد تا باگ جدید و قدیم کشف میشود. باز برمیگردد، تعمیر میشود، ...
خلاصه که «شب تاریک و بیم موج و گردابی چنین هایل، کجا دانند حال ما سبکباران ساحلها»اصلن غمش برایم تازه شد! بگذارید بقیهش را بعدن برایتان بنویسم. شاید بعد یک فنجان قهوه تلخ. ادامه دارد...
سلام. امروز یک پست چند قسمتی طولانی فنی درباره تجربه نوشتن فیچر «کارت به کارت» در «بله»ی بند دل مان داریم! تجربه اصول Open-Closed، DI و پترن MVP !
یکی بود یکی نبود. اولین بار سال ۹۵ بود که تحت فشار زیاد کاری و زمانی این فیچر کارت به کارت را رساندیم.کد تقریبن اینجور چیزی بود:
نسخه یک : یک صفحه اکتیویتی اندروید داشتیم که داخلش یک «ویجت» کارت نمایش میدادیم. بعد با توجه به ورودیهای کاربر یک سری «لاجیک» داشتیم و همانجا هم API بکس باحال بام را صدا میزدیم:
show ui -> handle logic -> call API
خب! آفرین! چقدر تیم چابکی! رفتیم و دمو کردیم و همه کف و احسنت!منتها بعد از مدتی خواستیم یک ویژگی «ذخیره کردن» کارت را هم اضافه کنیم. دیگر دفعات بعد فقط رمز دوم را بزنیم.
نسخه دو اینجوری شد:
check some DataBase -> show ui -> handle logic -> call API
یعنی مجبور شدیم قبل از نمایش ویجت برویم و در همان «اکتویتی» اندروید یه سری چک بکنیم که آیا کارتی از قبل ذخیره داریم یا نه و ...
خب! این ویژگی را هم رفتیم و دمو کردیم و همه کف و احسنت!
بعد از مدتی خواستیم که آن کتابخانه/ماژولی که برای صدا زدن API استفاده میکردیم را ریفکتور کنیم. چون یه سری کدهای سمت سرور عوض شده بود. اینجوری شد:
نسخه سه :
check some DB -> show ui -> handle logic -> if (card is MELLI) call oldAPI else call newAPI
خب دیگر پیش نمیروم! بگذارید کمی روضه بخوانم:تا همینجا هم یک کد ما انواع و اقسام Bad Smellهای ممکن را دارد :
یک اکتویتی اندروید چند صد خطی داریم. که از لحاظ Clean Code واویلاست. کدها درهم. بدون نامگذاری صحیح. تابعهای طولانی با پارامترهای فراوان! ...
از لحاظ معماری هم:
کد به شدت Rigidiy دارد. همه بخشهای مختلف به شدت «وابسته» به هماند. Coupling شدیدی همه جا هستش. اگر بخواهی کد لاجیک را عوض کنی مجبوری همه کدهای قبل و بعدش را هم عوض کنی. ماستا قاتی قیمهها و لاجیک قاتی یوآی هستش!
کد به شدت Fragility دارد. یعنی مثلن میخواهی فقط رنگ بکگراند صفحه را عوض کنی و یهو میبینی دیگر کارتهای بانک تجارت کار نمیکند و باگهای منطقن نامرتبط دیگر!
کد به شدت Viscosity دارد. یعنی همهمان میدانیم که ادامه این مسیر اشتباه است و کار درست چیز دیگری است. اما «انجام کار درست» خیلی سختتر از «راه معمول و اشتباه» است. خصوصن در فشار زمانی و بیزینسی!
طبعن کد هیچ گونه قابلیت آزمون اتومات ندارد (TDD و از قبل آزمون نوشتن را فراموش کنید تازه). بماند که حتا دیباگ دستیش هم بسیار دشوار است.
خب چه کنیم؟ چه میبایستی میکردیم؟ خصوصن که حجم درخواستهای بیزینس همیشه بالاست و فشار بیامانی برای ویژگیهای جدید وجود دارد!
و البته برایشان (و حتا برای خود ما) سوال شده که کوچکترین درخواستشان (در حد ویرایش جملات رابط کاربری و خطاها) هم خیلی زیاااد زمان میبرد.چرا که کد نوشته میشود، به تیم تست داده میشود. شونصد تا باگ جدید و قدیم کشف میشود. باز برمیگردد، تعمیر میشود، ...
خلاصه که «شب تاریک و بیم موج و گردابی چنین هایل، کجا دانند حال ما سبکباران ساحلها»اصلن غمش برایم تازه شد! بگذارید بقیهش را بعدن برایتان بنویسم. شاید بعد یک فنجان قهوه تلخ. ادامه دارد...
۸:۵۴
به نام خدا
طربنامه چابکی (خبرنامه داخلی چابکی بله)شماره ۱۲
به مجمعی که درآیند شاهدان دو عالم
به گفتوپول تو خیزم، به جستوجوی تو باشم
سلام رفقا، با درود به روح پرفتوح زنان، مادران و مهندسان گرام (به جز سیتواو).
برنامه مجمع بیست و دویم: از ساعت ۱۵:۳۰ تا ۱۷ امروز یکشنبه ۵ اسفند ۱۳۹۷ خورشیدیدر محل سالن اجتماعات.امید که با همکاری شما در خور دوستان باشد.
1551009600-1551009900: Mother's Anthem1551009900-1551010500: Arm & Marketing Teams1551010500-1551010800: CTO1551010800-1551011400: Success & Bank Teams1551011400-1551012300: Premier League1551012300-1551012900: BeKhatereTeam
چهار تیم گفتهشده به سه سوال اساسی پاسخ میدهند: - مهمترین «دستاورد تحویلشده» سه هفته اخیرشان چه بوده است؟ - چرا این مساله خاص را برای تمرکز انتخاب کردند؟ - چه دیتا و آمار دقیق و مشخص و عددی از دستاوردشان دارند؟
لیگ برتر تیمی هم با محوریت «کل تیم باصفای بله» هستش. یعنی در سه هفته اخیر با کار کدام تیم بیشتر حال کردید؟ چه تیمی بیشتر به کل بله انرژی مثبت داده است؟ لطفن از قبل رایهاتان را آماده کنید. هر تیمی دو رای دارد :)
در بخش هشتگ #بهخاطرتیم هم با کمک سرمایهانسانی میزبان تیم پیشروی پول هستیم. با بیان تجربیات و شکستهای کار تیمیشان.
در نهایت حق هرگونه تغییر برنامه بدون اطلاع قبلی برای اجایلکوچ مهربان محفوظ است و زیاده جسارت است!
طربنامه چابکی (خبرنامه داخلی چابکی بله)شماره ۱۲
به مجمعی که درآیند شاهدان دو عالم
به گفتوپول تو خیزم، به جستوجوی تو باشم
سلام رفقا، با درود به روح پرفتوح زنان، مادران و مهندسان گرام (به جز سیتواو).
برنامه مجمع بیست و دویم: از ساعت ۱۵:۳۰ تا ۱۷ امروز یکشنبه ۵ اسفند ۱۳۹۷ خورشیدیدر محل سالن اجتماعات.امید که با همکاری شما در خور دوستان باشد.
1551009600-1551009900: Mother's Anthem1551009900-1551010500: Arm & Marketing Teams1551010500-1551010800: CTO1551010800-1551011400: Success & Bank Teams1551011400-1551012300: Premier League1551012300-1551012900: BeKhatereTeam
چهار تیم گفتهشده به سه سوال اساسی پاسخ میدهند: - مهمترین «دستاورد تحویلشده» سه هفته اخیرشان چه بوده است؟ - چرا این مساله خاص را برای تمرکز انتخاب کردند؟ - چه دیتا و آمار دقیق و مشخص و عددی از دستاوردشان دارند؟
لیگ برتر تیمی هم با محوریت «کل تیم باصفای بله» هستش. یعنی در سه هفته اخیر با کار کدام تیم بیشتر حال کردید؟ چه تیمی بیشتر به کل بله انرژی مثبت داده است؟ لطفن از قبل رایهاتان را آماده کنید. هر تیمی دو رای دارد :)
در بخش هشتگ #بهخاطرتیم هم با کمک سرمایهانسانی میزبان تیم پیشروی پول هستیم. با بیان تجربیات و شکستهای کار تیمیشان.
در نهایت حق هرگونه تغییر برنامه بدون اطلاع قبلی برای اجایلکوچ مهربان محفوظ است و زیاده جسارت است!
۶:۲۰
پروژه چابکیشماره ۲۴. بخش دوم (ادامه از پست قبل)
در بانکداری اینگونه میگویند که «وام در حقیقت قرض گرفتن از خودمان در آینده است.» و من میافزایم که «بیمحلی به SOLID در حقیقت خنجر زدن به خودمان در آینده است»باری، ما در بله، این پلتفرم بانکداری دیجیتال ، خونین و مالین هستیم :) طبعن خونمان هم بر گردن خودمان هست! اما چشم امید داریم به این گفتهی نیچه: «آن بدهی فنی که تو را نکشد قویترت میسازد.» پس صبورانه پاچهها را بالا زدیم و تا زانو غرق گل در کار refactoring هستیم!
و اما ادامه مثنوی قبلی که مدتی هم تاخیر رفت. داستان پرآب چشم یک فیچر به ظاهر ساده «کارت به کارت». که قرار بود قهوهای بخوریم و ادامه بدهیم. اما لااقل سی و چند اسپرسو لازم بود که قوتی در سرانگشتانم شکل بگیرد که بگویم برایتان:
مصطفا رادمرد آمد و با غصه شکایت کرد که این که نشد کار. فقط از شما خواستم فونت صفحه را درشتتر کنید و دیگر کارتهای بانک کشاورزیم کار نمیکند. چقدر Fragile هستید رفقا! البته شکایت مصطفا همیشه با مقداری شدت و تشر هم همراه هست. خب راهحل چیست؟؟ چگونه امنیت خاطر مصطفا و بقیه مردم را حفظ کنیم؟(ادامه دارد...)
در بانکداری اینگونه میگویند که «وام در حقیقت قرض گرفتن از خودمان در آینده است.» و من میافزایم که «بیمحلی به SOLID در حقیقت خنجر زدن به خودمان در آینده است»باری، ما در بله، این پلتفرم بانکداری دیجیتال ، خونین و مالین هستیم :) طبعن خونمان هم بر گردن خودمان هست! اما چشم امید داریم به این گفتهی نیچه: «آن بدهی فنی که تو را نکشد قویترت میسازد.» پس صبورانه پاچهها را بالا زدیم و تا زانو غرق گل در کار refactoring هستیم!
و اما ادامه مثنوی قبلی که مدتی هم تاخیر رفت. داستان پرآب چشم یک فیچر به ظاهر ساده «کارت به کارت». که قرار بود قهوهای بخوریم و ادامه بدهیم. اما لااقل سی و چند اسپرسو لازم بود که قوتی در سرانگشتانم شکل بگیرد که بگویم برایتان:
مصطفا رادمرد آمد و با غصه شکایت کرد که این که نشد کار. فقط از شما خواستم فونت صفحه را درشتتر کنید و دیگر کارتهای بانک کشاورزیم کار نمیکند. چقدر Fragile هستید رفقا! البته شکایت مصطفا همیشه با مقداری شدت و تشر هم همراه هست. خب راهحل چیست؟؟ چگونه امنیت خاطر مصطفا و بقیه مردم را حفظ کنیم؟(ادامه دارد...)
۱۲:۵۴
شماره ۲۴. بخش سوم (ادامه از پست قبل)
خب راهحل چیست؟؟ اول از همه و فارغ از بحثهای SOLID و ... به اصلی بنیادین مهندسی نرمافزار رجوع کردیم:
FTSE: «We can solve any problem by introducing an extra level of indirection»
بنابرین خواستیم یک سطح انتزاع تعریف کنیم! کدهای کثیف و بدبومان را برای خودمان نگه داریم و اما بتوانیم مصطفا را راضی و خوشحال کنیم. سعی کنیم که اصل Single Responsiblity را بیشتر رعایت کنیم. هر کلاسی مسول یک چیزی باشد. نه اینکه هم مسوول شکل و شمایل باشد و هم مسول شیوه رفتار. طبعن به Best Practiceهای ممکن رجوع کردیم: MVP
(حالا قصه MVC, MVP, MVVM, MVI و ... چیست و چرا سراغ کدام رفتیم در حوصله این پست نیست) و اما MVP چه مشکلی را حل کرد؟
خیلی ساده میشود گفت کمک کرد اصل بنیادین Seperation Of Concern را رعایت کنیم. جدایی VIEW از LOGIC تا حدی اتفاق بیفتد.و همه اینها یعنی کمی از بوی بد Fragility و تا حدودی Rigidiy کاسته شد.
دیگر برای عوض کردن فونت درگیر اشتباهی خرابکردن بعضی کدها نمیشدم! دیگر مصطفا میتوانست ده بار با ده فونت مختلف خروجی بگیرد! الآن
architect:
خب حالا کمی از آن کد شونصد خطی درهم و برهم فاصله گرفتم. میشود کدها را کمی راحتتر فهمید و توسعه داد. اما این آغاز مسیر refactoring است. یک مسیر این است که به همین بسنده کنیم و خوشحال بشویم و جشن بگیریم و همه جا داد بزنیم که ما MVP هستیم و خفن!
اما یک مسیر این است که دانشمان را عمیقتر کنیم و به خوب قانع نشویم. بلکه دنبال عالی باشیم برویم و اصول بنیادین SOLID را در سطح هر کدام ازین لایههای بزرگ هم پیاده کنیم. برای اینکه کدهایی آماده تغییر بیشتر داشته باشیم! چرا که میدانیم تغییر جزو جداییناپذیر محصول است!
چه کنیم؟ شاید جواب باحال پیشفرض صداوسیماطور «مسیر دوم» باشد. اما هشدار بدهم! مسیر سخت، دشوار، نیازمند مطالعه، تمرین و آمادگی فراوان است! خیلیها را دیدم که حالش را نداشتند یا فکر میکردند حقوق شرکت فقط تا همین اندازه مسیر اول ارزش دارد و ...
ادامه دارد...
خب راهحل چیست؟؟ اول از همه و فارغ از بحثهای SOLID و ... به اصلی بنیادین مهندسی نرمافزار رجوع کردیم:
FTSE: «We can solve any problem by introducing an extra level of indirection»
بنابرین خواستیم یک سطح انتزاع تعریف کنیم! کدهای کثیف و بدبومان را برای خودمان نگه داریم و اما بتوانیم مصطفا را راضی و خوشحال کنیم. سعی کنیم که اصل Single Responsiblity را بیشتر رعایت کنیم. هر کلاسی مسول یک چیزی باشد. نه اینکه هم مسوول شکل و شمایل باشد و هم مسول شیوه رفتار. طبعن به Best Practiceهای ممکن رجوع کردیم: MVP
(حالا قصه MVC, MVP, MVVM, MVI و ... چیست و چرا سراغ کدام رفتیم در حوصله این پست نیست) و اما MVP چه مشکلی را حل کرد؟
خیلی ساده میشود گفت کمک کرد اصل بنیادین Seperation Of Concern را رعایت کنیم. جدایی VIEW از LOGIC تا حدی اتفاق بیفتد.و همه اینها یعنی کمی از بوی بد Fragility و تا حدودی Rigidiy کاسته شد.
دیگر برای عوض کردن فونت درگیر اشتباهی خرابکردن بعضی کدها نمیشدم! دیگر مصطفا میتوانست ده بار با ده فونت مختلف خروجی بگیرد! الآن
architect:
- VIEW => RECEIVE updates of ui from USER and SEND user events to PRESENTER
- PRESENTER => RECEIVE user events from VIEW and SEND actions to MODEL
- PRESENTER => RECEIVE states from MODEL and SEND updates of ui to VIEW
- MODEL => RECEIVE actions from PRESENTER, Handle logic (melli or ...) and SEND states to PRESENTER
خب حالا کمی از آن کد شونصد خطی درهم و برهم فاصله گرفتم. میشود کدها را کمی راحتتر فهمید و توسعه داد. اما این آغاز مسیر refactoring است. یک مسیر این است که به همین بسنده کنیم و خوشحال بشویم و جشن بگیریم و همه جا داد بزنیم که ما MVP هستیم و خفن!
اما یک مسیر این است که دانشمان را عمیقتر کنیم و به خوب قانع نشویم. بلکه دنبال عالی باشیم برویم و اصول بنیادین SOLID را در سطح هر کدام ازین لایههای بزرگ هم پیاده کنیم. برای اینکه کدهایی آماده تغییر بیشتر داشته باشیم! چرا که میدانیم تغییر جزو جداییناپذیر محصول است!
چه کنیم؟ شاید جواب باحال پیشفرض صداوسیماطور «مسیر دوم» باشد. اما هشدار بدهم! مسیر سخت، دشوار، نیازمند مطالعه، تمرین و آمادگی فراوان است! خیلیها را دیدم که حالش را نداشتند یا فکر میکردند حقوق شرکت فقط تا همین اندازه مسیر اول ارزش دارد و ...
ادامه دارد...
۱۰:۴۴
پروژه چابکیشماره ۲۴. بخش چهارم و آخر (ادامه از پست قبل)
خب قوطی اسپرسوی من سه بار خالی شد و پر شد و من برگشتم!تا حالا قصه این بود که یه کد اسپاگتی داشتیم که البته کار میکرد. نیاز ما برای MVP را برطرف میکرد.اما Agility کلن به معنای آماده بودن برای تغییر هستش. و تغییر جزو جدایی ناپذیر توسعه نرمافزار هست.توو این مثال خاص ما «اضافه شدن بانکهای دیگر» و «عوض شدن apiهای بانکها» یک پیشفرض قطعی هستش.
حالا اگر ما بخواهیم لاجیک داخل model را تند تند عوض کنیم که خیلی سخت میشود. یک کلاس بزرگ داریم که به صورت مداوم بایستی عوضش کنیم.احتمالش هم هست که بعد این عوض کردن «تست»هامان به درستی کار نکند. Rigidiy کدمان بالاست و قس.
راه حل چیست؟ اینجا ما خیلی ساده از یک مرحله Inversion Of Control استفاده کردیم. یعنی چه؟ یعنی تصمیمگیری راجع به نوع کارت و apiی که باید صدا زده بشود را از کلاس اولیه MODEL خارج کردیم. به جایش این قضیه را بهش Inject کردیم! هم Single Responsility را رعایت کردیم و هم کدهامان را برای تغییر آمادهتر کردیم.
old Model:
new Model:
حالا اگر مصطفا آمد و هر درخواست جدیدی از «عوض کردن فونت» یا «اضافه کردن بانک» داشت خیلی راحتتر و سریعتر میتوانیم انجامش بدهیم.
خب! اینجا فقط خواستیم نشان بدهم که از همان اول لازم نیست کدتان خیلی معماری عجیبی داشته باشد. اما درنظر گرفتن SOLID به شما کمک میکند همگام با تغییر نیازمندیها و ... بتوانید کدتان را به شیوه درستی ریفکتور کنید.گول مدیرتان را هم نخورید که اول قضیه میگوید این فقط یک فیچر خیلی کوچک است که هیچ وقت هم تغییر نمیکند.در دنیای نرمافزار امروز تنها چیز ثابت «تغییر» است! چابک باشید و آماده تغییر!
خب قوطی اسپرسوی من سه بار خالی شد و پر شد و من برگشتم!تا حالا قصه این بود که یه کد اسپاگتی داشتیم که البته کار میکرد. نیاز ما برای MVP را برطرف میکرد.اما Agility کلن به معنای آماده بودن برای تغییر هستش. و تغییر جزو جدایی ناپذیر توسعه نرمافزار هست.توو این مثال خاص ما «اضافه شدن بانکهای دیگر» و «عوض شدن apiهای بانکها» یک پیشفرض قطعی هستش.
حالا اگر ما بخواهیم لاجیک داخل model را تند تند عوض کنیم که خیلی سخت میشود. یک کلاس بزرگ داریم که به صورت مداوم بایستی عوضش کنیم.احتمالش هم هست که بعد این عوض کردن «تست»هامان به درستی کار نکند. Rigidiy کدمان بالاست و قس.
راه حل چیست؟ اینجا ما خیلی ساده از یک مرحله Inversion Of Control استفاده کردیم. یعنی چه؟ یعنی تصمیمگیری راجع به نوع کارت و apiی که باید صدا زده بشود را از کلاس اولیه MODEL خارج کردیم. به جایش این قضیه را بهش Inject کردیم! هم Single Responsility را رعایت کردیم و هم کدهامان را برای تغییر آمادهتر کردیم.
old Model:
handleCard(Card card) {
if (card is Melli) new MelliApi(card)
else if (card is Mellat) new MellatApi(card)
...
}
new Model:
handleCard(Card card, BankApiInterface api) {
api(card)
...
}
حالا اگر بخواهیم فرضن از Branch By Abstraction هم استفاده کنیم خیلی راحتتر هستیم.کافیست که برویم و کلاسهای پیادهشده اینترفیس BankApi را درست کنیم.برای تست نوشتن هم راحتتریم. امکان استفاده مجدد کد هم بالاتر است.حالا اگر مصطفا آمد و هر درخواست جدیدی از «عوض کردن فونت» یا «اضافه کردن بانک» داشت خیلی راحتتر و سریعتر میتوانیم انجامش بدهیم.
خب! اینجا فقط خواستیم نشان بدهم که از همان اول لازم نیست کدتان خیلی معماری عجیبی داشته باشد. اما درنظر گرفتن SOLID به شما کمک میکند همگام با تغییر نیازمندیها و ... بتوانید کدتان را به شیوه درستی ریفکتور کنید.گول مدیرتان را هم نخورید که اول قضیه میگوید این فقط یک فیچر خیلی کوچک است که هیچ وقت هم تغییر نمیکند.در دنیای نرمافزار امروز تنها چیز ثابت «تغییر» است! چابک باشید و آماده تغییر!
۱۰:۴۴
طربنامه چابکی (خبرنامه داخلی چابکی بله)شماره ۱۳
سلام رفقا.الف- در راستای تاکید بر دو اصل - اصل WIP Limit در همه stateها (محدودیت کارهای هر ستون. خصوصن در حال اجراها. فارغ از ابزاری که استفاده میکنید! اسکرام یا کانبان یا جیرا یا ...) - اصل Trunk Based Development قرار شد که پروژه «طلایه» حداکثر دو تا merge request باز در هر لحظه داشته باشد. این محدودیت کلی هست. یعنی برای کل پروژه (شامل همه وب و اندروید و آیاواس) هست. یعنی همه کدها باید زوود زوود ریویو و مرج بشود تا کسی پشت صف معطل نماند.
ب-برای تاکید بیشتر برین قضیه گزینه Semi Linear History را هم فعال کردیم. یعنی کدها برای ادغام شدن باید Rebase بشوند.قدیمیهای بله میدانند که اگر کدها قدری معطل بمانند و بیات بشوند و تعداد کامیتها هم زیاد بشود rebase کردن به یک خونریزی تمامعیار تبدیل میشود!اما و اما اگر تغییرات سریع اعمال بشوند و مرج ریکوئست هم سریع داده بشود فعالیت ساده و مفرحی خواهد بود!
و زیاده جسارت است!
سلام رفقا.الف- در راستای تاکید بر دو اصل - اصل WIP Limit در همه stateها (محدودیت کارهای هر ستون. خصوصن در حال اجراها. فارغ از ابزاری که استفاده میکنید! اسکرام یا کانبان یا جیرا یا ...) - اصل Trunk Based Development قرار شد که پروژه «طلایه» حداکثر دو تا merge request باز در هر لحظه داشته باشد. این محدودیت کلی هست. یعنی برای کل پروژه (شامل همه وب و اندروید و آیاواس) هست. یعنی همه کدها باید زوود زوود ریویو و مرج بشود تا کسی پشت صف معطل نماند.
ب-برای تاکید بیشتر برین قضیه گزینه Semi Linear History را هم فعال کردیم. یعنی کدها برای ادغام شدن باید Rebase بشوند.قدیمیهای بله میدانند که اگر کدها قدری معطل بمانند و بیات بشوند و تعداد کامیتها هم زیاد بشود rebase کردن به یک خونریزی تمامعیار تبدیل میشود!اما و اما اگر تغییرات سریع اعمال بشوند و مرج ریکوئست هم سریع داده بشود فعالیت ساده و مفرحی خواهد بود!
و زیاده جسارت است!
۱۳:۳۹
طربنامه چابکی (خبرنامه داخلی چابکی بله)شماره ۱۴
سلام رفقا.
خب الآن مدتی هست که در فرانت و بک از پترن mono-repo استفاده میکنیم. در مخازن طلایه و دارکوب. فیالواقع هم برای موافقت و هم برای مخالفت با mono-repo دلایل محکمهپسندی وجود دارد. همچنین برای موافقت و مخالفت با multi-repo.
مونو-ریپو خوب است چون ساده است. همه به همه چیز دسترسی دارند. از کدهای مشترک به راحتی استفاده میشود. تغییرات چند-ماژولی را راحت میکند. برای CI هم بهتر است. (ما شبیه گوگل هستیم :)
مونو-ریپو بد است. چون همه به همه چیز دسترسی دارند. حجم مخزن خیلی زیاد است و کار را سخت میکند. معمولن نیاز به ابزارها و پترنهای تکمیلی برای درست کار کردن است. (اما که گوگل نیستیم :)
مالتی-ریپو خوب است. چون مدیریت دسترسی دارد. حجم مخزن مدیریتشده است. و پیچیدگی ندارد. (اما گوگل اینجوری نیست :)
مالتی-ریپو بد است. تعداد مخازن خیلی زیاد میشود. تغییرات چند ماژولی سخت است. ... (ما و گوگل این را فهمیدیم :)
در نهایت سو وات؟ بایستی بگویم که هر تصمیمی trade-off خودش را دارد و ما فعلن میخواهیم از mono-repo استفاده کنیم. البته ما نگرانی «مدیریت دسترسی» نداشتیم. چراکه اعتماد زیادی به شما داریم و دوست داریم شما به راحتی به حداکثر بهرهوری خودتان برسید و قوانینِ اضافه و فرایندهای دستوپاگیر و بوروکراسی شرکت مانع کار شما نشود.
باری اما یک چیزی را باید باهم توافق کنیم: نامگذاری برنچها . اگرچه با توجه به پترن Trunk* Based Development و Branch By Abstraction* خیلی نگران نام برنچ نیستیم و اما الآن قدری شلوغ پلوغ شده است.
باری من سند داکستانش را به روز میکنم و اما اینجا چند مثال درست را بگویم:web/fix-hafez-adds-some-featureios/feat-molana-fixes-some-bugcore/fix-parvin-cleans-some-configandroid/feat-feredi-adds-some-giftschapar/fix-molana-fixes-some-giftsnasim/server/feat-shahriar-adds-some-eventwallet/gift/fix-vahshi-remove-cache
اینها هم غلط است:
feature/sdk_validationbugfix/ANDROID-videoplayer-captionCoronaTestBranchfix/FEREDI-fix-dialog-gift-emoji
و اما استاندارد کامیتها: باید شکل زیر را داشته باشد:feat(api-gateway): refactor-mtproto
وقتی مرجریکوئستی انجام میشود CI بایستی برود و آخرین کامیت آن مرجریکوئست را نگاه کند. با توجه به نام سرویس مورد نظر داخل پرانتز ۱- pipelineش را تریگر کند و ۲-نسخه را build کند، ۳- test کند و ۴- باتوجه به pipeline-id برود و tag مناسب بزند و ۵-در آرتیفکتوری push کند.
هم تگ گیت و هم اسم آرتیفکت همچه چیزی میشود:api-gateway-0.1+123android-5+1059web-4.0.4+271web-4.0.4+272web-4.0.5+283web-4.1.0+284
فایده: با این tag گذاری مقصودهای اصلی ما برآورده میشود:اینکه بتوانیم diff نسخهها را داشته باشیم. بتوانیم rollback کنیم و هم ما (سمت بکند) و هم کاربران (سمت فرانتاند) بدانیم که چه نسخهای در حال کار است.
راستی تذکر بدهم که نام سرویس و پایپلاین و داکر باید عینن با نام دایرکتوری آن سرویس یکسان باشد. یعنی اینجور نباشد که اسم دایرکتوری api-gateway باشد و اما اسم داکر ghapoo باشد.
و زیاده جسارت است!
سلام رفقا.
خب الآن مدتی هست که در فرانت و بک از پترن mono-repo استفاده میکنیم. در مخازن طلایه و دارکوب. فیالواقع هم برای موافقت و هم برای مخالفت با mono-repo دلایل محکمهپسندی وجود دارد. همچنین برای موافقت و مخالفت با multi-repo.
مونو-ریپو خوب است چون ساده است. همه به همه چیز دسترسی دارند. از کدهای مشترک به راحتی استفاده میشود. تغییرات چند-ماژولی را راحت میکند. برای CI هم بهتر است. (ما شبیه گوگل هستیم :)
مونو-ریپو بد است. چون همه به همه چیز دسترسی دارند. حجم مخزن خیلی زیاد است و کار را سخت میکند. معمولن نیاز به ابزارها و پترنهای تکمیلی برای درست کار کردن است. (اما که گوگل نیستیم :)
مالتی-ریپو خوب است. چون مدیریت دسترسی دارد. حجم مخزن مدیریتشده است. و پیچیدگی ندارد. (اما گوگل اینجوری نیست :)
مالتی-ریپو بد است. تعداد مخازن خیلی زیاد میشود. تغییرات چند ماژولی سخت است. ... (ما و گوگل این را فهمیدیم :)
در نهایت سو وات؟ بایستی بگویم که هر تصمیمی trade-off خودش را دارد و ما فعلن میخواهیم از mono-repo استفاده کنیم. البته ما نگرانی «مدیریت دسترسی» نداشتیم. چراکه اعتماد زیادی به شما داریم و دوست داریم شما به راحتی به حداکثر بهرهوری خودتان برسید و قوانینِ اضافه و فرایندهای دستوپاگیر و بوروکراسی شرکت مانع کار شما نشود.
باری اما یک چیزی را باید باهم توافق کنیم: نامگذاری برنچها . اگرچه با توجه به پترن Trunk* Based Development و Branch By Abstraction* خیلی نگران نام برنچ نیستیم و اما الآن قدری شلوغ پلوغ شده است.
باری من سند داکستانش را به روز میکنم و اما اینجا چند مثال درست را بگویم:web/fix-hafez-adds-some-featureios/feat-molana-fixes-some-bugcore/fix-parvin-cleans-some-configandroid/feat-feredi-adds-some-giftschapar/fix-molana-fixes-some-giftsnasim/server/feat-shahriar-adds-some-eventwallet/gift/fix-vahshi-remove-cache
اینها هم غلط است:
feature/sdk_validationbugfix/ANDROID-videoplayer-captionCoronaTestBranchfix/FEREDI-fix-dialog-gift-emoji
و اما استاندارد کامیتها: باید شکل زیر را داشته باشد:feat(api-gateway): refactor-mtproto
وقتی مرجریکوئستی انجام میشود CI بایستی برود و آخرین کامیت آن مرجریکوئست را نگاه کند. با توجه به نام سرویس مورد نظر داخل پرانتز ۱- pipelineش را تریگر کند و ۲-نسخه را build کند، ۳- test کند و ۴- باتوجه به pipeline-id برود و tag مناسب بزند و ۵-در آرتیفکتوری push کند.
هم تگ گیت و هم اسم آرتیفکت همچه چیزی میشود:api-gateway-0.1+123android-5+1059web-4.0.4+271web-4.0.4+272web-4.0.5+283web-4.1.0+284
فایده: با این tag گذاری مقصودهای اصلی ما برآورده میشود:اینکه بتوانیم diff نسخهها را داشته باشیم. بتوانیم rollback کنیم و هم ما (سمت بکند) و هم کاربران (سمت فرانتاند) بدانیم که چه نسخهای در حال کار است.
راستی تذکر بدهم که نام سرویس و پایپلاین و داکر باید عینن با نام دایرکتوری آن سرویس یکسان باشد. یعنی اینجور نباشد که اسم دایرکتوری api-gateway باشد و اما اسم داکر ghapoo باشد.
و زیاده جسارت است!
۵:۲۲