گفتگوی گروهی از متخصصان صنعت نرم افزار در کانادا: طلیعه دوانی، یوسف عمادی، مهدی شکوهی، شریف یزدیان و محمد نادی
در این پادکست خلاصه ای از فصل
16 Refactoring SerialDate
بررسی کتابخانه org.jfree.date از jfree.org/jcommon و کلاسی به نام SerialDate که دیوید گیلبرت نوشته توسط رابرت مارتین تمیز شده
فصل 17 Smells and Heuristics
برگرفته از کتاب مارتین فاولر Martin Fowler در به نام Refactoring، خیلی از Code Smells «کدهای بودار» را تعریف کرده، رابرت مارتین این فصل را به تفصیل شرح داده
16 Refactoring SerialDate
در کتابخانه org.jfree.date از http://www.jfree.org/jcommon/index.php
کلاسی به نام SerialDate وجود داره که دیوید گیلبرت نوشته
قراره رابرت مارتین اون ور زیر ذره بین بذاره
رابرت: من فکر نمی کنم که خیلی بهتر از دیوید هستم، قصد بدی از تجزیه و تحلیل این کد ندارم
شما هم میتونید کد من رو زیر ذره بین بذارید و بررسی کنید ، باید راحت باشیم و بذاریم که کدمون رو دیگران ببینند و نظرشون رو بدند
ما هم از این قضاوت ها چیزهایی رو یاد میگیریم ، مثل پزشکا ، خلبان ها یا وکلا که روی کارشون قضاوت میشه
دیوید هم جرات داشته که کدش رو آزاد بذاره تا همه نگاش کنند
این کلاس سریال دیت کلاسیه که تاریخ را تو جاوا نشان می ده
خیلی از تست ها پاس میشن ولی متأسفانه یک نگاه که می کنیم بعضی از تست ها رو جا انداختیم
مثلا برای Find Usages جستجو روی متد MonthCodeToQuarter
من مطمئن نبودم که چرا متد testWeekdayCodeToString استفاده کرده
اختصارات “Tues” و “Thurs” باید پشتیبانی شوند.
تابع stringToMonthCode باید تست می شد
از فرمت بندی HTML در Javadoc چشم پوشی می کنم
ولی اینکه تو رفرنس ها از چهارتا زبان استفاده شده من رو آزار میده Java, English, Javadoc, and html
خط 86 تعریف های کلاس هست . اصلا چرا این کلاس SerialDate نام گذاری کرده؟
نشونه چی هست؟
Is it because the class is derived from Serializable?
سرنخ در تعریف های SERIAL_LOWER_BOUND و SERIAL_UPPER_BOUND در خط 98 و خط 101.
سرنخ حتی بهتری هم هست
اسم این کلاس SerialDate چون بایه دونه serial number پیاده سازی شده
که تعداد روزهایی است که از 30 دسامبر 1899 به بعد هست
من با این دو تا مشکل دارم. اولاً، عبارت « serial number » واقعاً صحیح نیست.
مشکل دوم مهمتره
اسم SerialDate به معنای پیاده سازیه
این کلاس یک کلاس انتزاعیه اصلاً نیازی نیست که به پیاده سازی اشاره بشه
من DayDate را به عنوان بهترین اسم انتخاب کردم.
کلاس DayDate از Comparable و Serializable ارث بری می کنه
ولی چرا این کار از MonthConstants ارث بری میکنه؟
فقط یک دسته ای از تعریف ثابت ماه ها است که عددی تعریف شده برای یک ماه یک int می گرفت
بعد از تغییر من یک ماه شمار می گیره یعنی ما می توانیم از روش isValidMonthCode خلاص شویم و بررسی خطای کدهای ماه مانند که در monthCodeToQuarter رو نداشته باشیم
بعد، ما تو خط 91، serialVersionUID را داریم.که این متغیر برای کنترل سریال ساز استفاده می شه
اگر اون را تغییر بدیم، هر DayDate که با نسخه قدیمیتر نوشته شده باشد، دیگه کار نمی کنه و منجر به InvalidClassException می شود.
… دردسر های انتقال تاریخ ها به اکسل …
سه تابع، getPreviousDayOfWeek، getNearestDayOfWeek یا getFollowingDayOfWeek داریم
که با createInstance میتونیم برای اکسل آماده سازیش کنیم
در این کلاس متدهای createInstance را با متدهای makeDate جایگزین می کنیم که اسمش کمی بهبود پیدا می کنه
متد ها از ترکیبی از SINGLETON، 4 DECORATOR، 5 و Abstract Factory استفاده می کنند.
الگوهایی که به نظر من مفید هستند.
SpreadsheetDateFactory شبیه این است.
——
Smells and Heuristics
استشمام و اکتشافات
مارتین فاولر Martin Fowler در کتاب فوقالعاده عالی اش به نام Refactoring، خیلی از Code Smells «کدهای بودار» را تعریف کرده.
لیستی که اینجا آورم شامل استشمام مارتین فاولر است و همچنین سایر اکتشافاتی که من برای کارهای تجاری خودم استفاده می کنم.
1. [Refactoring].
در حین بازنگری و انجام هر تغییر، از خودم پرسیدم که چرا این تغییر را انجام دادم و بعدش دلیلش رو هم نوشتم.
نتیجه یک لیست نسبتا طولانی از چیزهایی شد که بدونم چرا وقتی کد را می خونم بوی بدی به من میده.
این لیست برای خواندن از بالا به پایین و همچنین به عنوان مرجع استفاده می شود.
برای هر اکتشافی یک رفرنس متقابل وجود دارد که نشان می دهد در ادامه در “پیوست C” به کجا ارجاع داده شده است.
C1: اطلاعات نامناسب Inappropriate Information
C2: کامنت منسوخ Obsolete Comment
C3: نظر اضافی Redundant Comment
C4: نظر بد نوشته شده است Poorly Written Comment
C5: کد کامنت شده Commented-Out Code ( کدی که کامنت شده یک کار زشته .)
محیط Environment
E1: وقتی که بیشتر از یک مرحله برای Build نیاز داریم
E2: وقتی تست ها بیشتر از یک مرحله نیاز دارند ( باید بتوانیم تمام یونیت تست ها را تنها با یک دستور اجرا کنیم )
در بهترین حالت می توانید با کلیک بر روی یک دکمه در IDE تمام تست ها را اجرا کنید.
در بدترین حالت شما باید بتوانید یک فرمان ساده را کنید. توانایی اجرای تمام تست ها آنقدر اساسی و مهمه که باید سریع، آسان و واضح باشه.
توابع
F1: آرگومان های زیاد Too Many Arguments
F2: آرگومان های خروجی Output Arguments آرگومان های خروجی واقعا غیرقابل درک هستند. خوانندگان انتظار دارند که آرگومان ها ورودی باشند، نه خروجی برنامه .
F3: نشونه گذاری آرگومانها Flag Arguments ( مثلا آرگومان های بولی با صدای بلند اعلام می کنند که تابع بیش از یک کار را انجام می دهد. )
F4: تابع مرده Dead Function
کلی
G1: چندین زبان در یک فایل منبع Multiple Languages in One Source File
محیط های برنامه نویسی مدرن امروزی امکان قرار دادن زبان های مختلف را در یک فایل سورس فراهم می کند.
به عنوان مثال، یک فایل منبع جاوا ممکن است حاوی قطعاتی از XML، HTML، YAML، JavaDoc، انگلیسی، جاوا اسکریپت و غیره باشد.
ایده آل این است که یک فایل سورس فقط یک زبان داشته باشد.
میدونیم که در واقعیت، بیشتر از یک زبان استفاده کنیم. اما هر چی حداقل باشه بهتره
G2: کار واضحی هنوز اجرا نشده Obvious Behavior Is Unimplemented
با پیروی از «اصل کمترین غافلگیری» هر تابع یا کلاس باید کارهایی را اجرا کند که برنامه نویس دیگری به طور منطقی انتظار دارد. به عنوان مثال، تابعی را در نظر بگیرید که نام یک روز را به یک enum که نشان دهنده روز است
G3: رفتار نادرست در شرایط مرزی Incorrect Behavior at the Boundaries
G4: ایمنی های نادیده گرفته شده Overridden Safeties با مثال چرنوبیل
G5: تکرار Duplication اصل DRY3 (خودت را تکرار نکن)
G6: کد در سطح نادرست ابسترکشن Code at Wrong Level of Abstraction
G7: Base Classes Depending on Their Derivatives
G8: Too Much Information
G9: Dead Code
G10: Vertical Separation
G11: ناسازگاریInconsistency
G12: Clutter
G13: Artificial Coupling
G14: Feature Envy
G15: Selector Arguments
G16: Obscured Intent
G17: Misplaced Responsibility
G18: Inappropriate Static
G19: Use Explanatory Variables
G20: Function Names Should Say What They Do
G21: Understand the Algorithm
G22: Make Logical Dependencies Physical
G23: Prefer Polymorphism to If/Else or Switch/Case
G24: Follow Standard Conventions
G25: Replace Magic Numbers with Named Constants
G26: Be Precise
G27: Structure over Convention
G28: Encapsulate Conditionals
G29: Avoid Negative Conditionals
G30: Functions Should Do One Thing
G31: Hidden Temporal Couplings
G32: Don’t Be Arbitrary
G33: Encapsulate Boundary Conditions
G34: Functions Should Descend Only
One Level of Abstraction
G35: Keep Configurable Data at High Levels
G36: Avoid Transitive Navigation.
Java
J1: Avoid Long Import Lists by Using Wildcard
J2: Don’t Inherit Constants
J3: Constants versus Enums
Names
N1: Choose Descriptive Names
N2: Choose Names at the Appropriate Level of Abstraction
N3: Use Standard Nomenclature Where Possible
N4: Unambiguous Names
N5: Use Long Names for Long Scopes
N6: Avoid Encodings
N7: Names Should Describe Side-Effects
Tests
T1: Insufficient Tests
T2: Use a Coverage Tool!
T3: Don’t Skip Trivial Tests
T4: An Ignored Test Is a Question about an Ambiguity
T5: Test Boundary Conditions
T6: Exhaustively Test Near Bugs
T7: Patterns of Failure Are Revealing
T8: Test Coverage Patterns Can Be Revealing
T9: Tests Should Be Fast
Conclusion
G8: اطلاعات بیش از حد
G9: کد مرده
G10: جداسازی عمودی 292
G11: ناسازگاری 0.292
G12: Clutter293
G13: کوپلینگ مصنوعی.293
G14: ویژگی Envy293
G15: Arguments Selector294
G16: Obscured Intent .295
G17: مسئولیت نابجا.295
G18: استاتیک نامناسب.296
G19: از متغیرهای توضیحی 296 استفاده کنید
G20: نام توابع باید بیان کنند که چه کاری انجام می دهند 297
G21: درک الگوریتم .297
G22: وابستگی های منطقی را فیزیکی کنید.298
G23: ترجیح چند شکلی به If/Else یا Switch/Case 299
G24: از قراردادهای استاندارد پیروی کنید299
G25: اعداد جادویی را با نام ثابت300 جایگزین کنید
G26: دقیق باشید301
G27: Structure over Convention.301
G28: Conditionals 0.301 را کپسوله کنید
G29: اجتناب از شرایط منفی.302
G30: توابع باید یک کار را انجام دهند. 302
G31: کوپلینگ های زمانی پنهان302
G32: Don’t Be Arbitrary.303
G33: احاطه کردن شرایط مرزی304
G34: توابع فقط باید نزول کنند
One Level of Abstraction 304
G35: داده های قابل تنظیم را در سطوح بالا نگه دارید306
G36: اجتناب از ناوبری گذرا.30
جاوا .307
J1: با استفاده از Wildcards307 از فهرستهای وارداتی طولانی اجتناب کنید
J2: ثابت 307 را به ارث نبرید
J3: Constants در مقابل Enums.308
نام ها.309
N1: نامهای توصیفی309 را انتخاب کنید
N2: نامها را در سطح مناسب Abstraction311 انتخاب کنید
N3: در صورت امکان از نامگذاری استاندارد استفاده کنید.311
N4: نامهای بدون ابهام.312
N5: از نام های طولانی برای Long Scopes استفاده کنید.312
N6: از Encodings312 اجتناب کنید
N7: نام ها باید عوارض جانبی را توصیف کنند. .313
تست ها313
T1: تست های ناکافی.313
T2: از ابزار پوشش استفاده کنید!.313
T3: تست های بی اهمیت 313 را نادیده نگیرید
T4: یک تست نادیده گرفته شده یک سوال در مورد ابهام است313
T5: شرایط مرزی آزمون314
T6: به طور کامل Near Bugs314 را آزمایش کنید
T7: الگوهای شکست آشکار می شوند 314
T8: الگوهای پوشش آزمایشی می توانند آشکار شوند 0.314
T9: تست ها باید سریع باشند.314
نتیجه 314