پرش به محتویات

استاندارد کدنویسی Go

کد بک‌اند باید ساده، قابل مشاهده و مطابق Idiomهای Go باشد. خوانایی و Correctness بر اختصار، Abstraction زودهنگام یا استفاده نمایشی از Patternها اولویت دارد.

نسخه و Toolchain

  • go.mod نسخه Major/Minor تصویب‌شده را مشخص می‌کند و CI با آخرین Patch همان خط اجرا می‌شود.
  • Image ساخت باید نسخه کامل Toolchain و Digest پایه را Pin کند.
  • ارتقای Patch پس از CI خودکار است؛ ارتقای Major با ADR و بررسی Release Note انجام می‌شود.
  • go mod tidy نباید Diff غیرمنتظره باقی بگذارد و go mod verify در CI اجرا می‌شود.
  • Dependency فقط برای نیاز واقعی اضافه می‌شود؛ کتابخانه کوچک بدون مزیت روشن با Standard Library جایگزین می‌شود.
  • HTTP Server، Routing و قرارداد Middleware با net/http و http.ServeMux پیاده‌سازی می‌شوند و Feature به Context اختصاصی Framework وابسته نمی‌شود.

قالب و نام‌گذاری

  • gofmt و goimports اجباری‌اند و CI هر Diff قالب‌بندی را رد می‌کند.
  • نام Package کوتاه، lowercase، بدون underscore و بدون تکرار نام والد است.
  • نام Exportشده باید Doc Comment معنادار داشته باشد؛ نام محلی کوتاه فقط وقتی دامنه آن کوتاه است مجاز است.
  • Acronymها یکدست نوشته می‌شوند: ID، URL، HTTP و OTP.
  • Boolean با مفهوم مثبت و قابل خواندن نام‌گذاری می‌شود؛ مانند isActive در JSON و active در Go در صورت نبود ابهام.
  • Magic Number، Status و Permission به Constant دامنه‌ای تبدیل می‌شوند.

تابع و Interface

  • تابع باید یک مسئولیت داشته و مسیر اصلی آن کم‌تورفتگی باشد؛ Guard Clause ترجیح دارد.
  • ورودی‌های مرتبط با رفتار در یک Command یا Value Object جمع می‌شوند، نه در فهرست بلند پارامترها.
  • Interface کوچک و در سمت Consumer تعریف می‌شود. بازگرداندن Struct و پذیرفتن Interface اصل پیش‌فرض است.
  • Interface خالی یا any در Domain و Application فقط در مرز Serialization یا Telemetry و با دلیل روشن مجاز است.
  • Global Mutable State ممنوع است. Dependencyها در Composition Root تزریق می‌شوند.
  • تکرار منطق یا Policy ممنوع است؛ کد مشترک فقط وقتی Extract می‌شود که رفتار یکسان، نام روشن، مالک مشخص و Test مستقل داشته باشد.

Context و Timeout

  • context.Context نخستین پارامتر عملیات I/O یا عملیات قابل لغو است و در Struct ذخیره نمی‌شود.
  • Context ورودی از HTTP تا Database و Provider عبور می‌کند و با context.Background() قطع نمی‌شود.
  • هر I/O باید Deadline داشته باشد؛ Timeout Provider از بودجه کلی درخواست کمتر است.
  • Cancellation خطا نیست که پنهان شود؛ context.Canceled و context.DeadlineExceeded به پاسخ و Metric مناسب نگاشت می‌شوند.
  • Valueهای Context فقط برای metadata درخواست مانند Trace ID استفاده می‌شوند، نه Dependency یا داده کسب‌وکار.

مدیریت خطا

  • خطا دقیقا یک‌بار و در مرز دارای Context ثبت می‌شود؛ لایه‌های پایین همان خطا را چندبار Log نمی‌کنند.
  • خطا با %w Wrap می‌شود و تشخیص با errors.Is یا errors.As انجام می‌شود، نه مقایسه متن.
  • Domain Error پایدار و قابل نگاشت به HTTP تعریف می‌شود؛ جزئیات Driver، SQL، Stack یا Provider به Client نشت نمی‌کند.
  • Panic برای خطای برنامه‌نویسی است، نه ورودی کاربر یا خطای قابل انتظار. Middleware در مرز Process آن را Recover، ثبت و به خطای عمومی تبدیل می‌کند.
  • نتیجه مالی یا Permission بر اساس Fail-open اجرا نمی‌شود؛ خطای Dependency به رد امن عملیات منجر می‌شود.

هم‌زمانی

  • هر Goroutine باید مالک Lifecycle، مسیر Cancellation و روش Wait مشخص داشته باشد.
  • Goroutine بدون Bound، Channel بدون مالک و time.Tick بدون Stop ممنوع است.
  • برای Fan-out از Limit هم‌زمانی و errgroup با Context استفاده می‌شود.
  • Map مشترک باید Synchronization صریح داشته باشد؛ استفاده از sync.Map فقط پس از اندازه‌گیری و تناسب الگو مجاز است.
  • go test -race ./... برای Pull Requestهای عادی اجرا می‌شود؛ آزمون‌های بسیار سنگین می‌توانند در Workflow زمان‌بندی‌شده جدا باشند.

Config و Secret

  • Config در Startup از Environment یا Secret File خوانده، Validate و به Struct immutable تبدیل می‌شود.
  • نبود Config الزامی باعث Fail-fast پیش از Listen شدن Server می‌شود.
  • Secret، Token، OTP، DSN کامل و Credential هرگز در Repository، Error، Metric یا Log قرار نمی‌گیرد.
  • .env فقط برای Development محلی و خارج از Git است؛ .env.example فقط Placeholder غیرواقعی دارد.
  • Rotation Keyها باید بدون Downtime ممکن باشد؛ Verifier حداقل Key فعال و Key قبلی را در بازه مهاجرت می‌شناسد.

Log و Audit

  • Log عملیاتی با log/slog به‌صورت JSON و با فیلدهای ثابت مانند service، version، environment، request_id و trace_id تولید می‌شود.
  • متن آزاد جای فیلد ساخت‌یافته را نمی‌گیرد و داده با Cardinality بالا وارد Label متریک نمی‌شود.
  • شماره موبایل، نام، متن Ticket، محتوای فایل و داده مالی در Log Redact یا Tokenize می‌شوند.
  • Audit Log دامنه‌ای با Log عملیاتی یکی نیست؛ Audit تغییرناپذیر، Actor، Tenant، Action، Target، نتیجه، زمان و Correlation ID را ثبت می‌کند.

Definition of Done کد

  • کد gofmt، go vet، Lint، Test، Race Test و govulncheck را پاس می‌کند.
  • تغییر قرارداد با OpenAPI، Migration و مستند مرتبط همراه است.
  • مسیر خطا، Authorization، Tenant Isolation و Idempotency آزمون دارد.
  • Log یا Fixture شامل Secret و PII واقعی نیست.
  • TODO بدون Issue، مالک و دلیل قابل پیگیری باقی نمانده است.

منابع رسمی