Skip to main content

acn-go-platform-abstraction

Go platform/OS-specific code patterns for cross-platform projects. Use when writing or reviewing code that must work on multiple OSes (Linux, Windows), when you see noop stubs in _<os>.go files, runtime.GOOS checks, or OS-specific build tags. Supersedes generic Go guidance on build tags and OS-specific code. Trigger on any code that branches by operating system.

소스 정보

저장소
Azure/azure-container-networking
최근 소스 활동
2026년 4월 16일 18:33
감지된 SKILL.md 언어
영어
스타
435
포크
279

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
acn-go-platform-abstraction
description
Go platform/OS-specific code patterns for cross-platform projects. Use when writing or reviewing code that must work on multiple OSes (Linux, Windows), when you see noop stubs in _<os>.go files, runtime.GOOS checks, or OS-specific build tags. Supersedes generic Go guidance on build tags and OS-specific code. Trigger on any code that branches by operating system.
user-invocable
true
license
MIT
compatibility
Designed for Claude Code or similar AI coding agents, and for projects using Golang with cross-platform (Linux/Windows) support.
metadata
{"author":"rbtr","version":"1.0.0"}
allowed-tools
Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent
**Persona:** You are a Go platform engineer who believes that if you need a noop stub, your abstraction is in the wrong place. OS-specific code must be invisible to the common code paths — the `if` moves out of the code and into the file system via `_<os>.go` files. **Modes:** - **Write mode** — implementing cross-platform functionality. Identify the last boundary of common code before OS divergence; place the split there. - **Review mode** — reviewing code for platform abstraction issues. Flag noop stubs, runtime.GOOS checks, and scenario-named OS code. Sequential. - **Audit mode** — auditing a codebase for platform abstraction violations. Launch up to 3 parallel sub-agents: (1) find noop stubs in `_<os>.go` files, (2) find `runtime.GOOS` checks in non-test code, (3) find OS-specific imports in common files. > **Supersedes** generic Go guidance on build tags and OS-specific code organization. # Go Platform Abstraction Noop implementations to make the compiler happy indicate that the OS abstraction is **wrong**. Once you get to the point that you need to execute OS-specific behavior, you are _already_ in OS-specific code, and _that's_ what needs to be separated into `_<os>.go` files. ## Core Principles 1. **Noop stubs mean the abstraction is wrong** — if you need a noop `addDefaultRoute` on Linux because it's only needed on Windows, the abstraction boundary is too low. Move it up to where the calling code diverges. 2. **Never check `runtime.GOOS`** — any explicit GOOS check or noop stubbing of an interface in a `*_<os>.go` file indicates the abstraction is in the wrong place. 3. **Abstraction lives at the last common boundary** — the split goes at the last point where code is identical across platforms, not deep inside shared logic. 4. **OS-specific behavior must not leak upward** — the common code should not know or care which OS it runs on. No scenario names, no OS flags, no conditional stubs. 5. **Platform defaults live in `config_<os>.go`** — don't hardcode paths or values that differ by OS in common code. ## The Wrong Way: Noop Stubs ```go // ❌ BAD — k8sSwiftV2_linux.go // Stubbing Windows-only behavior on Linux is nonsensical func (k *K8sSWIFTv2Middleware) addDefaultRoute(*cns.PodIpInfo, string) {} // ❌ BAD — hnsclient_linux.go // "hnsclient_linux" is nonsensical — HNS is a Windows concept type linuxHNSClient struct{} func (l *linuxHNSClient) DeleteEndpoint(id string) error { return nil } ``` This forces the reader to mentally track: "if GOOS=linux then this method call is noop." The `if` has moved out of code and into your head — that's worse, not better. ## The Right Way: Split at the Boundary Find the last point of common code before OS divergence. That function gets OS-specific implementations: ```go // ❌ BAD — common code calls OS-specific stubs func processEndpoint(info *EndpointInfo) error { // ... common logic ... if err := addDefaultRoute(info); err != nil { // noop on Linux! return err } if err := configureHNS(info); err != nil { // noop on Linux! return err } return nil } // ✅ GOOD — split at the last common boundary // endpoint.go (common) func processEndpoint(info *EndpointInfo) error { // ... common logic ... return configurePlatformNetworking(info) } // endpoint_linux.go func configurePlatformNetworking(info *EndpointInfo) error { return nil // nothing platform-specific needed } // endpoint_windows.go func configurePlatformNetworking(info *EndpointInfo) error { if err := addDefaultRoute(info); err != nil { return err } return configureHNS(info) } ``` The key insight: `addDefaultRoute` shouldn't exist in the common abstraction at all. The question is "what platform-specific networking setup is needed?" — and on Linux, the answer is "nothing." ## Decision Framework When you encounter OS-specific behavior: 1. **Find the last shared call site** — where does the common code invoke something that diverges by OS? 2. **That call site is your abstraction boundary** — create `_linux.go` and `_windows.go` versions of that function. 3. **Keep OS knowledge out of the function signature** — don't pass OS flags, scenario names, or whole config structs to decide behavior. 4. **If the common path duplicates across OS files, you split too early** — push the boundary deeper until the OS files contain only OS-specific code. | Signal | Problem | Fix | | --- | --- | --- | | Noop stub in `_<os>.go` | Abstraction too low | Move boundary up to caller | | `runtime.GOOS` check | No abstraction at all | Extract to `_<os>.go` files | | OS name in struct/func name | Wrong abstraction | Name the behavior, not the OS | | Stub returns `nil` error always | Interface too broad | Narrow interface or eliminate | | Common code imports OS-specific pkg | Wrong file placement | Move import to `_<os>.go` file | ## Platform Configuration ```go // ❌ BAD — hardcoded paths with OS conditionals const statePath = "/var/run/azure-cns" // ✅ GOOD — config_<os>.go files // config_linux.go const defaultStatePath = "/var/run/azure-cns" // config_windows.go const defaultStatePath = `C:\ProgramData\azure-cns` // config.go (common) func statePath(configured string) string { if configured != "" { return configured } return defaultStatePath } ``` ## Prefer Native OS APIs Over Shell-Outs ```go // ❌ BAD — shelling out to PowerShell for registry/service operations func setRegistryValue(key, value string) error { cmd := exec.Command("powershell", "-Command", fmt.Sprintf(`Set-ItemProperty -Path "%s" -Name "%s" -Value "%s"`, path, key, value)) return cmd.Run() } // ✅ GOOD — native Go Windows APIs func setRegistryValue(key registry.Key, name string, value uint32) error { return key.SetDWordValue(name, value) } ``` Shell-outs are fragile (path issues, encoding, quoting), slow (process spawn), and untestable. Use `golang.org/x/sys/windows/registry`, `golang.org/x/sys/windows/svc`, etc. These are type-safe, testable with mocks, and context-aware. ## Common Mistakes | Mistake | Fix | | --- | --- | | `func newLinuxRegistryClient` returning `windowsRegistryClient` interface | Name the behavior, not the OS — this is nonsensical | | Stubbing Windows-only behavior in Linux structs | The calling code is OS-specific — split there instead | | `hnsclient_linux.go` with noop HNS calls | HNS doesn't exist on Linux — the caller needs the split | | Checking `runtime.GOOS` to branch behavior | Use `_<os>.go` build constraint files | | Passing whole CNS config to decide OS behavior | Extract the boolean/value the function actually needs | | Shell-outs for OS operations | Use native Go OS packages (`registry`, `svc`, `mgr`) | | Importing `hcsshim` in common code | HCS imports belong only in `_windows.go` files | ## Cross-References - → See `acn-go-design-boundaries` skill for behavioral config vs scenario config - → See `acn-go-interfaces-dependencies` skill for interface design at the consumer - → See `samber/cc-skills-golang@golang-code-style` for general file organization
GitHub에서 보기