{"slug": "markdown-file-to-de-slop-your-go-codebase", "title": "Markdown file to de-slop your go codebase", "summary": "A developer has published a markdown file that aggressively simplifies AI-generated, defensive, or overly abstract Go code, aiming to make it look like it was written by an experienced Go engineer. The guide emphasizes validating untrusted data at boundaries, using concrete types, avoiding generic maps and unnecessary helpers, and not hiding invalid states with zero values.", "body_md": "Audit this Go codebase and aggressively simplify AI-generated, defensive, overly abstract, or unnecessarily generic code.\n\nThe goal is to make the code look like it was written by an experienced Go engineer:\n\n- simple\n- explicit\n- strongly typed\n- boring\n- idiomatic\n- easy to trace\n- minimal abstraction\n- minimal magic\n\nDo not optimize for cleverness.\n\nDo not replace simple code with frameworks, generic helpers, reflection, interfaces, factories, adapters, builders, or excessive layering.\n\nThe primary rule is:\n\n**Validate untrusted data at the boundary. Use concrete types everywhere else.**\n\nSearch aggressively for:\n\n```\nany\ninterface{}\nmap[string]any\nmap[string]interface{}\n```\n\nAsk why the value is untyped.\n\nBad:\n\n```\nfunc getDomain(data map[string]any) string {\n\tvalue, ok := data[\"domain\"]\n\tif !ok {\n\t\treturn \"\"\n\t}\n\n\tdomain, ok := value.(string)\n\tif !ok {\n\t\treturn \"\"\n\t}\n\n\treturn domain\n}\n```\n\nPrefer:\n\n```\ntype DomainEvent struct {\n\tDomain string `json:\"domain\"`\n}\n```\n\nThen:\n\n```\nevent.Domain\n```\n\nDo not carry generic maps through the application and repeatedly recover types from them.\n\nIf the JSON shape is known, unmarshal directly into a struct.\n\nBe suspicious of functions like:\n\n```\ntoString()\nasString()\nstringValue()\nsafeString()\ntoInt()\nasInt()\ntoBool()\ntoMap()\nasMap()\ngetString()\ngetOptionalString()\nvalueOrDefault()\n```\n\nBad:\n\n```\nfunc toString(value any) string {\n\tswitch v := value.(type) {\n\tcase string:\n\t\treturn v\n\tcase int:\n\t\treturn strconv.Itoa(v)\n\tcase int64:\n\t\treturn strconv.FormatInt(v, 10)\n\tcase fmt.Stringer:\n\t\treturn v.String()\n\tcase nil:\n\t\treturn \"\"\n\tdefault:\n\t\treturn fmt.Sprintf(\"%v\", v)\n\t}\n}\n```\n\nAsk instead:\n\nWhat type is this value actually supposed to be?\n\nIf it is a string:\n\n```\nfunc normalizeDomain(domain string) string {\n\treturn strings.ToLower(strings.TrimSpace(domain))\n}\n```\n\nDo not accept `any` just to make a helper \"flexible.\"\n\nSearch for code that silently converts invalid states into:\n\n```\n\"\"\n0\nfalse\nnil\n[]T{}\nmap[K]V{}\n```\n\nExamples:\n\n```\nif value == nil {\n\treturn \"\"\n}\nif err != nil {\n\treturn nil\n}\nif project == nil {\n\treturn &Project{}\n}\n```\n\nDo not hide invalid states.\n\nIf data is required, return an error.\n\nBad:\n\n```\nfunc projectID(project *Project) string {\n\tif project == nil {\n\t\treturn \"\"\n\t}\n\n\treturn project.ID\n}\n```\n\nPrefer fixing the caller so `project` cannot be nil there.\n\nOr, if absence is genuinely possible:\n\n```\nif project == nil {\n\treturn ErrProjectNotFound\n}\n```\n\nValidate/narrow once, then continue with clean code.\n\nNil checks should correspond to actual nullable states.\n\nBad:\n\n```\nfunc handleProject(project *Project) error {\n\tif project == nil {\n\t\treturn errors.New(\"project is nil\")\n\t}\n\n\tif project.Config == nil {\n\t\treturn errors.New(\"project config is nil\")\n\t}\n\n\tif project.Config.Domain == nil {\n\t\treturn errors.New(\"domain is nil\")\n\t}\n\n\t// actual logic\n}\n```\n\nIf those fields are required by the application model, redesign the types instead.\n\nPrefer:\n\n```\ntype Project struct {\n\tConfig ProjectConfig\n}\n\ntype ProjectConfig struct {\n\tDomain string\n}\n```\n\nThen:\n\n```\nproject.Config.Domain\n```\n\nDo not represent required values as pointers merely because Go allows pointers.\n\nReview struct fields like:\n\n```\n*string\n*bool\n*int\n*time.Time\n```\n\nDo not use pointers merely to distinguish \"missing\" from zero unless the distinction actually matters.\n\nBad:\n\n```\ntype Config struct {\n\tEnabled *bool\n\tPort    *int\n\tName    *string\n}\n```\n\nIf those values are required:\n\n```\ntype Config struct {\n\tEnabled bool\n\tPort    int\n\tName    string\n}\n```\n\nPointers should communicate real optionality or identity/mutation semantics.\n\nDo not create a helper for every 2–3 lines.\n\nBe suspicious of:\n\n```\ngetDomainID()\nextractProjectID()\nresolveName()\nbuildKey()\nparseValue()\nstringFrom()\ndomainFrom()\n```\n\nwhen the helper:\n\n- has one caller\n- only accesses a field\n- only checks nil\n- only calls `strings.TrimSpace`\n- only calls `.String()`\n- only performs a type assertion\n- only forwards arguments\n\nBad:\n\n```\nfunc domainIDFrom(record *DNSRecord) string {\n\tif record == nil {\n\t\treturn \"\"\n\t}\n\n\treturn record.DomainID.String()\n}\n```\n\nPrefer:\n\n```\nrecord.DomainID.String()\n```\n\nprovided `record` is already known to exist.\n\nA helper should represent a real reusable concept, not hide straightforward code.\n\nGo interfaces should usually be defined by the consumer and kept small.\n\nBe suspicious of:\n\n```\ntype ProjectService interface {\n\tCreateProject(...)\n\tGetProject(...)\n\tUpdateProject(...)\n\tDeleteProject(...)\n\tListProjects(...)\n\tValidateProject(...)\n\tSyncProject(...)\n\tRefreshProject(...)\n}\n```\n\nespecially if there is only one implementation.\n\nDo not create an interface merely because \"services should have interfaces.\"\n\nPrefer concrete types unless you genuinely need:\n\n- multiple implementations\n- substitution\n- testing at that boundary\n- plugin behavior\n- a narrow consumer contract\n\nBad:\n\n```\ntype DomainManager interface {\n\tMap(...)\n}\n```\n\nwith only:\n\n```\ntype domainManagerImpl struct{}\n```\n\nPrefer:\n\n```\ntype DomainManager struct{}\n```\n\nDo not create Java-style `IFoo` / `FooImpl` architecture in Go.\n\nWhen an interface is justified, define only what the consumer needs.\n\nBad:\n\n```\ntype Repository interface {\n\tCreate(...)\n\tUpdate(...)\n\tDelete(...)\n\tGet(...)\n\tList(...)\n\tCount(...)\n\tExists(...)\n\tSearch(...)\n}\n```\n\nwhen a component only needs:\n\n```\nGet(...)\n```\n\nPrefer:\n\n```\ntype projectGetter interface {\n\tGet(ctx context.Context, id string) (*Project, error)\n}\n```\n\nDo not expose giant interfaces just because a concrete repository has many methods.\n\nLook for chains like:\n\n```\nhandler\n↓\ncontroller\n↓\nservice\n↓\nmanager\n↓\nprocessor\n↓\nrepository\n↓\nstore\n↓\ndatabase client\n```\n\nwhere most layers simply forward arguments.\n\nBad:\n\n```\nfunc (s *Service) GetProject(ctx context.Context, id string) (*Project, error) {\n\treturn s.manager.GetProject(ctx, id)\n}\n```\n\nand:\n\n```\nfunc (m *Manager) GetProject(ctx context.Context, id string) (*Project, error) {\n\treturn m.repository.GetProject(ctx, id)\n}\n```\n\nIf these layers do not contain meaningful business logic, remove them.\n\nOne meaningful layer is better than five pass-through layers.\n\nSearch for functions whose entire body is:\n\n```\nreturn dependency.Do(...)\n```\n\nor:\n\n```\nreturn helper(value)\n```\n\nor:\n\n```\nresult, err := dependency.Do(...)\nif err != nil {\n\treturn nil, err\n}\nreturn result, nil\n```\n\nSimplify:\n\n```\nreturn dependency.Do(...)\n```\n\nDo not add wrappers purely to make the architecture look layered.\n\nBad:\n\n```\nresult, err := repo.Get(ctx, id)\nif err != nil {\n\treturn nil, err\n}\n\nreturn result, nil\n```\n\nPrefer:\n\n```\nreturn repo.Get(ctx, id)\n```\n\nBad:\n\n```\nif err != nil {\n\treturn fmt.Errorf(\"error: %w\", err)\n}\n```\n\nThis adds no useful context.\n\nIf wrapping, add meaningful context:\n\n```\nif err != nil {\n\treturn fmt.Errorf(\"load project %s: %w\", id, err)\n}\n```\n\nBut do not mechanically wrap every error at every layer.\n\nAn error should not become:\n\n```\nfailed to process project:\nfailed to get project:\nfailed to retrieve project:\nfailed to query project:\nsql: no rows\n```\n\nAdd context where it materially improves debugging.\n\nFind:\n\n```\nif err != nil {\n\treturn nil\n}\n```\n\nor:\n\n```\nif err != nil {\n\tlog.Println(err)\n\treturn nil\n}\n```\n\nor:\n\n```\n_ = doSomething()\n```\n\nDetermine whether ignoring the error is intentional.\n\nDo not turn bugs into silent success.\n\nIf an error can safely be ignored, make the reasoning obvious.\n\nExample:\n\n```\nif err := cache.Delete(ctx, key); err != nil {\n\tlogger.Warn(\"failed to invalidate cache\", \"key\", key, \"error\", err)\n}\n```\n\nonly when cache invalidation failure genuinely should not fail the operation.\n\nBe suspicious of enormous error hierarchies.\n\nDo not create:\n\n```\ntype ValidationError struct{}\ntype RepositoryError struct{}\ntype ServiceError struct{}\ntype DomainError struct{}\ntype InternalError struct{}\n```\n\nunless callers actually need different behavior based on the error.\n\nPrefer:\n\n``` js\nvar ErrProjectNotFound = errors.New(\"project not found\")\n```\n\nand:\n\n```\nerrors.Is(err, ErrProjectNotFound)\n```\n\nUse structured custom errors only when they carry meaningful information.\n\nDo not manually inspect error strings.\n\nBad:\n\n```\nif strings.Contains(err.Error(), \"duplicate\") {\n```\n\nPrefer the underlying driver's supported error type/code.\n\nExample:\n\n``` js\nvar writeErr mongo.WriteException\nif errors.As(err, &writeErr) {\n\t...\n}\n```\n\nBut do not turn a simple known-driver check into enormous generic error inspection code.\n\nKeep it proportional to the actual need.\n\nSearch for:\n\n```\nreflect.\n```\n\nReflection is suspicious in ordinary business logic.\n\nBad:\n\n```\nfunc isEmpty(value any) bool {\n\tv := reflect.ValueOf(value)\n\t...\n}\n```\n\nPrefer explicit typed logic.\n\nDo not use reflection to avoid writing five obvious lines.\n\nReflection is reasonable in areas such as:\n\n- serializers\n- frameworks\n- generic libraries\n- tooling\n\nIt should rarely appear in normal handlers/services/domain logic.\n\nGo generics are useful, but AI often introduces them for trivial problems.\n\nBe suspicious of:\n\n```\nfunc Ptr[T any](value T) *T\nfunc ValueOrDefault[T comparable](...)\nfunc ConvertSlice[T any, R any](...)\nfunc SafeCast[T any](...)\nfunc GetOrDefault[K comparable, V any](...)\n```\n\nDo not create generic utilities just because two lines look similar.\n\nPrefer concrete domain code where it is easier to understand.\n\nA generic abstraction should solve a real recurring problem.\n\nBad:\n\n```\nfunc GetString(data map[string]any, key string) string\nfunc GetInt(data map[string]any, key string) int\nfunc GetBool(data map[string]any, key string) bool\n```\n\nThis is usually evidence that structured data should have been decoded into a struct.\n\nPrefer:\n\n```\ntype DeploymentEvent struct {\n\tProjectID string `json:\"project_id\"`\n\tPort      int    `json:\"port\"`\n\tEnabled   bool   `json:\"enabled\"`\n}\n```\n\nThen use:\n\n```\nevent.ProjectID\nevent.Port\nevent.Enabled\n```\n\nBad:\n\n``` js\nvar payload map[string]any\n\nif err := json.Unmarshal(body, &payload); err != nil {\n\treturn err\n}\n\nevent, _ := payload[\"event\"].(string)\ndata, _ := payload[\"data\"].(map[string]any)\nprojectID, _ := data[\"project_id\"].(string)\n```\n\nPrefer:\n\n```\ntype QueueEvent struct {\n\tEvent string          `json:\"event\"`\n\tData  json.RawMessage `json:\"data\"`\n}\n```\n\nThen decode the event-specific payload once:\n\n``` js\ntype ProjectSyncEvent struct {\n\tProjectID string `json:\"project_id\"`\n}\n\nvar event ProjectSyncEvent\n\nif err := json.Unmarshal(payload.Data, &event); err != nil {\n\treturn fmt.Errorf(\"decode project sync event: %w\", err)\n}\n```\n\nAfter decoding, business logic should operate on typed structs.\n\nIf MongoDB, JSONB, Redis, or another store returns known document shapes, define structs.\n\nBad:\n\n``` js\nvar document map[string]any\n```\n\nfollowed by:\n\n```\nid, ok := document[\"domain\"].(primitive.ObjectID)\n```\n\nPrefer:\n\n```\ntype DNSDocument struct {\n\tDomain primitive.ObjectID `bson:\"domain\"`\n}\n```\n\nThen:\n\n```\ndocument.Domain.Hex()\n```\n\nFix broad types at the data-access boundary rather than adding extractors everywhere.\n\nBad:\n\n```\nvalue, ok := data.(map[string]any)\nif !ok {\n\treturn nil\n}\n\ndomain, ok := value[\"domain\"].(string)\nif !ok {\n\treturn nil\n}\n```\n\nif the data came from a contract already controlled by the application.\n\nEither:\n\n- type it correctly upstream, or\n- genuinely validate it at the external boundary\n\nDo not repeatedly rediscover types inside trusted application code.\n\nBe suspicious when the same data has:\n\n```\nProjectRequest\nProjectDTO\nProjectInput\nProjectParams\nProjectData\nProjectModel\nProjectEntity\nProjectResponse\n```\n\nwith nearly identical fields.\n\nSeparate types when the contracts are materially different.\n\nDo not duplicate structs solely because each layer \"needs its own model.\"\n\nIf two layers genuinely share the same concept, use the same type.\n\nLook for functions like:\n\n```\nfunc projectToDTO(project Project) ProjectDTO {\n\treturn ProjectDTO{\n\t\tID:   project.ID,\n\t\tName: project.Name,\n\t}\n}\n```\n\nwhen `ProjectDTO` and `Project` are effectively identical and no boundary requires the distinction.\n\nDo not maintain fleets of:\n\n```\ntoDTO\nfromDTO\ntoModel\nfromModel\ntoEntity\nfromEntity\n```\n\nwithout a meaningful difference in representation.\n\nBad:\n\n```\nfunc NewProjectService(repo Repository) *ProjectService {\n\treturn &ProjectService{\n\t\trepo: repo,\n\t}\n}\n```\n\nThis constructor can be reasonable if it provides a stable construction API.\n\nBut do not add constructors for simple data structs:\n\n```\nfunc NewDomain(name string) Domain {\n\treturn Domain{Name: name}\n}\n```\n\nwhen:\n\n```\nDomain{Name: name}\n```\n\nis clearer.\n\nConstructors should establish invariants or hide meaningful setup.\n\nDo not introduce Java-style builders for simple structs.\n\nBad:\n\n```\ndeployment := NewDeploymentBuilder().\n\tWithProjectID(projectID).\n\tWithRegion(region).\n\tWithPort(port).\n\tWithImage(image).\n\tBuild()\n```\n\nPrefer:\n\n```\ndeployment := Deployment{\n\tProjectID: projectID,\n\tRegion:    region,\n\tPort:      port,\n\tImage:     image,\n}\n```\n\nBuilders are justified only when construction is genuinely complex.\n\nAvoid:\n\n```\nNewService(\n\tWithRepository(repo),\n\tWithLogger(logger),\n\tWithMetrics(metrics),\n)\n```\n\nwhen all fields are required.\n\nPrefer:\n\n```\nNewService(repo, logger, metrics)\n```\n\nFunctional options are useful primarily for optional configuration or APIs with many optional settings.\n\nDo not introduce them just because they are a popular Go pattern.\n\nBad:\n\n```\ntype RepositoryFactory struct{}\n\nfunc (f *RepositoryFactory) CreateRepository(kind string) Repository\n```\n\nwhen the application has one concrete repository.\n\nPrefer constructing the concrete dependency directly.\n\nFactories should exist because runtime selection is real, not because \"factory pattern\" sounds architectural.\n\nNormal Go dependency injection is usually just:\n\n```\nservice := NewService(repo, logger)\n```\n\nDo not introduce:\n\n- containers\n- service locators\n- registries\n- providers\n- dependency graphs\n- reflection-based injection\n\nunless the project genuinely needs them.\n\nExplicit wiring is a strength of Go.\n\nBad:\n\n``` js\nvar shouldProcess bool\n\nif project != nil {\n\tif project.Enabled {\n\t\tif project.Status == StatusActive {\n\t\t\tshouldProcess = true\n\t\t}\n\t}\n}\n```\n\nPrefer early returns:\n\n```\nif project == nil {\n\treturn nil\n}\n\nif !project.Enabled {\n\treturn nil\n}\n\nif project.Status != StatusActive {\n\treturn nil\n}\n\n// actual work\n```\n\nOr when simple:\n\n```\nshouldProcess := project != nil &&\n\tproject.Enabled &&\n\tproject.Status == StatusActive\n```\n\nChoose whichever is easier to read.\n\nDo not optimize for clever one-liners.\n\nBad:\n\n```\nif err == nil {\n\tif project != nil {\n\t\tif project.Enabled {\n\t\t\t// 80 lines\n\t\t}\n\t}\n}\n```\n\nPrefer:\n\n```\nif err != nil {\n\treturn err\n}\n\nif project == nil {\n\treturn ErrProjectNotFound\n}\n\nif !project.Enabled {\n\treturn nil\n}\n\n// main logic\n```\n\nKeep the happy path visually obvious.\n\nBad:\n\n```\nrawDomain := event.Domain\nnormalizedDomain := strings.TrimSpace(rawDomain)\ndomain := strings.ToLower(normalizedDomain)\n```\n\nPrefer:\n\n```\ndomain := strings.ToLower(strings.TrimSpace(event.Domain))\n```\n\nBut do not compress code so aggressively that readability decreases.\n\nIntermediate variables should represent meaningful concepts.\n\nClean up:\n\n```\nif enabled == true\nif enabled == false\n```\n\nPrefer:\n\n```\nif enabled\nif !enabled\n```\n\nUnless an API uses nullable booleans where the distinction matters.\n\nQuestion code like:\n\n```\nitems := make([]Item, 0)\n```\n\nwhen:\n\n``` js\nvar items []Item\n```\n\nis sufficient.\n\nLikewise do not create:\n\n```\nmake(map[string]string)\n```\n\nuntil the map actually needs writes.\n\nBut keep capacity preallocation where profiling/data size makes it useful.\n\nBe suspicious of defensive copying with no mutation threat.\n\nBad:\n\n```\nresult := make([]string, len(input))\ncopy(result, input)\nreturn result\n```\n\nunless ownership/mutation semantics require the copy.\n\nDo not add allocations \"for safety\" without a concrete reason.\n\nDo not introduce:\n\n- `sync.Pool`\n- manual buffer reuse\n- unsafe conversions\n- custom allocators\n- elaborate caches\n- goroutine pools\n- lock-free structures\n\nwithout evidence that the code needs them.\n\nSimple correct code first.\n\nPerformance optimizations should solve measured problems.\n\nBe suspicious of:\n\n```\ngo func() {\n\t...\n}()\n```\n\nadded merely to make something \"non-blocking.\"\n\nEvery goroutine introduces:\n\n- lifecycle concerns\n- cancellation concerns\n- race potential\n- error propagation problems\n- shutdown complexity\n\nUse concurrency when the operation actually benefits from concurrency.\n\nBad:\n\n```\nhandler\n↓\nchannel\n↓\nworker\n↓\nchannel\n↓\nprocessor\n```\n\nfor logic that could simply be:\n\n```\nprocessor.Process(ctx, event)\n```\n\nChannels are synchronization primitives, not an architectural requirement.\n\nDo not use them to make normal function calls look concurrent.\n\nDo not:\n\n- store context permanently on structs\n- create `context.Background()` deep in request processing\n- accept `context.Context` where cancellation/deadlines are irrelevant\n- nil-check context\n\nBad:\n\n```\nif ctx == nil {\n\tctx = context.Background()\n}\n```\n\nA context parameter should not be nil.\n\nPass the caller's context through I/O boundaries.\n\nTypical signature:\n\n```\nfunc (s *Service) GetProject(ctx context.Context, id string) (*Project, error)\n```\n\nDo not create new contexts just to satisfy a function signature.\n\nDo not mechanically write:\n\n```\nctx, cancel := context.WithTimeout(ctx, 5*time.Second)\ndefer cancel()\n```\n\ninside every repository/service function.\n\nTimeout policy should usually live at meaningful boundaries.\n\nRepeated nested arbitrary timeouts are difficult to reason about.\n\nAvoid logs that merely narrate every function:\n\n```\nlogger.Info(\"entering CreateProject\")\nlogger.Info(\"validating project\")\nlogger.Info(\"calling repository\")\nlogger.Info(\"repository completed\")\nlogger.Info(\"leaving CreateProject\")\n```\n\nLog meaningful events:\n\n- failures\n- important state transitions\n- operational decisions\n- external interactions worth tracing\n\nDo not turn application logs into execution commentary.\n\nBad:\n\n```\nresult, err := repo.Get(ctx, id)\nif err != nil {\n\tlogger.Error(\"failed to get project\", \"error\", err)\n\treturn nil, err\n}\n```\n\nif the caller will also log it.\n\nPrefer logging once at the boundary responsible for handling the failure.\n\nLibraries/services should generally return errors.\n\nHandlers/workers/process supervisors decide when to log.\n\nDelete comments like:\n\n```\n// Check if project exists.\nif project == nil {\n// Return the result.\nreturn result\n// Convert string to lowercase.\ndomain = strings.ToLower(domain)\n```\n\nKeep comments for:\n\n- business rules\n- invariants\n- non-obvious decisions\n- external system quirks\n- workarounds\n- concurrency reasoning\n\nComments should explain why, not narrate syntax.\n\nDo not create a package for every type/helper.\n\nBad:\n\n```\ninternal/\n  domainparser/\n  stringutils/\n  validationhelper/\n  projectmapper/\n  pointerhelper/\n  responsebuilder/\n```\n\nPrefer packages around actual domains/capabilities.\n\nA package should represent a coherent concept, not one function.\n\nAudit packages named:\n\n```\nutils\nhelpers\ncommon\nshared\nmisc\ncore\nbase\n```\n\nThese often accumulate unrelated abstractions.\n\nMove useful functions to the domain that owns them.\n\nDelete trivial helpers.\n\nAvoid creating another generic utility package during cleanup.\n\nBad:\n\n```\ntype ProjectID struct {\n\tValue string\n}\n```\n\nwhen a plain string is sufficient.\n\nA custom type may be appropriate:\n\n```\ntype ProjectID string\n```\n\nif it prevents mixing IDs or adds domain behavior.\n\nBut do not wrap primitives in structs without a concrete benefit.\n\nThis can be useful:\n\n```\ntype ProjectID string\ntype Region string\n```\n\nwhen it prevents accidental mixing.\n\nBut do not produce:\n\n```\ntype ProjectName string\ntype ProjectDescription string\ntype ProjectImage string\ntype ProjectStatusString string\n```\n\nfor every field.\n\nUse domain types where they materially improve correctness.\n\nBefore keeping a helper, check whether Go already has the operation.\n\nPrefer:\n\n```\nstrings.TrimSpace\nstrings.ToLower\nslices.Contains\nmaps.Clone\nerrors.Is\nerrors.As\ncmp.Or\nstrconv.Atoi\n```\n\nwhere appropriate.\n\nDo not maintain custom helpers that poorly reimplement the standard library.\n\nBad:\n\n```\nregexp.MustCompile(`\\s+`).ReplaceAllString(...)\n```\n\nfor simple trimming or known delimiters.\n\nPrefer `strings` functions where sufficient.\n\nRegex should solve regex-shaped problems.\n\nAvoid:\n\n```\nfmt.Sprintf(\"%s\", value)\n```\n\nwhen `value` is already a string.\n\nAvoid:\n\n```\nfmt.Sprintf(\"%d\", n)\n```\n\nin hot/simple paths when:\n\n```\nstrconv.Itoa(n)\n```\n\nis clearer.\n\nBut do not replace readable formatting merely for micro-performance.\n\nBad:\n\n```\nfunc validateProject(project Project) error {\n\tif project.ID == \"\" {\n\t\treturn errors.New(\"missing project ID\")\n\t}\n\t...\n}\n```\n\ncalled in every internal service.\n\nIf `Project` is created from external input, validate when creating/parsing it.\n\nDo not repeatedly validate the same object throughout the system.\n\nDo not blindly remove validation.\n\nValidation is appropriate for:\n\n- HTTP requests\n- query/path parameters\n- queue messages\n- webhooks\n- config/env vars\n- external APIs\n- user input\n- decoded untrusted JSON\n- persisted schemaless documents\n\nThe rule is:\n\n**Defend against external uncertainty, not against your own correctly typed code.**\n\nIf normal Go code is sufficient:\n\n```\nif req.Domain == \"\" {\n\treturn ErrDomainRequired\n}\n```\n\ndo not introduce a large validation framework solely to avoid three `if` statements.\n\nUse an existing validation library if the project already relies on it and the schema complexity warrants it.\n\nDo not hide meaningful rules behind generic abstractions.\n\nBad:\n\n```\nif validator.IsValid(project) {\n```\n\nwhen the real business rule is:\n\n```\nif project.Status != StatusActive {\n\treturn ErrProjectInactive\n}\n```\n\nDomain rules should be visible in the code.\n\nBad:\n\n```\nfunc Process(ctx context.Context, cfg Config, options Options, metadata Metadata)\n```\n\nwhen the function needs:\n\n```\nprojectID\nregion\n```\n\nPass the data the function actually needs.\n\nNarrow function signatures improve readability and testability.\n\nBad:\n\n```\ntype GetProjectOptions struct {\n\tID string\n}\n```\n\nfor:\n\n```\nGetProject(ctx, GetProjectOptions{ID: id})\n```\n\nPrefer:\n\n```\nGetProject(ctx, id)\n```\n\nOption structs are useful when several meaningful parameters travel together or optional parameters exist.\n\nBad:\n\n```\ntype ExistsResult struct {\n\tExists bool\n}\n```\n\nPrefer:\n\n```\nfunc Exists(...) (bool, error)\n```\n\nUse structs when multiple related return values form a meaningful object.\n\nBad:\n\n```\nfunc GetProject(id string) (project *Project, err error) {\n\t...\n}\n```\n\nunless named returns materially improve the function.\n\nPrefer:\n\n```\nfunc GetProject(id string) (*Project, error) {\n```\n\nAvoid naked returns in non-trivial functions.\n\nSearch for:\n\n```\ndefer func() {\n\tif r := recover(); r != nil {\n\t\t...\n\t}\n}()\n```\n\nDo not use `recover` to turn programming bugs into normal control flow.\n\nRecover only at genuine process/request boundaries where keeping the process alive is intentional.\n\nDo not put `recover()` inside normal business functions.\n\nDo not use `panic` for:\n\n- validation failures\n- missing DB rows\n- network errors\n- malformed user input\n\nReturn errors.\n\nPanics are appropriate for states that make program initialization or continued execution impossible.\n\nReview:\n\n``` js\nvar defaultClient ...\nvar globalConfig ...\nvar singleton ...\n```\n\nGlobals are fine for true constants/immutable package state.\n\nDo not use mutable package globals as a shortcut for dependency wiring.\n\nPass dependencies explicitly.\n\nBad:\n\n```\nService\n→ Repository\n→ Store\n→ DAO\n→ QueryExecutor\n→ sql.DB\n```\n\nUse the minimum layering that matches the application.\n\nA repository around SQL/Mongo queries is reasonable.\n\nA repository wrapped by another object that just forwards everything is not.\n\nDo not create elaborate query builders for three static queries unless dynamic composition is actually needed.\n\nPlain SQL is often easier to understand:\n\n``` js\nconst query = `\n\tSELECT id, name\n\tFROM projects\n\tWHERE id = $1\n`\n```\n\nDo not hide straightforward SQL behind abstraction solely to avoid writing SQL.\n\nDo not invent elaborate:\n\n```\nTransactionManager\nUnitOfWork\nTransactionProvider\nTransactionRunner\n```\n\nif this suffices:\n\n```\ntx, err := db.BeginTx(ctx, nil)\nif err != nil {\n\treturn err\n}\n\ndefer tx.Rollback()\n\n...\n\nreturn tx.Commit()\n```\n\nAbstract transaction handling only when repeated complexity justifies it.\n\nDo not replace every string with a constant.\n\nGood:\n\n``` js\nconst duplicateKeyCode = 11000\n```\n\nwhen the number has domain/driver meaning.\n\nUnnecessary:\n\n``` js\nconst emptyString = \"\"\nconst trueValue = true\n```\n\nConstants should communicate meaning.\n\nCustom string constants are useful:\n\n```\ntype DeploymentStatus string\n\nconst (\n\tDeploymentPending DeploymentStatus = \"pending\"\n\tDeploymentRunning DeploymentStatus = \"running\"\n)\n```\n\nBut do not create enums for every arbitrary string if there is no closed set of valid values.\n\nGo `switch` is often better than abstraction.\n\nBad:\n\n```\nhandlers := map[string]func(Event) error{\n\t\"insert\": handleInsert,\n\t\"delete\": handleDelete,\n}\n```\n\nwhen a simple switch is clearer:\n\n```\nswitch event.Type {\ncase \"insert\":\n\treturn handleInsert(event)\n\ncase \"delete\":\n\treturn handleDelete(event)\n\ndefault:\n\treturn ErrUnsupportedEvent\n}\n```\n\nUse dispatch maps when dynamic registration is genuinely valuable.\n\nIf there are only two slightly different cases, a switch may be clearer than:\n\n```\ntype Strategy interface {\n\tExecute(...)\n}\n```\n\nplus:\n\n```\nInsertStrategy\nDeleteStrategy\nReplaceStrategy\n```\n\nGo does not require every branch to become polymorphism.\n\nDo not create interfaces purely so every dependency can be mocked.\n\nPrefer testing real behavior where practical.\n\nUse small interfaces around expensive/external boundaries.\n\nDo not turn every internal type into an interface because \"tests need mocks.\"\n\nApply the cleanup to tests.\n\nRemove:\n\n- enormous test builders\n- generic fixture systems\n- helper pyramids\n- mocks for pure logic\n- repeated `any`\n- excessive test abstractions\n\nPrefer explicit table-driven tests where appropriate:\n\n```\ntests := []struct {\n\tname string\n\tin   string\n\twant string\n}{\n\t{\"lowercase\", \"EXAMPLE.COM\", \"example.com\"},\n\t{\"trim\", \" example.com \", \"example.com\"},\n}\n```\n\nDo not make tests harder to understand than the code they test.\n\nThis cleanup must not mistake normal Go code for slop.\n\nThis is idiomatic and should remain:\n\n```\nif err != nil {\n\treturn err\n}\n```\n\nLikewise:\n\n```\nvalue, ok := m[key]\nif !ok {\n\t...\n}\n```\n\nand:\n\n```\nif project == nil {\n\t...\n}\n```\n\ncan all be correct.\n\nThe question is whether the failure/absence is genuinely possible and meaningful.\n\nDo not remove necessary checks merely to reduce line count.\n\nThe desired code should be shorter because unnecessary concepts disappeared.\n\nNot because everything was compressed into unreadable expressions.\n\nBad cleanup:\n\n```\nif err := func() error { ... }(); err != nil { return fmt.Errorf(...) }\n```\n\nPrefer boring readable Go.\n\nWhenever you see:\n\n```\nasString(value)\nasObjectID(value)\nextractDomain(value)\nsafeValue(value)\ntoMap(value)\n```\n\ntrace where `value` originated.\n\nAsk:\n\n1. Why isn't this value already strongly typed?\n2. Is this data external?\n3. Can it be decoded into a concrete struct at the boundary?\n4. Can downstream functions accept the concrete type?\n5. Can this helper then disappear?\n\nAlways prefer fixing the source of poor typing.\n\nBe particularly suspicious of combinations like:\n\n```\ninterfaces.go\nfactory.go\nbuilder.go\nmapper.go\nconverter.go\nvalidator.go\nutils.go\nhelpers.go\nmanager.go\nprocessor.go\nservice.go\nrepository.go\n```\n\ninside one small feature.\n\nDo not assume all these layers are necessary.\n\nDetermine what each one actually does.\n\nCollapse layers that merely forward calls or transform identical structures.\n\nSearch the repository for:\n\n```\nany\ninterface{}\nmap[string]any\nmap[string]interface{}\nreflect.\nrecover(\npanic(\nfmt.Sprintf\nstrconv.\nerrors.New\nfmt.Errorf\nerrors.As\nerrors.Is\n== nil\n!= nil\ntype .* interface\nFactory\nBuilder\nManager\nProcessor\nHelper\nUtils\nMapper\nConverter\nValidator\nOptions\nParams\nDTO\nEntity\nModel\nValueOr\nSafe\nNormalize\nExtract\nResolve\nParse\nGetString\nAsString\nToString\nWith\ncontext.Background\ncontext.TODO\nsync.Pool\ngo func\nmake([]\n```\n\nDo not automatically change every match.\n\nUse them as places to inspect for unnecessary complexity.\n\nBefore adding or keeping code, ask:\n\nDoes this handle something that can genuinely happen?\n\nIf no, delete it.\n\nAsk:\n\nIs this complexity caused by poor typing upstream?\n\nIf yes, fix the upstream type.\n\nAsk:\n\nDoes this interface have more than one meaningful implementation or consumer-driven purpose?\n\nIf no, consider using the concrete type.\n\nAsk:\n\nDoes this helper express a real concept?\n\nIf no, inline it.\n\nAsk:\n\nDoes this abstraction reduce total complexity?\n\nIf no, remove it.\n\nAsk:\n\nWould plain Go be easier to understand?\n\nIf yes, use plain Go.\n\nPrefer code like:\n\n```\nfunc (s *Service) MapDomain(ctx context.Context, event DomainMapEvent) error {\n\tdomain := strings.ToLower(strings.TrimSpace(event.Domain))\n\n\treturn s.domains.Map(ctx, event.ProjectID, domain)\n}\n```\n\nover:\n\n```\nfunc (s *Service) MapDomain(ctx context.Context, raw any) error {\n\tevent, err := convertToDomainMapEvent(raw)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed converting domain event: %w\", err)\n\t}\n\n\tprojectID := safeString(event.ProjectID)\n\tif projectID == \"\" {\n\t\treturn nil\n\t}\n\n\tdomain := normalizeStringValue(event.Domain)\n\tif domain == \"\" {\n\t\treturn nil\n\t}\n\n\treturn s.domainManager.ProcessDomainMapping(\n\t\tctx,\n\t\tNewDomainMappingParams(projectID, domain),\n\t)\n}\n```\n\nWork feature-by-feature.\n\nFor each feature:\n\nIdentify where data enters the system.\n\nExamples:\n\n- HTTP\n- queue\n- Kafka/NATS/RabbitMQ\n- MongoDB\n- PostgreSQL\n- Redis\n- webhook\n- external API\n- environment/config\n\nGive the input a concrete type.\n\nValidate/decode once.\n\nFollow the data through the application.\n\nRemove unnecessary:\n\n- `any`\n- type assertions\n- generic maps\n- nil guards\n- converters\n- extractors\n- wrapper structs\n- interfaces\n- pass-through methods\n- duplicate DTOs\n- generic helpers\n\nCollapse forwarding layers.\n\nDelete dead abstractions.\n\nRun tests and static analysis.\n\nUse the project's normal commands, including where applicable:\n\n```\ngo test ./...\ngo vet ./...\nstaticcheck ./...\n```\n\nRun formatters after changes:\n\n```\ngofmt\n```\n\nDo not change behavior merely to satisfy style preferences.\n\nDo not remove:\n\n- useful interfaces\n- meaningful error wrapping\n- legitimate nil handling\n- boundary validation\n- context propagation\n- proper resource cleanup\n- `defer rows.Close()`\n- `defer resp.Body.Close()`\n- transaction rollback safety\n- mutexes protecting real shared state\n- channel synchronization that is actually needed\n- driver-specific error handling\n- correct integer/error checks\n- security-related checks\n\nThis is a complexity cleanup, not reckless deletion.\n\nThe codebase should end up with:\n\n- more concrete structs\n- fewer `any` values\n- fewer generic maps\n- fewer type assertions\n- fewer conversion helpers\n- fewer tiny wrapper functions\n- fewer pointless interfaces\n- fewer forwarding layers\n- fewer factories/builders/managers\n- less reflection\n- less defensive nil handling\n- less silent fallback behavior\n- simpler error handling\n- fewer redundant DTOs\n- more direct function calls\n- narrower function signatures\n- explicit business logic\n- validation concentrated at boundaries\n- straightforward idiomatic Go\n\nThe important metric is not the number of files changed.\n\nThe important metric is:\n\n**Can an engineer trace the behavior without jumping through unnecessary abstractions?**\n\nDo not replace one kind of slop with another.\n\nDo not turn:\n\n```\nvalue := data[\"domain\"].(string)\n```\n\ninto:\n\n```\nvalue, ok := data[\"domain\"]\nif !ok {\n\treturn \"\"\n}\n\ndomain, ok := value.(string)\nif !ok {\n\treturn \"\"\n}\n```\n\nand call that a cleanup.\n\nThe correct solution is usually:\n\n```\ntype Event struct {\n\tDomain string `json:\"domain\"`\n}\n```\n\nfollowed by:\n\n```\nevent.Domain\n```\n\nLikewise, do not replace a simple direct call with:\n\n```\ninterface\n→ implementation\n→ manager\n→ helper\n→ converter\n→ validator\n→ actual function\n```\n\nThe overriding principle is:\n\n**Make untrusted input safe at the edge. Keep trusted Go code boring everywhere else.**", "url": "https://wpnews.pro/news/markdown-file-to-de-slop-your-go-codebase", "canonical_source": "https://gist.github.com/pipethedev/0bc97d0d4a13edafbad95a00ad8b7ffe", "published_at": "2026-09-07 13:10:43+00:00", "updated_at": "2026-09-07 13:57:23.499916+00:00", "lang": "en", "topics": ["developer-tools"], "entities": [], "alternates": {"html": "https://wpnews.pro/news/markdown-file-to-de-slop-your-go-codebase", "markdown": "https://wpnews.pro/news/markdown-file-to-de-slop-your-go-codebase.md", "text": "https://wpnews.pro/news/markdown-file-to-de-slop-your-go-codebase.txt", "jsonld": "https://wpnews.pro/news/markdown-file-to-de-slop-your-go-codebase.jsonld"}}