Ownership as code

In software development, ownership is a term that’s often thrown around but poorly understood. What does it mean to own something? Why is this something we strive to attain?

At Samsung Ads, the engineering team had been growing very rapidly (2x yearly) over the last 3 years and it’s become clear that ownership is something critical. Who owns that codebase? Who’s responsible for the uptime of that service? Who should I reach out to if the service goes down? When you’re a startup these questions are trivial, but as you grow things becomes messy (shared monolith, old codebases, etc).

What is code ownership? #

Before we continue, I think it’s important to define what is ownership. Code ownership can be broken down into 3 facets:

Responsibility #

If you own a codebase, you should be responsible for it. You should care that it’s well maintained and make sure that it gets the right level of attention (new features, code cleanups, updating dependencies, architecture improvements, etc).

Accountability #

If you own a codebase (service), you should also be accountable if you introduce a bug or if it breaks in production. You should be pro-active in fixing it and communicating (incident management) to anyone that depends on it.

Autonomy #

If you own a codebase, you should be setting the coding standards and enforcing them (CI checks and PR reviews). You should be in charge of the architecture and you should document (ADRs). You should be in control of the service deployments in production (CD). You also should be in control of the app/product metrics and monitoring for that service.

Awkward phase #

Now that I’ve explained what ownership is, let’s get back to the story. Clearly, we’re not the first one to experience the pains associated with hyper-growth. There’s plenty of organizational models out there that can solve these issues. Most famously, the service oriented architecture (SOA) which was popularized by Amazon (see Jeff Bezos 2002 memo). But how do you go from the “startup organizational model” (aka no model) to a full out SOA model? What structure or tools can you use to untangle the mess during this transition phase?

The first thing we tried was to build a Google sheet that documents all the products, features and services and assign them clear owners. After a few weeks of back and forth it became clear that this wasn’t the right tool for the job. The Google sheet was complex to navigate and only a few individuals had enough product depth to keep it up to date.

Ownership as code #

As a software developer (I’m still a software dev in my heart), my go to tool for solving problems is code. In this case, it took me a while to realize that code could actually help me since this is an organizational issue. My first realization was that most of the data in our Google sheet was denormalized (remember that database class?). The second one, was that each owner (management, product, engineering) should be in control of updating the model at the level they understand. And voilà, the best way to solve this problem was to introduce a data model that can represent our organizational structure. And so is born the concept of “ownership as code”.

I decided to abuse some of the tools I love as a developer (mostly Git and Github) to build something simple that answers our current needs. Since this data doesn’t change often, I decided to build a file based database (yaml-file-db) that uses YAML documents as source data and JSON schemas for validation. The database is committed into Git which gave us history for free. The database is hosted on Github, which give us user management for free and also pull requests to review changes. The big advantage of having this as code is that I can actually automate and enforce code ownership using Github Actions and the Github API. Every time the “ownership database” is updated, we do the following:

By doing this we make sure that our model is always in sync with reality. We also get metrics (for free) to track progress which is a nice bonus.

Database example #

The directory structure matches the database structure. Each folder within the database directory is a table. Each YAML document within a table directory is a row. The filename of the YAML document is used as the primary key for that row.

database/
  features/
    comment.yml
    post.yml
  services/
    comment-api.yml
    neo4j.yml
    post-api.yml
    postegresql.yml
  teams/
    alpha.yml
    beta.yml

Keys that match a table name (singular or plural form) are automatically converted into relationships.

# features/comment.yml
description: Create and edit comments
services:
    - comment-api
    - neo4j
# services/neo4j.yml
description: Graph database
team: alpha
# teams/alpha.yml
name: Alpha team
product_owner: Alice
engineers:
    - name: John Doe
      github: johndoe
    - name: Jane Doe
      github: janedo

You can easily navigate the data using the YDB:Database object. Each table is indexed by primary key and columns are exposed via accessors.

irb(main):001:0> require 'yaml-file-db'
=> true

irb(main):002:0> db = YDB::Database.new("/path/to/database", "/path/to/schemas").build
=> #<YDB::Database:0x00007fedb1922c68 ... >

irb(main):03:0> db.features["comment"].services.first.id
=> "comment-api"

irb(main):04:0> db.features["comment"].services.first.team.engineers
=> [{"name"=>"John Doe", "github"=>"johndoe"}, {"name"=>"Jane Doe", "github"=>"janedoe"}]

Next steps #

Code ownership is just one piece of the puzzle and we still have a lot of work to do to get to “full ownership”. In my next post, I’ll cover our progress on the “Ownership as code” journey and talk about other important aspects of ownership.

 
18
Kudos
 
18
Kudos