Clean Code
مقدمه
اگر اصول Clean Code را در توسعه فرانتاند رعایت نکنیم، با چالشهای جدی و متعددی روبرو خواهیم شد. این چالشها میتوانند شامل کد پیچیده و غیرقابل خواندن، دشواری در نگهداری و بهروزرسانی، افزایش زمان و هزینهی رفع اشکال، و مشکلات در همکاری تیمی باشند. در نتیجه، پروژهها با تأخیر مواجه شده، کیفیت محصول نهایی کاهش یافته و هزینههای توسعه به طور قابل توجهی افزایش مییابد. همچنین، عدم رعایت این اصول میتواند منجر به ایجاد بدهی فنی شود که در طول زمان انباشته شده و مدیریت پروژه را دشوارتر میکند.
برای جلوگیری از این مشکلات، رعایت اصول Clean Code در فرانتاند ضروری است. این اصول به ایجاد کدی خوانا، قابل نگهداری و قابل توسعه کمک میکنند که برای تیمهای توسعه بسیار حیاتی است. با پیروی از این اصول، توسعهدهندگان میتوانند کدی بنویسند که به راحتی توسط سایر اعضای تیم قابل درک و ویرایش باشد. این امر باعث کاهش زمان و هزینههای مربوط به رفع اشکال، بهبود و توسعه پروژه در آینده میشود. همچنین، کد تمیز به بهبود عملکرد و کارایی برنامه کمک میکند، زیرا ساختار بهینه و منطقی کد، اجرای سریعتر و کارآمدتر را تضمین میکند.
- نوشتن کد تمیز چه مزایایی دارد؟
- از چه اصول و از چه تکنیکهایی برای دستیابی به کد تمیز میتوان استفاده کرد؟
- کد تمیز به طور خاص در فرانتاند دارای چه ویژگیهایی است؟
یادگیری
Clean Code
شاید برای شما هم پیش آمده باشد که بعد از چند ماه به پروژهای که خودتان آن را توسعه دادهاید سر بزنید و احساس کنید تقریباً هیچچیز از آن متوجه نمیشوید. زمانی که بر روی پروژهای کوچک، به صورت انفرادی کار میکنید شاید هیچوقت به اهمیت کد تمیز پی نبرید؛ اما اگر همین پروژه، در آینده احتیاج به توسعه داشته باشید یا اگر به همراه یک تیم بر روی آن کار ک نید، بدونِ داشتنِ کد تمیز، محکوم به شکست خواهید بود.
برای آشنایی بیشتر با این مفهوم میتوانید از لینکهای زیر استفاده کنید:
Code Smells
یکی از راههای افزایش کیفیت کد، پیدا کردن نشانههای کد کثیف و بازنویسی آنهاست. به این نشانهها Code Smell میگوییم.
برای آشنایی بیشتر با این مفهوم میتوانید از لینک زیر استفاده کنید:
S.O.L.I.D
یکی از مهمترین مجموعه اصول در برنامهنویسی، اصول پنجگانهٔ SOLID میباشد که عبارت است از:
- Single Responsibility
- Open for Extension/Closed for Modification
- Liskov Substitution
- Interface Segregation
- Dependency Inversion
برای آشنایی بیشتر با این مفهوم میتوانید از لینکهای زیر استفاده کنید:
- Medium - S.O.L.I.D in TypeScript
- Medium - SOLID Principles in TypeScript
- Medium - Brutally SOLID Typescript
Refactoring Techniques
با گذشت زمان و کسب تجربه توسط توسعهدهندگان، مجموعهای از تکنیکها برای تمیزسازی کد فراهم شده که تقریباً برای تمام نیازهای شما راهحل دارد. پیشنهاد میکنیم فعلاً به صورت روزنامهوار توضیحات هر تکنیک را مطالعه کنید و فقط زمانی که به آن احتیاج پیدا کردید، آن را به طور کامل بخوانید.
برای آشنایی بیشتر با این مفهوم میتوانید از لینک زیر استفاده کنید:
Open-Source
README.md
فایل
README.md
معرفینامۀ پروژۀ شماست.
تمام مواردی که یک کاربر بیرونی احتیاج دارد در مورد پروژه بداند
باید در این فایل آورده شوند یا حداقل به جایی که در مورد آنها توضیح داده شده است،
اشاره شود.
پیشنهاد میکنیم موارد زیر را حتماً در این فایل بیاورید:
- نام پروژه
- لوگو شخص، تیم یا شرکت
- لینک به سایت اصلی پروژه
- وضعیت CI/CD، بالا بودن سرورها، پاسشدن تستها و موارد مشابه
- توضیحی چند خطی و کوتاه در مورد کاربرد پروژه
- اهداف پروژه و نیازهایی که میتواند برطرف کند
- پیشنیازهای استفاده از پروژه
- لینک دانلود فایل نهایی/اجرایی پروژه
- باگهای احتمالی و مواردی که کاربر باید به آنها توجه کند
- قابلیتهای فعلی و نحوۀ استفاده از آنها
- مستندات کامل یا لینک به جایی که آنها را قرار دادهاید
- برنامههای آینده و قابلیتهایی که میخواهید به پروژه اضافه کنید
- شرایط پشتیبانی و نحوۀ ثبت درخواست
- توضیح اجمالی، دعوت به مشارکت و لینک به
CONTRIBUTING.md
- لینک به صفحات پروژه در شبکههای اجتماعی
- معرفی اجمالی توسعهدهندگان پروژه و لینک به صفحات مرتبط آنها در شبکههای اجتماعی
CONTRIBUTING.md
در دنیای
Open-Source
، آدمهای زیادی پیدا میشوند که به طور رایگان بخواهند به شما کمک کنند؛
بنابراین شما باید با فراهمکردن فایل
CONTRIBUTING.md
مناسب، آنها را در این راه یاری کنید.
پیشنهاد میکنیم موارد زیر را حتماً در این فایل بیاورید:
- پیشنهاد برای چککردن لیست Issue های فعلی و جلوگیری از ثبت Issue تکراری
- لیست قابلیتهایی که دوست دارید توسط دیگران به پروژه اضافه شوند
- لیست قابلیتهایی که دوست ندارید به پروژه اضافه شوند
- لیست باگهایی که دوست دارید توسط دیگران حل شوند
- لیست باگهایی که از وجود آنها باخبرید اما قصد برطرفکردن آنها را ندارید
- مراحل ثبت باگ، درخواست امکانات جدید، ارتباط با توسعهدهندگان و موارد مشابه
- پیشنیازهای راهاندازی پروژه بر روی سیستم شخص
- نحوۀ Clone کردن و راهاندازی پروژه به صورت خط به خط با بیشترین جزئیات ممکن
- قوانین کدنویسی که در پروژه رعایت میکنید
- قواعد نوشتن Commit Message
IDE
استفاده از Text Editor هایی مانند VS Code فقط برای پروژههای کوچک مناسب است. برای پروژههای بزرگ، مخصوصاً پروژههایی که به صورت تیمی آنها را توسعه میدهید، حتماً از WebStorm استفاده کنید.
ESLint
برای فعالکردن تنظیمات ESLint از لینک زیر استفاده کنید:
Prettier
برای فعالکردن تنظیمات Prettier از لینک زیر استفاده کنید:
Stylelint
معمولاً هر شخص زمانی که کد CSS مینویسد، برای آن قواعدی در نظر میگیرد؛ بهعنوان مثال ترتیب و اولویت Property های مختلف یا استفاده از یک فرمت رنگ خاص. اما زمانی که به صورت تیمی بر روی پروژهای کار میکنید، بهتر است این قواعد به صورت عمومی اعمال شوند تا کدی که در نهایت نوشته میشود برای همه قابلفهم و در یک چارچوب باشد. Stylelint ابزاری است که به ما امکان تعریف چنین قواعدی را میدهد.
برای آشنایی بیشتر با StyleLint از لینکهای زیر استفاده کنید:
General
Download Size
گاهی اوقات مشاهده میشود که بعضی از توسعهدهندگان از فایلهای حجیمی در پروژۀ خود استفاده میکنند که نهتنها مزیت خاصی ندارند، بکله باعث کند شدن سایت میشوند و حجم زیادی از اینترنت کاربر را اشغال میکنند.
پیشنهاد میکنیم برای کاهش حجم عکسها از سایت
Squoosh
استفاده کنید.
همچنین به طور کلی حجم فایلهای
svg
از فرمتهای دیگر کمتر است،
بنابراین سعی کنید تا جای ممکن از این فرمت استفاده کنید.
در صورتی که عکس شما به صورت
Raster
بود و امکان استفاده از
svg
را نداشتید، پیشنهاد ما فرمت
webp
میباشد.
به طور کلی توصیه میکنیم تا جای ممکن از ویدئو استفاده نکنید.
Comment
زمانی که در حال توسعۀ پروژه هستید، ممکن است بخواهید بهطور موقت قسمتی از کد را کامنت کنید؛
این مورد به تنهایی مشکلی ندارد اما زمانی که خواستید کد را بر روی نسخۀ
master
یا main
ببرید،
حتماً کامنتهای اضافی را پاک کنید.
همچنین به طور کلی زمانی که مجبور شدید برای توضیح قسمتی از کد، از کامنت استفاده کنید،
احتمالاً کدی که نوشتید تمیز نیست؛ سعی کنید همیشه کدی بنویسید که بدونِ نیاز به توضیحات، قابلفهم باشد.
Unicode Characters
بعضاً مشاهده میشود که توسعهدهندگان برای نمایش اعداد فارسی از کاراکترهای
۰۱۲۳۴۵۶۷۸۹
استفاده میکنند؛
ما پیشنهاد میکنیم بههیچوجه چنین کاری نکنید؛
در عوض از فونتی استفاده کنید که کاراکترهای
0123456789
را به شکل درست نمایش دهد.
CSS
Reset
مرورگرهای مختلف، استایلهای پیشفرض متفاوتی برای المانهای مختلف دارند که این موضوع باعث بروز مشکلات متعددی در روند توسعه میشود؛ بهعنوان مثال ممکن است ظاهر سایت شما در یک مرورگر خاص دقیقاً همانطور باشد که میخواهید اما در یک مرورگر دیگر کاملاً بههمریخته باشد.
برای حل این مشکل Reset های متعددی وجود دارد اما ما در اینجا از سادهترین آنها استفاده میکنیم:
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
BEM
یکی از معروفترین و محبوبترین متدولوژیهای موجود که در نامگذاری المانها استفاده میشود، BEM است. با استفاده از این متدولوژی میتوانید صرفاً با نگاهکردن به اسم یک المان، ساختاری که در آن قرار دارد را متوجه شوید. همچنین از آنجایی که برای هر المان از یک کلاس مشخص استفاده میکنید، به مشکلات مربوط به Specificity برنخواهید خورد.
استفاده از
BEM
در
SCSS
بسیار راحت است:
.card {
&__header {
&__icon {
// ...
}
&__title {
// ...
}
}
&--primay {
// ...
}
}
برای آشنایی بیشتر با این مفهوم میتوانید از لینکهای زیر استفاده کنید:
Color Syntax
در CSS به طور کلی از 4 روش مختلف میتوان رنگ یک المان را تعیین کرد که در ادامه به مقایسۀ آنها میپردازیم.
Names
شاید به نظر برسد بهترین راه برای مشخصکردن یک رنگ، استفاده از اسم آن است.
برای رنگهایی که به طور معمول با آنها سروکار داریم و اسم آنها را میدانیم،
این قضیه صادق است؛
اما
CSS
دارای بیش از 100 رنگ است که تعداد زیادی از آنها برای توسعهدهندگان،
به خصوص کسانی که زبان مادری آنها انگلیسی نیست،
ناآشنا هستند.
از طرفی حتی در مورد رنگهایی که اسم آنه ا را میدانیم،
نمیتوانیم به طور دقیق میزان پُررنگ یا کمرنگبودن آنها را تشخیص دهیم.
بهعنوان مثال تفاوت رنگهای
pink
و
lightpink
در چیست؟
یا کدامیک از رنگهای
hotpink
و
deeppink
پُررنگتر است؟
البته این نوع رنگها کاملاً هم بلااستفاده نیستند، بلکه بعضاً برای زمانی که صرفاً بهدنبال تستکردن پروژه یا شناسایی باگ هستید، بهترین گزینهاند.
HEX
این فرمت از سه عدد در مبنای 16 تشکیل شده است؛ آیا برای اثبات نابهینهبودن این فرمت احتیاج به توضیح بیشتری هست؟ جدای از آنکه تشخیص یک عدد مبنای 16 و محاسبه ذهنی برای تبدیل آن به مبنای 10 کاری دشوار است، این فرمت دارای مشکل بزرگ دیگری است که در قسمت RGB به آن اشاره میکنیم.
RGB
این فرمت از سه عدد در مبنای 10 تشکیل شده است که به ترتیب نشاندهندۀ رنگهای قرمز، سبز و آبی هستند. این اعداد از 0 تا 255 میتوانند متغیر باشند و هر چه عدد متناظر یک رنگ بزرگتر باشد، مقدار بیشتری از آن در رنگ نهایی استفاده خواهد شد.
مشکل این فرمت آن است که نمیتوان رنگ فعلی را به راحتی تشخیص داد.
بهعنوان مثال
rgb(48, 15, 16)
مربوط به چه رنگی است؟
درست است که میتوان متوجه شد رنگ قرمز تقریباً 3 برابر رنگهای سبز و آبی استفاده شده است،
اما اینکه رنگ نهایی چه چیزی است، بسیار دشوار است.
همچنین ساخت نسخههای روشنتر یا تیرهتر با استفاده از این فرمت به هیچ عنوان ساده نیست.
HSL
این فرمت از سه قسمت تشکیل شده است که به ترتیب یک زاویه در Color Wheel ، درصد استفاده از رنگ پایه و درصد روشنایی رنگ نهایی را مشخص میکنند. اگر Color Wheel و زاویۀ رنگهای اصلی را حفظ کنید، به راحتی میتوانید رنگی که با این فرمت ساخته میشود را تشخیص دهید. حفظکردن Color Wheel بسیار سادهتر از چیزی است که فکر میکنید؛ صرفاً کافی است رنگهای رنگینکمان را بلد باشد:
- قرمز: 0
- نارنجی: 30
- زرد: 60
- سبز: 120
- آبی: 180
- نیلی: 240
- بنفش: 270
ایجاد قالبهای رنگی با استفاده از این فرمت بسیار ساده است؛ از قسمت اول برای تغییر رنگ پایه میتوانید استفاده کنید و صرفاً با افزودن 180 درجه، به رنگ مکمل میرسید؛ قسمت دوم برای تعیین میزان روشنا یی در قالبهای Light و Dark کاربرد دارد؛ قسمت سوم مربوط به روشنایی رنگ نهایی است و میتوانید از آن برای ایجاد رنگ State هایی مانند Hover استفاده کنید.
:root {
--primary-hue: 220;
--secondary-hue: 260;
--success-hue: 120;
--warning-hue: 20;
--danger-hue: 0;
--color-gray-98: hsl(0, 0%, 98%);
--color-gray-90: hsl(0, 0%, 90%);
--color-gray-80: hsl(0, 0%, 80%);
--color-gray-70: hsl(0, 0%, 70%);
--color-gray-40: hsl(0, 0%, 40%);
--color-gray-30: hsl(0, 0%, 30%);
--color-gray-20: hsl(0, 0%, 20%);
--color-gray-10: hsl(0, 0%, 10%);
--color--default-background: var(--color-gray-98);
--color--default-foreground: var(--color-gray-10);
--color--primary: hsl(var(--primary-hue), 100%, 56%);
--color--primary-fade: hsl(var(--primary-hue), 100%, 96%);
--color--primary-lighter: hsl(var(--primary-hue), 100%, 60%);
--color--primary-darker: hsl(var(--primary-hue), 100%, 52%);
--color--primary-opposite: var(--color-gray-98);
--color--secondary: hsl(var(--secondary-hue), 50%, 50%);
--color--secondary-fade: hsl(var(--secondary-hue), 100%, 90%);
--color--secondary-lighter: hsl(var(--secondary-hue), 50%, 56%);
--color--secondary-darker: hsl(var(--secondary-hue), 50%, 44%);
--color--secondary-opposite: var(--color-gray-98);
--color--warning: hsl(var(--warning-hue), 100%, 44%);
--color--warning-fade: hsl(var(--warning-hue), 100%, 90%);
--color--warning-lighter: hsl(var(--warning-hue), 100%, 50%);
--color--warning-darker: hsl(var(--warning-hue), 100%, 40%);
--color--warning-opposite: var(--color-gray-98);
--color--success: hsl(var(--success-hue), 100%, 40%);
--color--success-fade: hsl(var(--success-hue), 100%, 92%);
--color--success-lighter: hsl(var(--success-hue), 100%, 44%);
--color--success-darker: hsl(var(--success-hue), 100%, 36%);
--color--success-opposite: var(--color-gray-98);
--color--danger: hsl(var(--danger-hue), 100%, 36%);
--color--danger-fade: hsl(var(--danger-hue), 100%, 90%);
--color--danger-lighter: hsl(var(--danger-hue), 100%, 42%);
--color--danger-darker: hsl(var(--danger-hue), 100%, 30%);
--color--danger-opposite: var(--color-gray-98);
}
Font Management
Multiple Fonts
در کل پروژه فقط از یک فونت استفاده کنید. کمتر پیش میآید استفاده از دو فونت مجزا، نتیجۀ مطلوبی داشته باشد؛ مخصوصاً برای سایتهای فارسی. اگر قسمتی از سایت شما فارسی و قسمت دیگر انگلیسی است، از دو فونت برای آنها استفاده نکنید؛ بلکه بهدنبال فونتی بگردید که هر دو را به خوبی نشان دهد.
ما فونتهای فارسی رایگان زیر را پیشنهاد میکنیم:
font-family
استایلهای مربوط به
font-family
را به
*
ندهید چراکه باعث بالا رفتن
Specificity
میشود
و در کار بعضی از کتابخانهها مانند
Fontawesome
یا
Monaco Editor
خلل ایجاد میکند.
در عوض میتوانید این استایل را به
html
بدهید.
از آنجایی که
font
از المان پدر به ارث میرسد،
تمام المانهای شما فونت مورد نظر را خواهند داشت.
اما بعضی از المانها مانند
input
و
button
احتیاج دارند که به طور دقیق فونت آنها را مشخص کنید.
برای راحتی کار میتوانید از کد زیر استفاده کنید:
html {
font-family: Poppins, sans-serif;
}
input,
label,
select,
textarea,
button,
fieldset,
legend,
datalist,
output,
option,
optgroup {
font-family: inherit;
}
Generic Default Fonts
همیشه یک فونت پیشفرض مانند
sans-serif
را به آخر
font-family
اضافه کنید
تا در صورتی که به هر دلیلی فونت اصلی از کار افتاد،
مرورگر بتواند از فونت پیشفرض استفاده کند.
دقت کنید که فقط فونتهای
Generic
میتوانند بهعنوان
Fallback
استفاده شوند؛ یعنی:
- serif
- sans-serif
- cursive
- fantasy
- monospace
rem & px
همانطور که میدانید به طور پیشفرض هر
rem
برابر با
16px
است.
این موضوع باعث میشود زمانی که میخواهید از
rem
استفاده کنید،
مجبور به انجام محاسبات نسبتاً سختی باشید که سرعت توسعه و از همه مهمتر خوانایی کد را کاهش میدهد.
برای حل این مشکل پیشنهاد میکنیم سایز فونت
html
را به
%62.5
تغییر دهید؛
با این کار هر
rem
برابر با
10px
خواهد شد.
Variables
ما پیشنهاد میکنیم همیشه به طور پیشفرض از متغیرهای CSS استفاده کنید و تنها در صورتِ نیاز به متغیرهای SCSS رجوع کنید.
همچنین پیشنهاد میکنیم متغیرها را قبل از بقیۀ Rule ها تعریف کنید تا خوانایی کد بالا رود و از اشتباهات احتمالی جلوگیری شود:
.item {
--size: 10rem;
--gap: 1rem;
/* ... */
}
Transition/Animation Performance
در صورتی که فقط از
transform
و
opacity
برای انجام
Animation
های خود استفاده کنید،
فقط مرحله
Composite
اجرا میشود و مرورگر میتواند تمام کارها را بر عهدۀ
GPU
بگذارد.
بنابراین همیشه سعی کنید فقط از این دو
Property
استفاده کنید.
دقت کنید که در اینجا منظور تنها کلیدواژۀ
animation
یا
keyframe
نیست،
بلکه
transition
و به طور کلی هر راهی که بتوان با آن ظاهر یک المان را به تدریج عوض کرد، مد نظر است.
Zero Unit
در
CSS
زمانی که از عدد 0
استفاده میکنید،
بهتر است واحدی برای آن در نظر نگیرید.
/* Bad */
.item {
margin: 0rem auto;
}
/* Good */
.item {
margin: 0 auto;
}
Logical Properties
اگر قبلاً بر روی پروژهای کار کرده باشید که همزمان باید از دو زبان انگلیسی و ف ارسی پشتیبانی میکرد،
قطعاً متوجه شدهاید که نیاز است خیلی از استایلهایی که به راست یا چپ ربط دارند را عوض کنید.
بهعنوان مثال اگر از
margin-left
در نسخۀ انگلیسی استفاده کردید،
باید در نسخۀ فارسی آن را به
margin-right
تغییر میدادید.
خوشبختانه در
CSS
برای حل این مشکل میتوان از
Logical Properties
استفاده کنیم؛
در این صورت، مرورگر بر اساس
Direction
سایت، استایلها را اعمال میکند.
در ادامه برای سایتی که LTR است، معادل چند Property پُر استفاده را میآوریم:
Normal Property | Logical Property |
---|---|
top | inset-block-start |
bottom | inset-block-end |
left | inset-inline-start |
right | inset-inline-end |
margin-top | margin-block-start |
margin-bottom | margin-block-end |
margin-left | margin-inline-start |
margin-right | margin-inline-end |
padding-top | padding-block-start |
padding-bottom | padding-block-end |
padding-left | padding-inline-start |
padding-right | padding-inline-end |
height | block-size |
min-height | min-block-size |
max-height | max-block-size |
width | inline-size |
min-width | min-inline-size |
max-width | max-inline-size |
همچنین میتوانید دو Logical Property را که هر دو Inline یا Block هستند، همزمان مقداردهی کنید. برای روشنتر شدن موضوع، سه کد معادل زیر را در نظر بگیرید:
.item {
padding-top: 1rem;
padding-bottom: 1rem;
}
/* or */
.item {
padding-block-start: 1rem;
padding-block-end: 1rem;
}
/* or */
.item {
padding-block: 1rem;
}
برای آشنایی بیشتر با این مفهوم میتوانید از لینک زیر استفاده کنید:
پروژه
هدف
بررسی کد پروژه فاز Angular با استفاده از قواعد Clean Code
مراحل
- کد پروژه خود در فاز Angular را بررسی کنید و اگر جایی قواعدی که توضیح داده شده است را رعایت نکردید آن را اصلاح کنید
- پس از بررسی کد خود شما باید حداقل Pull Request یکی از تیمهارا بررسی کنید