Skip to content

Latest commit

 

History

History
989 lines (589 loc) · 76 KB

README-ir.md

File metadata and controls

989 lines (589 loc) · 76 KB

中文版 | 日本語版 | 한국어 | Русский | Português | Italiana | English | Persian/فارسی

دستورالعمل‌های پروژه · PRs Welcome

وقتی که شروع و توسعه یک پروژه جدید برای شما شبیه به حرکت در یک میدان سبز و خالی (که هیچ ساختاری ندارد) است (استعاره از شروع کردن یک پروژه یا کار جدید از ابتدا و بدون هیچ محدودیت و ساختاری است)، نگهداری از آن می‌تواند کابوسی پیچیده و تاریک برای شخص دیگری باشد. در اینجا لیستی از دستورالعمل‌ها آمده است که ما آن‌ها را پیدا کرده‌ایم، نوشته‌ایم و گردآوری کرده‌ایم و فکر می‌کنیم که برای اکثر پروژه‌های جاوااسکریپت در elsewhen به خوبی عمل می‌کند. اگر می‌خواهید یک روش بهینه را به اشتراک بگذارید، یا فکر می‌کنید یکی از این دستورالعمل‌ها باید حذف شود، با خیال راحت آن را با ما به اشتراک بگذارید.


1. گیت/Git

1.1 برخی از قوانین Git

مجموعه‌ای از قوانین وجود دارد که باید آن‌ها را به خاطر داشته باشید:

  • کار را در برنچ feature انجام دهید

چرا:

این روش باعث می‌شود که تمام کارها به صورت مجزا در یک برنچ اختصاصی انجام شوند، نه در برنچ اصلی. این کار به شما امکان را می‌دهد تا چندین درخواست Pull Request بدون سردرگمی ارسال کنید. همچنین می‌توانید به طور مکرر کد را به‌روزرسانی کنید، بدون اینکه برنچ اصلی را با کد ناپایدار و ناتمام آلوده کنید. توضیحات بیشتر ...

  • از برنچ develop انشعاب بگیرید

چرا:

به این ترتیب، می‌توانید مطمئن شوید که کد برنچ master تقریباً همیشه بدون مشکل build می‌شود و معمولاً می‌توان آن را مستقیماً برای releases استفاده کرد (این کار ممکن است برای برخی پروژه‌ها بیش از حد لازم باشد).

  • هرگز مستقیماً به برنچ develop یا master پوش نکنید. بلکه یک درخواست Pull Request ایجاد کنید.

چرا:

این کار به اعضای تیم اطلاع می‌دهد که یک feature تکمیل شده است. همچنین امکان بررسی آسان کد توسط سایرین را فراهم می‌کند و فضایی برای بحث درباره feature پیشنهادی ایجاد می‌کند.

  • برنچ develop محلی/local خود را قبل از پوش کردن یک feature، ابتدا بروزرسانی و مورد بازبینی تعاملی (interactive rebase) قرار دهید، سپس درخواست Pull Request ایجاد کنید.

چرا:

ری‌بیس (Rebase) برنچ درخواست‌شده (master یا develop) را merge می‌کند و کامیت‌هایی که به‌صورت locally انجام داده‌اید را به بالای تاریخچه اعمال می‌کند، بدون اینکه کامیت merge ایجاد کند (در صورتی که تعارضی وجود نداشته باشد). نتیجه آن یک تاریخچه تمیز و مرتب خواهد بود. توضیحات بیشتر ...

  • تعارضات احتمالی را در حین rebase و قبل از ایجاد درخواست Pull Request برطرف کنید.
  • برنچ‌های feature ایجاد شده در local و remote را پس از ادغام حذف کنید.

چرا:

لیست برنچ‌های شما را با برنچ‌های بی‌استفاده درهم می‌آمیزد (شلوغ می‌کند). حذف برنچ‌های feature باعث می‌شود که هر برنچ تنها یک‌بار به برنچ اصلی (master یا develop) ادغام شود. برنچ‌های feature باید فقط تا زمانی که کار هنوز در حال انجام است وجود داشته باشند.

  • قبل از ایجاد درخواست Pull Request، مطمئن شوید که برنچ feature شما با موفقیت build می‌شود و همه testها (شامل بررسی‌های سبک/استایل کد) با موفقیت انجام می‌شود.

چرا:

شما قصد دارید که کد خود را به یک برنچ stable اضافه کنید. اگر testهای برنچ feature شما ناموفق باشند، احتمال زیادی وجود دارد که build برنچ مقصد نیز شکست بخورد. علاوه بر این، قبل از ایجاد درخواست Pull Request، نیاز است که بررسی سبک و استایل کد را انجام شود. این کار باعث بهبود خوانایی کد می‌شود و احتمال ترکیب شدن تغییرات قالب‌بندی با تغییرات واقعی را کاهش می‌دهد.

چرا:

این فایل از قبل دارای لیستی از فایل‌های سیستمی است که نباید همراه با کد شما به مخزن remote ارسال شوند. علاوه بر این، پوشه‌ها و فایل‌های تنظیمات برای بیشتر ویرایشگرهای مورد استفاده و همچنین پوشه‌های dependency رایج را نیز مستثنی می‌کند.

  • از برنچ‌های develop و master محافظت کنید.

چرا:

این کار از برنچ‌های آماده برای production در برابر دریافت تغییرات غیرمنتظره و غیرقابل بازگشت محافظت می‌کند. توضیحات بیشتر ... GitHub, Bitbucket and GitLab

1.2 گردش‌کار گیت/Git workflow

به خاطر دلایل ذکرشده در بالا، ما از Feature-branch-workflow همراه با Interactive Rebasing و برخی عناصر Gitflow (نام‌گذاری و داشتن یک develop branch). استفاده می‌کنیم. مراحل اصلی به شرح زیر هستند:

  • برای یک پروژه جدید، یک مخزن گیت (Git repository) را در پوشه پروژه مقداردهی اولیه کنید. برای ویژگی‌ها/تغییرات بعدی، این مرحله باید نادیده گرفته شود.
cd <project directory>
git init
  • یک شاخه جدید برای توسعه یک feature یا رفع یک bug ایجاد کنید و به آن منتقل شوید.
git checkout -b <branchname>
  • تغییری در آن ایجاد کنید.
git add <file1> <file2> ...
git commit

چرا:

کامند git add <file1> <file2> ... - شما باید فقط فایل‌هایی را اضافه کنید که یک تغییر کوچک و منسجم را تشکیل می‌دهند.

کامند git commit یک ویرایشگر باز می‌کند که به شما اجازه می‌دهد مقادیر subject را از body در کامیت خود از هم جدا کنید.

در بخش 1.3 بیشتر درباره آن بخوانید.

نکته:

می‌توانید به جای آن از دستور git add -p استفاده کنید که به شما این امکان را می‌دهد تمام تغییرات اعمال‌شده را یک به یک بررسی کنید و تصمیم بگیرید که آیا آنها را در کامیت وارد کنید یا نه.

  • با مخزن remote همگام‌سازی کنید تا تغییراتی که از دست داده‌اید را دریافت کنید.
git checkout develop
git pull

چرا:

این کار به شما فرصت می‌دهد که با conflictها در سیستم خود در حین rebasing برخورد کنید، به جای اینکه یک درخواست Pull Request ایجاد کنید که حاوی conflictها باشد.

  • برنچ feature خود را با استفاده از interactive rebase با آخرین تغییرات از برنچ develop به‌روزرسانی کنید.
git checkout <branchname>
git rebase -i --autosquash develop

چرا:

می‌توانید از --autosquash استفاده کنید تا تمام کامیت‌های خود را به یک کامیت ترکیب کنید. هیچ‌کس نمی‌خواهد برای یک ویژگی در شاخه develop چندین کامیت داشته باشد. توضیحات بیشتر ...

  • اگر conflicts ندارید، این مرحله را رد کنید. در غیراینصورت، آنها را حل کنید و rebase را ادامه دهید.
git add <file1> <file2> ...
git rebase --continue
  • برنچ خود را push کنید. rebase تاریخچه را تغییر می‌دهد، بنابراین باید از -f برای اجبار تغییرات به برنچ remote استفاده کنید. اگر شخص دیگری روی برنچ شما کار می‌کند، از گزینه کمتر مخرب --force-with-lease استفاده کنید.
git push -f

چرا:

وقتی که rebase انجام می‌دهید، تاریخچه برنچ feature خود را تغییر می‌دهید. در نتیجه، گیت git push معمولی را رد می‌کند. به جای آن باید از فلگ -f یا --force استفاده کنید. توضیحات بیشتر ...

  • یک درخواست Pull Request ایجاد کنید.
  • درخواست Pull Request توسط یک بررسی کننده پذیرفته، ادغام و بسته خواهد شد.
  • در صورت اتمام کار، برنچ feature محلی/local خود را حذف کنید.
git branch -d <branchname>

تمام برنچ‌های local را که در مخزن remote وجود ندارند را حذف کنید. (این کار باعث می‌شود که برنچ‌های که دیگر وجود ندارند، از مخزن local حذف شوند، در نتیجه محیط توسعه شما تمیز و مرتب‌ باقی می‌ماند.)

git fetch -p && for branch in `git branch -vv --no-color | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done

1.3 نگارش بهتر متن کامیت‌ها

داشتن یک راهنمای مناسب برای ایجاد کامیت‌ها و پایبندی به آن، کار با گیت و همکاری با دیگران را بسیار آسان‌تر می‌کند. در اینجا چند قانون کلی وجود دارد:(منبع):

  • موضوع (subject) را از بدنه (body) جدا کنید و بین این دو یک خط خالی قرار دهید.

چرا:

گیت به اندازه کافی هوشمند است که خط اول پیام کامیت شما را به‌عنوان خلاصه تشخیص دهد. در واقع، اگر به‌جای استفاده از git log از git shortlog استفاده کنید، یک لیست طولانی از پیام‌های کامیت خواهید دید که شامل شناسه کامیت و تنها خلاصه پیام است.

  • طول خط موضوع (subject) را به ۵۰ کاراکتر محدود کنید و بدنه پیام را در ۷۲ کاراکتر بشکنید.

چرا:

کامیت‌ها تا حد ممکن باید جزئی و متمرکز باشند؛ نیازی به طولانی‌نویسی در آن‌ها نیست. توضیحات بیشتر ...

  • حرف اول موضوع (subject) را با عبارت بزرگ (Capitalize) شروع کنید.
  • موضوع (subject) را با نقطه تمام نکنید.
  • از وجه امری در موضوع (subject) استفاده کنید.

چرا:

به جای نوشتن پیام‌هایی که فقط بیانگر/توصیف‌کننده کاری است که کامیت‌کننده انجام داده، بهتر است این پیام‌ها را به عنوان دستورالعمل‌هایی در نظر بگیرید که بیان می‌کنند پس از اعمال کامیت در مخزن، چه چیزی قرار است انجام شود. (توضیح مترجم: پیام‌های کامیت باید بر نتیجه و هدف تمرکز کنند، نه صرفاً بر عملیات انجام‌شده.) توضیحات بیشتر ...

  • از قسمت بدنه (body) برای توضیح چه کاری و چرا انجام شده، استفاده کنید، نه چگونگی انجام آن.

2. مستندات

Documentation

  • از این قالب برای فایل README.md استفاده کنید؛ اگر بخش‌هایی وجود دارد که پوشش داده نشده‌اند، با خیال راحت آن‌ها را اضافه کنید.
  • برای پروژه‌هایی که بیش از یک مخزن (repository) دارند، لینک به مخازن دیگر را در فایل‌های README.md مربوطه قرار دهید..
  • با پیشرفت پروژه، فایل README.md را به‌روز نگه دارید.
  • کد خود را کامنت‌گذاری کنید. سعی کنید با هر بخش اصلی کد، به‌وضوح توضیح دهید که قصد دارید چه کاری انجام دهید.
  • اگر درباره کد یا روش مورد استفاده شما در گیت‌هاب یا استک‌اورفلو بحثی باز وجود دارد، لینک آن را در کامنت خود بگنجانید.
  • از کامنت‌ها به‌عنوان توجیهی برای کد ضعیف استفاده نکنید. کد خود را تمیز نگه دارید.
  • از کد تمیز به‌عنوان بهانه‌ای برای عدم کامنت‌گذاری استفاده نکنید.
  • با پیشرفت کد، کامنت‌ها را نیز متناسب به‌روز نگه دارید.

3. متغیرهای محیطی/Environments

Environments

  • در صورت نیاز، environmentهای جداگانه‌ای برای development، test و production تعریف کنید.

چرا:

در محیط‌ها (environments) مختلف ممکن است data، tokens، APIs، ports و... متفاوتی نیاز باشند. ممکن است بخواهید یک حالت development ایزوله داشته باشید که به APIهای جعلی متصل می‌شود و داده‌های قابل پیش‌بینی برمی‌گرداند، که این کار هم تست‌های خودکار و هم تست‌های دستی را بسیار ساده‌تر می‌کند. یا شاید بخواهید Google Analytics را فقط در محیط production فعال کنید و به همین ترتیب. توضیحات بیشتر ...

  • پیکربندی‌های مختص هر محیط اجرایی را از متغیرهای محیطی (environment variables) بارگذاری کنید و هرگز آن‌ها را به‌عنوان مقادیر ثابت در کد قرار ندهید. به این نمونه نگاه کنید.

چرا:

در این فایل‌ها ممکن است tokens، passwords و دیگر اطلاعات ارزشمند وجود داشته باشند. پیکربندی/کانفیگ شما باید به‌درستی از بخش‌های داخلی برنامه جدا باشد، به گونه‌ای که کد در هر لحظه ممکن است عمومی شود.

چگونه:

فایل‌های .env را برای ذخیره متغیرهای خود استفاده کنید و آن‌ها را به .gitignore اضافه کنید تا از مخزن مستثنی شوند. در عوض، یک فایل .env.example کامیت کنید که به‌عنوان راهنما برای توسعه‌دهندگان عمل کند. برای محیط production، باید همچنان متغیرهای محیطی را به روش استاندارد تنظیم کنید. بیشتر بخوانید

  • توصیه می‌شود قبل از شروع برنامه، متغیرهای محیطی را اعتبارسنجی کنید. این نمونه را مشاهده کنید که از joi برای اعتبارسنجی مقادیر ارائه‌شده استفاده می‌کند.

چرا:

این کار می‌تواند دیگران را از ساعت‌ها مشکل‌یابی/troubleshooting نجات دهد.

3.1 ایجاد محیط‌های توسعه‌ی یکپارچه/Consistent dev environments:

  • نسخه‌ی Node خود را در بخش engines در فایل package.json تنظیم کنید..

چرا:

این کار به دیگران اطلاع می‌دهد که پروژه با کدام نسخه‌ی Node کار می‌کند. توضیحات بیشتر ...

  • همچنین از nvm استفاده کنید و یک فایل .nvmrc در ریشه‌ی پروژه‌ی خود ایجاد کنید. فراموش نکنید که به آن در مستندات اشاره کنید.

چرا:

هر کسی که از nvm استفاده می‌کند، می‌تواند به سادگی با اجرای کامند nvm use به نسخه‌ی مناسب Node سوئیچ کند. توضیحات بیشتر ...

  • تنظیم یک اسکریپت preinstall که نسخه‌های Node و npm را بررسی کند، ایده‌ی خوبی است.

چرا:

برخی وابستگی‌ها/dependencies ممکن است در صورت نصب توسط نسخه‌های جدیدتر npm با خطا مواجه شوند.

  • در صورت امکان از Docker استفاده کنید.

چرا:

این کار می‌تواند یک محیط سازگار در کل فرآیند کاری شما فراهم کند، بدون نیاز به تنظیمات یا وابستگی‌های پیچیده. توضیحات بیشتر ...

  • از پکیج‌های محلی/local به‌جای پکیج‌های نصب‌شده به‌صورت گلوبالی/globally استفاده کنید.

چرا:

این کار به شما اجازه می‌دهد پکیج‌های خود را با همکارانتان به اشتراک بگذارید، به جای اینکه انتظار داشته باشید آن‌ها را به‌صورت گلوبالی روی سیستم خود نصب کرده باشند.

3.2 وابستگی‌های یکسان و هماهنگ/Consistent dependencies:

  • اطمینان حاصل کنید که اعضای تیم دقیقاً همان وابستگی‌ها (dependencies) را مانند شما دریافت کنند.

چرا:

زیرا می‌خواهید که کد، در هر محیط توسعه‌ای به همان شکل مورد انتظار عمل کند و یکسان باشد. توضیحات بیشتر ...

چگونه:

از package-lock.json در نسخه 5 از npm یا بالاتر، استفاده کنید.

من npm@5 ندارم:

در این صورت می‌توانید از Yarn استفاده کنید و اطمینان حاصل کنید که این موضوع را در فایل README.md. پس از هر به‌روزرسانی وابستگی‌ها، lock file و package.json باید نسخه‌های یکسانی داشته باشند. توضیحات بیشتر ...

من اسم Yarn را دوست ندارم:

متأسفانه انتخاب دیگری ندارید. برای نسخه‌های قدیمی‌تر npm, هنگام نصب وابستگی جدید از —save --save-exact استفاده کنید و قبل از انتشار پروژه، فایل npm-shrinkwrap.json ایجاد کنید. توضیحات بیشتر ...

4. وابستگی‌ها/Dependencies

modules

  • بر روی پکیج‌های فعلی خود را که در حال حاضر در دسترس هستند، پیگیری و نظارت کنید: به عنوان مثال، از دستور npm ls --depth=0 استفاده کنید. (توضیحات مترجم: با استفاده از دستور npm ls --depth=0 در محیط خط فرمان، می‌توانید فهرستی از پکیج‌های سطح اول (بدون نمایش وابستگی‌های زیرمجموعه‌ای) را مشاهده کنید. این کار به شما کمک می‌کند تا بدانید چه بسته‌هایی در حال حاضر در پروژه‌تان نصب هستند و از وضعیت آن‌ها مطلع باشید.) توضیحات بیشتر ...
  • بررسی کنید آیا هیچ‌یک از پکیج‌های شما بی‌استفاده یا نامربوط (غیرضروری یا غیرکاربردی) شده‌اند: با استفاده از ابزار depcheck توضیحات بیشتر ...

چرا:

ممکن است یک کتابخانه بی‌استفاده را در کد خود داشته باشید که باعث افزایش حجم نهایی برنامه شود. وابستگی‌های بی‌استفاده را پیدا کرده و حذف کنید.

  • قبل از استفاده از یک وابستگی، آمار دانلود آن را بررسی کنید تا ببینید آیا توسط جامعه به‌طور گسترده‌ای استفاده می‌شود یا خیر: با استفاده از ابزار npm-stat. توضیحات بیشتر ...

چرا:

استفاده بیشتر (از پکیج‌ها) معمولاً به معنای داشتن تعداد بیشتری از مشارکت‌کنندگان است که اغلب منجر به نگهداری بهتر می‌شود و همه این‌ها باعث می‌شود که باگ‌ها سریع‌تر کشف و اصلاحات سریع‌تر توسعه داده شوند.

  • پیش از استفاده از یک وابستگی، بررسی کنید که آیا آن وابستگی نسخه‌های منظم و پایداری ارائه می‌دهد و تعداد زیادی نگهدارندگان (maintainers) دارد یا نه. به عنوان مثال، می‌توانید از دستور npm view async استفاده کنید. توضیحات بیشتر ...

چرا:

داشتن تعداد زیادی از مشارکت‌کنندگان زمانی مؤثر است که نگهدارندگان بتوانند اصلاحات و تغییرات را به سرعت merge کنند.

  • اگر به وابستگی کمتر شناخته شده‌ای (غیرمشهور) نیاز دارید، قبل از استفاده از آن، با تیم خود مشورت کنید.
  • همیشه مطمئن شوید که برنامه شما با آخرین نسخه از وابستگی‌هایش بدون هیچگونه مشکلی/خرابی کار می‌کند: از دستور npm outdated استفاده کنید. توضیحات بیشتر ...

چرا:

بروزرسانی‌ وابستگی‌ها (dependencies) گاهی شامل تغییرات مخرب می‌شوند. هر زمان که بروزرسانی‌ها نمایش داده می‌شوند، حتماً release note ها را بررسی کنید. وابستگی‌های (dependencies) خود را یکی‌یکی بروزرسانی کنید، زیرا اگر مشکلی پیش بیاید، عیب‌یابی آن آسان‌تر خواهد بود. از ابزارهای کاربردی مانند موارد زیر استفاده کنید: npm-check-updates.

  • بررسی کنید که آیا بسته موردنظر مشکلات امنیتی شناخته‌شده‌ای دارد یا خیر؛ به عنوان مثال، با استفاده از Snyk.

5. تست کردن/Testing

testing

  • در صورت نیاز، یک environment به نام test (برای حالت تست) ایجاد کنید.

چرا:

گاهی تست end to end در حالت production ممکن است کافی به نظر برسد، اما در موارد خاص نیاز به محیط تست جداگانه‌ای وجود دارد. مثلاً ممکن است نخواهید اطلاعات تحلیلی در حالت production فعال شود و داشبورد افراد را با داده‌های تست آلوده کنید. (توضیحات مترجم: چون داده‌های تستی ممکن است اطلاعات واقعی را تحت تأثیر قرار دهد، مثلا باعث شلوغی و ایجاد داده‌های غیرضروری شوند و یا مانع از درک دقیق اطلاعات واقعی توسط کاربران یا تیم تحلیل شوند.) مثال دیگر این است که ممکن است API شما در حالت تولید محدودیت‌ تعداد درخواست (rate limit) داشته باشد و پس از تعداد مشخصی درخواست، فراخوانی APIها توسط تست را مسدود کند.

  • فایل‌های تست خود را در کنار ماژول‌های مورد آزمایش با استفاده از الگوی نام‌گذاری خاصی *.test.js یا *.spec.js قرار دهید، مانند moduleName.spec.js.

چرا:

برای پیدا کردن یک تست واحد، در ساختار پوشه‌ها جستجو و پیمایش نکنید. توضیحات بیشتر ...

  • برای جلوگیری از سردرگمی، فایل‌های تست اضافی خود را پر یک پوشه جداگانه قرار دهید.

چرا:

برخی از فایل‌های تست مستقیماً به فایل پیاده‌سازی خاصی مرتبط نیستند. باید این فایل‌ها را در پوشه‌ای قرار دهید که احتمالاً توسط سایر توسعه‌دهندگان به راحتی یافت شود: پوشه __test__. این نام __test__ هم اکنون یک استاندارد است و توسط اکثر فریم‌ورک‌های تست جاوااسکریپت تشخیص داده می‌شود.

  • کد قابل تست بنویسید، از اثرات جانبی (side effect) خودداری کنید، اثرات جانبی را جدا کنید، و توابع خالص (pure functions) بنویسید.

چرا:

هر بخش از منطق کسب‌وکار (business logic) باید به صورت مستقل و جداگانه مورد آزمایش و تست قرار گیرد تا مطمئن شوید که هر قسمت به درستی کار می‌کند. باید "تأثیر عوامل تصادفی یا فرآیندهای غیرقابل‌پیش‌بینی را در کد به حداقل برسانید" توضیحات بیشتر ...

یک تابع خالص (pure function) تابعی است که همیشه برای ورودی یکسان، خروجی یکسانی را باز می‌گرداند. برعکس، یک تابع ناخالص (impure function) تابعی است که ممکن است اثرات جانبی داشته باشد یا برای تولید یک مقدار به شرایط خارجی وابسته باشد، که این امر باعث می‌شود کمتر قابل پیش‌بینی باشد. توضیحات بیشتر ...

  • از یک static type checker استفاده کنید

چرا:

گاهی ممکن است به یک Static type checker نیاز داشته باشید. این ابزارها، سطحی از قابلیت اطمینان را برای کد شما به ارمغان می‌آورند. توضیحات بیشتر ...

  • قبل از آنکه درخواست pull request به برنچ develop را ارسال کنید، تست‌ها را به‌صورت locally اجرا کنید.

چرا:

قطعاً نمی‌خواهید کسی باشید که باعث شکست فرایند بیلد برنچ آماده‌ی production شده است. تست‌های خود را پس از rebase و پیش از ارسال به شاخه feature-branch به مخزن ریموت اجرا کنید.

  • تست‌های خود را از جمله دستورالعمل‌های مربوطه در بخش مناسب فایل README.md پروژه را مستندسازی کنید.

چرا:

این مستندات مانند یک یادداشت راهنما است که برای توسعه‌دهندگان دیگر، کارشناسان DevOps، یا تیم تضمین کیفیت (QA) و هر کسی که با کد شما کار می‌کند، مفید خواهد بود.

6. ساختار و نام‌گذاری/Structure and Naming

Structure and Naming

  • فایل‌های خود را بر اساس ویژگی‌های محصول / صفحات / کامپوننت‌ها سازمان‌دهی کنید، نه بر اساس نقش‌ها. همچنین فایل‌های تست را در کنار آن‌ها قرار دهید.

بد

.
├── controllers
|   ├── product.js
|   └── user.js
├── models
|   ├── product.js
|   └── user.js

خوب

.
├── product
|   ├── index.js
|   ├── product.js
|   └── product.test.js
├── user
|   ├── index.js
|   ├── user.js
|   └── user.test.js

چرا:

به جای داشتن لیست طولانی از فایل‌ها، ماژول‌های کوچک ایجاد کنید که هر کدام یک مسئولیت خاص را دربرمی‌گیرند، از جمله تست آن‌ها و موارد دیگر. این کار باعث می‌شود دسترسی به فایل‌ها ساده‌تر شده و بتوانید به سرعت و با یک نگاه فایل‌های مورد نظر را پیدا کنید.

  • فایل‌های تست اضافی خود را در یک پوشه‌ی جداگانه به نام test قرار دهید تا از سردرگمی جلوگیری شود.

چرا:

این کار برای سایر توسعه‌دهندگان یا کارشناسان DevOps تیم شما موجب صرفه‌جویی در زمان می‌شود.

  • از یک پوشه به نام ./config برای تنظیمات استفاده کنید و فایل‌های پیکربندی جداگانه برای محیط‌ها (environments) مختلف ایجاد نکنید.

چرا:

زمانی که یک فایل کانفیگ را برای اهداف مختلف (مانند پایگاه داده، API و غیره) تجزیه می‌کنید، قرار دادن آن‌ها در پوشه‌ای با نام مشخص مانند config منطقی است. فقط به خاطر داشته باشید که برای محیط‌های مختلف فایل‌های جداگانه نسازید، زیرا با افزایش استقرارهای برنامه، نام‌های محیط جدیدی مورد نیاز می‌شود و مدیریت آن پیچیده خواهد شد.

مقادیر مورد استفاده در فایل‌های کانفیگ باید از طریق متغیرهای محیطی (environment variables) فراهم شوند. توضیحات بیشتر ...

  • اسکریپت‌های خود را در یک پوشه به نام ./scripts قرار دهید. این شامل اسکریپت‌های bash و node است.

چرا:

احتمالاً به بیش از یک اسکریپت نیاز خواهید داشت، مانند production build, development build, database feeders, database synchronization و غیره.

  • خروجی بیلد خود را در یک پوشه به نام ./build قرار دهید. build/ را به .gitignore اضافه کنید.

چرا:

نام‌گذاری آن به سلیقه شما بستگی دارد، dist نیز گزینه خوبی است. اما با تیم خود این نام‌گذاری را هماهنگ کنید. فایل‌هایی که در این پوشه قرار می‌گیرند معمولاً تولید شده‌اند (bundled, compiled, transpiled) یا به این پوشه منتقل شده‌اند. چیزی که می‌توانید تولید کنید، هم‌تیمی‌های شما نیز باید قادر به تولید آن باشند؛ بنابراین نیازی به ارسال آن‌ها به مخزن ریموت نیست، مگر اینکه هدف خاصی داشته باشید.

7. سبک کدنویسی/Code style

Code style

7.1 برخی از اصول code style

  • برای پروژه‌های جدید از سینتکس جاوااسکریپت مدرن (استیج ۲ و بالاتر) استفاده کنید. برای پروژه‌های قدیمی، با سینتکس موجود سازگار بمانید مگر اینکه قصد به‌روزرسانی آن را داشته باشید.

چرا:

این موضوع به تصمیم شما بستگی دارد. ما از مبدل‌ها (ترنسپایلرها) برای بهره‌گیری از مزایای سینتکس جدید استفاده می‌کنیم. استیج ۲ با تغییرات جزئی احتمالا بخشی از استاندارد خواهد شد.

  • اطمینان حاصل کنید که بررسی سبک کدنویسی (code style) به عنوان بخشی از فرآیند build پروژه انجام شود. (تا هماهنگی و استاندارد بودن کدها در تمام مراحل توسعه حفظ شود.)

چرا:

متوقف کردن build برنامه یکی از روش‌های اعمال سبک کدنویسی در کد است. این کار از بی‌توجهی به سبک کدنویسی جلوگیری می‌کند. این روش را برای کد سمت client و server اجرا کنید. توضیحات بیشتر ...

چرا:

ما eslint را ترجیح می‌دهیم، اما شما می‌توانید انتخاب دیگری داشته باشید. این ابزار قوانین بیشتری را پشتیبانی می‌کند، همچنین قابلیت تنظیم و افزودن قوانین سفارشی را دارد.

چرا:

ابزار Flow سینتکس‌های جدیدی را معرفی می‌کند که نیاز به رعایت سبک کدنویسی خاصی دارند و باید بررسی شوند.

  • از فایل .eslintignore برای مستثنی کردن فایل‌ها یا پوشه‌ها از بررسی کد استایل استفاده کنید.

چرا:

برای مستثنی کردن چند فایل از بررسی سبک کدنویسی، لازم نیست کدتان را با کامنت‌های eslint-disable شلوغ کنید.

  • قبل از ارسال یک Pull Request، تمام کامنت‌های eslint-disable خود را حذف کنید.

چرا:

طبیعی است که هنگام کار بر روی یک بخش از کد، برای تمرکز بیشتر روی منطق، بررسی سبک را غیرفعال کنید. فقط به خاطر داشته باشید که کامنت‌های eslint-disable را حذف کرده و قوانین را رعایت کنید.

  • بسته به حجم و اندازه کار، از کامنت‌های //TODO: استفاده کنید یا یک تیکت باز کنید.

چرا:

استفاده از کامنت‌های //TODO: به شما و همکارانتان کمک می‌کند تا وظایف کوچک مانند بازنویسی یک تابع یا به‌روزرسانی یک توضیح را به خاطر بسپارید. برای وظایف بزرگ‌تر، از فرمت //TODO(#3456) استفاده کنید که توسط قوانین lint اعمال می‌شود، که شماره‌ی داخل پرانتز به یک تیکت باز اشاره دارد.

  • همیشه کامنت‌ها را به‌روز و مرتبط با تغییرات کد نگه دارید. بخش‌های کامنت‌شده کد را حذف کنید.

چرا:

کد شما باید تا حد ممکن خوانا باشد؛ هر چیزی که حواس را پرت می‌کند، حذف کنید. اگر یک تابع را بازنویسی کردید، تابع قدیمی را فقط کامنت نکنید، بلکه آن را حذف کنید.

  • از کامنت‌ها، لاگ‌ها یا نام‌های نامرتبط یا طنزآمیز پرهیز کنید.

چرا:

اگرچه در فرآیند build برنامه آن‌ شوخی‌ها ممکن است (و بهتر است بگویم باید) حذف شود، اما گاهی source code شما به شرکت یا مشتری دیگری منتقل می‌شود که ممکن است آن‌ها چنین شوخی‌هایی را نپسندند.

  • نام‌ها را به گونه‌ای انتخاب کنید که قابل جست‌وجو و دارای تفاوت‌های معنادار باشند و از نام‌های کوتاه‌شده و مخفف بپرهیزید. برای توابع، از نام‌های طولانی و توصیفی استفاده کنید. نام تابع باید یک فعل یا عبارت فعلی باشد و هدف آن را به وضوح بیان کند.

چرا:

این کار (استفاده از نام‌های کامل و توصیفی) باعث می‌شود کد خواناتر و درک آن راحت‌تر و ساده‌تر شود.

  • توابع خود را در فایل بر اساس «قانون نزولی» (Step-down Rule) سازمان‌دهی کنید؛ به این صورت که توابع سطح بالاتر در بالای فایل و توابع سطح پایین‌تر در زیر آن‌ها قرار گیرند.

چرا:

این کار کد را خواناتر و درک آن بهتر می‌کند

7.2 اعمال استانداردهای سبک کدنویسی

  • از فایل .editorconfig استفاده کنید که به توسعه‌دهندگان کمک می‌کند تا سبک‌های کدنویسی یکسانی را بین ویرایشگرها و IDEهای مختلف پروژه تعریف و حفظ کنند.

چرا:

پروژه EditorConfig شامل یک فرمت فایل برای تعریف سبک‌ و استال‌های کدنویسی است که شامل مجموعه‌ای از افزونه‌ها برای ویرایشگرهای متنی است، که به ویرایشگرها این امکان را می‌دهد تا فرمت فایل را بخوانند و از استایل‌های تعریف‌شده پیروی کنند. فایل‌های EditorConfig خوانا هستند و به‌خوبی با سیستم‌های کنترل نسخه کار می‌کنند.

  • ویرایشگر خود را طوری تنظیم کنید که به شما در مورد خطاهای سبک کدنویسی اطلاع دهد. از eslint-plugin-prettier و eslint-config-prettier همراه با پیکربندی ESLint خود استفاده کنید. توضیحات بیشتر ...
  • استفاده از Git hooks را مدنظر قرار دهید.

چرا:

استفاده از Git hooks به‌طور قابل‌توجهی بهره‌وری توسعه‌دهندگان را افزایش می‌دهد. با اعمال تغییرات، انجام commit و ارسال (push) به محیط‌های staging یا production، بدون نگرانی از خراب شدن build برنامه، می‌توانید با اطمینان بیشتری کار کنید. توضیحات بیشتر ...

  • از Prettier همراه با یک precommit hook استفاده کنید.

چرا:

اگرچه prettier به‌خودی‌خود قدرتمند است، اجرای دستی آن به‌عنوان یک تسک npm برای قالب‌بندی کد چندان کارآمد نیست. در اینجا lint-stagedhusky) وارد عمل می‌شوند. درباره پیکربندی lint-staged اینجا و پیکربندی husky اینجا بیشتر بخوانید..

8. ثبت وقایع/Logging

Logging

  • از استفاده از console.log در سمت کلاینت در محیط production خودداری کنید.

چرا:

حتی اگر فرآیند build برنامه شما می‌تواند (و باید) آن‌ لاگ‌ها را حذف کند، اطمینان حاصل کنید که ابزار بررسی استایل کدنویسی شما درباره‌ی باقی‌مانده‌های console.log هشدار می‌دهد.

  • برای تولید لاگ‌های خوانا در محیط production، بهتر است از کتابخانه‌های logging مناسب (مانند winston یا node-bunyan) استفاده کنید.

چرا:

این کار عیب‌یابی را آسان‌تر و دلپذیرتر می‌کند، چون می‌توانید از قابلیت‌هایی مانند رنگ‌بندی، افزودن زمان به لاگ‌ها، ثبت لاگ‌ها در فایل علاوه بر کنسول و حتی ثبت لاگ‌ها در فایل‌هایی که به‌صورت روزانه ایجاد و بایگانی می‌شوند، استفاده کنید. توضیحات بیشتر ...

9. ای‌پی‌آی/API

API

9.1 طراحی API

چرا:

هدف این است که رابط‌های RESTfulی طراحی کنیم که منطقی و ساده باشند تا اعضای تیم و مشتریان بتوانند به‌سادگی و به‌صورت یکنواخت از آن‌ها استفاده کنند.

چرا:

نبود هماهنگی و سادگی می‌تواند هزینه‌های یکپارچه‌سازی و نگهداری را به طور چشمگیری افزایش دهد؛ به همین دلیل طراحی API در این داکیومنت گنجانده شده است.

  • ما عمدتاً از طراحی مبتنی بر منابع (Resource-Oriented Design) پیروی می‌کنیم که سه عنصر اصلی دارد: منابع (Resource)، مجموعه‌ها (Collection) و URLها.
    • یک منبع شامل داده‌هایی است که می‌تواند به صورت تو در تو (nested) سازمان‌دهی شود و متدهایی برای عملیات روی آن وجود دارد.
    • گروهی از منابع، یک مجموعه نامیده می‌شود.
    • آدرس اینترنتی (URL) که مکان آنلاین یک منبع یا مجموعه را مشخص می‌کند.

چرا:

این یک طراحی بسیار شناخته‌شده برای توسعه‌دهندگان است (که اصلی‌ترین مصرف‌کنندگان API هستند). علاوه بر خوانایی و سهولت استفاده، این روش به ما اجازه می‌دهد کتابخانه‌ها و connectorهای عمومی بنویسیم بدون این‌که نیاز به شناخت جزئیات خاص هر API داشته باشیم.

  • برای URL‌ها از kebab-case استفاده کنید.
  • برای پارامترهای query string یا فیلدهای منابع از camelCase استفاده کنید.
  • از اسامی جمع به صورت kebab-case برای نام منابع در URLها استفاده کنید.
  • همیشه از اسامی جمع برای نامگذاری URLهایی که به یک مجموعه اشاره دارند استفاده کنید: /users.

چرا:

اساساً، این کار خوانایی را بهتر کرده و URLها را هماهنگ نگه می‌دارد. توضیحات بیشتر ...

  • در سورس کد، اسامی جمع را به متغیرها و پراپرتی‌ها با پسوند «List» تبدیل کنید.

چرا::

استفاده از اسامی جمع در URL مناسب است، اما در سورس کد ممکن است نامحسوس و مستعد خطا باشد.

  • همیشه از مفاهیم مفرد استفاده کنید که با یک مجموعه شروع شده و به یک شناسه ختم می‌شوند:
/students/245743
/airports/kjfk
  • از تولید URLهایی مانند زیر اجتناب کنید:
GET /blogs/:blogId/posts/:postId/summary

چرا:

این URL به جای ارجاع به یک منبع (resource)، به یک ویژگی (property) اشاره می‌کند. شما می‌توانید ویژگی مورد نظر را به‌عنوان یک پارامتر در درخواست ارسال کنید تا پاسخ دریافتی مختصرتر و بهینه‌تر باشد.

  • افعال را از URLهای منابع خود حذف کنید.

چرا:

زیرا اگر برای هر عملیات resource از یک فعل استفاده کنید، به زودی با لیستی بزرگ از URLها مواجه خواهید شد که الگوی ثابتی ندارند و یادگیری را برای توسعه‌دهندگان دشوار می‌کنند. علاوه بر این، ما از افعال برای چیز دیگری استفاده می‌کنیم.

  • از افعال برای موارد غیر منبع (non-resources) استفاده کنید. در این حالت، API شما هیچ منبعی برنمی‌گرداند. در عوض، یک عملیات را اجرا کرده و نتیجه را برمی‌گرداند. این‌ها عملیات CRUD (ایجاد، بازیابی، به‌روزرسانی و حذف) نیستند:
/translate?text=Hallo

چرا:

زیرا برای CRUD ما از متدهای HTTP بر روی URLهای resource یا collection استفاده می‌کنیم. افعالی که درباره آن‌ها صحبت می‌کنیم در واقع کنترلرها Controllers هستند. شما معمولاً تعداد زیادی از این‌ها را توسعه نمی‌دهید. توضیحات بیشتر ...

  • اگر بدنه درخواست (request body) یا پاسخ (response) از نوع JSON است، لطفاً برای نام‌گذاری پراپرتی‌های JSON از camelCase پیروی کنید تا یکپارچگی و سازگاری حفظ شود.

چرا:

این یک راهنما و دستورالعمل برای پروژه JavaScript است، که فرض بر این است که زبان برنامه‌نویسی مورد استفاده برای تولید و تجزیه JSON، جاوااسکریپت می‌باشد.

  • با وجود اینکه یک منبع (resource) مفهومی یکتا و مفرد است که مشابه با یک نمونه شیء یا رکورد پایگاه داده است، شما نباید از نام جدول (table_name) برای نام‌گذاری منبع و از نام ستون (column_name) برای پراپرتی‌های منبع استفاده کنید. به عبارت دیگر، نام‌گذاری منابع و پراپرتی‌های آن‌ها نباید مستقیماً از ساختار پایگاه داده مشتق شود؛ بلکه باید بر اساس مفاهیم و نیازهای دامنه‌ی کاربرد طراحی شود تا از وابستگی به جزئیات پیاده‌سازی جلوگیری شود.

چرا:

زیرا هدف شما نمایش منابع است، نه جزئیات ساختار پایگاه داده.

  • دوباره تکرار می‌کنم، فقط از اسم‌ها در URL خود هنگام نام‌گذاری منابع استفاده کنید و سعی نکنید عملکرد آن‌ها را توضیح دهید.

چرا:

فقط از اسامی در URLهای منبع استفاده کنید و از نوشتن مواردی مانند /addNewUser یا /updateUser خودداری کنید. همچنین از ارسال عملیات منابع به‌عنوان پارامتر اجتناب کنید.

  • عملکردهای CRUD را با استفاده از متدهای HTTP توضیح دهید:

چگونه:

متد GET: برای دریافت از یک resource استفاده می‌شود.

متد POST: برای ایجاد منابع (resources) جدید و زیرمنابع (sub-resources) به کار می‌رود.

متد PUT: برای به‌روزرسانی منابع موجود استفاده می‌شود.

متد PATCH: برای به‌روزرسانی جزئی منابع موجود به کار می‌رود؛ به‌طوری‌که فقط فیلدهای ارائه‌شده را به‌روزرسانی کرده و سایر فیلدها را بدون تغییر باقی می‌گذارد.

متد DELETE: برای حذف منابع موجود استفاده می‌شود.

  • برای منابع تو در تو (Nested Resources)، توصیه می‌شود رابطه بین آن‌ها را در ساختار URL منعکس کنید. به‌عنوان مثال، برای نمایش ارتباط بین یک کارمند و شرکت مربوطه، می‌توانید از شناسه‌ها (id) در URL استفاده کنید.

چرا:

این روش دسترسی به منابع مرتبط را آسان‌تر می‌کند.

چگونه:

درخواست GET /schools/2/students , باید لیست تمام دانش‌آموزان مدرسه با شناسه ۲ را برگرداند.

درخواست GET /schools/2/students/31 , باید جزئیات دانش‌آموز با شناسه ۳۱ را که متعلق به مدرسه ۲ است، برگرداند.

درخواست DELETE /schools/2/students/31 , باید دانش‌آموز با شناسه ۳۱ را که متعلق به مدرسه ۲ است، حذف کند.

درخواست PUT /schools/2/students/31 , باید اطلاعات دانش‌آموز با شناسه ۳۱ را که متعلق به مدرسه ۲ است، به‌روزرسانی کند.

درخواست POST /schools , باید یک مدرسه جدید ایجاد کرده و جزئیات مدرسه تازه ایجاد شده را برگرداند. از POST بر روی URLهای مجموعه‌ای (Collection) استفاده کنید.

  • برای نسخه‌دهی، از یک شماره ترتیبی ساده با پیشوند v استفاده کنید (مانند v1، v2) و آن را تا حد امکان در ابتدای URL قرار دهید تا دامنه بالاتری را (برای تاثیرگذاری) داشته باشد:
http://api.domain.com/v1/schools/3/students

چرا:

وقتی APIهای شما به‌طور عمومی برای سایر اشخاص ثالث در دسترس هستند، اعمال تغییرات ناسازگار (breaking changes)، می‌تواند باعث اختلال در عملکرد محصولات یا خدماتی شود که از APIهای شما استفاده می‌کنند. استفاده از نسخه‌بندی در URL می‌تواند از بروز چنین مشکلاتی جلوگیری کند. توضیحات بیشتر ...

  • پیام‌های پاسخ (Response) باید خودتوضیح‌دهنده باشند، به‌طوری‌که گیرنده بتواند به‌راحتی مفهوم آن‌ها را درک کند. یک پیام خطای مناسب ممکن است شبیه به این باشد:
{
	"code": 1234,
	"message": "Something bad happened",
	"description": "More details"
}

یا برای خطاهای اعتبارسنجی:

{
	"code": 2314,
	"message": "Validation Failed",
	"errors": [
		{
			"code": 1233,
			"field": "email",
			"message": "Invalid email"
		},
		{
			"code": 1234,
			"field": "password",
			"message": "No password provided"
		}
	]
}

چرا:

توسعه‌دهندگان در زمان‌های بحرانی که در حال عیب‌یابی و حل مشکلات پس از انتشار برنامه‌هایی که با استفاده از APIهای شما ساخته‌اند و در دست کاربران قرار گرفته‌اند، به خطاهای خوب و خوش‌طراحی‌شده وابسته هستند.

توجه: پیام‌های استثنا مربوط به امنیت را تا حد ممکن عمومی و ساده نگه دارید. به عنوان مثال، به جای اینکه بنویسید «رمز عبور اشتباه است»، می‌توانید پیام «نام کاربری یا رمز عبور نامعتبر است» را بازگردانید. این کار باعث می‌شود که به‌طور ناخودآگاه به کاربر اطلاع ندهید که نام کاربری درست است و تنها رمز عبور اشتباه است.

  • از این کدهای وضعیت (status codes) برای ارسال همراه با پاسخ‌های خود استفاده کنید تا مشخص کنید آیا همه چیز درست انجام شده است یا خیر، آیا کلاینت اشتباهی انجام داده یا مشکل از API بوده است.

    _کدام یک:_
    > پاسخ `200 OK` نشان‌دهنده موفقیت برای درخواست‌های `GET`, `PUT` یا `POST` است.
    
    > کد `201 Created` برای زمانی است که یک نمونه جدید ایجاد می‌شود. ایجاد یک نمونه جدید با استفاده از متد `POST` کد وضعیت `201` را برمی‌گرداند.
    
    > پاسخ `204 No Content` نشان‌دهنده موفقیت است، اما محتوایی برای ارسال در پاسخ وجود ندارد. از آن در زمانی استفاده کنید که عملیات `DELETE` با موفقیت انجام شده است.
    
    > پاسخ `304 Not Modified` برای به حداقل رساندن انتقال اطلاعات زمانی که گیرنده قبلاً نسخه‌های کش‌شده را دارد، استفاده می‌شود.
    
    > کد `400 Bad Request` برای زمانی است که درخواست پردازش نشده است، زیرا سرور نمی‌تواند بفهمد که مشتری چه چیزی درخواست کرده است.
    
    > کد `401 Unauthorized` برای زمانی است که درخواست فاقد اعتبارنامه‌های معتبر است و باید با اعتبارنامه‌های مورد نیاز دوباره ارسال شود.
    
    > کد `403 Forbidden` به این معنی است که سرور درخواست را فهمیده است، اما از اعطای مجوز خودداری می‌کند.
    
    > کد `404 Not Found` نشان می‌دهد که منبع درخواستی پیدا نشده است.
    
    > کد `500 Internal Server Error` نشان می‌دهد که درخواست معتبر است، اما سرور به دلیل برخی شرایط غیرمنتظره نمی‌تواند آن را انجام دهد.
    
    _چرا:_
    > بیشتر ارائه‌دهندگان API از تعداد کمی از کدهای وضعیت HTTP استفاده می‌کنند. برای مثال، API سرویس Google GData تنها از ۱۰ کد وضعیت، Netflix از ۹ کد، و Digg تنها از ۸ کد وضعیت استفاده می‌کنند. البته، این پاسخ‌ها معمولاً شامل بدنه‌ای هستند که اطلاعات بیشتری را ارائه می‌دهد. در کل، بیش از ۷۰ کد وضعیت HTTP وجود دارد. اما اکثر توسعه‌دهندگان همه این ۷۰ کد را به خاطر ندارند.بنابراین، اگر شما کدهای وضعیتی را انتخاب کنید که خیلی رایج نیستند، توسعه‌دهندگان مجبور می‌شوند به جای ادامه کار روی برنامه خود، وقتشان را صرف جستجو در ویکی‌پدیا کنند تا متوجه شوند شما چه چیزی را سعی دارید به آن‌ها بگویید. [توضیحات بیشتر ...](https://apigee.com/about/blog/technology/restful-api-design-what-about-errors)
    
  • تعداد کل منابع/دیتا را در پاسخ (response) خود اعلام کنید.

  • پارامترهای limit و offset را بپذیرید.

  • مقدار داده‌ای که یک منبع در پاسخ ارائه می‌دهد نیز باید مورد توجه قرار گیرد. مصرف‌کننده API همیشه به تمام اطلاعات مربوط به یک منبع نیاز ندارد. از پارامتر fields استفاده کنید که لیستی از فیلدها را به صورت جدا شده با کاما دریافت می‌کند تا مشخص کند کدام فیلدها در پاسخ گنجانده شوند:

GET /students?fields=id,name,age,class
  • پشتیبانی از صفحه‌بندی (pagination)، فیلتر کردن (filtering) و مرتب‌سازی (sorting) نیازی نیست از ابتدا برای همه منابع (resourceها) فعال باشد. منابعی که این قابلیت را دارند، باید به طور مستند (از طریق Document) مشخص شوند.

9.2 امنیت ای‌پی‌آی/API security

این موارد برخی از بهترین روش‌های امنیتی پایه هستند:

  • از احراز هویت پایه (Basic Authentication) استفاده نکنید، مگر اینکه از یک اتصال امن (HTTPS) استفاده کنید. توکن‌های احراز هویت نباید در URL منتقل شوند: GET /users/123?token=asdf....

چرا:

زیرا توکن یا شناسه کاربری و رمز عبور به صورت متن ساده (clear text) در شبکه ارسال می‌شوند (اگرچه به صورت Base64 کدگذاری شده است، اما Base64 یک کدگذاری برگشت‌پذیر است). بنابراین، روش احراز هویت پایه ایمن نیست. توضیحات بیشتر ...

  • توکن‌ها باید با استفاده از هدر Authorization در هر درخواست منتقل شوند: Authorization: Bearer xxxxxx, Extra yyyyy.
  • کدهای Authorization باید مدت‌زمان کوتاهی معتبر باشند.
  • هرگونه درخواست بدون TLS را رد کنید. به درخواست‌های HTTP (بدون TSL) پاسخ ندهید تا از تبادل داده‌های ناامن جلوگیری شود. اگر پاسخ می‌دهید، از کد وضعیت 403 Forbidden استفاده کنید.
  • استفاده از نرخ محدودیت (Rate Limiting) را در نظر بگیرید.

چرا:

برای حفاظت از API در برابر تهدیدات بات‌هایی که ممکن است هزاران بار در ساعت API شما را فراخوانی می‌کنند. باید محدودیت نرخ (rate limit) را از همان مراحل اولیه پیاده‌سازی مد نظر قرار دهید.

  • تنظیم مناسب هدرهای HTTP می‌تواند به ایمن‌سازی برنامه وب شما کمک کند. توضیحات بیشتر ...
  • API شما باید داده‌های دریافت‌شده را به فرم استانداردشان تبدیل کند یا آن‌ها را رد کند. در صورت وجود داده‌های نادرست یا ناقص، کد وضعیت 400 Bad Request را همراه با جزئیات خطا در پاسخ بازگردانید.
  • تمام داده‌های مبادله‌شده با REST API باید توسط خود API اعتبارسنجی شوند.
  • JSON خود را سریالایز (Serialize) کنید.

چرا:

یکی از نگرانی‌های اصلی کار با JSON، جلوگیری از اجرای کدهای جاوااسکریپت دلخواه از remote در مرورگر است... یا اگر از node.js در سمت سرور استفاده می‌کنید. بسیار مهم و حیاتی است که از یک سریالایزر JSON مناسب استفاده کنید تا داده‌های ورودی کاربر به درستی کدگذاری شوند و از اجرای داده‌های ورودی کاربر در مرورگر جلوگیری شود.

  • نوع محتوا (Content-Type) را اعتبارسنجی کنید و بیشتر از application/*json (هدر Content-Type) استفاده کنید.

چرا:

به عنوان مثال، پذیرش نوع application/x-www-form-urlencoded به مهاجم اجازه می‌دهد یک فرم ایجاد کند و یک درخواست POST ساده ارسال کند. سرور هرگز نباید نوع محتوا (Content-Type) را فرض کند. عدم وجود هدر Content-Type یا وجود یک Content-Type غیرمنتظره باید منجر به رد محتوا توسط سرور با یک پاسخ 4XX شود.

9.3 مستندسازی ای‌پی‌آی/API documentation

  • بخش API Reference را در README.md template برای API پر کنید.
  • روش‌های احراز هویت API را با یک نمونه کد توضیح دهید.
  • ساختار URL (فقط path بدون root URL) را به همراه نوع درخواست (Method) شرح دهید.

برای هر Endpoint، موارد زیر را توضیح دهید:

  • اگر پارامترهای URL وجود دارند، آن‌ها را مطابق با نام ذکر شده در بخش URL مشخص کنید:
Required: id=[integer]
Optional: photo_id=[alphanumeric]
  • اگر نوع درخواست POST است، نمونه‌های کاربردی ارائه دهید. قوانین پارامترهای URL در اینجا نیز اعمال می‌شوند. این بخش را به دو دسته اختیاری و الزامی تقسیم کنید.
  • پاسخ موفقیت‌آمیز (Success Response)، کد وضعیت (Status Code) چه باید باشد و آیا داده‌ای در پاسخ بازگردانده می‌شود یا خیر؟ این اطلاعات زمانی مفید است که کاربران نیاز دارند بدانند چه چیزی از پاسخ دریافت خواهند کرد:
Code: 200
Content: { id : 12 }
  • پاسخ خطا (Error Response)، بیشتر endpointها ممکن است به روش‌های مختلفی شکست بخورند. از دسترسی غیرمجاز گرفته تا پارامترهای اشتباه و غیره. تمامی این موارد باید در این بخش لیست شوند. ممکن است تکراری به نظر برسد، اما از ایجاد فرضیات جلوگیری می‌کند. به عنوان مثال:
{
	"code": 401,
	"message": "Authentication failed",
	"description": "Invalid username or password"
}
  • از ابزارهای طراحی API استفاده کنید؛ ابزارهای متن‌باز زیادی برای مستندسازی خوب وجود دارند، مانند API Blueprint و Swagger.

10. دسترس‌پذیری/Accessibility (a11y)

Accessibility

10.1 پیاده‌سازی روش‌های دسترسی‌پذیری

برای اطمینان از حفظ سطح مشخصی از دسترسی‌پذیری، از ابتدای پروژه خود مراحل زیر را انجام دهید:

چرا:

محتوای وب به‌طور پیش‌فرض دسترسی‌پذیراست. ما این ویژگی را زمانی به خطر می‌اندازیم که امکانات پیچیده ایجاد می‌کنیم. در نظر گرفتن دسترسی‌پذیری از ابتدا بسیار آسان‌تر از بازپیاده‌سازی این ویژگی‌ها در آینده است تا تأثیر آن را کاهش دهیم.

  • با استفاده از ابزارهایی مانند lighthouse برای دسترسی‌پذیری یا افزونه axe DevToolsبرنامه‌ریزی‌هایی را جهت انجام ممیزی‌های منظم انجام دهید. بر اساس نیازهای پروژه خود، بر روی یک امتیاز حداقلی توافق کنید. امتیازدهی در این ابزارها بر اساس ارزیابی تأثیر کاربر در axe می‌باشد.

نکته: برخی بررسی‌های مهم باید به‌صورت دستی انجام شوند، مانند ترتیب منطقی تب‌ها. ابزارهای فوق این موارد را به عنوان تست‌های دستی یا راهنمایی‌شده در کنار نتایج خودکار فهرست می‌کنند. در axe باید نتایج خودکار خود را ذخیره کنید تا این موارد را مشاهده کنید.

چرا:

یک لینتر به‌طور خودکار بررسی می‌کند که سطح پایه‌ای از دسترسی‌پذیری در پروژه شما رعایت شده است و راه‌اندازی آن نسبتاً آسان است.

  • با استفاده از axe-core یا ابزارهای مشابه، تست‌های دسترسی‌پذیری را راه‌اندازی و اجرا کنید.
  • اگر از Storybook استفاده می‌کنید، این راهنما را دنبال کنید.

چرا:

گنجاندن بررسی‌های دسترس‌پذیری در تست‌ها به شما کمک می‌کند تا هر تغییری که بر دسترس‌پذیری پروژه و امتیاز ممیزی تأثیر می‌گذارد، شناسایی کنید.

چرا:

این کامپوننت‌ها به صورت پیش‌فرض از سطح بالایی از دسترس‌پذیری برخوردار هستند.

10.2 برخی از قوانین پایه دسترس‌پذیری که باید به پروژه خود اضافه کنید:

  • اطمینان حاصل کنید که نام لینک‌ها دسترس‌پذیر هستند. از aria-label برای توصیف لینک‌ها استفاده کنید.

چرا:

لینک‌هایی که غیرقابل دسترس می‌باشند، برای دسترس‌پذیری موانعی ایجاد می‌کنند.

  • اطمینان حاصل کنید که لیست‌ها به‌درستی ساختاربندی شده باشند و عناصر لیست به صورت معنایی استفاده شده‌اند.

چرا:

لیست‌ها باید دارای عناصر والد و عناصر فرزند باشند تا معتبر باشند. صفحه‌خوان‌ها (Screen Readers) به کاربران اطلاع می‌دهند که وقتی به یک لیست می‌رسند، لیست شامل چند آیتم است.

  • اطمینان حاصل کنید که ترتیب سرفصل‌ها (Heading Order) از نظر معنایی صحیح است.

چرا:

سرفصل‌ها ساختار صفحه را منتقل می‌کنند. هنگامی که به درستی اعمال شوند، پیمایش صفحه آسان‌تر می‌شود.

  • اطمینان حاصل کنید که عناصر متنی دارای کنتراست کافی با پس‌زمینه‌ی صفحه هستند.

چرا:

برخی افراد با بینایی کم، کنتراست پایین را تجربه می‌کنند؛ به این معنی که تفاوت زیادی بین مناطق روشن و تاریک وجود ندارد. همه چیز تقریباً با همان میزان روشنایی ظاهر می‌شود، که تشخیص خطوط، حاشیه‌ها، لبه‌ها و جزئیات را دشوار می‌کند. متنی که از نظر روشنایی بسیار نزدیک به پس‌زمینه باشد، ممکن است سخت خوانده شود.

  • برای تصاویر، متن جایگزین (Alt Text) ارائه دهید.

چرا:

صفحه‌خوان‌ها نمی‌توانند تصاویر را به کلماتی تبدیل کنند که برای کاربر خوانده شود، حتی اگر تصویر فقط شامل متن باشد. در نتیجه، ضروری است که تصاویر دارای متن جایگزین کوتاه و توصیفی باشند تا کاربران صفحه‌خوان به‌وضوح محتوای تصویر و هدف آن را درک کنند.

قوانین بیشتری درباره دسترس‌پذیری را می‌توانید اینجا پیدا کنید.

11. مجوزدهی/Licensing

Licensing

اطمینان حاصل کنید که از منابعی استفاده می‌کنید که حق استفاده از آن‌ها را دارید. اگر از کتابخانه‌ها استفاده می‌کنید، به مجوزهای MIT، Apache یا BSD توجه کنید، اما اگر این کتابخانه‌ها را تغییر می‌دهید، حتماً جزئیات مجوز را بررسی کنید. استفاده از تصاویر و ویدئوهای دارای حق کپی‌رایت (Copyrighted) ممکن است مشکلات قانونی ایجاد کند.


منابع: RisingStack Engineering, Mozilla Developer Network, Heroku Dev Center, Airbnb/javascript, Atlassian Git tutorials, Apigee, Wishtack

Icons by icons8