گفتگوی گروهی از متخصصان صنعت نرم افزار در کانادا: طلیعه دوانی، محمد نادی، مهدی شکوهی، شریف یزدیان و یوسف عمادی
خلاصه ای از فصل های
12: Emergence
13: Concurrency
14: Successive Refinement
15: JUnit Internals
کتاب کد تمیز یا Clean code رابرت مارتین ارائه شد
—
Emergence
تمیز کردن کد از طریق طراحی اضطراری
چه میشد اگر قانون ساده وجود داشت که میتونستید با رعایت اونها طرحهای خوبی را ایجاد کنیم
بکارگیری اصولی مثل SRP و DIP
شاید 4 قانون Kent Beck’s کمک کنه
به گفته کنت، یک طرح “ساده” است اگر از این قوانین پیروی کنه:
1- تمام تست ها را اجرا کند
2- بدون تکرار باشه
3- منظور برنامه نویس را بیان کند
4- تعداد کلاس ها و متدها را به حداقل برساند
قوانین به ترتیب اهمیت آورده شده .
قانون 1 دیزاین ساده: تمام تست ها را اجرا کند
اول و مهمتر از همه، یک دیزاین باید سیستمی را تولید کند که مطابق خواسته ما عمل کند.
یک سیستم ممکنه روی کاغذ بی نقص باشه، ولی اگر هیچ راه ساده ای برای تأیید اینکه سیستم واقعاً همانطور که میخوایم کار می کنه نباشه کاغذ های هیچ فایده ای ندارند
سیستم هایی که قابل تست نیستند، قابل تأیید هم نیستند. مسلماً، سیستمی که نمی تواند تأیید شود، هیچ وقت نباید عملیاتی بشه
خوشبختانه، تست پذیر شدن سیستمها، در طراحی کلاسهای ما رو هم کوچک و تک هدفه می کنه. آزمایش کلاس هایی که با SRP مطابقت دارند هم ساده تر هستند.
هر چه تست های بیشتری بنویسیم، بیشتر به سمت تست ساده تر پیش میربم
بنابراین اطمینان از اینکه سیستم ما کاملاً قابل تست هست به ما کمک می کند تا طرح های بهتری رو داشته باشیم
ابزارهایی مثل dependency injection تزریق وابستگی ، interfaces رابط ها , و abstraction انتزاع برای اینکه دوتایی تست کنیم رو به حداقل میرسانند . طرح های ما حتی بهتر هم میشن.
قابل توجه است، پیروی از یک قانون ساده و واضح که می گوید ما باید آزمایش هایی داشته باشیم و آنها را به طور مداوم اجرا کنیم، بر پایبندی سیستم ما به اهداف اولیه OO یعنی اتصال کم و انسجام بالا تأثیر می گذارد. نوشتن تست ها منجر به طرح های بهتر می شود.
قوانین 2 طراحی ساده : بازسازی مجدد Refactoring
بعد از اینکه تست هارو انجام دادیم، این اختیار را داریم که کد و کلاس های خود را تمیز نگه داریم.
این کار را تدریجی روی کد انجام میدیم.
به ازای هر چند خط کدی که اضافه می کنیم، مکث می کنیم و طرح جدید را بازنگری می کنیم. آیا ما فقط کد ها رو کم کردیم؟
اگر اینطوری باشه، آن را تمیز می کنیم و تست ها را انجام می دهیم تا مطمئن بشیم چیزی را خراب نکرده ایم.
اینکه ما این تست ها را داریم دیگه ترسی از پاک کردن کد ها نداریم.
در طول این مرحله Refactoring بازسازی، ما می تونیم هر چیزی را که از دانش طراحی نرم افزار خوب داریم اعمال کنیم.
میتوانیم cohesion انسجام را افزایش دهیم، coupling دوبله کار کردن را کم کنیم، نگرانیها را تفکیک کنیم، نگرانیهای سیستم را مدولار کنیم، توابع و کلاسهایمان را کوچک کنیم، اسم های بهتری انتخاب کنیم و ….
این جا ، جایی است که ما سه قانون آخر simple design طراحی ساده را اعمال می کنیم: Eliminate duplication حذف تکراری ،ensure expressiveness اطمینان از بیان و به حداقل رساندن تعداد کلاس ها و روش ها.
تکراری کاری انجام ندیم No Duplication
تکراری شدن دشمن اصلی یک سیستم طراحی خوب هست.
کار اضافی، خطر اضافی و پیچیدگی غیر ضروری اضافی را نشان می دهد. تکراری شدن خود را به اشکال مختلف نشان می دهد. خطوط کدی که دقیقا شبیه هم هستند، البته تکراری هستند.
خطوط کد مشابه اغلب می توانند ورز داده بشن تا حتی بیشتر شبیه هم بشن تا بتونیم آنها را به راحتی refactor کنیم.
شفافیت Expressive
خیلی از ما تجربه کار بر روی کدهای پیچیده را داشتیم.
خیلی از ما کدهای پیچیده ای را خودمان تولید کردیم.
نوشتن کدی که میفهمیم آسان است، چون در زمان نوشتن آن، عمیقاً مشکلی را که میخواهیم حل کنیم، درک میکنیم.
سایر کسانی که کد رو می بینند قرار نیست درک عمیقی داشته باشند.
هزینه بیشتر یک پروژه نرم افزاری مربوط به نگهداری طولانی مدته
برای به حداقل رسوندن نقص منظور موقع معرفی تغییرات، برای ما خیلی مهمه که بتوانیم بفهمیم یک سیستم چکار می کنه
همانطور که سیستم ها پیچیده تر می شن، زمان بیشتری برای یک برنامه نویس میگره و و احتمال سوء تفاهم را زیاد می کنه
بنابراین، کد باید واضح هدف نویسنده را بیان کند. هر چه نویسنده بتواند کد را واضح تر بنویسه، بقیه افراد زمان کمتری را برای درک آن صرف می کنند.
پس باعث کم شدن عیب ها و کم شدن هزینه های نگهداری می شه
مثلا استفاده از اسامی استاندارد ، مثل COMMAND یا VISITOR، در نام کلاسهایی که آن پترن را پیادهسازی میکنن، میتونیم طرح خودمون رو به طور خلاصه برای برنامه نویسهای دیگه توضیح بدیم
اما مهمترین راه برای شفاف بودن، تلاش ما برای واضح نوشتن کد هست. اغلب بدون واضح نوشتن کد برای شخص بعدی، سراغ مشکل بعدی میریم.
باید بدونیم که احتمالاً فرد بعدی که کد را می خواند، ممکنه خود ما باشیم.
پس کمی به کار خودتون افتخار کنید.
برای هر یک از تابع ها و کلاس های خود کمی وقت بذارید.
نام های بهتری انتخاب کنید، توابع بزرگ را به توابع کوچکتر تقسیم کنید و به طور کلی فقط از آنچه ایجاد کردید مراقبت کنید.
مراقبت یک منبع با ارزش است.
Care is a precious resource.
کلاس ها و متد های حداقلی
حتی مفاهیم پایه ای مثل حذف تکراری ها، وضوح کد و SRP ممکنه بیش از حد باشه
در صورتیکه این قانون پیشنهاد می کنه که تعداد عملکرد و کلاس های خود را پایین و کم نگه داریم.
ولی میدونیم که تعداد زیاد کلاس ها و متد ها هم زیادی مته به خشخاش گذاشتنه
نتیجه
آیا مجموعه ای از روش های ساده وجود داره که میتونه جایگزین تجربه بشه ؟ واضح است که نه.
پیروی از تمرین طراحی ساده یا simple design می تونه برنامه نویسان را تشویق کنه تا به اصول و الگوهای خوب پایبند باشند که در غیر این صورت یادگیری اونها سال ها طول می کشه
بازسازی مداوم یا پالایش پی در پی
تو باتلاق نیفتیم
پالایش پی در پی چیست؟
فرآیندی برای پیاده سازی یک نرم افزار است که بومی سازی خطا را بسیار ساده می کنه.
اگر قبل از تست سعی کنیم یک نرم افزار کامل رو بنویسیم، اشتباهات زیادی خواهیم داشت و نمی دانیم برای بومی سازی هر اشکال کجا رو ببینیم.
میتونیم یک برنامه اصلاحی ایجاد کنیم که فرآیند اجرا را به نقاط عطف یا مراحل مجزا تقسیم کنه.
برای مثال، اگر یکی از کارهایی که برنامه شما باید انجام دهد خواندن برخی از داده ها از یک فایل هست، یک نقطه عطف ساده برنامه ای است که فقط داده ها را می خونه و آنچه را که خوانده نشان می ده.
باید بعد از هر مرحله نرم افزار را تست کنیم. اگر اشکالی وجود داشته باشد، معمولاً تو قسمت کوچکی هست که نوشتیم.
اغلب اوقات، بومی سازی یک اشکال خیلی آسان میشه.
البته فقط در صورتی کار می کنه که بعد از هر مرحله تست کنیم و اشکالاتی رو که قبل از رفتن به مرحله بعد پیدا کردیم برطرف کنیم
نرمافزار را با اصلاح متوالی با تعیین یک هدف کوچک و قابل آزمایش، نوشتن نرمافزار برای رسیدن به آن هدف، تست اینکه آیا نرمافزار به آن هدف میرسه یا نه، و در صورت لزوم قبل از رفتن به هدف بعدی، نرمافزار را اصلاح کنیم
—————————
پالایش پی در پی: روشی برای مشخصات افزایشی قدرت با استفاده از UPF
پالایش پی در پی: روشی برای تعیین افزایشی قصد قدرت
پالایش پی در پی – رویکردی برای جدا کردن هدف قدرت Front-End و Backend
—————-
تو این فصل یک مطالعه موردی برای پالایش متوالی هست.
یک ماژولی که خوب شروع شده ولی قیاس بندی نشده
تو این فصل می بینیم که چطور ماژول ریفکتور و تمیز میشه
خیلی از ما مجبوریم آرگومان های خط فرمان را جدا کنیم.
اگر ابزار مناسبی نداشته باشیم، خیلی راحت آرایه رشتههایی را که به تابع اصلی منتقل میشوند، میرویم.
چندین ابزار خوب از منابع مختلف موجود است،
اما هیچکدوم از آنها دقیقاً همان کاری را که من می خواهم انجام نمی دهند.
پس، تصمیم گرفتم خودم بنویسم. من به آن می گویم: Args
استفاده از Args بسیار ساده است. به سادگی کلاس Args را با آرگومان های ورودی و یک رشته قالب می سازیم و از نمونه Args برای مقادیر آرگومان ها کوئری می گیریم
جالب توجه که چقدر کد نیازداریم تا جزئیات این مفهوم ساده را مشخص کنیم
یکی از دلایل اینه که اینجا از زبان جاوا استفاده می کنیم، به عنوان یک زبان statically typed language، به کلمات زیادی نیاز داره تا بتونه تایپ سیستم را برآورده کنه
تو زبانی مثل Ruby، Python یا Smalltalk، این برنامه خیلی کوچکتره
این کد تمیز رو ببینید
چطور این کار را انجام دادم
بذارید راحت بگم من این برنامه را از ابتدا تا انتها به شکل فعلی آن به سادگی ننوشتم.
من انتظار ندارم که بتوانید برنامه های تمیز و شیک را در یک مرحله بنویسید.
اگر در طول چند دهه گذشته چیزی یاد گرفته باشیم، اینه که برنامه نویسی بیش از آنکه یک علم باشد، یک هنر است.
برای نوشتن کد تمیز ابتدا باید کد کثیف بنویسید و سپس آن را پاک کنید.
این نباید تعجب آور باشه که ما در حقیقت تو مدرسه ابتدایی زمانی یاد گرفتیم که معلم ها سعی می کردند (معمولاً بیخودی) ما را وادار کنند که پیشنویسهای تقریبی از ترکیبات خودمون رو بنویسیم.
معلم ها یاددادند که روند کار این هست که باید یک پیش نویس خام بنویسیم، بعد یک پیش نویس دوم و چندین پیش نویس بعدی تا زمانی که نسخه نهایی را بسازیم.
آنها سعی می کردند به ما بگن که نوشتن انشای تمیز، موضوعی است که بهبود مستمر می طلبد.
اکثر برنامه نویسان سال اول (مانند اکثر دانش آموزان کلاس) این توصیه را خوب رعایت نمی کنند.
آنها عقیده دارند که هدف اصلی اینه که برنامه فقط باید کار کنه.
وقتی هنگامی که “کار می کنه”، میرن سراغ کار بعدی و برنامه را تو همون حالتی که همونجوری “کار می کنه” رها می کنند.
ولی اکثر برنامه نویسان باتجربه می دانند که این خودکشی حرفه ای است.
امیدوارم واکنش اولیه شما به این حجم از کد این باشه که “مطمئناً خوشحالم که او آن را اینطور نگذاشته !”
اگر چنین حسی دارید، یادتون باشه که این احساس دیگران در مورد کدهایی است که شما به صورت پیش نویس خام می گذارید.
در واقع “پیش نویس خشن” یا rough draft احتمالا ملایم ترین چیزیه که می تونید در مورد این کد بگید.
تعداد زیاد متغیرهای نمونه اضطراب میاره رشتههای عجیب و غریب مانند «TILT»، HashSets و TreeSets، و بلوکهای try-catch-catch همگی به تلنبار شدن منجر میشن
من نمی خواستم یک درهم بنویسم. در واقع، من داشتم سعی می کردم همه چیز را به خوبی سر و سامون بدم.
احتمالاً می توانید این رو از انتخاب من برای نام تابع و متغیرها متوجه بشید. ولی، واضح است که میخواستم که مشکل رو دور کنم
درهم نویسی به تدریج ساخته شد. نسخه های قبلی تقریباً آنقدر بد نبودند.
در مورد افزایش گرایی
On Incrementalism
یکی از بهترین راهها برای خراب کردن یک برنامه، تغییرات گسترده در ساختار آن به اسم بهبود است.
بعضی از برنامه ها هرگز از چنین “بهبودهایی” بهبود نمی یابند.
مشکل اینجاست که کار کردن برنامه به همان روشی که قبل از “بهبود” کار می کرد بسیار سخت است.
برای جلوگیری از این امر، من از Test-Driven Development (TDD) استفاده می کنم.
یکی از دکترین های اصلی این رویکرد این است که سیستم را همیشه در حال اجرا نگه دارید.
به عبارت دیگر، با استفاده از TDD، من اجازه ندارم تغییری در سیستمی ایجاد کنم که آن سیستم را خراب کنه.
هر تغییری که من ایجاد می کنم باید سیستم را همانطور که قبلاً کار می کرد حفظ کند.
برای رسیدن به این هدف، من به مجموعهای از تستهای خودکار یا automated tests نیاز دارم که بتوانم اجراشون کنم و تأیید بشه که رفتار سیستم تغییری نکرده
نتیجه
همین که کد کار کنه کافی نیست. کدی که فقط کار می کنه اغلب بد جوری هم شکسته می شه.
برنامه نویسانی که خود را صرفاً با کد کار ارضا می کنند، غیرحرفه ای رفتار می کنند.
آنها ممکنه نگران باشن که زمان کافی برای بهبود ساختار و طراحی کد خود ندارند، اما من مخالفم.
هیچ چیز به اندازه کد بد، تأثیر مخرب عمیق و بلندمدتی بر یک پروژه در حال توسعه نداره
زمانبندی بد را میشه دوباره کار کرد، ملزومات بد را میشه دوباره تعریف کرد.
پویایی بد تیم قابل بازسازی است.
اما کد بد پوسیده و به هم چسبیده مثل وزنه ای غیرقابل تحملی می شه که تیم را به پایین می کشه
بارها و بارها تیمهایی را دیدم که تو هم میلولیدند ( grind to a crawl ) ، زیرا با عجلهشان،کاری کردند که برای همیشه کد روی سرشون خراب شده
البته کد بد را میشه پاک کرد.
ولی خیلی گرون در میاد که با کد پوسیده، ماژول ها را به یکدیگر وصل کنید و وابستگی های پنهان و درهم زیادی ایجاد می کنند.
پیدا کردن و از بین بردن وابستگی های قدیمی کار طولانی و سختی است.
در صورتیکه، تمیز نگه داشتن کد نسبتاً آسان است. اگر صبح یک ماژول رو بهم ریختید، بعد از ظهر تمیز کردنش آسون تره
بهتره که اگر چند دقیقه قبل رو به هم ریخته اید، الان در حال تمیز کردنش باشید ، که خیلی راحت تره
بنابراین
راه حل اینه که به طور مداوم کد خود را تا آنجا که می توانید تمیز و ساده نگه دارید.
هرگز اجازه ندهید پوسیدگی توی کد شروع بشه