Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Adding context to existing code

Adding context to existing code

Avatar for Alexey Palazhchenko

Alexey Palazhchenko

March 24, 2019
Tweet

More Decks by Alexey Palazhchenko

Other Decks in Programming

Transcript

  1. Solution 1: «just» add ctx QueryRow(string, ...interface{}) *Row QueryRow(context.Context, string,

    ...interface{}) *Row Query(string, ...interface{}) (*Rows, error) Query(context.Context, string, ...interface{}) (*Rows, error) Exec(string, ...interface{}) (Result, error) Exec(context.Context, string, ...interface{}) (Result, error)
  2. Solution 1 problems • Internal code – large-scale refactoring. •

    Use context.TODO(). • «TODO is recognized by static analysis tools that determine whether Contexts are propagated correctly in a program.»
  3. Solution 1 problems • Internal code – large-scale refactoring. •

    Use context.TODO(). • «TODO is recognized by static analysis tools that determine whether Contexts are propagated correctly in a program.» • This tool does not exist.
  4. Solution 2x QueryRow(string, ...interface{}) *Row QueryRowContext(context.Context, string, ...interface{}) *Row Query(string,

    ...interface{}) (*Rows, error) QueryContext(context.Context, string, ...interface{}) (*Rows, error) Exec(string, ...interface{}) (Result, error) ExecContext(context.Context, string, ...interface{}) (Result, error)
  5. Solution 2x Delete(record Record) error DeleteFrom(view View, tail string, args

    ...interface{}) (uint, error) Exec(query string, args ...interface{}) (sql.Result, error) FindAllFrom(view View, column string, args ...interface{}) ([]Struct, error) FindByPrimaryKeyFrom(table Table, pk interface{}) (Record, error) FindByPrimaryKeyTo(record Record, pk interface{}) error FindOneFrom(view View, column string, arg interface{}) (Struct, error) FindOneTo(str Struct, column string, arg interface{}) error FindRows(view View, column string, arg interface{}) (*sql.Rows, error) Insert(str Struct) error InsertColumns(str Struct, columns ...string) error InsertMulti(structs ...Struct) error NextRow(str Struct, rows *sql.Rows) error QualifiedColumns(view View) []string QualifiedView(view View) string Query(query string, args ...interface{}) (*sql.Rows, error) QueryRow(query string, args ...interface{}) *sql.Row Reload(record Record) error Save(record Record) error SelectAllFrom(view View, tail string, args ...interface{}) (structs []Struct, err error) SelectOneFrom(view View, tail string, args ...interface{}) (Struct, error) SelectOneTo(str Struct, tail string, args ...interface{}) error SelectRows(view View, tail string, args ...interface{}) (*sql.Rows, error) Update(record Record) error UpdateColumns(record Record, columns ...string) error UpdateView(str Struct, columns []string, tail string, args ...interface{}) (uint, error)
  6. Solution 3 type Querier struct { Context context.Context } func

    (q *Querier) QueryRow(query string, args ...interface{}) *sql.Row
  7. https://golang.org/pkg/context/ «Do not store Contexts inside a struct type; instead,

    pass a Context explicitly to each function that needs it. The Context should be the first parameter, typically named ctx.» Solution 3 «problem»
  8. https://github.com/golang/go/issues/14660 «While we've told people not to add contexts to

    structs, I think that guidance is over-aggressive. The real advice is not to store contexts. They should be passed along like parameters. But if the struct is essentially just a parameter, it's okay.» Solution 3
  9. Solution 3b type Querier struct { ctx context.Context } func

    (q *Querier) WithContext(ctx context.Context) *Querier func (q *Querier) QueryRow(query string, args ...interface{}) *sql.Row
  10. Conclusion • "Just" add ctx to internal code. • Consider

    your options for the external code. • Know best practices beyond their short versions.