این متن یک طرح اساسی برای پروژههای برنامهنویسی به زبان 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 را بخوانید:
- https://talks.golang.org/2014/names.slide
- https://golang.org/doc/effective_go.html#names
- https://blog.golang.org/package-names
- https://go.dev/wiki/CodeReviewComments
- Style guideline for Go packages (rakyll/JBD)
برای اطلاعات بیشتر ، Go Project Layout
را ببینید.
اطلاعات بیشتر در مورد نامگذاری و سازماندهی بستهها و همچنین سایر توصیههای ساختار کد:
- GopherCon EU 2018: Peter Bourgon - Best Practices for Industrial Programming
- GopherCon Russia 2018: Ashley McNamara + Brian Ketelsen - Go best practices.
- GopherCon 2017: Edward Muller - Go Anti-Patterns
- GopherCon 2018: Kat Zien - How Do You Structure Your Go Apps
این دایرکتوری شامل برنامههای اصلی پروژه شما است. نام هر دایرکتوری فرعی باید با نام برنامه اجرایی مطابقت داشته باشد (برای مثال، /cmd/myapp
).
از قرار دادن حجم کد زیاد در دایرکتوری برنامه خودداری کنید. اگر فکر میکنید این کدها قابلیت وارد شدن و استفاده در پروژههای دیگر را دارد، باید در دایرکتوری /pkg
قرار گیرد. اگر کد قابل استفاده مجدد نیست یا نمیخواهید دیگران از آن استفاده مجدد کنند، آن کد را در دایرکتوری /internal
قرار دهید. تعجب خواهید کرد که دیگران چه کارهایی انجام میدهند، بنابراین در مورد اهداف خود صریح باشید!
معمولاً یک تابع اصلی کوچک وجود دارد که کد را از دایرکتوریهای /internal
و /pkg
وارد کرده و فراخوانی میکند و کار دیگری انجام نمیدهد.
بهعنوانمثال به دایرکتوری /cmd
مراجعه کنید.
شامل کد 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/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 مراجعه کنید).
وابستگیهای برنامه (بهصورت دستی یا توسط ابزار مدیریت وابستگی مورد علاقه شما مانند ویژگی جدید 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
نیاز نخواهید داشت.
مشخصات OpenAPI/Swagger، فایلهای طرحواره JSON، فایلهای تعریف پروتکل.
برای مثال به دایرکتوری /api/
مراجعه کنید.
اجزای خاص برنامه وب: static web assets و templateهای سمت سرور و SPAها.
قالبهای فایل پیکربندی یا تنظیمات پیشفرض.
فایلهای قالب confd
یا consul-template
خود را اینجا قرار دهید.
پیکربندیهای init سیستم (systemd، upstart، sysv) و process manager/supervisor (runit, supervisord).
اسکریپتهایی برای انجام عملیاتهای مختلف build, install, analysis و غیره.
این اسکریپتها Makefile سطح ریشه را کوچک و ساده نگه میدارند (به عنوان مثال،https://github.com/hashicorp/terraform/blob/main/Makefile
).
برای مثال به دایرکتوری scripts/
مراجعه کنید.
Packaging و Continuous Integration
- پیکربندیها و اسکریپتهای packageهای ابری (AMI)، کانتینری (Docker)، سیستمعامل (deb، rpm، pkg) را در این دایرکتوری قرار دهید.
- پیکربندیها و اسکریپتهای CI (travis، circle، drone) را در این دایرکتوری قرار دهید. توجه داشته باشید که برخی از ابزارهای CI (مانند Travis CI) در مورد مکان فایلهای پیکربندی خود بسیار حساس هستند. سعی کنید فایلهای پیکربندی را در دایرکتوری
/build/ci
قرار داده و آنها را به مکانی که ابزارهای CI انتظار دارند (در صورت امکان) لینک کنید.
- پیکربندیها و قالبهای deployment یا استقرار IaaS، PaaS، سیستم و orchestration کانتینر (dockerCompose, kubernetes/helm, terraform). توجه داشته باشید که در برخی از repoها (به ویژه برنامههایی که با kubernetes استقرار مییابند) این دایرکتوری
deploy/
نامیده میشود.
- برنامههای تست خارجی اضافی و دادههای تست. میتوانید دایرکتوری
test/
را به هر شکلی که میخواهید ساختار دهید. برای پروژههای بزرگتر، داشتن یک زیردایرکتوری data منطقی است. برای مثال، میتوانیدtest/testdata/
یاtest/data/
را داشته باشید اگر نیاز دارید که Go آنچه در آن دایرکتوری است را نادیده بگیرد. توجه داشته باشید که Go همچنین دایرکتوریها یا فایلهایی که با "." یا "" شروع میشوند را نادیده میگیرد، بنابراین در نحوه نامگذاری دایرکتوری دادههای تست خود انعطاف بیشتری دارید.
برای نمونهها به دایرکتوری test/
مراجعه کنید.
اسناد طراحی و کاربر (علاوه بر مستندات ایجاد شده توسط godoc شما).
برای مثال به دایرکتوری docs/
مراجعه کنید.
ابزارهای پشتیبانی این پروژه توجه داشته باشید که این ابزارها می توانند کد را از دایرکتوری های pkg/ و internal/ وارد کنند.
برای مثال به دایرکتوری tools/ مراجعه کنید.
نمونههایی برای application و یا کتابخانههای public شما.
برای مثال به دایرکتوری examples/
مراجعه کنید.
ابزارهای کمکی خارجی، کد fork شده و سایر ابزارهای شخص ثالث (مانند Swagger UI).
Git hooks.
سایر assetها برای همراهی با repository شما (image, logoها و غیره).
اگر از GitHub pages استفاده نمیکنید، اینجا مکانی است که می توانید دادههای وبسایت پروژه خود را قرار دهید.
برای مثال به دایرکتوری website/
مراجعه کنید.
برخی از پروژههای 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 ایده خوبی است.
Go Report Card کد شما را با gofmt، go vet، gocyclo، golint، ineffassign، مجوز و غلط املایی اسکن می کند. مرجع پروژه خود را جایگزین github.com/golang-standards/project-layout کنید.
GoDoc
این نسخه آنلاین اسناد تولید شده GoDoc شما را ارائه میدهد. link را تغییر دهید تا به پروژه شما اشاره کند.
Pkg.go.dev Pkg.go.dev مقصد جدیدی برای شناسایی و مستندات Go است. میتوانید با استفاده از badge generation toolآن را ایجاد کنید.
در مورد Release - آخرین شماره انتشار پروژه شما را نشان می دهد. لینک github را تغییر دهید تا به پروژه شما اشاره کند.
یک الگوی پروژه با نظر بیشتر با تنظیمات sample/reusable استفاده مجدد، اسکریپتها و کد یک WIP است.