Clean Commit

امروز قراره واژه ی جدیدی رو ابداع کنیم. دو مرد بزرگ یکی از قاره ی سبز و دیگری از آمریکا, یکی خالق Git و دیگری خالق واژه ی Clean, امروز به ما کمک میکنن تا واژه ی جدیدمون رو به دنیا معرفی کنیم.

Robert C. Martin, عموی 70 ساله و دوست داشتنی برنامه نویس ها, متولد سال 1952 در آمریکا و خالق فرهنگ Clean با مجموعه اثار شگفت انگیز خودش, در کنار Linus Benedict Torvalds, مرد 53 ساله ی فنلاندی و خالق Git, نقش مهمی رو در انگیزه ی شکل گیری داستان امروزمون ایفا میکنن.

من و تو خیلی خوب Git رو میشناسیم و ازش استفاده میکنیم. یه تیکه کد مینویسیم و میبریمش به حالت stage و بعد commit اش میکنیم و بعدش احتمالن push اش میکنیم و … .

از طرفی احتمالن تا حالا وازه ی Clean Code به گوشت خورده. ما سعی میکنیم کدهامون رو پیوسته و پیوسته Clean کنیم تا برای خودمون و البته بقیه قابل فهم تر باشن. Clean Code و رعایت اصول نوشتن کد Clean, بیشتر از همه وقتی که وارد یک تیم میشی و قراره با بقیه کار کنی خودش رو نشون میده. اگر هر کسی توی یه تیم بخواد با میل و اصول شخصی خودش کد بزنه, سنگ روی سنگ بند نمیشه و اعضای تیم نمیتونن به خوبی با همدیگه ارتباط برقرار کنن. فراموش نکن ابزار ارتباط اعضای مختلف یه تیم با هم دیگه, کدهایی هست که مینویسن و این کدها باید طبق اصول خاصی نوشته شده باشه, به گونه ای که همه بتونن اون اصول رو درک و باهاش کنار بیان. در غیر این صورت پروژه به قهقرا میره.

حالا مخصوصن وقتی که روی پروژه ی تیمی کار میکنی, علاوه بر سعی در Clean کردن پیوسته کدها, یه چیز دیگه خیلی خیلی خودش رو نشون میده. تو پیوسته کد میزنی و اون ها رو commit میکنی و میفرستی روی git و دوستات یا همکار هات با دیدن commit هات باید خیلی خوب و سریع بتونن بفهمن که اون commit چیه و برای چه هدفی زده شده و کدوم بخش از کد رو مورد اصابت قرار داده و قراره چکار کنه.

پس باید یه اصولی رو برای نوشتن commit هامون داشته باشیم. ما باید Commit های Clean بنویسیم و اگه در اینده یه Commit خوشگل تر پیدا کردیم و میتونستیم Commit قبلی رو بهترش کنیم, برگردیم و ویرایش بزنیم. همون طور که بارها و بارها میزنیم توی سر کدهامون و بهتر و بهتر ترش میکنیم.

پس توی این مقاله ی جذاب میخوایم یه سری قوانین که برای نوشتن Commit های خوب و تو دل برو هست رو از جاهای مختلف گردآوری کنیم و با هم قرار بگذاریم که از الان به بعد بهشون پایبند باشیم. اسمش رو هم میگذرایم Clean Commit.

پ.ن: جایی که من خیلی دیدم به این قوانین پایبند هستن توی Community انگولار بوده.

ساختار Commit

برای داشتن یه Clean Commit میتونیم از ساختار زیر استفاده کنیم:

همچنین ساختار ساده تر و البته خیلی مرسوم و در اکثر مواقع کار راه بنداز به صورت زیر هست:

اگه به ساختار ساده شده ی بالا نگاه کنی میتونی موراد زیر رو داخلش ببینی:

  • type
  • scope
  • subject

پ.ن: حواست باشه حتمن به اسپیس ها و خط های خالی توجه کنی.

type

میتونی به صورت قراردادی توی پروژه ای که داری انجام میدی type های مختلفی رو مشخص کنی. حالا با هم یه سری type ها که خیلی مرسوم هست رو میبینیم:

وقتی یه امکان جدیدی رو به کدت اضافه کردیfeat(feature)
وقتی داکیومنت تغییر کرده یا داکیومنت جدید نوشتی (مثلن کامنت نوشتی)docs
وقتی یه باگی رو فیکس کردیfix
یه کدی رو تغییر دادی که نه ویژگی جدید اضافه شده و نه باکی فیکس شده (مثلن کدت رو Clean تر کردی, یا اسم یه فانکشن رو تغییر دادی یا به هر طریقی بهبودش دادی)refactor
کد ها رو فرمت کردی
مثلا خطهای اضافه رو پاک کردی, اسپیس ها رو درست کردی که فقط کدها قشنگتر به نظر بیان
style
یه تست جدید نوشتیtest
کارهایی مثل اضافه کردن یه دپندنسی یا ویراش فایل pubspec( توی پروژه های دارت) و … که تغییری توی کدها ایجاد نمیکننchore

پ.ن: حتمن توجه کن که باید از حروف کوچیک استفاده کنی. لازم نکرده که ابتکار عمل به خرج بدی و حرف اول رو بزرگ بنویسی.

پ.ن: میتونی type های دیگه رو به پروژه ی خودت اضافه کنی و بین خودت و هم تیمی هات قرارداد کنی.

پ.ن: type الزامی هست و حتمن حتمن حتمن باید توی commit باشه.

نتیجه:

اگه جدول بالا رو نگاه کنی کاملن متوجه میشی که توی همین اولین قدم چقد به هدفمند شدن Commit هامون کمک کردیم. متوجه نشدی؟ پس توضیحات زیر رو بخون….

آقا مثلن اگه توی یه فایلی یه کدی رو refactor کردی و اسم یه فانکشن رو تغییر دادی و توی یه فایل دیگه یه سری خط اضافه و اسپیس رو پاک کردی, نمیای هر دو رو با هم commit کنی. هر کدوم رو جدا جدا میبری رو stage و جدا جدا commit میکنی. اولی که مربوط به تغییر اسم یه فانکشن بوده رو با type مخصوص خودش یعنی refactor و دومی رو هم که صرفت فرمت کردن کدها و پاک کردن یه سری خط اضافه بوده رو با type مختص خودش یعنی style کامیت میکنی.

یا اگه یه جایی یه باگی رو برطرف کردی و یه جای دیگه یه کدی رو ریفکتور کردی, جفتش رو با یه commit رد نمیکنی بره. اولی رو با fix و دومی رو با refactor به خدمتش میرسی.

یا اگه فایل Change Log پروژت رو تغییر دادی و همزمان یه ویژگی جدید هم به کدت اضافه کرده بودی, مثل بچه های خنگ هر دو رو باهم commit نمیکنی. تغییرات فایل Change Log رو با doc و ویژگی جدید رو با feat یا feature کامیت میکنی.

حالا بیا و از زاویه دید کسی که داره به پروژه نگاه میکنه و مثلن گیت هاب یا گیت لب رو باز کرده و لیست کامیت ها رو نگاه میکنه به داستان نگاه کن.

خیلی راحت با دیدن type دو زاریش میوفته که این commit برای چه کاریه.

مثلن اگه type اش style بود میدونه که چیز خیلی مهمی نیست و میتونه ردش کنه و وقت نذاره برای بررسی کردنش.

یا اگه type اش feat بود یا test بود میدونه که این یه commit اساسی هست و باید 4 چشمی حواسش رو جمع کنه.

فرض کن type رو مشخص نکرده باشی. یعنی چی که مشخص نکرده باشی؟ 😡😡😡 اصن فرضش هم حرامه. گناه کبیرس. اقا… خانم… به فکر خودت نیستی به فکر اون بدبختی باش که میخواد بخونه. اصن نمیتونه بفهمه هدف commit چیه؟ داره چکار میکنه؟ مهم هست یا نه؟ میتونه ردش کنه یا نه؟

دیگه بیشتر توضیح نمیدم 😝.

scope

این بخش اختیاری هست و بستگی به پروژت داره که ازش استفاده کنی یا نه.

اگه نیازی به scope نداشتی که بلافاصله بعد از type یه : میگذاری,

اگه هم بهش نیاز داشتی, جلوی type یه پرانتز باز میکنی و scope مورد نظر رو مشخص میکنی و پرانتز رو میبندی و بلافاصله یه : میگذاری,

پ.ن: باز هم تاکید میکنم که اینجا هم باید همه حروف رو کوچیک بنویسی.

مثال:

اگه ریپوزیتوری Bloc (یه پکیج برای زبان دارت و فریمورک هاش) رو نگاه کنی میبینی که خودش از بخش های مختلف تشکیل شده:

یه ریپوزیتوری اصلی داره و داخلش پکیج های مختلف رو قرار داده. مثلن:

  • bloc
  • flutter_bloc
  • bloc_test

حالا اگه نگاهی به لیست commit ها بندازیم:

میبینی که از همین ها برای مشخص کردن scope های مختلف استفاده کرده. مثلن:

  • وقتی داره داخل پکیج Flutter Bloc کد میزنه از flutter_bloc برای scope استفاده میکنه.
  • یا وقتی داره داخل Bloc Test کد میزنه از bloc_test برای scope استفاده میکنه و…

به عنوان یه مثال دیگه پروزه ی
tdd_data_structures_and_algorithms رو که روی گیتهاب خودم هست رو میتونی ببینی:

https://github.com/mohammadtaherri/tdd_data_structures_and_algorithms

توی این پروژه سعی کردم یه سری از Data Structure ها رو با روش TDD و با زبان دارت بنویسیم و از پکیج dartunit هم برای نوشتن یونیت تست ها استفاده شده.

همون طور که میبینی این پروژه بخش های مختلفی داره و هر Data Structure رو توی یه پروژه ی جدا قرار دادم:

حالا از همین ها هم برای مشخص کردن scope های مختلف استفاده کردم:

البته خیلی جاها هم ممکنه نیاز نباشه که ازش استفاده کنی و سعی نکن که الکی توی commit هات بچپونیش. برای خوشکلی کاری رو انجام نمیدیم بلکه هدفمون خوانایی و Clean بودنه. برای نمونه توی پروژه ی dartunit که یه پکیج برای زبان دارت هست و بهت کمک میکنه که شبیه به JUnit یونیت تست هات رو بنویسی, من نیازی ندیدم که از scope استفاده کنم:

https://github.com/mohammadtaherri/dartunit

subject

به نظر من اگه دو بخش قبلی رو به خوبی انجام بدی, تا حد زیادی به سمت یه commit آدمیزادی (منظورم Clean عه) حرکت کردی.

اما توی subject که الزامی هم هست باید با یه جمله ی کوتاه (تاکید میکنم کوتاه…انشا ننویس خواهشن) commit مورد نظر رو شرح بدی.

این جمله باید حتمن:

  • زمان حال ساده باشه.
  • امری باشه.
  • با حروف کوچک شروع بشه (حروف کوچک 😡)
  • و تهش نقطه نباشه.

✅update something
❌Update something
❌update something.
❌updated something
❌something is updated
❌something was updated
❌something has been updated

هر موقع احساس کردی که میتونی یه توضیح بهتر نسبت به قبل برای commit ات داشته باشی میتونی commit قبلی رو edit کنی.

امیدوارم لذت برده باشی.

این مقاله در آینده بروز رسانی میشه.

منابع

https://www.conventionalcommits.org/en/v1.0.0/

گیتهاب انگولار

گیتهاب پکیج بلاک

برچسب ها :

دیدگاهتان را بنویسید

error: Alert: Content is protected !!