4.26 ساختار پروژه

4.26 ساختار پروژه

4.26.1 نمای کلی project-layout #

این متن یک طرح اساسی برای پروژه‌های برنامه‌نویسی به زبان Go است. توجه داشته باشید که این طرح از نظر محتوا ساده است، زیرا فقط روی layout کلی تمرکز دارد و نه آنچه در داخل آن قرار دارد. همچنین ساده است هر چند که از نظر محتوی پیشرفته است ولی به جزئیات زیادی در مورد نحوه ساختاردهی بیشتر پروژه شما نمی‌پردازد. برای مثال، سعی نمی‌کند ساختار پروژه‌ای را با چیزی مانند Clean Architecture پوشش دهد. برای بررسی نمونه کدهای مشابه و مرجع این متن به این لینک مراجعه کنید. این یک استاندارد رسمی تعریف شده توسط تیم توسعه اصلی Go نیست. این مجموعه‌ای از الگوهای layout پروژه‌های رایج با سابقه و نوظهور در اکوسیستم Go است. برخی از این الگوها از بقیه محبوب‌تر هستند. همچنین دارای تعدادی بهبود کوچک همراه با چندین دایرکتوری پشتیبانی مشترک در هر برنامه واقعی به اندازه کافی بزرگ است. توجه داشته باشید که تیم اصلی Go مجموعه خوبی از دستورالعمل‌های عمومی در مورد ساختاردهی پروژه‌های Go و معنای آن برای پروژه شما هنگام وارد شدن و نصب آن ارائه می‌دهد. برای اطلاعات بیشتر، به صفحه Organizing a Go module در اسناد رسمی Go مراجعه کنید. این صفحه شامل الگوهای دایرکتوری داخلی و cmd (که در زیر توضیح داده شده است) و سایر اطلاعات مفید است. اگر در حال یادگیری Go هستید یا یک PoC یا یک پروژه ساده برای خودتان می‌سازید، این طرح پروژه بیش از حد پیچیده است. در عوض، با چیزی بسیار ساده شروع کنید (یک فایل main.go و go.mod بیش از اندازه کافی است). با پیشرفت پروژه، به خاطر داشته باشید که ساختاردهی مناسب کد شما بسیار مهم خواهد بود، در غیر این صورت در نهایت با یک کد نامرتب با وابستگی‌های پنهان (hidden dependencies) و global state زیادی مواجه خواهید شد. وقتی افراد بیشتری روی پروژه کار می‌کنند، به ساختار بیشتری نیاز خواهید داشت. در این زمان است که معرفی یک روش مشترک برای مدیریت بسته‌ها/کتابخانه‌ها اهمیت دارد. وقتی یک پروژه متن‌باز دارید یا می‌دانید که پروژه‌های دیگر کد را از مخزن پروژه شما وارد می‌کنند، آن زمان است که داشتن بسته‌ها و کدهای خصوصی (معادل internal) اهمیت دارد. repository را کپی کنید، آنچه را که نیاز دارید نگه دارید و بقیه را حذف کنید! فقط به این دلیل که وجود دارد، به این معنی نیست که باید از همه آن استفاده کنید. هیچ یک از این الگوها در هر پروژه‌ای استفاده نمی‌شوند. حتی الگوی vendor نیز universal نیست. با آمدن Go 1.14 در نهایت Go Modules برای production آماده شدند. از Go Modules استفاده کنید، مگر اینکه دلیل خاصی برای استفاده نکردن از آن‌ها داشته باشید و اگر اینطور است، نیازی به نگرانی در مورد $GOPATH و جایی که پروژه خود را قرار می‌دهید ندارید. فایل go.mod پایه در مخزن فرض می‌کند که پروژه شما در GitHub میزبانی می‌شود، اما این یک الزام نیست. module path می‌تواند هر چیزی باشد، اگرچه اولین جزء module path باید یک نقطه در نام خود داشته باشد (نسخه فعلی Go دیگر آن را اجباری نمی‌کند، اما اگر از نسخه‌های کمی قدیمی‌تر استفاده می‌کنید، تعجب نکنید اگر ساخت‌های شما بدون آن شکست بخورد). اگر می‌خواهید درباره آن بیشتر بدانید، به Issues 37554 و 32819مراجعه کنید. این طرح پروژه عمداً عمومی است و سعی نمی‌کند یک ساختار پکیج Go خاص را تحمیل کند. این یک تلاش مشترک است. اگر الگوی جدیدی مشاهده کردید یا فکر می‌کنید یکی از الگوهای موجود نیاز به به‌روزرسانی دارد، یک issue را باز کنید. اگر به کمک در مورد نام‌گذاری، قالب‌بندی و style نیاز دارید، ابتدا gofmt و staticcheck را اجرا کنید. linter استاندارد قبلی، golint، اکنون منسوخ شده است و نگهداری نمی‌شود؛ استفاده از یک linter در حال توسعه و نگهداری شده مانند staticcheck توصیه می‌شود. همچنین مطمئن شوید که این دستورالعمل‌ها و توصیه‌های Go code style را بخوانید:

4.25.2 دایرکتوری‌ها در Go #

/cmd #

این دایرکتوری شامل برنامه‌های اصلی پروژه شما است. نام هر دایرکتوری فرعی باید با نام برنامه اجرایی مطابقت داشته باشد (برای مثال، /cmd/myapp). از قرار دادن حجم کد زیاد در دایرکتوری برنامه خودداری کنید. اگر فکر می‌کنید این کد‌ها قابلیت وارد شدن و استفاده در پروژه‌های دیگر را دارد، باید در دایرکتوری /pkg قرار گیرد. اگر کد قابل استفاده مجدد نیست یا نمی‌خواهید دیگران از آن استفاده مجدد کنند، آن کد را در دایرکتوری /internal قرار دهید. تعجب خواهید کرد که دیگران چه کارهایی انجام می‌دهند، بنابراین در مورد اهداف خود صریح باشید! معمولاً یک تابع اصلی کوچک وجود دارد که کد را از دایرکتوری‌های /internal و /pkg وارد کرده و فراخوانی می‌کند و کار دیگری انجام نمی‌دهد. به‌عنوان‌مثال به دایرکتوری /cmd مراجعه کنید.

/internal #

شامل کد Private application و library code است. این کدی است که نمی‌خواهید دیگران آن را در برنامه‌ها یا کتابخانه‌های خود وارد کنند. توجه داشته باشید که این الگوی چیدمان توسط خود کامپایلر Go اعمال می‌شود. برای جزئیات بیشتر، Go 1.4 release notesرا ببینید. توجه داشته باشید که شما به دایرکتوری internal سطح بالا محدود نیستید. شما می‌توانید در هر سطحی از درخت پروژه خود بیش از یک دایرکتوری internal داشته باشید. به‌صورت اختیاری می‌توانید برای جدا کردن کد داخلی مشترک و غیرمشترک خود، کمی ساختار اضافی به بسته‌های داخلی (internal packages) خود اضافه کنید. این کار الزامی نیست (به ویژه برای پروژه‌های کوچک‌تر)، اما داشتن نشانه‌های بصری برای نشان دادن نحوه استفاده موردنظر package بسیار مناسب است. کد application واقعی شما می‌تواند در دایرکتوری /internal/app (مثلاً /internal/app/myapp) و کد مشترک بین آن برنامه‌ها در دایرکتوری /internal/pkg/ (مثلاً , /internal/pkg/myprivlib) قرار گیرد. شما از دایرکتوری‌های internal برای private کردن package‌ها استفاده می‌کنید. اگر یک package را داخل یک internal directory قرار دهید، بسته‌های دیگر نمی‌توانند آن را وارد کنند مگر اینکه یک جد مشترک (common ancestor) داشته باشند. این تنها دایرکتوری‌ای است که در مستندات Go نام برده شده و نحوه برخورد با آن توسط کامپایلر Go خاص و متفاوت است.

/pkg #

کد کتابخانه که امکان استفاده توسط برنامه‌های خارجی را دارد (به‌عنوان مثال، /pkg/mypubliclib). سایر پروژه‌ها این کتابخانه‌ها را import می‌کنند و انتظار کارکرد درست آنها را دارند، بنابراین قبل از قرار دادن چیزی در اینجا خوب فکر کنید :-) و توجه داشته باشید که internal directory، راه بهتری برای اطمینان از وارد نشدن private packages شماست، زیرا توسط Go اجرا می‌شود. دایرکتوری /pkgهمچنان راه خوبی برای بیان صریح این است که کد موجود در آن دایرکتوری برای استفاده توسط دیگران ایمن است. مقاله وبلاگ « I'll take pkg over internal» توسط Travis Jeffery، نمای کلی خوبی از دایرکتوری‌های pkg و internal و زمان‌هایی که استفاده از آنها منطقی است ارائه می‌دهد. همچنین این راهی برای گروه‌بندی کد Go در یک مکان است، زمانی که دایرکتوری اصلی شما حاوی بسیاری از اجزا و دایرکتوری‌های غیر Go باشد، این کار اجرای ابزارهای مختلف Go را آسان‌تر می‌کند (همانطور که در این سخنرانی‌ها ذکر شده است: Best Practices for Industrial Programming از GopherCon EU و GopherCon 2018: Kat Zien - How Do You Structure Your Go Apps و GoLab 2018 - Massimiliano Pippi - Project layout patterns in Go). اگر می‌خواهید ببینید کدام مخازن محبوب Go از این layout pattern پروژه استفاده می‌کنند، به دایرکتوری /pkg مراجعه کنید. این یک الگوی layout رایج است، اما به‌طور جهانی پذیرفته نشده است و برخی از اعضای جامعه Go آن را توصیه نمی‌کنند. اگر پروژه برنامه‌ی شما واقعاً کوچک است و جایی که لایه‌ی اضافی تودرتو بودن ارزش زیادی اضافه نمی‌کند، استفاده نکردن از آن اشکالی ندارد (مگر اینکه واقعاً بخواهید :-)). در مورد آن فکر کنید زمانی که پروژه به اندازه کافی بزرگ می شود و دایرکتوری اصلی شما شلوغ می شود (به خصوص اگر اجزای برنامه غیر Go زیادی دارید). ریشه‌های دایرکتوری pkg: کد منبع قدیمی Go برای بسته‌های خود از pkg استفاده می‌کرد و سپس پروژه‌های مختلف Go در جامعه شروع به کپی کردن این الگو کردند (برای درک بهتر به این توییت Brad Fitzpatrick مراجعه کنید).

/vendor #

وابستگی‌های برنامه (به‌صورت دستی یا توسط ابزار مدیریت وابستگی مورد علاقه شما مانند ویژگی جدید Go Modulesداخلی مدیریت می‌شود). دستور go mod vendor دایرکتوری vendor/ را برای شما ایجاد می‌کند. توجه داشته باشید که اگر از Go 1.14 استفاده نمی‌کنید که به صورت پیش‌فرض فعال است، ممکن است نیاز به اضافه کردن پرچم -mod=vendor به دستور go build خود داشته باشید. اگر در حال ساخت کتابخانه هستید، وابستگی‌های برنامه خود را commit نکنید. توجه داشته باشید که از Go 1.13 ، قابلیت module proxy نیز در Go فعال شد (که به طور پیش‌فرض از https://proxy.golang.org به عنوان سرور پراکسی ماژول خود استفاده می‌کند). برای اینکه ببینید آیا این قابلیت با تمام الزامات و محدودیت‌های شما مطابقت دارد، در اینجا بیشتر در مورد آن بخوانید. اگر اینطور باشد، اصلاً به دایرکتوری vendor نیاز نخواهید داشت.

4.26.3 دایرکتوری‌های سرویس application #

/api #

مشخصات OpenAPI/Swagger، فایل‌های JSON schema، فایل‌های تعریف پروتکل. برای مثال به دایرکتوری /api/ مراجعه کنید.

4.26.4 دایرکتوری‌های سرویس وب #

اجزای خاص برنامه وب: static web assets و templateهای سمت سرور و SPAها.

4.26.5 دایرکتوری‌های مشترک در application #

/configs #

قالب‌های فایل پیکربندی یا تنظیمات پیش‌فرض. فایل‌های قالب confd یا consul-template خود را اینجا قرار دهید.

/init #

پیکربندی‌های init سیستم (systemd، upstart، sysv) و process manager/supervisor (runit, supervisord).

/scripts #

اسکریپت‌هایی برای انجام عملیات‌های مختلف build, install, analysis و غیره. این اسکریپت‌ها Makefile سطح ریشه را کوچک و ساده نگه می‌دارند (به عنوان مثال،https://github.com/hashicorp/terraform/blob/main/Makefile). برای مثال به دایرکتوری scripts/ مراجعه کنید.

/build #

‏برای Packaging و Continuous Integration

  • پیکربندی‌ها و اسکریپت‌های package‌های ابری (AMI)، کانتینری (Docker)، سیستم‌عامل (deb، rpm، pkg) را در این دایرکتوری قرار دهید.

/build #

  • پیکربندی‌ها و اسکریپت‌های CI (travis، circle، drone) را در این دایرکتوری قرار دهید. توجه داشته باشید که برخی از ابزارهای CI (مانند Travis CI) در مورد مکان فایل‌های پیکربندی خود بسیار حساس هستند. سعی کنید فایل‌های پیکربندی را در دایرکتوری /build/ci قرار داده و آن‌ها را به مکانی که ابزارهای CI انتظار دارند (در صورت امکان) لینک کنید.

/deployments #

  • پیکربندی‌ها و قالب‌های deployment یا استقرار IaaS، PaaS، سیستم و orchestration کانتینر (dockerCompose, kubernetes/helm, terraform). توجه داشته باشید که در برخی از repoها (به ویژه برنامه‌هایی که با kubernetes استقرار می‌یابند) این دایرکتوری deploy/ نامیده می‌شود.

/test #

  • برنامه‌های تست خارجی اضافی و داده‌های تست. می‌توانید دایرکتوری test/ را به هر شکلی که می‌خواهید ساختار دهید. برای پروژه‌های بزرگ‌تر، داشتن یک زیردایرکتوری data منطقی است. برای مثال، می‌توانید test/testdata/ یا test/data/ را داشته باشید اگر نیاز دارید که Go آنچه در آن دایرکتوری است را نادیده بگیرد. توجه داشته باشید که Go همچنین دایرکتوری‌ها یا فایل‌هایی که با “.” یا "" شروع می‌شوند را نادیده می‌گیرد، بنابراین در نحوه نام‌گذاری دایرکتوری داده‌های تست خود انعطاف بیشتری دارید. برای نمونه‌ها به دایرکتوری test/مراجعه کنید.

دایرکتوری‌های دیگر #

اسناد طراحی و کاربر (علاوه بر مستندات ایجاد شده توسط godoc شما). برای مثال به دایرکتوری docs/ مراجعه کنید.

/tools #

ابزارهای پشتیبانی این پروژه توجه داشته باشید که این ابزارها می توانند کد را از دایرکتوری های pkg/ و internal/ وارد کنند. برای مثال به دایرکتوری tools/ مراجعه کنید.

/examples #

نمونه‌هایی برای application و یا کتابخانه‌های public شما. برای مثال به دایرکتوری examples/ مراجعه کنید.

/third_party #

ابزارهای کمکی خارجی، کد fork شده و سایر ابزارهای شخص ثالث (مانند Swagger UI).

/githooks #

برای Git hooks.

/assets #

سایر assetها برای همراهی با repository شما (image, logoها و غیره).

/website #

اگر از GitHub pages استفاده نمی‌کنید، اینجا مکانی است که می توانید داده‌های وب‌سایت پروژه خود را قرار دهید. برای مثال به دایرکتوری website/مراجعه کنید.

دایرکتوری‌هایی که نباید داشته باشید #

/src #

برخی از پروژه‌های Go دارای یک پوشه src هستند، اما این معمولاً زمانی اتفاق می‌افتد که توسعه‌دهندگان از دنیای جاوا آمده‌اند که در آنجا یک الگوی رایج است. اگر می‌توانید، سعی کنید این الگوی جاوا را نپذیرید. شما واقعاً نمی‌خواهید که کد Go یا پروژه‌های Go شما شبیه جاوا به نظر برسند :-) دایرکتوری /src در سطح پروژه را با دایرکتوری /src که Go برای کارگاه‌های خود استفاده می‌کند، اشتباه نگیرید که در How to Write Go Code توضیح داده شده است. $GOPATH environment variable به (current) workspace فعلی شما اشاره می‌کند (به طور پیش‌فرض به $HOME/go در سیستم‌های غیر ویندوزی اشاره می‌کند). این workspace شامل دایرکتوری‌های سطح بالا /pkg, /bin و /src است. پروژه واقعی شما در نهایت یک زیردایرکتوری زیر /src می‌شود، بنابراین اگر دایرکتوری /src را در پروژه خود دارید، مسیر پروژه به این شکل خواهد بود: /some/path/to/workspace/src/your_project/src/your_code.go. توجه داشته باشید که با Go 1.11 امکان دارد پروژه خود را خارج از GOPATH خود داشته باشید، اما این هنوز به معنای این نیست که استفاده از این الگوی layout pattern ایده خوبی است.

4.26.6 بررسی Badgeها #

Go Report Card کد شما را با gofmt، go vet، gocyclo، golint، ineffassign، مجوز و غلط املایی اسکن می کند. مرجع پروژه خود را جایگزین github.com/golang-standards/project-layout کنید. Go Report CardGoDoc این نسخه آنلاین اسناد تولید شده GoDoc شما را ارائه می‌دهد. link را تغییر دهید تا به پروژه شما اشاره کند. Go DocPkg.go.dev ‏ Pkg.go.dev مقصد جدیدی برای شناسایی و مستندات Go است. می‌توانید با استفاده از badge generation toolآن را ایجاد کنید. PkgGoDev در مورد Release - آخرین شماره انتشار پروژه شما را نشان می دهد. لینک github را تغییر دهید تا به پروژه شما اشاره کند.

4.26.8 نکته‌ها #

یک الگوی پروژه با نظر بیشتر با تنظیمات sample/reusable استفاده مجدد، اسکریپت‌ها و کد یک WIP است.