کار تیمی (قسمت اول: گیت)

تعدادِ زیادی از توسعه‌دهندگان برای توسعه‌ی محصول خود از سیستم‌های مرتبط با کنترل ورژن استفاده می‌کنند و «گیت» یکی از ابزارهاست که در بین برنامه‌نویسان و سازمان‌ها از محبویتِ خاصی برخوردار است اما صرف استفاده از گیت و توسعه‌یِ کد بر رویِ آن به این معنی نیست که شما در حالِ انجامِ کارِ تیمی هستید و یا اینکه به درستی کارِ تیمی را انجام می‌دهید.

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

فرض کنید شما یک آرایشگر ماهر هستید که از ابزار اشتباهی برایِ کار استفاده می‌کنید، چیزی شبیه به ویدیو زیر:


https://www.aparat.com/v/NzixF


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

پروژه و کلان پروژه

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

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

  • امکان استفاده‌یِ مجدد از هر زیر پروژه‌ای وجود داشته باشد، به عنوان مثال فرض کنید شما برای یک محصول دو پروژه‌ی متفاوت یکی برای کارگزار (server) و یکی برای کارخواه (client) تعریف کرده‌اید که توسط دو تیمِ مستقل توسعه داده می‌شوند، به احتمال زیاد بخشی از هر دو پروژه به صورتِ مشترک در هر دو وجود دارد و اگر مشکلی در این بحش باشد، نیاز است که در هر دو پروژه اصلاحات انجام گیرد، همچنین باید مراقب باشیم که به‌روزرسانی این بخش به شکل همزمان در تمامی پروژه‌ها صورت بگیرد. در ساختارِ کلان پروژه‌ای ما بخشِ مشترک را به عنوانِ یک پروژه‌ی مستقل تعریف و در تمامیِ پروژه‌ها آنرا بازتعریف می‌کنیم، در حقیقت اشاره‌گری به شاخه‌یِ (branch) موردِ نظر از آن پروژه را در گیت قرار می‌دهیم، حال با هر تغیری در submodule تغییرات به شکل همزمان و خودکار در تمامی‌ِ پروژه‌ها اعمال می‌شود، تصویر زیر می‌تواند تا حدی این موضوع را به شکل نمادین بیان کند.
نمایی از کلان پروژه
نمایی از کلان پروژه


  • درخواست‌ها و گزارشات اشکال مجتمع باشند، در مثال فوق تصور کنید یک مشکل حیاتی در پروژه‌ی common گزارش شده و نیاز است به سرعت این مشکل مرتفع شود، گزارش اشکال در هر دو پروژه‌یِ client و server قابل دسترسی است و هر تیمی که اقدام به رفع مشکل کنید، مشکل در تمامیِ پروژه‌ها حل می‌شود. همچنین درخواست‌ها به شکل مجتمعی قابل دسترسی است، اگر درخواستی برای پروژه‌ی common ارسال شود، تمامیِ اعضا در دو تیم می‌توانند درخواست را بررسی کنند و نظراتِ خود را در موردِ آن مطرح کنند.

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

راهبردِ گیت

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

  • شاخه‌ی master: این شاخه شامل آخرین نسخه از کد می‌باشد که بدون مشکل در محیطِ عملیاتی قابلِ استفاده است. این شاخه دارایِ نسخه‌گذاری استاندارد می‌باشد، tag گذاری شده و تا زمان انتشار بعدی هیچ ادغامی در این شاخه انجام نمی‌شود. ادغام در این شاخه فقط از شاخه‌های Hot fix و Release و توسط مدیر پروژه امکان پذیر است.
اگر شما در حال کار بر رویِ یک پروژه‌ی متن باز هستید و بستر توسعه‌یِ شما یک پروژه‌ی دیگر است می‌توانید پروژه‌ی اصلی را در داخل شاخه‌یِ master قرار دهید و تنها زمانی این شاخه به روز می‌شود که شما قصد دارید آخرین تغییرات را از سرچشمه (upstream) دریافت کنید
  • شاخه‌ی dev: این شاخه بعد از کامل شدنِ هر ویژگی (feature) به‌روز می‌شود، کد قرار گرفته شده در این شاخه باید بدون مشکل باشد، عملیات مربوط به بازبینی کد، آزمون‌های خودکار و ... قبل از ادغام رویِ کد اعمال شده باشد و در هر زمان بتوان بطور مستقل پروژه‌ را از این شاخه اجرا کرد. ادغام در این شاخه تنها از طریق شاخه‌ی feature صورت می‌گیرد (برای اطلاع از نحوه‌ی ادغام به قسمت «اعمال و ارسال تغییرات» از همین مستند مراجعه کنید)
  • شاخه‌ی feature: هر ویژگی جدیدی که قرار هست به پروژه اضافه شود در یک شاخه‌یِ موقت ایجاد شده و در همان شاخه توسعه داده می‌شود، این شاخه به شکل feature_X نامگذاری می‌شود که X در حقیقت عنوان ویژگی است. به عنوان مثال feature_user نشان دهنده‌ی اضافه شدنِ کاربر به سیستم است، هر شاخه برای یک ویژگی ایجاد می‌شود و تنها فقط شامل یک ویژگی است و نه بیشتر، پس از اتمام ویژگی درخواست ادغام توسط توسعه‌دهنده از این شاخه به شاخه‌ی dev ارسال و پس از طی شدن روال‌های ادغام، ادغام بر روی شاخه‌ی dev انجام شده و این شاخه حذف می‌گردد.
  • شاخه‌ی Hot-Fix: این شاخه تنها از مسیر master در دسترس است و برای مشکلات حیاتی بعد از انتشار نسخه‌ی پایدار استفاده می‌شود، در زمانی که نسخه‌ی منتخب برای انتشار و یا نسخه‌ی منتشر شده دارای یک اشکالِ حیاتی باشد، توسعه دهنده یک شاخه از کد ایجاد و با عنوان hotfix-X مشخص می‌کند که این رفع اشکال مربوط به چه چیزی بوده و سپس درخواست ادغام را برای نسخه‌ی منتخب یا نسخه‌ی منتشر شده ارسال می‌کند.(این درخواست باید خارج از نوبت و در اسرعِ وقت روال‌های بررسی قبل از ادغام را طی کند)
  • شاخه‌ی Release: این شاخه حدِ فاصلِ بینِ شاخه‌ی توسعه و شاخه‌یِ اصلی می‌باشد، این شاخه حاوی کدهای عملیاتی است که شاملِ ویژگی‌های زیادی بوده و قابلیتِ انتشار به عنوانِ نسخه‌ی پایدار را دارند ولی قبل از انتشار نیاز است تا آزمون‌های کارایی و عملکرد بر روی آنها به طور کامل اعمال شود، در این مرحله ممکن است خطاهایی در عملکرد و یا کارایی توست تیم آزمون گزارش شوند و این مشکلات در قالب یک شاخه‌یِ موقت به عنوان bugfix حل و در شاخه‌یِ release مجددا ادغام می‌شوند.


نمایی از شاخه‌های مختلف در یک پروژه
نمایی از شاخه‌های مختلف در یک پروژه


برای اطلاع بیشتر می‌توانید از ابزار «git-flow» استفاده کنید و همچنین این راهنما را بخوانید.

اعمال و ارسال تغییرات

خب تا اینجایِ کار پروژه با ساختارِ مناسب ایجاد شده و فرایند توسعه در ساختارِ تعریف شده انجام می‌شود، در این قسمت لازم است تا ساختاری برای «ارسال تغییرات» و روالی برای «اعمال تغییرات» تعیین شود. این ساختار و روال در ابتدا توسط تیم توسعه تعیین شده و در تمامیِ طولِ پروژه نیاز است تا مواردِ تعیین شده توسطِ تمامی اعضا به طورِ کامل رعایت شوند.

ساختار و قوانین مربوط به ارسالِ تغییرات

هر درخواستِ تغییر باید توسط یکی از اعضایِ تیمِ توسعه ارسال شود و رعایت تمامیِ مواردِ زیر برایِ تمامی درخواست‌ها الزامی می‌باشد:

۱ - نام شاخه‌ی مربوط به درخواست باید از قواعدِ تیم پیروی کند، به عنوان مثال در قالبِ X-Y باشد، که X نشان دهنده‌یِ نوع درخواست می‌باشد و Y نشان دهنده‌یِ توضیحاتِ مربوطه که نوع درخواست می‌تواند feature، hotfix و یا bugfix باشد.

۲ - به ازایِ هر درخواست حتما و حداقل یک issue ثبت شده وجود داشته باشد، در صورتی که هیچ موردی ثبت نشده، نیاز است تا توسعه دهنده یک issue ایجاد کرده و دلایل خود را برای ارسال تغییرات در پروژه در آن به طور کامل بیان کند، همچنین این issue باید شامل روندهایی برای اعتبارسنجی صحت تغییرات باشد.

۳ - عنوانِ درخواست باید مطابق با issue ثبت شده‌یِ مرتبط با تغییرات باشد، همچنین اگر تغییرات هنوز آماده‌یِ ارسال نیست، توسعه دهنده «باید» عبارتِ WIP را قبل از عنوانِ درخواست درج کند.

۴ - درخواست تنها زمانی باید ارسال شود که تمامیِ روندهایِ مربوط به اعتبارسنجی حداقل یکبار توسط توسعه‌دهنده طی شده باشد، درخواستِ ارسالی حتما باید قابلیت اجرا داشته باشد و در روندِ اجرایِ پروژه خللی ایجاد نکند و شخص توسعه‌دهنده قبل از درخواست موظف است تا از صحتِ این موارد اطمینان پیدا کند.

۵ - در هنگامِ ارسالِ درخواست، اعضایِ تیمِ توسعه برایِ بازبینیِ کد مخاطب قرار می‌گیرند. توصیه می‌شود در گامِ اول اعضایی مخاطب قرار گیرند که آشنایی بیشتری با تغییراتِ اعمال شده دارند و سپس بعد از بررسیِ اولیه، سایرِ اعضا مخاطب قرار گیرند.

۶ - در متنِ درخواست، توسعه‌دهنده باید قالبِ کلیِ درخواست را که توسطِ تیم قبلا تهیه شده را رعایت کند. پیشنهاد می‌شود قالب شاملِ توضیحاتی مربوط به تغییراتِ انجام شده به زبانِ فارسی باشد و شماره‌یِ issue هایِ مرتبط و درخواست‌هایِ مرتبط با این درخواست در متن اشاره شود و پیوند‌هایی به این درخواست‌ها و issue ها قرار گیرد.

۷ - درخواستِ ارسالی باید بر رویِ شاخه‌یِ درست ارسال شود، در غیرِ اینصورت درخواست باید در اولین فرصت توسط مدیرِ پروژه بسته شده و توسعه‌دهنده درخواست مجدد را بر رویِ شاخه‌یِ درست ارسال کند.

۸ - متن، توضیحات، عنوان و سایر قسمت‌هایِ درخواست‌ها و نظرات، توسط هیچ یک از اعضا در هیچ زمانی نباید تغییر داده شود و در صورت نیاز به تصحیح می‌توان درخواست را حذف و یا در قالب نظرِ جدید مواردِ اصلاحی را گزارش داد.

۹ - هر فرد مسئولِ مستقیمِ درخواست‌هایِ ارسال شده از طرف خودش است، به این معنی که فردِ درخواست کننده موظف است درخواست را تا تعیین وضعیت پیگیری کند، به تمامی بحث‌هایِ مرتبط به درخواست در زمانِ مشخص پاسخ داده و در پایانِ زمانِ تعیین شده (مثلا ده روز از زمانِ ارسالِ درخواست) وضعیت درخواست را از «درخواستِ باز» به یکی از حالت‌هایِ «درخواستِ بسته شده»، «درخواستِ آماده‌یِ ادغام» و یا «درخواستِ در حالِ تغییر (WIP) » درآورده و این موضوع را به اطلاعِ مدیر پروژه برساند در غیرِ اینصورت مدیرِ پروژه می‌تواند راسا نسبت به تغییر وضعیتِ درخواست اقدام کند.

۱۰- فردِ درخواست دهنده پس از پاسخ دهی به تمامیِ ابهامات و سوالات و اطمینان از صحتِ عملکردِ تغییرات (منطبق بر روندِ اعتبار سنجیِ مطرح شده در issue مرتبط)، مدیرِ پروژه را از آمادگیِ اعمال تغییرات مطلع می‌کند.

۱۱- در صورتی که ابهامات و سوالات و یا بررسیِ اعضا از زمانِ معین شده بیشتر شد، شخصِ درخواست دهنده می‌تواند مستقیما درخواستِ جلسه‌یِ حضوری و یا بر خط داده و اعضایِ تیمِ توسعه در موردِ تغییرات در جلسه‌یِ مذکور تصمیم‌گیری نمایند.

۱۲- بر هر فردی از اعضا در هر جایگاه و درجه‌یِ علمی واجب است که در تمامیِ بحث‌ها و نظرات جانبِ ادب را رعایت کرده و صرفا بر اساسِ شواهد و مدارکِ علمی و فنی و تنها پیرامونِ تغییراتِ مطرح شده صحبت کنند.

۱۳- هر درخواستِ تغییر صرفا باید شاملِ رفعِ یک مشکل و یا افزودنِ یک ویژگی باشد، ارسالِ چندین تغییرات و یا تغییراتِ زیاد در قالبِ یک درخواست موردِ قبول نیست و این مورد بدونِ بررسی باید توسطِ مدیرِ پروژه بسته شده و شخص در خواست‌هایِ خود را در قالب چند درخواستِ مجزا مجددا ارسال نماید.

۱۴- اولین در خواست به عنوان (init) شناخته می‌شود، این درخواست که شالوده و محور اصلی پروژه می‌باشد باید از تمامیِ قواعدِ فوق پیروی کند و ارسال یک درخواست با حجمِ بالایِ تغییرات به عنوانِ درخواست init زمانی مجاز است که این قسمت از تغییرات، انشعابی از یک پروژه‌یِ دیگر باشد و مسولیت آن با شخصِ درخواست دهنده خواهد بود.

۱۵- توسعه دهنده موظف است تا تغییرات را به شکلِ کامل در قالبِ ویکی مستند کرده و مستندات را با دیگران به اشتراک بگذارد. این مستندات شاملِ مستندسازیِ کد و همچنین توضیحاتِ مربوط به عملکرد کلیِ تغییرات می‌باشد. (این بخش می‌تواند به قالبِ درخواست اضافه شود)

۱۶- توسعه دهنده موظف است همراه با ارسالِ تغییرات، آزمون‌هایِ لازم را منطبق بر نیازمندی‌ها و استاندارهایِ تعیین شده توسطِ تیم تهیه کرده و گزارشِ مربوط به خروجیِ آزمون‌ها را نیز در اختیارِ سایرِ اعضا قرار دهد. (این بخش می‌تواند به قالبِ درخواست اضافه شود)


نکته: هیچ توسعه دهنده‌ای نباید در زمانِ ترکِ محیطِ کار، کدِ ارسال نشده‌ای داشته باشد، نیازی نیست درخواست برای تیم ارسال شود ولی توسعه دهنده باید همیشه آخرین تغییرات را در گیت قرار دهد

ساختار و قوانین مربوط به اعمالِ تغییرات

۱ - برایِ اعمالِ تغییرات نیاز است تا تغییرات توسط تعدادِ تمامیِ توسعه‌دهنده‌گان بازبینی شده و تعدادِ مشخصی از افراد صحتِ تغییرات را با «لایک» یا «approve» و یا هر روشِ دیگری تایید کنند.

۲ - درصورتی که تنها و تنها یک نفر از توسعه‌دهنده‌گان به هر دلیلی تغییراتِ ارسالی را نادرست بداند و این موضوع را به شکلی به اطلاعِ عموم برساند، تا زمانِ رفع ابهام تغییرات به هیچ عنوان اعمال نخواهد شد.

۳- در صورتی که هر یک از روندهایِ اعتبار سنجیِ « دستی و یا ماشینی» و آزمون‌هایِ مربوطه با خطا یا اشکال مواجه شود، عملیات ادغام متوقف شده و وضعیت درخواست به «بسته شده» یا در «حالِ تغییر» درخواهد آمد و گزارشِ اشکال در قالبِ نظرات به درخواست اضافه خواهد شد.

۴- در صورتی که با اعمالِ یک تغییر، سایرِ درخواست‌ها دچارِ ناسازگاری (conflict) شود، روندِ ادغامِ درخواست‌های ناسازگار متوقف خواهد شد و شخصِ درخواست کننده موظف است در اسرع وقت نسبت به رفع ناسازگاری اقدام کند. (به همین دلیل پیشنهاد می‌شود توسعه‌دهنده‌گان درخواست‌هایی را که می‌توانند ایجادِ ناسازگاری کنند را در اولویتِ بررسی قرار دهند)

۵- تمامیِ صحبت‌ها (discussion) عموما توسط درخواست کننده پاسخ داده شود، فردِ سوال کننده می‌تواند پس از دریافتِ جوابِ مطلوب این صحبت را حل شده قلمداد کند (برایِ اینکار باید حتما دگمه‌یِ resolve را برایِ صحبتِ موردِ نظر فشار دهد). شخصِ پاسخ‌دهنده اجازه‌یِ حل کردنِ هیچ صحبتی را بدونِ هماهنگی با مدیر پروژه و یا شحص سوال‌کننده نخواهد داشت و فرایند ادغام زمانی ممکن است که هیچ صحبتِ حل نشده‌ای باقی نمانده باشد.


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


بهتر است قبل از اینکه ادامه دهید، این پست را بخوانید.

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

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