How to talk about architecture?

Author:
Daniel Antos

What are we talking about today?

  • Why?
  • When good intentions go south
  • Approaches that have helped me
  • How to continue conversation in the code (Go)

Why?

  • The best ideas come from clashing opinions
  • Some techniques promote deep thinking
  • If everyone is rowing in the same direction,
    we will get there faster

When good intentions go south

I believe that we all have good intentions.

And even the flawed approach is better than inactivity.

Large pull requests

I was working on a feature. There was this architectural issue. One thing led to the other, and...

Being too excited for specific solution

Dictating from the ivory tower

Approaches that have helped me

Decision records

Diagrams

Proof of Concept (PoC)

  • Show the journey.
  • What are the worst ways to solve the problem?
  • At which point the other opinion is better?

How to continue the conversation in Go

Folder structure is a good guide

3 stages

Folder structure is a good guide

Domain Driven Design?

bids.go seems more important

Let types tell the story

func init() {
	var bids auction.Bids
	var tricks int

	contract := bids[len(bids)-1]
	CountPoints(contract, tricks)
}

func CountPoints(
	contract auction.Bid,
	tricks int,
) int {
	return 0
}

Nothing stops us from passing the wrong thing

// Domain
type Contract Bid

func (bs Bids) Contract() Contract

// Scoring
func init() {
	var bids auction.Bids
	var tricks int

	CountPoints(bids.Contract(), tricks)
}

func CountPoints(
	contract auction.Contract,
	tricks int,
) int {
	return 0
}

Little work to create a new type, but developer will be warned about a wrong type usage

Restrict access

package scoring

var tricks int
contract := infra.Repo{}.Find().Contract()

CountPoints(contract, tricks)
package scoring

var tricks int
contract := infra.Logs{Repo: infra.Repo{}}.
	Find().Contract()

CountPoints(contract, tricks)
package scoring

var tricks int
contract := infra.New().Find().Contract()

CountPoints(contract, tricks)
package infra

func New() Repo {
	return logs{Repo: repo{}}
}

type Repo interface {
	Find() internal.Bids
}

// ...

We can restrict developers from misusing our creations

Restrict access

package scoring

import (
	"bridge/pkg/auction"
	"bridge/pkg/auction/api"
)

func init() {
	var tricks int
	contract := api.API{}.FindContract()

	CountPoints(contract, tricks)
}
package scoring

import (
	"bridge/pkg/auction"
    
    // compilation error!
	"bridge/pkg/auction/internal/infra"
)

func init() {
	var tricks int
	contract := infra.New().Find().Contract()

	CountPoints(contract, tricks)
}

Or even hide entire packages!

Restrict access

package auction

type Contract = internal.Contract

// ...

package scoring

import (
	"bridge/pkg/auction"
)

func init() {
	var tricks int
	contract := auction.API{}.FindContract()

	CountPoints(contract, tricks)
}

func CountPoints(
	contract auction.Contract,
    tricks int,
) int {
	return 0
}

Let's architect a game - Contract Bridge!

Summary

  • Don't do it alone
  • Find a way to collaborate that fits you and your team
  • The best architecture doesn't matter, if you don't have buy-in
  • Expressing ideas in the code explicitly lengthen their lives
  • Don't do it alone

Thanks!

Let's have some questions!

☝️My blog
danielantos.com

☝️Slides

How to talk about architecture?

By antosdaniel

How to talk about architecture?

  • 40