ارزیابیها
ارزیابیها 📊
فصل ۱
- یکی از نتایج کد ضعیف این است که ممکن است در نهایت با قطعهای از کد بسیار بد و سخت برای درک مواجه شوید. این موضوع اغلب به استرس برنامهنویس و نرمافزاری منجر میشود که باگ دارد، نگهداری آن دشوار است و تست و توسعه آن سخت است.
- یکی از نتایج کد خوب این است که خواندن و درک آن آسان است، زیرا قصد برنامهنویس مشخص است. این باعث کاهش استرس برای برنامهنویسانی میشود که باید کد را دیباگ، تست و توسعه دهند.
- وقتی یک پروژه بزرگ را به کامپوننتها و کتابخانههای ماژولار تقسیم میکنید، هر ماژول میتواند بهطور همزمان توسط تیمهای جداگانه کار شود. ماژولهای کوچک آسانتر تست، کدنویسی، مستندسازی، انتشار، توسعه و نگهداری میشوند.
- DRY مخفف Don’t Repeat Yourself است. به دنبال کدهای تکراری باشید و با بازسازی (Refactor) آنها، کدهای تکراری را حذف کنید. مزیت این کار برنامههای کوچکتر است، زیرا اگر چنین کدی دارای باگ باشد، تنها کافی است آن را در یک مکان اصلاح کنید.
- KISS به معنای نوشتن کدی ساده است که برنامهنویسان، بهویژه افراد تازهکار، را گیج نکند. کد KISS آسان برای خواندن و نوشتن تست است.
- S اصل Single Responsibility Principle، O اصل Open/Closed Principle، L اصل Liskov Substitution، I اصل Interface Segregation Principle و D اصل Dependency Inversion Principle است.
- YAGNI مخفف You Aren’t Going to Need It است. به عبارت دیگر، کدی اضافه نکنید که به آن نیاز ندارید. فقط کدی را اضافه کنید که واقعاً لازم است و بس.
- Occam’s Razor اصل میگوید: «موجودیتها نباید بدون ضرورت چند برابر شوند.» فقط با واقعیتها سر و کار داشته باشید و تنها در صورت لزوم فرضیات بسازید.
فصل ۲
-
دو نقش در بازبینی همتای کد (Peer Code Review) وجود دارد: Reviewer و Reviewee.
-
مدیر پروژه افراد شرکتکننده در بازبینی همتا را مشخص میکند.
-
شما میتوانید زمان و تلاش Reviewer را قبل از درخواست بازبینی همتا ذخیره کنید، با اطمینان از اینکه کد و تستهای شما بهدرستی کار میکنند، تحلیل کد (Code Analysis) روی پروژه انجام داده و مشکلات را رفع کرده و اطمینان حاصل کنید که کد شما از دستورالعملهای کدنویسی شرکت پیروی میکند.
-
هنگام بررسی کد، به نامگذاری، قالببندی، سبکهای برنامهنویسی، باگهای احتمالی، صحت کد و تستها، امنیت و مسائل مربوط به عملکرد توجه کنید.
-
سه دسته بازخورد شامل مثبت، اختیاری و بحرانی است.
فصل ۳
- میتوانیم کد خود را در فایلهای منبع جداگانه و در ساختار پوشهای قرار دهیم و کلاسها، اینترفیسها، Structها و Enumها را در Namespaceهایی که به ساختار پوشهها نگاشت دارند، قرار دهیم.
- یک کلاس باید فقط یک مسئولیت داشته باشد.
- میتوانید برای تولید مستندات از نظرات XML استفاده کنید که مستقیماً بالای عضو Public که باید مستندسازی شود قرار میگیرد.
- Cohesion به گروهبندی منطقی کدی گفته میشود که روی همان مسئولیت کار میکند.
- Coupling به وابستگی بین کلاسها اشاره دارد.
- Cohesion باید بالا باشد.
- Coupling باید پایین باشد.
- میتوانید از DI و IoC برای طراحی قابل تغییر استفاده کنید.
- DI مخفف Dependency Injection است.
- IoC مخفف Inversion of Control است.
- اشیاء Immutable ایمن از نظر نوع هستند و بنابراین میتوان آنها را بین Threads بهطور ایمن منتقل کرد.
- اشیاء باید متدها و Properties را آشکار کنند و دادهها را پنهان کنند.
- ساختارهای دادهای (Data Structures) باید دادهها را آشکار کنند و متدی نداشته باشند.
فصل ۴
-
متدهایی بدون پارامتر Niladic Methods نامیده میشوند.
-
متدهایی با یک پارامتر Monadic Methods نامیده میشوند.
-
متدهایی با دو پارامتر Dyadic Methods نامیده میشوند.
-
متدهایی با سه پارامتر Triadic Methods نامیده میشوند.
-
متدهایی با بیش از سه پارامتر Polyadic Methods نامیده میشوند.
-
باید از کد تکراری اجتناب کنید. این روش برنامهنویسی مولد نیست، میتواند برنامهها را بیدلیل بزرگ کند و احتمال دارد که همان Exception در کل کد تکرار شود.
-
برنامهنویسی تابعی (Functional Programming) روشی در کدنویسی است که محاسبات را بهعنوان ارزیابی ریاضی محاسبات در نظر میگیرد و وضعیت (State) را تغییر نمیدهد.
-
مزایای برنامهنویسی تابعی شامل کد ایمن در برنامههای چندنخی (Multithreaded) و متدهای کوچکتر و معنادار است که خواندن و درک آنها آسان است.
-
ورودی و خروجی میتواند برای برنامههای تابعی مشکلساز باشد، زیرا برنامهنویسی تابعی اجازه اثرات جانبی (Side-effects) نمیدهد.
-
کد WET برخلاف DRY است و هر بار که نیاز است نوشته میشود. این باعث تکرار میشود و همان Exception میتواند در چندین مکان رخ دهد و نگهداری و پشتیبانی را دشوار کند.
-
کد DRY برخلاف WET است و تنها یک بار نوشته میشود و هر جا نیاز است استفاده میشود. این باعث کاهش حجم کد و تعداد Exceptionها میشود و برنامهها را آسانتر برای خواندن و نگهداری میکند.
-
شما با بازسازی (Refactoring) کد WET و حذف کد تکراری، آن را به کد DRY تبدیل میکنید.
-
متدهای طولانی سنگین و مستعد Exception هستند. هر چه کوچکتر باشند، خواندن و نگهداری آنها آسانتر است و احتمال ایجاد باگهای منطقی توسط برنامهنویس کمتر میشود.
-
برای اجتناب از استفاده از Try/Catch، میتوانید Argument Validators بنویسید و آنها را در بالای متد خود فراخوانی کنید. اگر پارامترها در اعتبارسنجی شکست بخورند، Exception مناسب ایجاد شده و متد اجرا نمیشود.
فصل ۵
-
Checked Exception، Exceptionی است که در زمان Compile بررسی میشود.
-
Unchecked Exception، Exceptionی است که بررسی نمیشود یا بهسادگی نادیده گرفته میشود.
-
Overflow Exception زمانی رخ میدهد که بیتهای سطح بالا نتوانند به نوع مقصد اختصاص یابند. در حالت Checked، OverflowException رخ میدهد. در حالت Unchecked، بیتهای سطح بالا که نمیتوانند اختصاص یابند نادیده گرفته میشوند.
-
تلاش برای دسترسی به Property یا Method روی یک Object Null.
-
یک کلاس Validator و یک کلاس Attribute پیادهسازی کنید که پارامتر را برای Null بررسی کند و ArgumentNullException پرتاب کند. از کلاس Validator در بالای متدهای خود استفاده کنید تا قبل از اجرای متد، Exception رخ دهد.
-
Business Rule Exception (BRE)
-
BREها روش بدی هستند، زیرا انتظار دارند Exception ایجاد شود تا جریان برنامه کنترل شود.
-
برنامهنویسی صحیح نباید جریان برنامه را با انتظار Exception بهعنوان خروجی کنترل کند. بنابراین با توجه به اینکه BREها روش نادرستی هستند، راه بهتر استفاده از برنامهنویسی شرطی (Conditional Programming) است. در برنامه شرطی، از منطق بولی (Boolean Logic) استفاده میکنید.
-
منطق بولی دو مسیر ممکن برای اجرا فراهم میکند و هیچ Exceptionی پرتاب نمیکند. بررسیهای شرطی واضح هستند و خواندن و نگهداری برنامه را آسان میکنند و به راحتی قابل گسترش هستند، در حالی که با BREها این امکان وجود ندارد.
-
ابتدا با گرفتن خطا برای انواع شناخته شده Exception مانند ArgumentNullException و OverflowException با استفاده از انواع Exception موجود در Microsoft .NET Framework شروع کنید. اما وقتی اینها کافی نباشند و داده کافی برای موقعیت شما فراهم نکنند، Exceptionهای سفارشی خود را بنویسید و از آنها استفاده کنید و پیامهای Meaningful ارائه دهید.
-
Exception سفارشی شما باید از System.Exception ارثبری کند و سه سازنده (Constructor) داشته باشد: سازنده پیشفرض، سازندهای که پیام متنی را میپذیرد، و سازندهای که پیام متنی و Inner Exception را میپذیرد.
ادامه ارزیابیها 📊
فصل ۶
-
یک Unit Test خوب باید Atomic (اتمی)، Deterministic (قطعی)، Repeatable (قابل تکرار) و سریع باشد.
-
یک Unit Test خوب نباید نتیجه نامشخص (Inconclusive) داشته باشد.
-
Test-Driven Development (TDD)
-
Behavioral-Driven Development (BDD)
-
واحد کوچکی از کد که تنها هدفش تست یک واحد کد است که فقط یک کار انجام میدهد.
-
یک Fake Object که توسط Unit Test استفاده میشود تا متدها و Properties عمومی یک Object واقعی را تست کند، بدون اینکه وابستگیهای متد یا Property تست شوند.
-
یک Fake Object همانند Mock Object است.
-
ابزارهای تست: MSTest, NUnit, و xUnit
-
ابزارهای Rhino Mocks و Moq
-
SpecFlow
-
کامنتهای غیرضروری، کد مرده (Dead Code) و تستهای تکراری
فصل ۷
-
تست کل سیستم از ابتدا تا انتها (End-to-End Testing) که میتواند بهصورت دستی، خودکار یا ترکیبی انجام شود.
-
Integration Testing
-
تست دستی تمام ویژگیها، اطمینان از عبور تمام Unit Testها و نوشتن تستهای خودکار برای بررسی دستورها و دادههای عبور دادهشده بین دو ماژول.
-
Factories کلاسهایی هستند که الگوی Factory Method را پیاده میکنند و هدف آنها ایجاد اشیاء بدون مشخص کردن کلاسشان است. از آنها در سناریوهای زیر استفاده میکنیم:
- کلاس قادر به پیشبینی نوع شیء مورد نیاز برای ایجاد نیست.
- زیرکلاس باید نوع شیء را مشخص کند.
- کلاس کنترل ایجاد اشیاء خود را دارد.
-
DI روشی برای تولید کد کموابسته (Loosely Coupled) است که نگهداری و توسعه آن آسان است.
-
استفاده از Container مدیریت اشیاء وابسته را آسان میکند.
فصل ۸
-
یک Thread یک فرآیند است.
-
عدد: یک (One)
-
Background Threads و Foreground Threads
-
Background Thread
-
Foreground Thread
-
Thread.Sleep(500);
-
var thread = new Thread(Method1);
-
IsBackground را برابر True قرار دهید.
-
Deadlock وضعیتی است که دو Thread مسدود شده و منتظر آزاد شدن منابع توسط Thread دیگر هستند.
-
Monitor.Exit(objectName);
-
چندین Thread که از یک Resource استفاده میکنند، خروجیهای متفاوتی بسته به زمانبندی هر Thread تولید میکنند.
-
از TPL با
ContinueWith()
استفاده کنید و باWait()
منتظر بمانید تا Task تمام شود قبل از خروج از متد. -
استفاده از یک متغیر عضو که توسط متدهای دیگر به اشتراک گذاشته شده و ارسال Reference Variables
-
پاسخ: بله
-
ThreadPool
-
یک Object که پس از ساخته شدن قابل تغییر نیست.
-
اینها اجازه میدهند دادهها بهطور ایمن بین Threads به اشتراک گذاشته شوند.
فصل ۹
- Application Programming Interface (API)
- Representational State Transfer (REST)
- Interface یکنواخت، Client-Server، Stateless، Cacheable، Layered System، Optional Executable Code
- Hypermedia as the Engine of Application State (HATEOAS)
- RapidApi.com
- Authorization و Authentication
- Claims بیانیههایی هستند که یک Entity درباره خودش ارائه میدهد و سپس در برابر یک Data Store اعتبارسنجی میشوند. این موارد در امنیت Role-Based کاربرد دارند تا بررسی شود که Entity ادعاکننده مجاز است یا خیر.
- ارسال درخواستهای API و بررسی پاسخ آنها
- زیرا میتوان Data Store را مطابق نیاز تغییر داد
فصل ۱۰
- تقسیمبندی صحیح نرمافزار به Namespaceها، Interfaceها و کلاسهای منطقی که به تست نرمافزار کمک میکند.
- با درک APIها میتوانید کد خود را ساده (KISS) نگه داشته و با استفاده نکردن از کدهای موجود، DRY باشید. این کار زمان، انرژی و پول را صرفهجویی میکند.
- Structs
- APIهای Third-Party توسط توسعهدهندگان نوشته شده و احتمال خطای انسانی و باگ وجود دارد. با تست آنها میتوانید مطمئن شوید که همانطور که انتظار میرود عمل میکنند و در غیر این صورت کد را اصلاح کنید یا Wrapper بنویسید.
- APIهای شما مستعد خطا هستند. با تست آنها مطابق Specification و Acceptance Criteria، میتوانید اطمینان حاصل کنید که خروجی مورد نظر کسبوکار با کیفیت مورد توافق آماده انتشار است.
- Specification و Acceptance Criteria جریان طبیعی برنامه را فراهم میکنند. از آنها میتوان تعیین کرد که چه چیزی در جریان طبیعی اجرا باید تست شود و چه شرایط استثنایی ممکن است رخ دهد.
- Namespaceها، Interfaceها و کلاسها
ادامه ارزیابیها 📊
فصل ۱۱
- Cross-cutting concerns مسائلی هستند که جزو نیازمندیهای اصلی کسبوکار نیستند ولی باید در تمام بخشهای کد مورد توجه قرار گیرند. AOP به معنی Aspect-Oriented Programming است.
- یک Aspect صفتی است که وقتی به کلاس، متد، Property یا پارامتر اعمال میشود، کد را در زمان Compile تزریق میکند. Aspect در داخل Square Brackets قبل از آیتم مورد نظر قرار میگیرد.
- یک Attribute به یک آیتم معنا میدهد. Attribute نیز در Square Brackets قبل از آیتم اعمال میشود.
- Attributes به کد معنا میدهند، در حالی که Aspects کد تکراری (Boilerplate Code) را حذف میکنند و در زمان Compile تزریق میشود.
- وقتی کد ساخته میشود، Compiler کد Boilerplate که توسط Aspect پنهان شده است را وارد میکند. این فرآیند Code Weaving نام دارد.
فصل ۱۲
- Code Metrics مجموعهای از اندازهگیریهای کد منبع هستند که کمک میکنند پیچیدگی نرمافزار و قابلیت نگهداری آن را ارزیابی کنیم. این اندازهگیریها بخشهایی از کد که نیاز به سادهسازی یا Refactoring دارند را مشخص میکنند.
- مثالها: Cyclomatic Complexity, Maintainability Index, Depth of Inheritance, Class Coupling, تعداد خطوط Source Code، و تعداد خطوط Executable Code.
- Code Analysis تحلیل ایستا (Static Analysis) کد منبع برای شناسایی مشکلات طراحی، مشکلات Globalization، مسائل امنیتی، عملکرد و Interoperability است.
- Quick Actions دستوراتی هستند که با نماد Screwdriver یا Lightbulb مشخص میشوند و میتوانند هشدارها را سرکوب کنند، Using Statements اضافه کنند، Libraryهای از دست رفته را ایمپورت کنند، خطاها را اصلاح کنند و بهبودهای زبانی را اعمال کنند تا کد سادهتر و تعداد خطوط در یک Method کاهش یابد.
- ابزار JetBrains dotTrace برای پروفایلینگ کد و Assemblyهای کامپایل شده بهکار میرود تا مشکلات احتمالی نرمافزار شناسایی شود. قابلیتهایی شامل Sampling، Tracing، Line-by-Line و Timeline Profiling دارد و زمان اجرای Thread، دستورهای CPU در زمان واقعی و زمان چرخه Thread را بررسی میکند.
- ابزار JetBrains ReSharper ابزاری برای Refactoring کد است که به توسعهدهندگان کمک میکند مشکلات کد را شناسایی و رفع کنند و قابلیتهای زبانی را پیادهسازی کنند تا تجربه برنامهنویس سریعتر و بهتر شود.
- Decompilation کد منبع میتواند برای بازیابی کد از دست رفته، تولید PDB برای Debug و یادگیری استفاده شود. همچنین میتوان از Decompiler برای بررسی کیفیت Obfuscation استفاده کرد تا کد برای هکرها و افراد دیگر سختتر قابل سرقت باشد.
فصل ۱۳
-
سطوح: Application-level, Class-level, Method-level
-
مشکلات رایج: Boolean Blindness, Combinatorial Explosion, Contrived Complexity, Data Clump, Deodorant Comments, Duplicate Code, Lost Intent, Mutation of Variables, Oddball Solution, Shotgun Surgery, Solution Sprawl, Uncontrolled Side Effects
-
مشکلات دیگر: Cyclomatic Complexity, Divergent Change, Downcasting, Excessive Literal Use, Feature Envy, Inappropriate Intimacy, Indecent Exposure, Large Class (God Object), Lazy Class (Freeloader/Lazy Object), Middleman Class, Orphan Class of Variables/Constants, Primitive Obsession, Refused Bequest, Speculative Generality, Tell, Don’t Ask!, Temporary Field, Black Sheep, Dead Code, Excessive Data Return, Identifier Size, Long Line (God Line), Long Method (God Method), Long Parameter List, Message Chains, Oddball Solutions, Speculative Generality
-
راهکارها: از LINQ به جای حلقهها استفاده کنید، کلاسها را فقط مسئول یک کار کنید، متدها فقط یک کار انجام دهند، لیست طولانی پارامترها را با Parameter Object جایگزین کنید، از Creational Design Patterns برای بهینهسازی ایجاد اشیاء استفاده کنید، متدها را حداکثر ۱۰ خط نگه دارید، با AOP کد Boilerplate را حذف کنید، اشیاء را Decouple و قابل تست کنید، کد را Highly Cohesive نگه دارید.
-
Cyclomatic Complexity نمایانگر تعداد Branching و Looping در کد است.
-
کاهش Branching و Looping تا رسیدن به Cyclomatic Complexity ≤ ۱۰
-
سادهسازی کد: Keep It Simple, Stupid (KISS)
-
جلوگیری از انجام یک کار با چند روش مختلف
-
ایجاد Generic Methods برای دادههای متفاوت
-
اصلاح کد بد و حذف کامنتها
-
درخواست کمک و مراجعه به Stack Overflow
-
Refactor متدهای طولانی و حذف Boilerplate با AOP
-
محدودیت خطوط متد: ≤۱۰
-
متغیرها، کلاسها، Properties و متدهای بلااستفاده را حذف کنید
-
انتخاب بهترین روش پیادهسازی و Refactor برای استفاده از همان روش
-
Refactor Temporary Field و متدهای مرتبط به کلاس جدا
-
Refactor متغیرهای مشابه در کلاسهای مختلف به یک کلاس مجزا
-
کلاس به دیگری ارث میبرد ولی همه متدها استفاده نمیشوند
-
Law of Demeter: فقط اجازه ارتباط با همسایگان مستقیم
-
Refactor وابستگیها به کلاس یا متد جدا
-
Factory Method: از Base Class ارث ببرید و کلاس جدید بسازید
-
مسئولیتها را به یک کلاس متمرکز کنید (Single Responsibility)
-
دادهها باید در همان Object که عملیات روی آن انجام میشود، قرار گیرد
-
یک تغییر نیازمند تغییر در چندین مکان است → Duplication را حذف کنید، Coupling را کاهش دهید، Cohesion را افزایش دهید
-
Lost Intent: هدف کلاس یا متد نامشخص است → Refactor کنید و متدها را در کلاس درست قرار دهید
-
Refactor حلقهها با LINQ برای عملکرد بهتر و بدون تغییر متغیرهای مکان
فصل ۱۴
-
GoF مخفف Gang-of-Four Patterns است؛ ۲۳ الگو که شامل Creational, Structural, Behavioral هستند و پایه تمام Design Patternها محسوب میشوند. هدف آنها تولید کد Object-Oriented Clean است.
-
Creational Patterns به Abstraction و Inheritance اجازه میدهند تا Duplicate Code حذف شده و Performance در ایجاد اشیاء گران افزایش یابد. شامل: Abstract Factory, Factory Method, Singleton, Prototype, Builder
-
Structural Patterns مدیریت صحیح روابط بین اشیاء را فراهم میکنند، امکان همکاری Interfaceهای ناسازگار، Decouple Abstraction از Implementation و بهبود Performance. شامل: Adapter, Bridge, Composite, Decorator, Façade, Flyweight, Proxy
-
Behavioral Patterns نحوه تعامل و ارتباط بین اشیاء را مدیریت میکنند، تولید Pipeline، Encapsulate Commands، Mediator بین Objects، Observer برای تغییر وضعیت و … شامل: Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor
-
Singleton تنها یک Instance از Object را در طول عمر برنامه ایجاد میکند و قابل دسترسی جهانی است
-
Factory Methods برای ایجاد Object بدون مشخص کردن کلاس دقیق
-
Façade
-
استفاده از Flyweight Pattern
-
Bridge
-
استفاده از Builder Pattern
-
Chain of Responsibility Pattern برای ایجاد Pipeline از Handlers که هرکدام یک Task را انجام میدهند و اگر قادر نباشند، Task به Successor منتقل میشود