Skip to content

go design: SOLID vs functional options #18

@AmitKumarDas

Description

@AmitKumarDas

Use functional options when:

  • The behaviour needs to be tweaked
    • E.g.: DryRun, Debug, UseHttp, IgnoreChecks, etc.
    • E.g.: Support reuse a cached build as well as build always features
  • TIP: API needs boolean flags & optional features
  • TIP: Remember functional options is often used with variadic arguments
    • I.e.: There can be no args or a bunch of them & both of these should be perfectly valid
  • TIP: It is wrong if clients have to remember which functional option is mandatory vs. optional

Do not use functional options when:

  • Multiple behaviours are desired
    • Github release vs Gitlab release
  • Main actor / entity changes or requires additional entities/actors
    • Running on Mac vs Running on Windows
  • More examples:
    • Save file to Database vs. Publish file to CDN
    • Build using make vs. Build using make inside container
    • Build inside container vs. Build inside K8s Pod
    • Build inside Gitlab runner vs. Build inside Jenkins runner
  • Use of functional options in above case leads to:
    • [1] A single structure that caters to all possible requirements
    • [2] Explosion in the number of functions exposed from a single package
    • Most importantly the Single Responsibility Pattern (i.e. S in SOLID) is violated due to [1]
  • Summary: Functional options is not right if it breaks any of the SOLID principles
  • Remedy: Stick to old school patterns, idiomatic & effective practices
  • Test: Keep verifying the implementations against SOLID principles

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions