Time box work
Tags: productivity
Published: 2023-01-29 20:04:17

I work as a technical lead. I started working remotely in 2020. My job permits flexible working hours. In the start of 2020, I worked for periods of varying hours interspersed with long breaks. I never felt like I was "done" with work. This schedule stressed me and made me less productive. This post describes habits that have helped me define work-life boundaries and best utilize my time working.

# Work fairly

Consider compensation. I am salaried and expected to work 40 hours a week. I uphold my agreement and work for 40 hours a week. During those 40 hours, I work to the best of my ability. If I need to work less, I request PTO. I may work more than 40 hours on exception if there is a need. Working more than 40 hours devalues my time.

Working 8 hours a day gives a clear "done" criteria. Once I have worked 8 hours, I sign off. I have upheld my side of the agreement with work.

One way to develop this habit is by tracking time. Another way to develop this habit is working a regular schedule.

# Work a regular schedule

I set a schedule of working 8:30-4:30pm. Other employees can rely on me being online and responsive during my working hours. I set the working hours in Google Calendar. If meetings are scheduled outside of my working hours, I ask to reschedule.

I take breaks to refresh. Between tasks, I get up and walk around for ~5 minutes. I take a 30 minute lunch. Lunch is scheduled on my calendar. I do not check slack or e-mail during lunch.

I do not use working more than 40 hours as an excuse for working less than 40 hours the next week. I continue to work my regular schedule.

One counterargument to consider: I have varying energy during the day. I have the most energy in the morning, and less in the afternoon. I may be more productive by taking a long nap in the afternoon, and working later in the evening. But also consider: why use all of the highest energy on work? If I only work when I have energy, I will have no energy left for my personal life. I prefer working for a continuous 8 hour period, signing off, then using my remaining energy in my personal life.

# Time box tasks

Time box tasks to clarify "done" criteria for tasks.

Once the requirements are met, there are always optional improvements to make. I do the best work I can in the time allotted. Testing and self-reviewing code are requirements. Skipping tests may result in bugs that cost more time later. Skipping self-review may result in more time spent for my peers reviewing.

For example: I am writing a test to compare byte output of a function.

```c
ASSERT(got.len == expected.len && 0 == memcmp(got.data, expected.data, expected.len));
```

That line took ~5 seconds to write. It meets the minimum requirements. If the assertion fails, it prints this message:

```
FAIL:/home/kevin/code/test_c_driver/test-timebox.c:14  main()
  Condition 'got.len == expected.len && 0 == memcmp(got.data, expected.data, expected.len)' failed.
```

The message may be more helpful if the data is also printed on failure. I add that:

```c
// bytes_to_hex returns string for the hex representation of `in`.
// The returned string must be freed with `free`.
static char *bytes_to_hex(const uint8_t *in, size_t len) {
    char *out = malloc(len * 2 + 1);
    const char *hex_table = "01234567890ABCDEF";
    char *start = out;
    for (size_t i = 0; i < len; i++) {
        uint8_t v = in[i];
        *out++ = hex_table[v / 16];
        *out++ = hex_table[v % 16];
    }
    *out = '\0';
    return start;
}

```

The assertion becomes:
```c
ASSERTF(got.len == expected.len && 0 == memcmp(got.data, expected.data, expected.len),
        "got     : %s\n"
        "expected: %s",
        bytes_to_hex(got.data, got.len), bytes_to_hex(expected.data, expected.len));
```

That took ~2 minutes. If the assertion fails, it prints this message:
```
FAIL:/home/kevin/code/test_c_driver/test-timebox.c:33  main()
  Condition 'got.len == expected.len && 0 == memcmp(got.data, expected.data, expected.len)' failed.
got     : 626E6E626172
expected: 666E6E626172
```

That looks better. After refactoring other `ASSERTF` statements, this becomes verbose. I write a macro to reduce the repetition:

```c
#define ASSERT_MEMEQUAL(got, expected)                                                             \
    ASSERTF(got.len == expected.len && 0 == memcmp(got.data, expected.data, expected.len),         \
            "got     : %s\n"                                                                       \
            "expected: %s",                                                                        \
            bytes_to_hex(got.data, got.len), bytes_to_hex(expected.data, expected.len));
```

And the assert becomes:
```c
ASSERT_MEMEQUAL(got, expected);
```

That took another ~30 seconds.

The whole task took ~2 minutes 35 seconds. The extra effort added value. Good test assertion messages can save time diagnosing test failures later.

This could further be improved. Tests with large data print large horizontal strings on failure. `bytes_to_hex` could add newlines. Assert failures can print a side-by-side diff. I can audit other tests that compare bytes and use the new `ASSERT_MEMEQUAL`. How far I go with improvements is informed by how much time I want to spend on this task.


# Handling notifications

Turn off notifications off-hours. Only check notifications off-hours if you are prepared to act on them.
Example: I kick off a CI test run just before signing off. That night I feel anxious about the results and want to check. I want the tests to pass. But I ask myself, "If the tests failed, do I have energy to investigate?" The answer is "No". Checking the test results will not change my behavior in that moment. Seeing failing tests will stress me. So I do not check the results.

Turn on notifications on-hours. For someone in on-call, on-hours may be 24 hours. Be responsive on-hours. Respond to direct messages with a specific ETA "I will investigate this afternoon" rather than a vague "I will investigate later". If you do not respond, the sender can check in at that time. If it is urgent, the sender can request you prioritize it sooner.