<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Yiming Chen</title>
    <description>The latest articles on Forem by Yiming Chen (@dsdshcym).</description>
    <link>https://forem.com/dsdshcym</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F224831%2F678e32a4-e6e4-4c81-b478-1d8c1490cdc6.jpeg</url>
      <title>Forem: Yiming Chen</title>
      <link>https://forem.com/dsdshcym</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dsdshcym"/>
    <language>en</language>
    <item>
      <title>How to Partially Restore a PostgreSQL Database?</title>
      <dc:creator>Yiming Chen</dc:creator>
      <pubDate>Tue, 14 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/dsdshcym/how-to-partially-restore-a-postgresql-database-o03</link>
      <guid>https://forem.com/dsdshcym/how-to-partially-restore-a-postgresql-database-o03</guid>
      <description>&lt;p&gt;Recently, I need to restore a PostgreSQL Database from production to staging.&lt;br&gt;
Unfortunately, our staging server is not as powerful as our production server.&lt;br&gt;
Specifically, our staging only has ~800GB of disk storage.&lt;br&gt;
But the total spaces needed for production database is slightly over 800GB.&lt;br&gt;
And due to some technical constraints, we can't add more spaces to staging.&lt;br&gt;
So we choose to do a partial restore, i.e. only restoring data from tables we needed, excluding data we didn't need.&lt;br&gt;
This task turns out to be harder than I expected.&lt;br&gt;
I've made many mistakes until I find the correct way to do it.&lt;br&gt;
Hope you can learn from my mistakes and restore your data correctly.&lt;/p&gt;

&lt;h2 id="org7aaa3fe"&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;
Don't use &lt;code&gt;pg_restore -t&lt;/code&gt; for a clean restore!
Don't use &lt;code&gt;pg_restore -t&lt;/code&gt; for a clean restore!
Don't use &lt;code&gt;pg_restore -t&lt;/code&gt; for a clean restore!
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;pg_restore -l&lt;/code&gt; to dump a table of contents of the archive.&lt;/li&gt;
&lt;li&gt;Comment out unneeded DATA from the ToC&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;pg_restore -L&lt;/code&gt; to restore the whole database except DATA that were excluded in 2&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="orgca6281f"&gt;Problems with &lt;code&gt;pg_restore -t&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;
I searched on StackOverflow.
&lt;a href="https://stackoverflow.com/questions/37038193/exclude-table-during-pg-restore"&gt;The first solution&lt;/a&gt; I found was &lt;code&gt;pg_restore -t&lt;/code&gt;.
So I dropped the staging db, ran the &lt;code&gt;pg_restore -t&lt;/code&gt; command immediately.
&lt;/p&gt;

&lt;p&gt;
But I ran into three annoying issues.
Only after I'd fixed all of them, did I realize I shouldn't have used &lt;code&gt;pg_restore -t&lt;/code&gt; at the first place.
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;
Indices were missing
&lt;/p&gt;

&lt;p&gt;
The first thing I noticed was the staging app became so slow after the restore.
Then I checked the indices in staging database and found nothing.
This was the moment I realized that the &lt;code&gt;-t&lt;/code&gt; option is doing its job too well.
&lt;/p&gt;

&lt;p&gt;
(Apparently, another developer has already run into the same issue before:
 &lt;a href="https://serverfault.com/questions/806271/pg-restore-on-a-single-table-not-restoring-indexes"&gt;postgresql - pg_restore on a single table not restoring indexes - Server Fault&lt;/a&gt;)
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Constraints were missing
&lt;/p&gt;

&lt;p&gt;
The next issue happened when I started using the Rails app.
Whenever I requested a record, I got the same error: &lt;code&gt;Unknown primary key for table&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
This was because all the primary key CONSTRAINTS were missing (not restored) from the database.
When these constraints were missing, &lt;code&gt;ActiveRecord&lt;/code&gt; didn't know &lt;code&gt;id&lt;/code&gt; was the primary key, which triggered the error.
&lt;/p&gt;

&lt;p&gt;
After primary key constraints were restored, this issue was fixed.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Sequences/Defaults were missing
&lt;/p&gt;

&lt;p&gt;
Finally, I got another issue about &lt;code&gt;id&lt;/code&gt;.
Whenever I saved a record, I got this error: &lt;code&gt;ActiveRecord::StatementInvalid: PG::Error: ERROR: null value in column “id” violates not-null constraint&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
This was because all the SEQUENCES and DEFAULTS for the &lt;code&gt;id&lt;/code&gt; columns were missing (not restored) from the database.
&lt;code&gt;ActiveRecord&lt;/code&gt; uses SEQUENCES and DEFAULTS to make primary keys automatically increment itself when a new record is created in the db.
When these two were missing from the database, &lt;code&gt;ActiveRecord&lt;/code&gt; could only assign primary key to &lt;code&gt;nil&lt;/code&gt;, which violated the constraint.
&lt;/p&gt;

&lt;p&gt;
More interestingly, I only restored the &lt;code&gt;SEQUENCES&lt;/code&gt; for &lt;code&gt;id&lt;/code&gt; columns.
But the issue still persisted.
So I also tried to &lt;a href="http://www.osny.me/blog/how-to-reset-postgres-id-sequence-in-a-ruby-on-rails-app"&gt;reset the &lt;code&gt;SEQUENCES&lt;/code&gt; (which didn't work because &lt;code&gt;DEFAULTS&lt;/code&gt; were still missing):&lt;/a&gt;
&lt;/p&gt;

&lt;pre&gt;ActiveRecord::Base.connection.tables.each do |t|
  ActiveRecord::Base.connection.reset_pk_sequence!(t)
end
&lt;/pre&gt;


&lt;p&gt;
After I restored &lt;code&gt;DEFAULTS&lt;/code&gt;, the issue was fixed.
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
After these three annoying issues, I knew I did something wrong.
Fortunately, it was only our staging server, so I only wasted my own time and energy.
&lt;/p&gt;

&lt;p&gt;
Reading the documentation for &lt;code&gt;pg_restore -t&lt;/code&gt;, I finally realized it wasn't the right tool for the job.
&lt;/p&gt;

&lt;pre&gt;
-t table
--table=table
    Restore definition and/or data of only the named table. For this purpose,
    "table" includes views, materialized views, sequences, and foreign tables.
    Multiple tables can be selected by writing multiple -t switches. This
    option can be combined with the -n option to specify table(s) in a
    particular schema.

        Note
        When -t is specified, pg_restore makes no attempt to restore any other
        database objects that the selected table(s) might depend upon.
        Therefore, there is no guarantee that a specific-table restore into a
        clean database will succeed.
&lt;/pre&gt;

&lt;p&gt;
As you may have notices from the &lt;code&gt;Note&lt;/code&gt;, pg_restore makes no attempt to restore any other database objects that the selected table(s) might depend upon.
(I didn't read this Note because I thought &lt;a href="https://stackoverflow.com/questions/37038193/exclude-table-during-pg-restore"&gt;StackOverflow&lt;/a&gt; was trustworthy.)
&lt;/p&gt;

&lt;p&gt;
Besides all the missing indices, constraints, sequences, defaults, and more, &lt;code&gt;pg_restore -t&lt;/code&gt; won't create any tables that were not specified with the &lt;code&gt;-t&lt;/code&gt; option.
So any db migration related to the missing tables would fail on staging in the future.
Which means this solution is absolutely unacceptable in this use case.
&lt;/p&gt;

&lt;p&gt;
What else shall we do?
&lt;/p&gt;

&lt;h2 id="org43e973a"&gt;Introducing &lt;code&gt;pg_restore -l&lt;/code&gt; and &lt;code&gt;pg_restore -L&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;
Turns out the correct answer is right below the first one in &lt;a href="https://stackoverflow.com/questions/37038193/exclude-table-during-pg-restore"&gt;the same StackOverflow page&lt;/a&gt;.
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;
&lt;code&gt;pg_restore -l psql_backup.dump &amp;gt; db.list&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
Passing &lt;code&gt;-l&lt;/code&gt; option to &lt;code&gt;pg_restore&lt;/code&gt; would produce a table of content for the dump file.
This ToC includes all the data and their locations included in the dump file:
&lt;/p&gt;
&lt;pre&gt;
;
; Archive created at Mon Sep 14 13:55:39 2009
; dbname: DBDEMOS
; TOC Entries: 81
; Compression: -1
; Dump Version: 1.13-0
; Format: CUSTOM
; Integer: 4 bytes
; Offset: 8 bytes
; Dumped from database version: 10.10
; Dumped by pg_dump version: 10.10
;
;
; Selected TOC Entries:
;
28920 70946 DATABASE - DBDEMOS pasha
55141; 15509 237 SCHEMA - public pasha
50798; 80741 51835 COMMENT - SCHEMA public pasha
66197; 75700 30831 ACL - public pasha
79603; 43218 86982 TYPE public composite pasha
59759; 64565 4792 EXTENSION - pg_trgm
95301; 10755 17786 COMMENT - EXTENSION pg_trgm
31637; 99705 30851 TABLE public users DBDEMOS
18171; 24739 26392 SEQUENCE public users_id_seq DBDEMOS
81822; 19526 48192 SEQUENCE OWNED BY public users_id_seq DBDEMOS
59215; 11301 6736 DEFAULT public users id DBDEMOS
2227; 53943 37511 TABLE DATA public users DBDEMOS
37029; 1384 1099 SEQUENCE SET public users_id_seq DBDEMOS
14500; 53947 96995 CONSTRAINT public users users_pkey DBDEMOS
26691; 92878 55511 INDEX public index_users_on_email DBDEMOS
85474; 88765 68415 TRIGGER public users username_update DBDEMOS
&lt;/pre&gt;

&lt;p&gt;
Notice that this file contains all types of data in the dump: databases, schemas, comments, access control lists (ACL), extensions, tables, sequences, defaults, table data, constraints, indices, triggers, and so on.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Comment out data we do not need
&lt;/p&gt;

&lt;p&gt;
We can change this ToC by commenting out or deleting the part we don't want to restore.
In this case, we don't want to restore &lt;code&gt;DATA&lt;/code&gt; from &lt;code&gt;users&lt;/code&gt; table, so we delete it.
&lt;/p&gt;
&lt;pre&gt;
;
; Archive created at Mon Sep 14 13:55:39 2009
; dbname: DBDEMOS
; TOC Entries: 81
; Compression: -1
; Dump Version: 1.13-0
; Format: CUSTOM
; Integer: 4 bytes
; Offset: 8 bytes
; Dumped from database version: 10.10
; Dumped by pg_dump version: 10.10
;
;
; Selected TOC Entries:
;
28920 70946 DATABASE - DBDEMOS pasha
55141; 15509 237 SCHEMA - public pasha
50798; 80741 51835 COMMENT - SCHEMA public pasha
66197; 75700 30831 ACL - public pasha
79603; 43218 86982 TYPE public composite pasha
59759; 64565 4792 EXTENSION - pg_trgm
95301; 10755 17786 COMMENT - EXTENSION pg_trgm
31637; 99705 30851 TABLE public users DBDEMOS
18171; 24739 26392 SEQUENCE public users_id_seq DBDEMOS
81822; 19526 48192 SEQUENCE OWNED BY public users_id_seq DBDEMOS
59215; 11301 6736 DEFAULT public users id DBDEMOS
; 2227; 53943 37511 TABLE DATA public users DBDEMOS
37029; 1384 1099 SEQUENCE SET public users_id_seq DBDEMOS
14500; 53947 96995 CONSTRAINT public users users_pkey DBDEMOS
26691; 92878 55511 INDEX public index_users_on_email DBDEMOS
85474; 88765 68415 TRIGGER public users username_update DBDEMOS
&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
&lt;code&gt;pg_restore -L db.list&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;-L&lt;/code&gt; option would tell &lt;code&gt;pg_restore&lt;/code&gt; to only restore the data specified in the Table of Content file.
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
After restoring with this solution, our staging behaves the same as production.
No weird issues like &lt;code&gt;Unknown primary key for table&lt;/code&gt; anymore!
&lt;/p&gt;

&lt;h2 id="orgb460ade"&gt;Lessons Learned&lt;/h2&gt;

&lt;p&gt;
The biggest lesson from this experience for me is to always RTFW (read the f**king manual).
Don't trust StackOverflow or blog posts online too much.
They can be misleading more often than not.
Always read the documentation to fully understand the meaning of the script, command, option I'm going to use.
&lt;/p&gt;

&lt;p&gt;
It's lucky that these issues only happened to our staging server, so they didn't impact our users.
But I need to train myself to be more careful on staging, and even on my local.
Only after good habits are cultivated, can I perform these actions (or automate them) on production safely.
&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>postges</category>
      <category>database</category>
      <category>rails</category>
    </item>
    <item>
      <title>How to Write Elixiry Ruby - Result Object</title>
      <dc:creator>Yiming Chen</dc:creator>
      <pubDate>Wed, 08 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/dsdshcym/how-to-write-elixiry-ruby-result-object-5h77</link>
      <guid>https://forem.com/dsdshcym/how-to-write-elixiry-ruby-result-object-5h77</guid>
      <description>&lt;h2&gt;Table of Contents&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Why do we need Result Objects?
&lt;ul&gt;
&lt;li&gt;Returning &lt;code&gt;nil&lt;/code&gt;: The Billion Dollar Mistake&lt;/li&gt;
&lt;li&gt;Raising exceptions: The Million Dollar Mistake&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Tagged Tuple: Modeling Errors in Elixir&lt;/li&gt;
&lt;li&gt;
Result Objects: Introducing an extra level of indirection

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;OpenStruct&lt;/code&gt;: Tagged Tuple in Ruby&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Struct&lt;/code&gt;: Don't Repeat Yourself&lt;/li&gt;
&lt;li&gt;Result Object: Adding More Behaviours to a &lt;code&gt;Struct&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Result Struct in Elixir?&lt;/li&gt;
&lt;li&gt;Summary: Modeling Business Error as Data/Objects&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;
&lt;a href="http://sasamat.xen.prgmr.com/michaelochurch/wp/2013/04/03/gervais-macleod-21-why-does-work-suck/"&gt;"A language that doesn't affect the way you think about programming is not worth knowing." - Alan J. Perlis&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
Elixir/Erlang certainly affected the way I think about programming.
Specifically, how to handle inevitable failure/error cases in my program.
In Elixir/Erlang, &lt;a href="https://yiming.dev/blog/2019/08/16/use-return-value-to-defer-decisions/"&gt;error cases can be easily modeled as tagged tuples&lt;/a&gt;: &lt;code&gt;{:error, reason}&lt;/code&gt;.
But in a more Object-Oriented language like Ruby, it's hard to model error as a lightweight data structure like Elixir tuples.
After some trial-and-error, I've found a great way to model errors in OO languages: Result Object.
&lt;/p&gt;

&lt;h2 id="org0989e7a"&gt;Why do we need Result Objects?&lt;/h2&gt;

&lt;p&gt;
Before explaining what is Result Object and how to write it, it's necessary to know why do we need it.
Error handling is inevitable in every programming language.
Take parsing CSV for example:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The file might be missing.&lt;/li&gt;
&lt;li&gt;The header might be invalid.&lt;/li&gt;
&lt;li&gt;The row might not match the header.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Our program cannot always run in a happy path.
We have to handle errors one way or another.
&lt;/p&gt;

&lt;p&gt;
Two methods I used to handle errors in Ruby are:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;returning &lt;code&gt;nil&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;raising an exception.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
Let's see why these two methods are not enough for us.
&lt;/p&gt;

&lt;h3 id="org4458d29"&gt;Returning &lt;code&gt;nil&lt;/code&gt;: The Billion Dollar Mistake&lt;/h3&gt;

&lt;p&gt;
Before learning Elixir, I used to return &lt;code&gt;nil&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; to indicate some error happens in Ruby:
&lt;/p&gt;

&lt;pre&gt;def parse_csv(path)
  if file_exists?(path)
    file = read(path)
    parse(file)
  else
    nil
  end
end

# client
if results = parse_csv
  # do something
else
  # assuming file read failed
end
&lt;/pre&gt;

&lt;p&gt;
It worked okay when the requirements were simple.
But it quickly broke down when another error needs to be handled.
&lt;/p&gt;

&lt;pre&gt;def parse_csv(path)
  if file_exists?(path)
    file = read(path)
    rows = parse(file)
    if valid_header?(rows)
      # return results
    else
      # what to return here?
      # nil is already used
    end
  else
    nil
  end
end
&lt;/pre&gt;

&lt;p&gt;
When there are multiple error cases, a simple &lt;code&gt;nil&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; cannot tell the client what really goes wrong.
&lt;/p&gt;

&lt;p&gt;
More importantly, if the client doesn't handle &lt;code&gt;nil&lt;/code&gt; and use &lt;code&gt;nil&lt;/code&gt; as a normal return value, then a &lt;code&gt;NoMethodError&lt;/code&gt; would be raised and the whole application would crash.
Countless bugs are produced due to this reason.
That's why &lt;a href="https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare"&gt;null (nil) references is called The Billion Dollar Mistake&lt;/a&gt;.
We need a better way to handle error cases than &lt;code&gt;nil&lt;/code&gt;!
&lt;/p&gt;

&lt;h3 id="org426ca1e"&gt;Raising exceptions: The Million Dollar Mistake&lt;/h3&gt;

&lt;p&gt;
If &lt;code&gt;nil&lt;/code&gt; is not enough to tell what error happened, we can raise different exceptions, right?
&lt;/p&gt;

&lt;pre&gt;def parse_csv(path)
  file = read!(path)
  parse!(file)
end

private

def read!(path)
  raise NoFileError unless file_exists?(path)
  # ...
end

def parse!(file)
  raise InvalidHeadersError unless valid_headers?
  # ...
end
&lt;/pre&gt;

&lt;p&gt;
It worked okay at first glance.
Happy path is separated from sad paths.
The code is much simpler and straight-forward now!
&lt;/p&gt;

&lt;p&gt;
But if we dig deeper, using exceptions has tremendous costs:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Raising/Catching exceptions have a performance penalty.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Method API is now unpredictable.
&lt;/p&gt;

&lt;p&gt;
We cannot see all the possible returns from a method.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;"Are there any exceptions being raised beside the normal return value?"&lt;/li&gt;
&lt;li&gt;"Are there any other exceptions being raised in these private methods?"&lt;/li&gt;
&lt;li&gt;"Are there any other exceptions being raised in other object methods that are used in this method?"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Adding behaviours to exception class is hard.
&lt;/p&gt;

&lt;p&gt;
Exception classes are inherited from &lt;code&gt;StandardError&lt;/code&gt;.
So they have some default methods: &lt;code&gt;backtrace&lt;/code&gt;, &lt;code&gt;cause&lt;/code&gt;, etc.
If we add more domain-related methods to it (e.g. &lt;code&gt;reason&lt;/code&gt;), is it still an &lt;code&gt;StandardError&lt;/code&gt; class?
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
All the costs above are fixable.
We can optimize the exception raising/catching performance so it won't be an issue.
We can declare all the exceptions raised by a method (like Java).
We can add a base class (inherited from &lt;code&gt;StandardError&lt;/code&gt;) and inherit this base class to reuse behaviours.
&lt;/p&gt;

&lt;p&gt;
But the fundamental flaw of using exceptions to handle sad paths is unsolvable:
&lt;b&gt;using exceptions mixes &lt;i&gt;fatal exceptions&lt;/i&gt; with &lt;i&gt;domain errors&lt;/i&gt;.&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
Every program needs to handle fatal exceptions: syntax error, divided by zero, and so on.
But the errors we are handling here are domain errors: missing files, invalid inputs, and so on.
&lt;/p&gt;

&lt;p&gt;
They need to be handled differently.
For fatal exceptions, the program may crash and notify a developer to fix the bug that leads to the exception.
For domain errors, the program may need to recover from the error and notify the user for a better user experience.
&lt;/p&gt;

&lt;p&gt;
Raising exception like &lt;code&gt;StandardError&lt;/code&gt; is the only solution for fatal exceptions for now.
That's why almost every programming language has this feature.
If we use exceptions for business errors, it's polluting the purity of fatal exceptions.
And both developers and operators would be confused when a non-fatal exception is raised on production.
&lt;/p&gt;

&lt;p&gt;
So we need our own way to handle business errors.
And different languages have different specific ways to do it.
&lt;/p&gt;

&lt;h2 id="org0f729c1"&gt;Tagged Tuple: Modeling Errors in Elixir&lt;/h2&gt;

&lt;p&gt;
Let's first see how errors are modeled in Elixir.
And we'll see how it inspired me to find Result Object.
In Elixir, a function would &lt;a href="https://yiming.dev/blog/2019/08/16/use-return-value-to-defer-decisions/"&gt;indicate its success/failure by returning a tagged tuple&lt;/a&gt;:
&lt;/p&gt;

&lt;pre&gt;def parse_csv(path) do
  if {:ok, file} = read_file(path) do
    # ...
    {:ok, results}
  else
    {:error, reason}
  end
end

# client
case pase_csv() do
  {:ok, results} -&amp;gt;
    # ...
    nil

  {:error, reason} -&amp;gt;
    nil
    # ...
end
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{:ok, results}&lt;/code&gt; means the operation succeeded, callee can safely assume the &lt;code&gt;results&lt;/code&gt; is correct.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{:error, reason}&lt;/code&gt; means the operation failed, and callee can know what caused the error based on the value of &lt;code&gt;reason&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
So now, when I work in a Ruby project, I want to write similar code to handle errors more gracefully.
But simply returning an array won't work elegantly as Elixir does:
&lt;/p&gt;

&lt;pre&gt;def parse_csv(path)
  if read(path)
    [:ok, results]
  else
    [:error, reason]
  end
end

# client
case parse_csv(path)
when [:ok, results] # results won't be bind to the return value
  # ...
when [:error, reason]
  # ...
end
&lt;/pre&gt;

&lt;p&gt;
Before Ruby 2.7, we don't have pattern matching to write Elixiry &lt;code&gt;case&lt;/code&gt; conditions.
What shall we do instead?
Is there a Object-Oriented way to modeling errors?
&lt;/p&gt;

&lt;h2 id="orgcdc2ea6"&gt;Result Objects: Introducing an extra level of indirection&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;
&lt;a href="https://en.wikipedia.org/wiki/Fundamental_theorem_of_software_engineering"&gt;We can solve any problem by introducing an extra level of indirection. - Fundamental theorem of software engineering&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
To get the similar result as tagged tuple in Elixir, I start with a lightweight approach.
Then I gradually add more behavior and refactor it.
Finally I landed with a more complicated design pattern: Result Object.
&lt;/p&gt;

&lt;h3 id="orga894f7e"&gt;
&lt;code&gt;OpenStruct&lt;/code&gt;: Tagged Tuple in Ruby&lt;/h3&gt;

&lt;p&gt;
My first try is to wrap the return value in an &lt;code&gt;OpenStruct&lt;/code&gt;:
&lt;/p&gt;

&lt;pre&gt;def parse_csv(path)
  if happy_path
    OpenStruct.new({valid: true, data: results})
  else
    # sad path
    OpenStruct.new({valid: false, reason: :file_missing})
  end
end

# client
result = parse_csv(path)
if result.valid
  p result.data
else
  case result.reason
  when :file_missing
    # ...
  end
end
&lt;/pre&gt;


&lt;p&gt;
As you can see above, &lt;code&gt;OpenStruct&lt;/code&gt; works just like tuples in Elixir.
We can create them and use them in a cheap and easy way.
And all the possible return values of a method is clearer than raising exceptions.
&lt;/p&gt;



&lt;h3 id="orgc67b5dc"&gt;
&lt;code&gt;Struct&lt;/code&gt;: Don't Repeat Yourself&lt;/h3&gt;

&lt;p&gt;
As more and more &lt;code&gt;OpenStruct&lt;/code&gt; objects are created, they start to attract behaviors.
The validation logic is a natural fit to be put in these objects, so I don't need to set &lt;code&gt;:valid&lt;/code&gt; to &lt;code&gt;true/false&lt;/code&gt; manually.
&lt;/p&gt;

&lt;pre&gt;Result = Struct.new(:path) do
  attr_reader :data, :reason

  def valid?
    if happy_path
      @data = ...
    else
      @reason = ...
    end
  end
end

# client
result = Result.new(path)
if result.valid?
  p result.data
else
  case result.reason
  when :file_missing
    # ...
  end
end
&lt;/pre&gt;


&lt;p&gt;
Defining &lt;code&gt;Struct&lt;/code&gt; classes like this helps us group &lt;code&gt;OpenStruct&lt;/code&gt; objects.
So the happy result and the sad result for the same method are always bundled together.
And different methods' result objects won't be mixed (since they are all &lt;code&gt;OpenStruct&lt;/code&gt; before).
&lt;/p&gt;



&lt;h3 id="org921b6df"&gt;Result Object: Adding More Behaviours to a &lt;code&gt;Struct&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;
Finally, when these &lt;code&gt;Struct&lt;/code&gt; classes become larger, they can have their own classes.
And if needed, they can have their own validation DSL, similar to what &lt;code&gt;ActiveModel::Validations&lt;/code&gt; does.
&lt;/p&gt;

&lt;pre&gt;class Result
  validate_file_existence :path

  def initialize(path)
    # ...
    # validate here
  end

  def valid?
    # run_validations!
  end
end
&lt;/pre&gt;

&lt;p&gt;
Most importantly, we can discover more domain concepts just by following the lead of Result Objects.
When I wrote the code to parse a CSV file and transform it into an &lt;code&gt;ActiveRecord&lt;/code&gt; object, I discovered these classes along the way:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;CSVWrapper&lt;/code&gt; as a wrapper around Ruby's builtin &lt;code&gt;CSV&lt;/code&gt; library.
It provides an API (&lt;code&gt;headers&lt;/code&gt;, &lt;code&gt;each_row&lt;/code&gt;) that's more suitable to our use cases.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CSVParser&lt;/code&gt; to transform a CSV file to a enumerator that returns valid domain objects.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RowParser&lt;/code&gt; to transform a CSV row to a valid domain objects.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
To quickly summarize, business errors are cases we need to handle as normal happy paths.
And just like normal business logic, we handle them by modeling them as data structures like tagged tuples or objects/classes like Result Objects.
&lt;/p&gt;

&lt;h2 id="org1a6a2ba"&gt;Result Struct in Elixir?&lt;/h2&gt;

&lt;p&gt;
Following the path from &lt;code&gt;OpenStruct&lt;/code&gt; to Result Object, I'm wondering if we need to define Result Struct in Elixir.
&lt;/p&gt;

&lt;pre&gt;defmodule Result do
  defstruct [:valid, :data, :reason]

  def new(data) do
    # ...
    # initialize data or reason based on the data passed in
  end
end
&lt;/pre&gt;

&lt;p&gt;
Result Struct seems to be an overkill in Elixir/Erlang.
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Elixir already has a great pattern matching system that working with tagged tuples is simple yet powerful.&lt;/li&gt;
&lt;li&gt;Tagged tuple is a more common way for handling errors in Elixir/Erlang.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
But I think if the business logic gets more complicated, we can follow the same thinking process to extract more domain concepts, too.
&lt;/p&gt;

&lt;h2 id="org7d12dbd"&gt;Summary: Modeling Business Error as Data/Objects&lt;/h2&gt;

&lt;p&gt;
In the end, tagged tuple in Elixir and Result Object in Ruby are both an extra level of indirection.
They both wrap the original results and provide an additional responsibility (to say if the operation succeeded or not or if the data is valid or not).
Again, they both demonstrate the power of &lt;a href="https://yiming.dev/blog/2019/08/16/use-return-value-to-defer-decisions/"&gt;modeling business knowledge as data&lt;/a&gt;.
Hope this technique can help you tackle other hard business problems as well!
&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>elixir</category>
      <category>objectorientedprogramming</category>
      <category>designpattern</category>
    </item>
    <item>
      <title>Growing a Result-Driven Mindset</title>
      <dc:creator>Yiming Chen</dc:creator>
      <pubDate>Tue, 31 Dec 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/dsdshcym/growing-a-result-driven-mindset-5og</link>
      <guid>https://forem.com/dsdshcym/growing-a-result-driven-mindset-5og</guid>
      <description>&lt;p&gt;Today is the last day of 2019.&lt;br&gt;
It's time for me to review the last year.&lt;br&gt;
Put everything aside, I think the biggest change of me is the mindset transition from a process-focused one to a result-driven one.&lt;/p&gt;

&lt;h2 id="org72f53ae"&gt;Connecting the dots (that led to a mindset shift)&lt;/h2&gt;

&lt;p&gt;
Inspired by &lt;a href="https://charity.wtf/2017/05/11/the-engineer-manager-pendulum/"&gt;The Engineer/Manager Pendulum&lt;/a&gt; written by Honeycomb CEO Charity Majors, I've been doing more management work in the past 12 months.
Management works like hiring, on-boarding, organizing meetings, planning, and goal setting really opened my mind.
When looking back, I realize that I've been unconsciously pushing myself and my team to a more result-driven style of working.
Let's see what I've done in a chronological order:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;
Setting up a goal-driven on-boarding program
&lt;/p&gt;

&lt;p&gt;
On-boarding is the most important thing if we want everyone to become a superstar in this team.
So I think of it as the highest leverage task for a team.
The goal of on-boarding in my team is to help the new-hire get familiar with our team and our way of work, so he/she can start delivering value as soon as possible.
&lt;/p&gt;

&lt;p&gt;
After some trial and error, we developed an on-boarding program for our team.
This program looks like this:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;On the first day a new member joins our team, a mentor would help him define a two-month roadmap.
This roadmap would define goals and tasks for the trial period.
For most developer roles, one of the most important goals is to deliver a feature to production (within one or two weeks).
Tasks are just checklists for guiding the new member to achieve the goals.&lt;/li&gt;
&lt;li&gt;At the end of every week, the mentor would have a catch-up meeting with the new member.
In this quick catch-up, they would review the past week, see if goals are achieved and maybe adjust/define the next goal.&lt;/li&gt;
&lt;li&gt;By the end of first month, the new member would join a more formal feedback meeting.
In this meeting, we would share feedback to the new member.
And the new member can share his/her feedback to the team, or the company.&lt;/li&gt;
&lt;li&gt;By the end of second month, our team would decide whether this new member passes the probation period or not.
Note that the decision is mostly based on if he/she has achieved the goal defined previously.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
With this program, we successfully on-boarded four backend developers.
They now all work at their full speed in various projects.
We also identified a mismatch between another web developer and our team.
He/She didn't achieve the goals we defined together even after we adjusted the goals accordingly.
Sadly, we had to let him/her go.
&lt;/p&gt;

&lt;p&gt;
As you can see, the goal plays an important role in the whole on-boarding process.
And we found that this process worked the best when the goal is clear and it's reviewed often.
If the goal is not clear, on-boarding would take much longer.
&lt;/p&gt;


&lt;/li&gt;


&lt;li&gt;

&lt;p&gt;
Defining expected results when writing a Tech Plan
&lt;/p&gt;

&lt;p&gt;
Turning the focus back to our internal team, I noticed that two of our major projects have the same delivery issue:
&lt;b&gt;a high rework rate.&lt;/b&gt;
&lt;/p&gt;

&lt;p&gt;
Team members rarely discuss the code change they are gonna make until they need to deploy it to production.
So, rework is often required during the code review phase (if there is one).
Or worse, sometimes hotfix is needed after deploy the change to production and there is a bug.
&lt;/p&gt;

&lt;p&gt;
This time, I introduced &lt;a href="https://yiming.dev/blog/2019/07/11/%E7%94%A8-tech-plan-%E6%9D%A5%E4%B8%BA%E5%BC%80%E5%8F%91%E6%8F%90%E9%80%9F/"&gt;Tech Plan&lt;/a&gt; (or RFC) to the team.
The purpose of defining a Tech Plan is for team members to have a common understanding of and how we are going to solve a problem.
&lt;/p&gt;

&lt;p&gt;
After introduced Tech Plan to more team members, we realized that the most important thing to do when defining a plan is &lt;b&gt;defining the problem&lt;/b&gt;.
Or put it in another way, defining the result we want to achieve.
Only when the result is clearly defined, can we come up with different solutions targeting at the same result, compare them, and make tradeoffs.
&lt;/p&gt;


&lt;/li&gt;


&lt;li&gt;

&lt;p&gt;
Clarifying expected results for each Sprint
&lt;/p&gt;

&lt;p&gt;
Next, I found our sprint meeting was not delivering the value as it should be.
Team members only go through the todo lists together, report the progress over the past sprint, and finally define the tasks for next sprint.
To me, the missing piece is the expectation of results, again.
People know what they should do (add sorting to a table),
but they don't know why they should do it or what result it is for (users can find the info they want more easily),
so they can't provide a better solution (add search functionality).
&lt;/p&gt;

&lt;p&gt;
So I helped clarify the purpose of sprint meeting:
sprint meetings is for reviewing the results from the previous sprint and getting aligned on the goal for the next sprint.
Most importantly, the goal here is not only a feature, but a hypothesis that if we ship feature A, then we can get outcome X.
Without this hypothesis, we don't know what we are targeting at.
&lt;/p&gt;

&lt;p&gt;
(And it also led me to &lt;a href="https://yiming.dev/clipping/2019/06/10/say-no-to-processes/"&gt;Say NO to Processes&lt;/a&gt;.)
&lt;/p&gt;


&lt;/li&gt;


&lt;li&gt;

&lt;p&gt;
Implementing OKR to define clear expectations
&lt;/p&gt;

&lt;p&gt;
Finally, I started working at every level of our team to help define OKRs for the next year/quarter.
&lt;/p&gt;

&lt;p&gt;
The idea is the same as before: to reach a common understanding of what results we want to achieve.
&lt;/p&gt;

&lt;p&gt;
There are still many challenges along the way, like how to define measurable key results for team building, design, project management.
Let's see how we can tackle these obstacles in 2020. :)
&lt;/p&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="orge8f2db6"&gt;What's the difference?&lt;/h2&gt;

&lt;p&gt;
Hopefully these stories sound interesting to you.
But you may ask what's the difference between action-driven (or process-focused) and result-driven, anyway?
&lt;/p&gt;

&lt;p&gt;
When I started working as a developer, I treated process as the heart of our work.
As long as we can use a new/fashion/professional process (like TDD), we can improve our efficiency.
Better processes can definitely do that, but probably not as efficient as if people are driven by results.
&lt;/p&gt;

&lt;p&gt;
When driven by results, we can experiment with different tools, different processes, compare them, and choose the best one for the current situation.
Let's see a few examples:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
Testing or not?
&lt;/p&gt;

&lt;p&gt;
I used to believe if a project doesn't have good test coverage, then it needs to be fixed.
But this thinking changed after I become more result-driven.
&lt;/p&gt;

&lt;p&gt;
What's the purpose of testing?
Or what's the desired results of well-tested code?
Correct behaviour and easier refactoring!
To achieve these result, we have way more tools than testing.
For example, a well defined type system can also help us ensure our code is correct and make refactoring easy.
(I guess that's why TypeScript is becoming more and more popular, and strict typed languages like Elm and Haskell can be so appealing.)
&lt;/p&gt;

&lt;p&gt;
More importantly, every tool has its pros and cons.
UI testing is a huge headache for automated tests.
Manual testing is probably a more efficient and more cost-effective choice.
&lt;/p&gt;

&lt;p&gt;
So now, I'm still a proponent of TDD, but also more open to other methods that can achieve the same result.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Detailed documentation or not?
&lt;/p&gt;

&lt;p&gt;
I used to ask for comments and documentations for most methods/classes/modules.
I used to copy private project discussion from Slack and paste it to our issue trackers.
But again, these practices changed after I become more result-driven.
&lt;/p&gt;

&lt;p&gt;
What's the purpose of writing everything down?
Better communication, better understanding, and not forgetting anything!
To achieve these results, detailed documentation may not help much.
For example, when there's a language barrier (people can hardly read English), descriptive notes can hardly help.
When others prefer discussing in person, sending an email can hardly lead to a receipt.
When everyone has a different way organizing their notes, documenting everything may not help because it's only useful to the author.
&lt;/p&gt;

&lt;p&gt;
So now, I still prefer to write things down, but only for myself, and I'll let everyone else to choose his/her preferable way to remember important things.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Single best solution or not?
&lt;/p&gt;

&lt;p&gt;
I used to want to write the best code, the best article, etc.
I used to think there is a best solution for every problem out there, everything is like an exam.
But again, this thinking becomes ridiculous when I become more result-driven.
&lt;/p&gt;

&lt;p&gt;
For most problems, its solution space is way larger than the problem itself.
The best thing we can do is to try as many solutions we can and choose the best one among them.
(In a geeky sense, most problems are NP-problems.)
&lt;/p&gt;

&lt;p&gt;
Because the solution space is so large that we cannot try them all, we can never know if a solution is the best or not.
There is always a better solution out there.
&lt;/p&gt;

&lt;p&gt;
So now, I would start a continuous experiment for a problem if I want to get the best result.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set a goal for the result.&lt;/li&gt;
&lt;li&gt;Find a hypothesis that may achieve this goal.&lt;/li&gt;
&lt;li&gt;Execute a plan to test the hypothesis.&lt;/li&gt;
&lt;li&gt;Revise the execution and see if the goal is achieved.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
As you can see from these examples, being result-driven doesn't equal to not taking actions.
On the contrary, it needs more actions being taken.
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Defining expectations clearly.&lt;/li&gt;
&lt;li&gt;Finding different solutions.&lt;/li&gt;
&lt;li&gt;Executing and comparing them.
(Maybe not taking any action achieves the best result.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
These all requires more efforts than just taking actions as a nobrainer.
Taking action is not the goal, achieving a better result is.
&lt;/p&gt;

&lt;p&gt;
Being result-driven doesn't equal to ditching every process, neither.
On the contrary, it means to always trying different solutions and always improving.
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If a process leads to a good result, then use it;&lt;/li&gt;
&lt;li&gt;If another process leads to a better result, then switch to it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
Improving process is not the goal, achieving a better result is.
&lt;/p&gt;

&lt;h2 id="orgf2b361a"&gt;Drawbacks of result-driven mindset&lt;/h2&gt;

&lt;p&gt;
That being said, result-driven mindset has its cons as well.
The biggest one is that the desired results need to be clear and explicit.
So when facing a problem that's unclear and requires some explorations, a result-driven mindset won't help us (and may even draw us back).
&lt;/p&gt;

&lt;p&gt;
Another thing is that if a goal is clear but doesn't reflect the result we want, it may lead us to a wrong direction.
For example, daily page view is a common metric for marketing.
And we set a goal for achieving 10,000 daily page view.
But what can we get out of it?
Maybe not what we want.
&lt;/p&gt;

&lt;p&gt;
Finally, focusing on the result too much may let us use whatever method to achieve it.
Take the same page view example.
To achieve the goal of 10,000 daily page view, we can buy a lot of fake clicks.
But by doing so, we've already lost what we really want.
&lt;/p&gt;

&lt;p&gt;
So, setting goals is an art on its own.
Let me explain it in a future post.
&lt;/p&gt;

&lt;h2 id="org7055621"&gt;What I've read&lt;/h2&gt;

&lt;p&gt;
Here are the books that guided me to this mindset in 2019:
&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;&lt;a href="https://www.amazon.com/gp/product/0996006028/"&gt;Radical Focus: Achieving Your Most Important Goals with Objectives and Key Results: Christina R Wodtke, Marty Cagan&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;How to set clear OKRs (goals) to help you achieve your desired results.&lt;/dd&gt;
&lt;dt&gt;&lt;a href="https://www.amazon.com/Right-Many-Ideas-Yours-Succeed/dp/0062884654/ref=sr_1_1?ie=UTF8&amp;amp;qid=1540239839&amp;amp;sr=8-1&amp;amp;keywords=alberto+savoia"&gt;The Right It: Why So Many Ideas Fail and How to Make Sure Yours Succeed&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Experiment quickly and cheaply to test if your hypothesis can bring you your desired results.&lt;/dd&gt;
&lt;dt&gt;&lt;a href="https://basecamp.com/shapeup"&gt;SHAPE UP: Stop Running in Circles and Ship Work that Matters&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Invest time and human resources once you've made your desired results clear.&lt;/dd&gt;
&lt;dt&gt;&lt;a href="https://www.amazon.com/gp/product/1942788290/"&gt;The Phoenix Project: A Novel about IT, DevOps, and Helping Your Business Win&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Find your constraints/bottle-necks when you want to optimize for a better result.&lt;/dd&gt;
&lt;dt&gt;&lt;a href="https://jonathanstark.com/hbin"&gt;Hourly Billing Is Nuts by Jonathan Stark&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;
&lt;a href="https://yiming.dev/blog/2019/11/12/why-billing-by-hours-is-a-bad-idea/"&gt;Focus on the results you've produced&lt;/a&gt;, instead of the sunk cost.&lt;/dd&gt;
&lt;/dl&gt;

&lt;h2 id="org16c9cbf"&gt;From result-driven mindset to growth mindset&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;
A growth mindset is the ability to not be fixed on a single solution, but to be consistently testing and iterating on your idea, and improving upon what you know so that you're focusing on the problem you are trying to solve, not the solution in your head.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
-- from &lt;a href="https://www.youtube.com/watch?v=k__XkwIpiCU&amp;amp;feature=share"&gt;Bot Thoughts: Growth Mindset&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Result-driven mindset is only a start point.
My goal for 2020 is to grow a growth mindset.
We'll see what results I can achieve then.
Happy New Year!
&lt;/p&gt;

</description>
      <category>mindset</category>
      <category>growthmindset</category>
      <category>yearlyreview</category>
      <category>goal</category>
    </item>
    <item>
      <title>Why do we need OKR (Objectives and Key Results)?</title>
      <dc:creator>Yiming Chen</dc:creator>
      <pubDate>Tue, 17 Dec 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/dsdshcym/why-do-we-need-okr-objectives-and-key-results-3n23</link>
      <guid>https://forem.com/dsdshcym/why-do-we-need-okr-objectives-and-key-results-3n23</guid>
      <description>&lt;p&gt;Misalignment in a team hurts.&lt;br&gt;
It hurts when a Sprint cycle ends, but none of the promised features are finished.&lt;br&gt;
It hurts when asking for a reason, everyone says "I have this other project that drags me."&lt;br&gt;
It hurts when project fails because we are not clear about what we really want and fight for it as a team.&lt;/p&gt;

&lt;p&gt;
I've been looking for a solution for misalignment for so long.
I've tried &lt;a href="https://yiming.dev/blog/2018/11/15/similarities_between_tdd_and_management/"&gt;organizing a meeting like TDD&lt;/a&gt;, &lt;a href="https://yiming.dev/blog/2019/07/11/%E7%94%A8-tech-plan-%E6%9D%A5%E4%B8%BA%E5%BC%80%E5%8F%91%E6%8F%90%E9%80%9F/"&gt;setting Tech Plans for dev team&lt;/a&gt;, and &lt;a href="https://yiming.dev/blog/2019/05/16/defining-a-mvp-by-setting-okrs/"&gt;defining a MVP by setting OKRs&lt;/a&gt;.
In retrospect, they are all practices of setting OKRs.
But their scopes are so small and can only cover a tiny portion of our daily works.
To solve the misalignment issue once and for all, I need to apply OKR at the team level.
&lt;/p&gt;

&lt;p&gt;
Fortunately, I just started working as an OKR Ambassador in my current team.
My main objective is to help everyone in my team get aligned and focused with well-defined OKRs.
And the following is what I show them the first: What is OKR and Why do we need it?
&lt;/p&gt;

&lt;h2 id="org024a797"&gt;What is OKR?&lt;/h2&gt;

&lt;p&gt;
OKR (Objectives and Key Results) is a goal system to create alignment around measurable goals.
Well defined OKRs unite everyone behind the same goals (objectives).
They provide focus so everyone can spend their time on things that matter the most.
They keep reminding us if we are in the comfort zone or the stretching zone, and nudging us toward stretching ourselves and thus grow as a team.
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
Objectives and Key Results
&lt;/p&gt;

&lt;p&gt;
OKR stands for &lt;b&gt;Objectives&lt;/b&gt; and &lt;b&gt;Key Results&lt;/b&gt;.
These two elements are the core of this goal setting system.
And they should always go together, as they are complementary to each other.
&lt;/p&gt;

&lt;p&gt;
An Objective is a qualitative and time-bound goal which gives a vision.
It needs to be inspiring and agreed by every team member.
So every team member is aligned upon the same mission.
A good example can be "Launch an Awesome MVP before 2020-03-31".
&lt;/p&gt;

&lt;p&gt;
But it's not enough to define a qualitative vision.
Everyone have a different understanding of "awesome", "MVP", and even "launch".
That's why we need Key Results as a complementary.
&lt;/p&gt;

&lt;p&gt;
Key Results are a few quantitative indicators which explains what the objective really means.
They need to be as objective (as opposed to subjective) as possible.
So every team member is aligned upon the same direction.
Some good examples are:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A web application that is used by at least 100 daily active users. ("launch" clarified)&lt;/li&gt;
&lt;li&gt;Users can write micro posts, follow new friends, read posts of his friends and re-post their posts. ("MVP" clarified)&lt;/li&gt;
&lt;li&gt;The loading time of friends' posts list is less than 100ms. ("awesome" clarified)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
After the OKR is defined and agreed by every team member, we need a few other things to help us execute the OKR well.&lt;sup&gt;1&lt;/sup&gt;
&lt;/p&gt;


&lt;/li&gt;


&lt;li&gt;

&lt;p&gt;
Plan
&lt;/p&gt;

&lt;p&gt;
Plans are actionable tasks that may contribute to at least one Key Result when finished.
Inspirational Objectives and Key Results cannot be achieved by their own.
So we need a road map that can lead us to our vision.
Some good examples are:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a production environment before 2019-12-31.&lt;/li&gt;
&lt;li&gt;Design, develop, and deploy the homepage before 2020-01-10.&lt;/li&gt;
&lt;li&gt;Purchase ads campaign on Twitter for our new MVP before 2020-01-15.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Notice that plans may or may not contribute to a Key Result.
The hypothesis behind purchasing a Twitter ads campaign is that it may help attract active users.
If we find it not working as expected, we must look for another way.
&lt;/p&gt;


&lt;/li&gt;


&lt;li&gt;

&lt;p&gt;
Baseline
&lt;/p&gt;

&lt;p&gt;
Baselines are some results that we need to keep and look out for.
We ought to make some trade-offs when we try to achieve a Key Result.
Baselines are here to help us make these trade-offs, or at least warn us if we make the wrong trade-off.
Some good examples are:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The overall cost must be lower than $20,000. (so we won't spend unlimited money on ads to attract active users.)&lt;/li&gt;
&lt;li&gt;The friends' posts list needs to show all the recent posts from every friend. (so we won't cut the loading time of this page by showing a incomplete list or even showing no posts at all.)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;


&lt;li&gt;

&lt;p&gt;
Future
&lt;/p&gt;

&lt;p&gt;
Futures are what we need to discuss again in the future.
Maybe we need to focus on the loading speed first, and postpone some new feature development to the future.
So Future serves as a backlog and can be reviewed when next OKR cycle begins.
&lt;/p&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="org40b75a2"&gt;Why do we need OKR?&lt;/h2&gt;

&lt;p&gt;
As it was mentioned briefly above, the main purpose of defining OKRs is to create alignment around measurable goals.
And as you may see, every build block of OKR contributes to this purpose in a different way.
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;
Objectives and Key Results defines clear direction and enables a continuous progress checking.
&lt;/p&gt;

&lt;p&gt;
Missions are inspiring and agreed upon beforehand.
Goals are no longer ambiguous because they are all measurable key results.
&lt;/p&gt;

&lt;p&gt;
Everyone can have the same understanding of our progress so far.
If the number of daily active users goes more up, we are moving closer to a successful launch.
If the number goes down instead, we can review our assumptions, hypothesis, plans, or actions to see if there are other things we can do.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Plans are defined and executed by the same people.
&lt;/p&gt;

&lt;p&gt;
OKR frees both managers and managees from micro-managing.
&lt;/p&gt;

&lt;p&gt;
Managers knows more about higher level stuffs like strategies, missions, and visions.
So they can focus on what results a team needs to achieve by defining better OKRs.
&lt;/p&gt;

&lt;p&gt;
Managees knows more about lower level (but not less important) stuffs like technologies, implementations, and constraints.
So they can come up with plans that match the reality the most.
These plans can even be more effective or creative than what managers can imagine.
&lt;/p&gt;

&lt;p&gt;
Note that doesn't mean only Managers define Objectives or Key Results, nor only managees define Plans.
OKRs are defined by all team members together.
And they can be defined from top down (Manager -&amp;gt; Managee, Objective -&amp;gt; Key Results -&amp;gt; Plan), or from bottom up (Managee -&amp;gt; Manager, Plan / Key Results -&amp;gt; Objective).
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Baseline prevents us from losing the whole picture.
&lt;/p&gt;

&lt;p&gt;
By human nature, we can easily lose the higher view when focusing on marching toward a narrowed goal.
By setting baselines and continuously monitoring them, OKR nicely reminds us and leads us to the correct road when we make a detour.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Future helps us focus on what matters now.
&lt;/p&gt;

&lt;p&gt;
We have limited resources (human power, time, money), so we have to spend them at the right places.
Being able to put things in Future can help us spend our resources wisely and get better results.
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
More importantly, when more OKRs are defined, we can sort out priorities more easily and become more focused.
How's "Launch an Awesome MVP" compared to "Build a better work place"?
Some teams may prioritize prior so people may work overtime a lot before the launch date.
Some teams may prioritize latter so the launch date is postponed by a month.
There is no right choice here, but at least we can discuss these choices explicitly based on OKRs.
&lt;/p&gt;

&lt;p&gt;
Finally, when everyone can see every team's OKR, every individual's OKR, transparency is improved by a lot.
When in conflicts, people can check each other's OKR, think about how to find a plan that can contribute to each other's Objectives, or compromise to a solution based on OKR priorities (if a plan cannot be find).
&lt;/p&gt;

&lt;h2 id="org6ff0dce"&gt;Final Words&lt;/h2&gt;

&lt;p&gt;
Hopefully, this short summary of OKR can help you understand this goal system better.
And I'll keep posting my experiences and learnings of implementing OKR in my team.
So, stay tuned!
&lt;/p&gt;

&lt;h2&gt;Footnotes: &lt;/h2&gt;

&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; &lt;/p&gt;
&lt;p&gt;&lt;br&gt;
These other things are from the great management book &lt;a href="https://www.amazon.com/Radical-Candor-Kickass-Without-Humanity/dp/1250103509"&gt;Radical Candor: Be a Kick-Ass Boss Without Losing Your Humanity: Kim Scott&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

</description>
      <category>okr</category>
      <category>goal</category>
      <category>management</category>
    </item>
    <item>
      <title>Management, Refactor, and Prune</title>
      <dc:creator>Yiming Chen</dc:creator>
      <pubDate>Tue, 26 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/dsdshcym/management-refactor-and-prune-4l48</link>
      <guid>https://forem.com/dsdshcym/management-refactor-and-prune-4l48</guid>
      <description>&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;blockquote&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Being a great manager and English gardening have more in common than you might imagine.
&lt;ol&gt;
&lt;li&gt;small, seemingly minor activity&lt;/li&gt;
&lt;li&gt;clip away the dead leaves or diseased areas of a garden to encourage healthy growth.&lt;/li&gt;
&lt;li&gt;done periodically&lt;/li&gt;
&lt;li&gt;The day that you stop pruning is the day that the garden is full of weeds and overrun&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;
-- from &lt;a href="https://m.signalvnoise.com/what-great-managers-do-prune/"&gt;What great managers do: Prune - Signal v. Noise&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Gardening is a spectacular analogy not only for management, but also for code refactoring.
We need to prune our codebase consistently.
And the activity of pruning in a software project is called refactoring.
&lt;/p&gt;

&lt;p&gt;
Like pruning, refactoring is a small, seemingly minor activity.
Renaming a variable, making a public function private, or moving a function from a module to another.
It's the accumulation of all these small, incremental steps that &lt;a href="https://yiming.dev/clipping/2018/06/07/livable_and_disposable_code/"&gt;make our codebase a better place to live&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
Like pruning, refactoring demands us to remove dead code or technical debt to encourage good design.
&lt;a href="https://en.wikipedia.org/wiki/Broken_windows_theory"&gt;Broken windows theory&lt;/a&gt; is real.
Only by constantly fixing the broken windows in our codebase, can we nudge others to not break another window.
&lt;/p&gt;

&lt;p&gt;
Like pruning, refactoring is a periodical activity.
We cannot be refactoring all the time, or we have no time for building the real thing.
Often, people schedule a repetitive event to tackle the technical debts accumulated along the way.
Further more, experimental messy is a necessary evil.
Because we need these experiments to tell us if there's a better design.
&lt;/p&gt;

&lt;p&gt;
So if you need to explain refactoring to other non-technical people, you can use pruning as an analogy.
And please remember this:
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
The day that you stop refactoring is the day that the project is full of tech debts and overrun.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
P.S. Refactoring is everywhere in our daily life.
I even &lt;a href="http://dsdshcym.github.io/blog/2018/01/28/using-vim-emacs-is-like-a-refactoring-process/"&gt;treat optimizing my editor workflow as a refactoring process&lt;/a&gt;.
Pruning is just one of the best analogies out there.
&lt;/p&gt;

</description>
      <category>management</category>
      <category>refactor</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>Nobody Wants To Use Your API</title>
      <dc:creator>Yiming Chen</dc:creator>
      <pubDate>Fri, 22 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/dsdshcym/nobody-wants-to-use-your-api-1joc</link>
      <guid>https://forem.com/dsdshcym/nobody-wants-to-use-your-api-1joc</guid>
      <description>&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When writing an API endpoint or a function, I often find myself being obsessed with it, adding tons of toggles or options so this endpoint handles too many use-cases.&lt;br&gt;
In the end, not all of the toggles are used by the client.&lt;br&gt;
Even worse, the code is too complex to maintain.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;
So how do we, as programmers, avoid this pitfall?
I think we should apply some product thinking here.
First, think of our API as our product.
Then, realize that &lt;a href="https://www.smashingmagazine.com/2016/01/nobody-wants-use-your-product/"&gt;Nobody Wants To Use Your Product&lt;/a&gt;.
Finally, we write simple APIs that are easy to learn and easy to use.
&lt;/p&gt;

&lt;h2 id="orgc0acb7b"&gt;API is the only product of programming&lt;/h2&gt;

&lt;p&gt;
What is an API, anyway?
According to &lt;a href="https://en.wikipedia.org/wiki/Application_programming_interface"&gt;Wikipedia&lt;/a&gt;,
an API is &lt;i&gt;a "contract" between "the client" and "the server"&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
Notice that "the client" and "the server" don't need to be talking over a network.
So we are defining an API ("a contract") at every level of our application:
&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;When writing a function, we are designing an API for the callers of this function.&lt;/dt&gt;
&lt;dd&gt;What's the name of the function?
What arguments does this function need?
What results would this function return?&lt;/dd&gt;
&lt;dt&gt;When writing a library, we are designing an API for other programmers.&lt;/dt&gt;
&lt;dd&gt;What classes/modules does this library have?
How to use these classes/modules?
What results can these classes/modules achieve?&lt;/dd&gt;
&lt;dt&gt;When writing a RESTful controller action, we are designing an API for the browser.&lt;/dt&gt;
&lt;dd&gt;What's the path to this action?
What's the verb to use here? (GET, POST, PUT, DELETE)
What's the response structure?&lt;/dd&gt;
&lt;dt&gt;When writing a page view with HTML, JS, and CSS, we are designing an API for the user.&lt;/dt&gt;
&lt;dd&gt;What's this form used for?
What would happen after clicking this button?
What's the content of this page?&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;
And everything else we do, is to fulfill the API ("the contract") we defined.
&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;Write business code&lt;/dt&gt;
&lt;dd&gt;Fulfill the business logic contract.&lt;/dd&gt;
&lt;dt&gt;Write automated tests&lt;/dt&gt;
&lt;dd&gt;Make sure we fulfill the business contract as specified.&lt;/dd&gt;
&lt;dt&gt;Fix various bugs&lt;/dt&gt;
&lt;dd&gt;The contract was broken, we need to fulfill it again.&lt;/dd&gt;
&lt;dt&gt;Improve performance&lt;/dt&gt;
&lt;dd&gt;Fulfill the performance contract (return the results within &lt;code&gt;x&lt;/code&gt; seconds).&lt;/dd&gt;
&lt;dt&gt;Document the API&lt;/dt&gt;
&lt;dd&gt;Explain the contract to the user.&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;
Or we can think it from the opposite.
If you as "the server" don't expose an API to "the client", then it doesn't matter how much work you do behind the scenes.
Because nobody can use it anyhow.
&lt;/p&gt;

&lt;p&gt;
So API is the most important, if not the only, product of programming.
&lt;/p&gt;

&lt;h2 id="orgf5ccf85"&gt;Nobody wants to use your API&lt;/h2&gt;

&lt;p&gt;
After understanding that &lt;code&gt;API == product&lt;/code&gt; in programming, we can start to think from a product perspective.
In the article &lt;a href="https://www.smashingmagazine.com/2016/01/nobody-wants-use-your-product/"&gt;Nobody Wants To Use Your Product&lt;/a&gt;, Goran Peuc summarizes this presumption about human nature as:
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
People are not really into using products.
Rather, people are more interested in the end result and in obtaining that result in the quickest, least intrusive and most efficient manner possible.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
The same product thinking applies to programming as well.
Other programmers are not really into using our API.
They may use our API to get some data.
Or they may use our API to avoid reinventing the wheel and thus simplify their own code.
In a word, they use our API to &lt;b&gt;achieve a result&lt;/b&gt;.
&lt;/p&gt;

&lt;h2 id="org1e0f56d"&gt;KISS (Keep it simple, stupid)&lt;sup&gt;1&lt;/sup&gt;
&lt;/h2&gt;

&lt;p&gt;
So what can we do as API designers?
If nobody wants to use our API, and people use it only because they want to achieve a result, then we should make our API really simple.
And by "simple", I mean easy to learn and easy to use.
It's simple to say, but it's hard to do.
The ultimate goal requires us to spend tons of efforts:
people can spend almost no time to learn our API and start using it.
So they can focus on their own concerns, and spend more time figuring out how to succeed in their own way.
&lt;/p&gt;

&lt;h2&gt;Footnotes: &lt;/h2&gt;

&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; &lt;/p&gt;
&lt;p&gt;&lt;br&gt;
&lt;a href="http://principles-wiki.net/principles:keep_it_simple_stupid"&gt;Keep It Simple Stupid (KISS) {Principles Wiki}&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

</description>
      <category>product</category>
      <category>api</category>
      <category>design</category>
    </item>
    <item>
      <title>Fault-Tolerant GTD</title>
      <dc:creator>Yiming Chen</dc:creator>
      <pubDate>Tue, 19 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/dsdshcym/fault-tolerant-gtd-47ca</link>
      <guid>https://forem.com/dsdshcym/fault-tolerant-gtd-47ca</guid>
      <description>&lt;h2&gt;Table of Contents&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How to do "Fault-Tolerant GTD"&lt;/li&gt;
&lt;li&gt;
"Fault-Tolerant GTD" in real life
&lt;ul&gt;
&lt;li&gt;From blogging to micro-blogging&lt;/li&gt;
&lt;li&gt;Break a book apart&lt;/li&gt;
&lt;li&gt;Contribute to open source&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Take it one step further&lt;/li&gt;
&lt;li&gt;When "Fault-Tolerant GTD" is not a good choice&lt;/li&gt;
&lt;li&gt;Why it's called "Fault-Tolerant GTD"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
I use &lt;a href="https://yiming.dev/blog/2019/05/22/my-gtd-workflow-2019-ver/"&gt;deadlines to urge me to finish tasks in time&lt;/a&gt;.
In an ideal world,
I can always finish a task before its deadline.
My todo list won't explode due to the accumulated overdue tasks.
And I won't declare todo bankruptcy.
&lt;/p&gt;

&lt;p&gt;
But the real world is not ideal.
I'm often over-optimized when setting a deadline for a task, since &lt;a href="https://yiming.dev/blog/2019/05/27/estimating-is-hard-lets-cut-scope/"&gt;estimating is hard&lt;/a&gt;.
I'm often not motivated to work on a boring task, but I have to finish it.
I'm often just too busy to finish all the tasks.
&lt;/p&gt;

&lt;p&gt;
Due to these various reasons, I always find I haven't finished, or even haven't started some of my tasks when they are already overdue.
&lt;/p&gt;

&lt;p&gt;
This situation happens to project management as well.
Often, a team cannot ship all the features they've promised before.
(And it's totally fine, because we are stretching!)
&lt;/p&gt;

&lt;p&gt;
But then what shall we do with these overdue tasks?
Postponing them to the next cycle? No, it will lead to todo bankruptcy.
Putting them back to the backlog? No, we need to finish some of them before a "hard" deadline.
&lt;/p&gt;

&lt;p&gt;
Here is a useful method for you in this kind of situation.
And I call it "Fault-Tolerant GTD".
&lt;/p&gt;

&lt;h2 id="org779c642"&gt;How to do "Fault-Tolerant GTD"&lt;/h2&gt;

&lt;p&gt;
The basic idea of "Fault-Tolerant GTD" is to
use deadlines as an opportunity to review the task, and fallback to a sub-task,
thus push the progress forward.
&lt;/p&gt;

&lt;p&gt;
When a task is overdue, often the reason is that the task is too large.
Maybe the task is too large so we have some steps left unfinished.
Maybe the task is too daunting so we don't have enough motivation to start it.
Maybe the task is low priority so we choose to work on other things first.
&lt;/p&gt;

&lt;p&gt;
No matter what the reason is, let's take a few minutes to find an easier sub-task.
The sub-task may be small enough. So we can finish it immediately and make some progress.
The sub-task can be put into next cycle. So our next cycle is less daunting, and the smaller sub-task is more likely to get worked on.
The sub-task can also be some planning work. &lt;a href="https://yiming.dev/blog/2019/05/22/my-gtd-workflow-2019-ver/"&gt;Maybe the task isn't worth doing at all, so we can cancel it.&lt;/a&gt; Maybe our priorities need to change so we can execute on the right things.
&lt;/p&gt;

&lt;p&gt;
In this way, we &lt;b&gt;eat the elephant one bite at a &lt;del&gt;time&lt;/del&gt; deadline.&lt;/b&gt;
&lt;/p&gt;

&lt;h2 id="org6c30ce7"&gt;"Fault-Tolerant GTD" in real life&lt;/h2&gt;

&lt;p&gt;
I've been using this method for quite some time.
Here are some examples from my real experiences:
&lt;/p&gt;

&lt;h3 id="org744485f"&gt;From blogging to micro-blogging&lt;/h3&gt;

&lt;p&gt;
&lt;a href="https://yiming.dev/clipping/2019/08/18/ideas-are-cheap/"&gt;Ideas are cheap.&lt;/a&gt;
I can come up with three blog ideas a day, if I'm lucky.
So I have many ideas I want to write about.
&lt;/p&gt;

&lt;p&gt;
But writing a blog post is time-consuming.
I need at least 2 hours to organize my words, polish them as a while, and finally publish it.
And I can hardly write more than two blog posts every week.
&lt;/p&gt;

&lt;p&gt;
So I have way more ideas than I can write about.
Solving this problem with "Fault-Tolerant GTD" is simple.
The only thing you need is a fallback chain.
&lt;/p&gt;

&lt;p&gt;
Whenever a post idea is overdue, I'll consider the following actions:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write it as a short &lt;a href="https://yiming.dev/clipping/"&gt;Clipping&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Write it briefly in a &lt;a href="https://yiming.dev/tags/newsletter/"&gt;collection post&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Post it on &lt;a href="https://twitter.com/dsdshcym"&gt;Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
Notice that these options are getting easier in order, so it's more likely for my idea to be out than stale in my notes.
&lt;/p&gt;

&lt;h3 id="orgf3e9236"&gt;Break a book apart&lt;/h3&gt;

&lt;p&gt;
&lt;a href="https://yiming.dev/clipping/2019/11/15/how-to-start-consuming-less-and-creating-more/"&gt;Reading is also a time consuming activity.&lt;/a&gt;
My personal goal for reading is to finish 3 books every month.
But what if the month ends but I haven't finished the book I want to read?
&lt;/p&gt;

&lt;p&gt;
I would also find some easier sub-tasks for reading a book:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read inspectionally to grasp the concept of this book, instead of reading the whole book word by word.&lt;/li&gt;
&lt;li&gt;Extract chapters from the table of content and setting deadlines for each of them.
Because chapters are the natural sub-tasks of a book, so this is easy.&lt;/li&gt;
&lt;li&gt;Stop reading a book because it's not interesting enough for me.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
With these two options, I can always finish a book without worrying if I would miss something important.
&lt;/p&gt;

&lt;h3 id="org5bfd0d0"&gt;Contribute to open source&lt;/h3&gt;

&lt;p&gt;
Working part-time on open source is not easy.
I'm not pushed by a boss.
The only thing I can rely on is my own motivations and disciplines.
&lt;/p&gt;

&lt;p&gt;
Take contributing to &lt;a href="https://github.com/hexpm/hexpm/issues?utf8=%E2%9C%93&amp;amp;q=author:dsdshcym+"&gt;hexpm&lt;/a&gt; for example.
I would first take &lt;a href="https://github.com/hexpm/hexpm/issues/753"&gt;an issue&lt;/a&gt; as a task and set a deadline for it.
When the deadline comes, and I didn't make much progress on the issue, I would fallback to an easier task: investigate the issue.
Basically, it's about &lt;a href="https://yiming.dev/blog/2019/07/11/%E7%94%A8-tech-plan-%E6%9D%A5%E4%B8%BA%E5%BC%80%E5%8F%91%E6%8F%90%E9%80%9F/"&gt;doing the planning work&lt;/a&gt;.
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understanding the background of the issue&lt;/li&gt;
&lt;li&gt;Writing down the plan for how to solve this issue (&lt;a href="https://github.com/hexpm/hexpm/issues/753#issuecomment-442475571"&gt;example: store and display publisher of package version&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Replacing the original task with the first step in the next cycle
(replace &lt;i&gt;store and display publisher of package version&lt;/i&gt; with &lt;i&gt;Add &lt;code&gt;release_publishers&lt;/code&gt; table&lt;/i&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
After these planning works are finished, the issue will no longer be intimidating anymore.
Execution becomes smooth and easy.
&lt;/p&gt;

&lt;h2 id="org64b2450"&gt;Take it one step further&lt;/h2&gt;

&lt;p&gt;
We've already seen the power and benefits of "Fault-Tolerant GTD".
But it's not the end of the story.
"Fault-Tolerant GTD" is about using deadline as an opportunity to review our task.
We can take this idea one step further.
Deadline is not merely an opportunity to review the task, but also an opportunity to review ourselves.
&lt;/p&gt;

&lt;p&gt;
Whenever I apply "Fault-Tolerant GTD" to a task, I learn a bit more about myself.
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"I may not be interested in this kind of task."&lt;/li&gt;
&lt;li&gt;"I didn't plan well for unexpected events."&lt;/li&gt;
&lt;li&gt;"I was over-optimistic of myself to finish all these tasks."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
As I know myself better, I can plan better next time.
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I may reject a type of tasks, because I know I'm not interested and I won't take any actions.&lt;/li&gt;
&lt;li&gt;I may break a huge task down upfront, rather than waiting for the deadline to come.&lt;/li&gt;
&lt;li&gt;I may put less tasks in my next cycles because I know how much I can take.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
As I know more about myself, I can prevent these "faults" from happening in the future.
In this way, I become more effective at getting things done.
&lt;/p&gt;

&lt;h2 id="org02af1df"&gt;When "Fault-Tolerant GTD" is not a good choice&lt;/h2&gt;

&lt;p&gt;
Enough goodies, what are the drawbacks of this method?
Or when shall we choose another GTD method?
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;
The task has a hard deadline.
&lt;/p&gt;

&lt;p&gt;
Obviously, this method cannot be used if we have a hard deadline.
Because we cannot fallback to another task after the deadline passes.
&lt;/p&gt;

&lt;p&gt;
"Fault-Tolerant GTD" works the best when the task has a soft deadline.&lt;sup&gt;1&lt;/sup&gt;
Like reading books, writing blog posts, and contributing to open source projects.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
The review cycle is too long.
&lt;/p&gt;

&lt;p&gt;
When we have a deadline that's far away (several months from now), we may have trouble applying "Fault-Tolerant GTD".
&lt;/p&gt;

&lt;p&gt;
"Fault-Tolerant GTD" only contributes to your productivity when deadline is here.
So if we keep doing nothing and just wait several months for the deadline, we will waste all the wait time.
&lt;/p&gt;

&lt;p&gt;
When we are in this kind of situation, we may consider two options:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://yiming.dev/blog/2019/09/16/agile-is-continuous-learning/"&gt;Shorten the feedback cycle.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Break the task down upfront.&lt;/li&gt;
&lt;li&gt;Only use "Fault-Tolerant GTD" as a backstop to prevent doing absolutely nothing.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;


&lt;li&gt;

&lt;p&gt;
The review cycle is too short.
&lt;/p&gt;

&lt;p&gt;
But "Fault-Tolerant GTD" also won't work if the cycle is too short.
&lt;/p&gt;

&lt;p&gt;
Let's take it to the extreme.
Say the review cycle is 1 second.
That means every second is a deadline for a task.
And we need to constantly review and fallback.
Then we'll have no time for us to execute.
&lt;/p&gt;

&lt;p&gt;
After all, "Fault-Tolerant GTD" or any GTD methods are only planning work.
We'll need time to really dive into the real work and finish it.
&lt;/p&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
After considering these drawbacks,
I now only use "Fault-Tolerant GTD" for tasks without a hard deadline.
&lt;a href="https://yiming.dev/blog/2019/05/22/my-gtd-workflow-2019-ver/"&gt;I also follow a combination of 1-day, 1-week, 1-month, and 1-year cycles.&lt;/a&gt;
And it works flawlessly.
&lt;/p&gt;

&lt;p&gt;
If you have any questions implementing "Fault-Tolerant GTD", I'd be glad to help.
&lt;/p&gt;

&lt;h2 id="org7e3bbf8"&gt;Why it's called "Fault-Tolerant GTD"&lt;/h2&gt;

&lt;p&gt;
After all these explanations about "Fault-Tolerant GTD", you may still be wondering, why is it called "Fault-Tolerant GTD"?
&lt;/p&gt;

&lt;p&gt;
Both the name and the idea of "Fault-Tolerant GTD" are inspired by Erlang.
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://yiming.dev/clipping/2019/09/04/3-key-ideas-behind-the-erlang-thesis/"&gt;Erlang is designed to be a "fault-tolerant" programming language.&lt;/a&gt;
(Here, "fault" means errors or exceptions that occur in our programs.)
What Erlang does when a program fault occurs is to fallback to an easier program task, like restarting the task.
&lt;/p&gt;

&lt;p&gt;
I'm just applying the same idea to daily task management.
A "fault" occurs in task management when a task dues.
And to "tolerate" this "fault", we fallback to an easier task.
&lt;/p&gt;

&lt;p&gt;
Most of the time, we apply what we learned from our life to programming, but we can also do the opposite.
You may find some programming paradigm helpful with your life, too!
&lt;/p&gt;

&lt;h2&gt;Footnotes: &lt;/h2&gt;

&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; &lt;/p&gt;
&lt;p&gt;&lt;br&gt;
This restriction also reminds me of &lt;a href="http://www.structuredprocrastination.com/"&gt;Structured Procrastination&lt;/a&gt;,&lt;br&gt;
a GTD tactic that also requires us to choose tasks wisely.&lt;br&gt;
&lt;/p&gt;

</description>
      <category>gtd</category>
      <category>erlang</category>
      <category>projectmanagement</category>
    </item>
    <item>
      <title>How to Start Consuming Less and Creating More?</title>
      <dc:creator>Yiming Chen</dc:creator>
      <pubDate>Fri, 15 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/dsdshcym/how-to-start-consuming-less-and-creating-more-3i53</link>
      <guid>https://forem.com/dsdshcym/how-to-start-consuming-less-and-creating-more-3i53</guid>
      <description>&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;blockquote&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;The most reliable way to get better results is to just produce more crap.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Most knowledge worth having comes from practice.
&lt;ul&gt;
&lt;li&gt;It comes from doing.&lt;/li&gt;
&lt;li&gt;It comes from creating.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The real tragedy of modern technology is that it’s turned us into &lt;b&gt;consumers&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;br&gt;


&lt;p&gt;
-- from &lt;a href="https://tjcx.me/posts/consumption-distraction/"&gt;Consume less, create more&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Inspired by this article, I decided to consume less crap, and to create more crap of my own.
&lt;/p&gt;

&lt;p&gt;
How to do that?
It's as simple as any improvements:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;b&gt;Measure&lt;/b&gt; your baseline&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;Identify&lt;/b&gt; the bottleneck&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;Improve&lt;/b&gt; the bottleneck&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;Review&lt;/b&gt; the progress&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Repeat&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
Below is my current status and how I plan to improve it:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
Consuming
&lt;/p&gt;

&lt;p&gt;
I consume a lot.
Every month, I
watch ~3 movies, ~10 episodes of tv shows, ~30 YouTube videos,
read ~3 books, ~150 blog posts, and ~3000 of tweets.
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Movies are an important part of my entertainment life. I can't leave them once and for all. But I can be more selective in what I watch. And set a deadline for what I want to watch. &lt;a href="https://yiming.dev/blog/2019/05/22/my-gtd-workflow-2019-ver/"&gt;If I don't watch it before the deadline, then I won't.&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TV is also a huge time consumer. So I don't watch the traditional TVs (that you can't decide what you watch) anymore. I choose what I want to watch and allocate time for them.&lt;/li&gt;
&lt;li&gt;Good books are a joy to read. And it can worth hundreds of blog posts due to its density of knowledge. But if I can't apply the knowledge I learned from the book, then reading it would be a waste of time.&lt;/li&gt;
&lt;li&gt;Blog posts and tweets are my way to follow the newest trends. But it's totally okay to not read them. &lt;a href="https://yiming.dev/clipping/2019/10/04/clippings-of-2019-sep/"&gt;We don’t miss what we don’t see.&lt;/a&gt; My current strategy is to read for accomplishing a goal. &lt;a href="https://yiming.dev/clipping/2019/10/18/google-is-the-modern-syntopicon/"&gt;Google is always my best friend&lt;/a&gt; when I need to find some blog posts to learn about a topic.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;


&lt;li&gt;

&lt;p&gt;
Creating
&lt;/p&gt;

&lt;p&gt;
On the other hand, I create a lot less.
Every month, I
open ~3 pull requests on GitHub,
write ~5 blog posts,
post ~25 tweets.
&lt;/p&gt;

&lt;p&gt;
Given a high consume-create ratio like this, I sometimes feel that I don't get enough chances to apply what I've learned.
&lt;/p&gt;

&lt;p&gt;
So, I'm trying to do my best to create more craps and make sure they are read or used by someone else.
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Contribute more to open source projects like &lt;a href="https://github.com/hexpm/hexpm"&gt;hexpm/hexpm&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Post 2 blog posts every week (= 8 posts every month).&lt;/li&gt;
&lt;li&gt;Use Twitter as a micro-blogging platform.
It will be a backstop for my blog post ideas.
If I can't convert an idea to a blog post in time, I would post it to Twitter.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
If you like the craps I've created so far, please do follow me on Twitter, or shot me an email to discuss any topics. :)
&lt;/p&gt;

</description>
      <category>gtd</category>
    </item>
    <item>
      <title>Why Billing by Hours is a Bad Idea?</title>
      <dc:creator>Yiming Chen</dc:creator>
      <pubDate>Wed, 13 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/dsdshcym/why-billing-by-hours-is-a-bad-idea-2ppj</link>
      <guid>https://forem.com/dsdshcym/why-billing-by-hours-is-a-bad-idea-2ppj</guid>
      <description>&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;blockquote&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;
&lt;b&gt;No one is paid to take action, people are paid to achieve results.&lt;/b&gt;
&lt;/p&gt;



&lt;p&gt;
I really like this quote from &lt;a href="https://www.amazon.com/Million-Dollar-Consulting-Professionals-Practice/dp/1259588610/ref=dp_ob_title_bk"&gt;Million Dollar Consulting&lt;/a&gt;.
It's the best summary for why we need to be results driven (if we want to get paid and make money).
It also resonates with my terrible experiences in some hourly-billing projects.
I want to share these experiences here, explain why hourly-billing caused these troubles, and what's the alternative way to hourly-billing.
&lt;/p&gt;

&lt;h2 id="org2ad807f"&gt;The hourly-billing nightmare&lt;/h2&gt;

&lt;p&gt;
An hourly-billing project is doomed from the start.
But it's just the beginning.
When building and delivering the project, we'll find more troubles due to hourly-billing.
&lt;/p&gt;

&lt;h3 id="org27f8a1a"&gt;A fancy plan with a tight timeline&lt;/h3&gt;

&lt;p&gt;
Before a project gets started, we need to agree with the client what to build.
Often, the project idea is from a simple need of the client.
With hourly-billing, it's natural to build upon a simple need, adding more and more fancy features.
Because why not? Client would need it, and we can bill more hours building it.
&lt;/p&gt;

&lt;p&gt;
Then we need to give a proposal for this fancy plan, with a budget estimation (price / fee).
To get this budget estimation, we need a time estimation, since we are billing for hours, right?
&lt;/p&gt;

&lt;p&gt;
After reading the draft proposal, a developer estimates: "For these many features, we may need two years."
&lt;/p&gt;

&lt;p&gt;
"What? That's impossible! The client need it as soon as possible.
Can we cut it to two months so it also fits into their budget?
Just use the native style and whatever third party library you can find."
&lt;/p&gt;

&lt;p&gt;
At this point, the project is already doomed.
After all, &lt;a href="https://yiming.dev/clipping/2019/04/19/good-fast-and-featureful-pick-two/"&gt;good, fast, and featureful. We can only pick two.&lt;/a&gt;
With a short time frame and a tight budget, we have to cut the only thing left in the equation: software quality.
&lt;/p&gt;

&lt;h3 id="org84b349a"&gt;Bad executions under a tight budget&lt;/h3&gt;

&lt;p&gt;
Once the project starts with a fixed budget and a fixed timeline, every minute counts.
&lt;/p&gt;

&lt;p&gt;
To ship the project in two months, a lot of meetings are skipped.
Because a 1 hour meeting with 5 people counts as 5 hours.
It's just cheaper to dive into design and code.
&lt;/p&gt;

&lt;p&gt;
After two weeks of prototyping and coding, we finally ship something, only to find it's not what the user needs.
&lt;/p&gt;

&lt;p&gt;
(This kind of story always reminds me of the old saying: &lt;a href="https://twitter.com/codewisdom/status/1002181404061552640?lang=en"&gt;weeks of coding can save you hours of planning&lt;/a&gt;.)
&lt;/p&gt;

&lt;p&gt;
Besides, no one has written a line of automated test.
Why?
Because programmers know the requirements are definitely going to change.
Changing and maintaining these tests are going to make our budget tighter!
&lt;/p&gt;

&lt;p&gt;
At the end of the sprint, what we've got is an untested, useless application.
We need to hack it to make it really useful to the user.
It's what we call a &lt;a href="https://en.wikipedia.org/wiki/Death_march_(project_management)"&gt;Death March&lt;/a&gt;.
&lt;/p&gt;

&lt;h3 id="org4f063af"&gt;Time for a time usage report&lt;/h3&gt;

&lt;p&gt;
After we've finished the Death March, there's one last challenge before we get fully paid:
generate the time usage report and justify for it.
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://yiming.dev/clipping/2019/11/05/think-of-time-as-a-series-of-timestamps/"&gt;Recording time usage is not easy.&lt;/a&gt;
Most people don't have the habit of doing it.
When we are asked how much time we spent on a feature, the only thing we can only rely on is our memory.
So the time usage report we generate would be inaccurate.
&lt;/p&gt;

&lt;p&gt;
Then we send the report to the client.
Even if the report is accurate, the client would have a lot of questions.
These questions would be difficult to answer, because few clients are familiar with software development.
For example,
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"Why did a simple feature ("centering things with CSS") took you an hour?"&lt;/li&gt;
&lt;li&gt;"Why is the time usage not like what you estimated? Are you not following the plan?"&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="orgc59e4d9"&gt;Why is hourly-billing a trouble maker?&lt;/h2&gt;

&lt;p&gt;
Of course, these troubles are not caused solely by hourly-billing.
Bad executions like poor planning, no automated testing do have their own problem, too.
But with hourly-billing, it's easier to fall into these traps like unrealistic estimations, lack of planning, no tests, etc.
Plus, even if everything being equal (plan well, test well, record time well), we would still be questioned for how the time is being used.
So it's worthwhile to look into why hourly-billing is bad and to see if we have other alternatives.
&lt;/p&gt;

&lt;p&gt;
I think the problem is at the core of hourly-billing: &lt;b&gt;coupling time and money together.&lt;/b&gt;
This coupling not only puts our relationship with our client in danger, but also makes scaling our business hard.
&lt;/p&gt;

&lt;h3 id="org1ee1fa3"&gt;The tension between our client and us&lt;/h3&gt;

&lt;p&gt;
Due the coupling of how much time we spend and how much money we make, we want to spend more hours on a project.
But what's our clients really want? Result!
All they want is a product, a solution that can make their life/business better.
This misalignment is the root conflict between our client and us.
&lt;/p&gt;

&lt;p&gt;
Due to this misalignment, we may prefer a fancier solution that costs more time.
But what the client really needs is a simple working solution, ASAP.
&lt;/p&gt;

&lt;p&gt;
Due to this misalignment, we may have less incentive to improve, which are required to get a better result.
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
"With this new X, we can deliver the same thing in half the time! But how can we charge it the same as before? Maybe we wait until next time."
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
Due to this misalignment, we may center our internal conversations around how many hours we've spent, but not how many values we can generate.
People tend to be misled by these conversions and thus lose their focus on value.
&lt;/p&gt;

&lt;p&gt;
Due to this misalignment, we may lose trust from our client.
If we are not really thinking from the value our client can get, they will find it out one day.
&lt;/p&gt;

&lt;p&gt;
A better alternative must keep us aligned with our client,
by focusing on what value we can bring to them.
&lt;/p&gt;

&lt;h3 id="orga4a8681"&gt;It doesn't scale&lt;/h3&gt;

&lt;p&gt;
The coupling of time and money makes the price calculation simple: &lt;code&gt;Price = Hours * Rate&lt;/code&gt;.
So scaling with hourly-billing should be simple, too.
Our only two options are obvious, but neither of them are scalable:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;
Spend more hours in projects.
&lt;/p&gt;

&lt;p&gt;
We can do this by working overtime, which is not sustainable for our own health.
And we would hit the hard limit (24-hour-per-day) quickly.
&lt;/p&gt;

&lt;p&gt;
Or we can try to multi-task on different project at the same time.
I don't think it's possible for me or any normal human beings.
But if you know how to do it without affecting the quality of your output, please do teach me. :)
&lt;/p&gt;

&lt;p&gt;
The last resort is to hire some junior people to spend their time for us.
But these people raise our internal cost by a lot, not only with their hourly rate, but also a management cost.
&lt;/p&gt;

&lt;p&gt;
A better alternative should decouple the time we spend and the fee we get paid, so we can get a higher leverage.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
Raise our hourly rate.
&lt;/p&gt;

&lt;p&gt;
To raise our hourly rate, we need to find more valuable clients.
They value their projects more, they value our work more, and more importantly, they have more budget to afford a higher hourly rate.
&lt;/p&gt;

&lt;p&gt;
Then the question becomes "How to justify a $1,000 hourly rate?"
A smart sales person would start from our client's perspective:
"Our experience can bring you tremendous value. By finishing this feature in 5 hours, you would get far more than $5,000."
&lt;/p&gt;

&lt;p&gt;
This is the A-ha moment for me:
if we need to "justify" our pricing from the perspective of value, then why not give a pricing based on value, so we don't need to "justify" it anymore?
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="org92aeebe"&gt;Bill by the value we've generated, not the time we've spent&lt;/h2&gt;

&lt;p&gt;
The solution to the coupling problem is easy and simple:
just decouple time and money and stop charging by hours.
&lt;/p&gt;

&lt;p&gt;
So how to decide how much we are going to charge?
Again, we need to start from our client's perspective: how do they convince themselves to pay.
&lt;/p&gt;

&lt;p&gt;
Our clients are paying us for a solution to make their lives better.
In another word, they are paying for the value this solution brings to them.
So the decision process is actually simple: if the value is higher than the cost, then it's a good deal.
&lt;/p&gt;

&lt;p&gt;
This decision process gives us a clear way to set our pricing.
Following this thinking, my programmer mindset shifts from writing code to a more complete one:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify the real problem first.&lt;/li&gt;
&lt;li&gt;Come up with multiple solutions with their own trade-offs.&lt;/li&gt;
&lt;li&gt;Compare different solutions and choose the best one in the current situation.&lt;/li&gt;
&lt;li&gt;Implement the solution.&lt;/li&gt;
&lt;li&gt;Review to see if the real problem get solved.&lt;/li&gt;
&lt;li&gt;Iterate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
And this magical thinking is just a simple sentence:
&lt;b&gt;Our pricing is proportional to the value we generated.&lt;/b&gt;
&lt;/p&gt;

</description>
      <category>billing</category>
      <category>consulting</category>
      <category>pricing</category>
      <category>value</category>
    </item>
    <item>
      <title>Think of time as a series of timestamps</title>
      <dc:creator>Yiming Chen</dc:creator>
      <pubDate>Wed, 06 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/dsdshcym/think-of-time-as-a-series-of-timestamps-3lda</link>
      <guid>https://forem.com/dsdshcym/think-of-time-as-a-series-of-timestamps-3lda</guid>
      <description>&lt;p&gt;&lt;br&gt;
I've been logging my daily time usage for almost 5 years.&lt;br&gt;
And by "daily time usage", I mean "every minute".&lt;br&gt;
Every day, I know where I spend every minute (sleeping, working, reading, writing, coding, etc.).&lt;br&gt;
As you may expected, it is not an easy task to do.&lt;br&gt;
&lt;/p&gt;

&lt;h2 id="orgfa3432a"&gt;Logging daily time usage is not easy&lt;/h2&gt;

&lt;p&gt;
When I first started logging time, I thought of time usage as ranges:
every task &lt;code&gt;T&lt;/code&gt; has a clock, and it starts from a point &lt;code&gt;t1&lt;/code&gt;, ends at a point &lt;code&gt;t2&lt;/code&gt;, lasts for &lt;code&gt;m&lt;/code&gt; minutes.
It's intuitive, but it didn't work well.
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When starting a task, I need to note down what I'm going to do.
But it may stop me from doing the real task.&lt;/li&gt;
&lt;li&gt;When adjusting a range, I need to adjust two data points at the same time: change one of &lt;code&gt;t1&lt;/code&gt; or &lt;code&gt;t2&lt;/code&gt;, then recalculate &lt;code&gt;m&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When switching from task A to task B, I need to stop task A first, then start task B.&lt;/li&gt;
&lt;li&gt;When multitasking, I need to keep multiple clocks running at the same time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
After several rounds of iteration, I now think of time usage as just two timestamps:
every task &lt;code&gt;T&lt;/code&gt; has a start point &lt;code&gt;t1&lt;/code&gt;, and an end point &lt;code&gt;t2&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
Here is how I do it now:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Whenever I need to spend a block of time on something, I jot down a timestamp &lt;code&gt;t1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then when I finish the task, I jot down a timestamp &lt;code&gt;t2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Finally I specify which task &lt;code&gt;T&lt;/code&gt; I was working on, and set &lt;code&gt;t1&lt;/code&gt; as its start time, &lt;code&gt;t2&lt;/code&gt; as its end time.&lt;/li&gt;
&lt;li&gt;If I start another task &lt;code&gt;T'&lt;/code&gt; immediately, &lt;code&gt;t2&lt;/code&gt; is the start time for &lt;code&gt;T'&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
It's a more lightweight and flexible workflow.
&lt;/p&gt;

&lt;h2 id="org72d6f41"&gt;Logging code time usage is not easy, either (and how Heroku solves this problem)&lt;/h2&gt;

&lt;p&gt;
More interestingly, if you think of time logging beyond our daily time usage, you'll find many other things that require time logging.
One of them is logging time spent in different parts of our program.
Heroku faced this exact problem before. In &lt;a href="https://ferd.ca/clever-functional-design.html"&gt;this post&lt;/a&gt;, Fred Hebert shared how they solved it.
&lt;/p&gt;

&lt;p&gt;
Their first straightforward solution was like how I started logging my daily time:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;note &lt;code&gt;t1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;doing the real work &lt;code&gt;T&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;note &lt;code&gt;t2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;calculate the duration &lt;code&gt;m&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
But this solution would couple the code for time logging and the code for doing the real work together.
&lt;/p&gt;

&lt;p&gt;
Then a better solution was like what I am doing now:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;note &lt;code&gt;t1&lt;/code&gt; with a label &lt;code&gt;l1: T started&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;note &lt;code&gt;t2&lt;/code&gt; with a label &lt;code&gt;l2: T stopped&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the analyzing library uses &lt;code&gt;t1, l1&lt;/code&gt; and &lt;code&gt;t2, l2&lt;/code&gt; to calculate how long task &lt;code&gt;T&lt;/code&gt; took&lt;/li&gt;
&lt;li&gt;the analyzing library may use &lt;code&gt;t1&lt;/code&gt; or &lt;code&gt;t2&lt;/code&gt; for other task calculations like &lt;code&gt;T'&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
With this solution, Heroku now fully decouples how the real work gets done (business logic) from how the time logs are analyzed (logging logic).
&lt;/p&gt;

&lt;h2 id="org74546c5"&gt;The power of data and deferring decisions&lt;/h2&gt;

&lt;p&gt;
Optimizing time logging reminds me of &lt;a href="https://yiming.dev/blog/2019/08/16/use-return-value-to-defer-decisions/"&gt;Use Return Value to Defer Decisions&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
In the case of Heroku, with the help of additional label &lt;code&gt;l1&lt;/code&gt; and &lt;code&gt;l2&lt;/code&gt;, we can defer the decision of how to analyze time logs to later.
&lt;/p&gt;

&lt;p&gt;
Again, this is the beauty of functional programming: &lt;i&gt;constraints breed creativity&lt;/i&gt;. To quote Fred:
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
it was the structural constraint of already being in an immutable context that prompted the cleaner design.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="org8802ccb"&gt;Further reading&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="https://www.geepawhill.org/2018/08/29/tdd-pro-tip-time-needs-technique/"&gt;TDD Pro-Tip: Time Needs Technique - GeePawHill.org -- Helping Geeks Produce&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
This was the first time I learned to &lt;i&gt;think of time as a series of timestamps&lt;/i&gt;.
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;
&lt;a href="https://www.youtube.com/watch?v=E8I19uA-wGY"&gt;Functional programming design patterns by Scott Wlaschin - YouTube&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
An interesting question after watching this talk: &lt;i&gt;Can we model time with Monoid?&lt;/i&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>functional</category>
      <category>gtd</category>
      <category>time</category>
      <category>logging</category>
    </item>
  </channel>
</rss>
