harisrid Tech News

Spanning across many domains – data, systems, algorithms, and personal

TOTW/19 ( Part One )- The Road to Tackling Ambiguity is … task decomposition and avoiding rigid all-or-nothing thinking.

The biggest struggle for a raft number of engineers isn’t their dearth of – their lack of – intellectual ability, bur rather, their executive dysfunction : their brains tendentious disposition to task avoidance, task initiation, and task prioritization faculties. A.k.a. where do I even begin?

Primer

Hi all,

Today, I wanna discuss another topic – task decomposition : how to break down large, unstructured, ambiguous tasks into smaller, well-defined, more concrete tasks.

It’s a skill that I personally struggled with – and still struggle with – to this day, but, something that I think everyone can rapidly improve on.

Task decomposition is a vital skill for engineers. It enables engineers to ship high urgency, high pressing deliverables and also holds us accountable to delivery. It helps enigneers make good estimates of tasks and identify how long they can expect units of work to take. And lastly, it empowers developers to communicate better-defined notions of progress and productivity to their team, their leadership, and their product managers.

The way to get better at this skill, is to well, practice it. And just like any other skill, some of us are naturally better, and others will struggle more.

Can you share real-world case studies!

I’m using a scenario I encountered at work as a good example. Let’s suppose a developer is tasked with the following

Task description : Invoke endpoint #2 on completion of calls to endpoint #1. Get code to a testable, deployable state by a DEADLINE.

Well, how should we do it? There’s so many ways? The task itself has multiple moving pieces – a few database tables, trigger code, and two API endpoint calls, and a remote Titan cloud logging posture. It’s not a one-off execution where I write a simple program to call endpoint #2 each time endpoint #1 finishes. There’s “internal plumbing” : components which need to be wired up and connected to facilitate communication at the right place and the right time. More ever, we make the calls only when data tier conditions and invariants are met.

How do we expedite our testing capabilities? Triggering the upstream code to execute our automated call is difficult and time consuming.

Where do I even begin? What’s the right place to start? Do I need to start with actual data – which I may need to announce as a major blocker – or can I I use mocks and make adjustments to test for behavior?

There’s no roadmap.

There’s no instruction steps like in academia.

Well,

That’s why we should engage in our mental skills toolbox, and think about three things : a sequence of steps, the minimal components needed, and the smallest stories.

Steps – The First Draft

Ok, so our engineer comes up with a first draft of steps, resembling the beneath structure :

  • Step #1 : Copy an existing, or create, a database trigger and test that it works.
  • Step #2 : Call API endpoint #1 and verify our code receives the the database trigger to call API endpoint #2.
  • Step #3 : Get the code working in lower level environments.

This is a good ( initial ) set of steps. But alas, issues arise up.

Trigger Testing : Turns out that it takes forever to test a database trigger on calls to API endpoint #1 because payloads pass through a lot of internal plumbing ; the invariant check doesn’t happen until 5-10 minutes into the call. And we might make a couple of config changes and execute the tests 5-6 times on a debug, leading to an hour ( or two ) spent on getting a working trigger. Isn’t there a faster way?

Server-Side Receiving : In the original writing, we have to verify that the trigger is received, but how do we do this? Do we have a concrete way? Did we identify mechanisms? Did we identify copyable, modifyable code constructs? If not, can we use tools like ChatGPT or Google Search to find minimal structures? What’s the right tool for this use case?

Alright, back to the drawing board. What do we do next, in version two of our steps?

Steps – The Final Draft
  • Step #1 : Copy an existing, or create, a database trigger, leveraging the database UI or tools. Inject a single mock record and use database functionality like LISTEN <target_channel_name> to verify the trigger is received.
  • Step #2 : Set up a server-side listener. Copy and make modifications to existing triggers or look online for examples. Verify that the listener can receive a single trigger notification with success.
  • Step #3 : Extend the listener to call API endpoint #2. Insert a single record of mock ( or real ) data and verify endpoint #2 is called.
  • Step #4 : Invoke API endpoint #1 – on mock or real data – and verify the internal plumbing – the database trigger, the payload, the listener, and call to API endpoint #2.
  • Step #5: Recreate these steps, from local environments, to lower level pre-prod envs.
  • Step #6 : Deploy and verify feature correctness in production.
Why this breakdown is better!
  • Smaller-sized steps – tasks have been broken down into a better identified sequence of execution steps.
  • Specificity – specificity destroys ambiguity :-). We know exactly what we need to do AND we have alternatives or places to investigate if we’re stuck.
  • Identifiable deliverables and time units – because we’ve broken down tasks, we can quickly make time estimates for how long each step steps should take. I’ve written an example time table.
The Time Table

In this time table, I’ve assigned units of time for upcoming tasks. Engineers can use these feature estimates to share how long they expect a deliverable to take across multiple parties – leadership, product managers, and other engineers. The sum of time needed for the case study’s feature equals an idealized seven business days. But I wanna err on caution and behave conservatively – I’m creating an adjustable buffer window and I’m throwing in an extra two extra days to account for personal time off or unexpected issues. Thus, our actual total time to delivery sums up to nine business days – which still leaves us under the standard 2-week Agile Sprint :-).

StepTime To Deliver
#18 hours
#28 hours
#38 hours
#44 hours
#58 hours
Totals8 hours = 16 hours
These visuals are super useful to share with others. I remember tech leads who used to work with similar task breakdowns written up in their design documents :-).

Posted in

Leave a comment