Approaching projects - Part 5 Thu Nov 11 2021 Do you have a project, a skill, a goal you'd like to complete or progress? Here's how to create an actionable plan by creating a model of its execution. -------------------------------------------------------------------------------- Approaching projects - Part 5 ============================= Published Nov 10, 2021 - 12 min read /------- Table of contents -------\ | Table of contents | | * Approaching projects - Part 5 | | * Creating a plan | | * Another approach | \---------------------------------/ Do you have a project, a skill, a goal you'd like to complete or progress? Are you on your own, lacking leadership and structure, or could use more of it for yourself and your team? Here's what I've discovered works for me as a solo software developer and later as an engineering manager. This is a series of posts, the next post part 6 on documenting a plan with tasks [L1] comes next. In the last post Approaching projects - Part 4 [L2], I described how to prepare for an actionable plan by vetting prototypes and finalizing resource needs. This post will focus on creating an actionable plan. Throughout this series of posts I will be using this user story: As a person with money, I want a custom computer desk to fit in a weird spot in my home. With the chosen solution: Build the desk myself. Creating a plan --------------- A plan is a procedure to get something done for the first time. It comes with risk, it comes with unknowns. The riskiest plans come without any steps. "YOLO" "lets wing it" may be energizing to some, but they do not inspire success. In fact, deliverables made without plans are pretty low quality. /--------------------------------------------------------------[cendyne: ughhh]\ | The ex-CTO / founder of my current employer YOLO'd a lot. He would | | experiment and introduce new toys over the weekend, deploy on fridays at | | five PM, and then be bogged down with meetings all week so he never cleaned | | up after himself. I actually told him that I did not have confidence in his | | contributions. He actually listened to me and changed his behavior. | \------------------------------------------------------------------------------/ /[cendyne: table-flip]---------------------------------------------------------\ | We have so much technical debt because of this that it regularly stalls our | | new engineers years later. Please, don't reinvent a database ORM. Please, | | don't reinvent GraphQL based on one week of experience. Please, don't | | reinvent an MVC tomcat servlet framework. Please, don't reinvent async work | | queues. | \------------------------------------------------------------------------------/ So let's talk about what makes a plan, what makes a procedure. A logical sequence of steps! Some steps can be performed concurrently. Some cannot, either due to depending on a prior step or contending for a shared resource. Really, tell me if you've watched TV, bathed, and done your taxes all at once. In a way, plans are also like programs. They come wind conditions, branches, loops, and so on. But you're writing it for the first time and executing it. Oh! But wait! When you're programming, you run it and review the results, revising until it meets expectations right? Well, project plans don't have the time and resources to redo it five times like unicorn venture capital funded companies like Uber. So take the time to measure and simulate each step. Consider if each step's preconditions are sane. That the postconditions are accounted for. Even when there's an exception. How will you handle exceptions? /-------------------------------------------------------------[cendyne: laptop]\ | Way back when with shared university mainframes and all that, I wonder how | | programmers thought about their program before the arduous work of getting | | it loaded on the mainframe with hole punch sheets. Only to get the answers | | hours later... and it might have been run against someone elses data punch | | cards. | \------------------------------------------------------------------------------/ /[cendyne: heart]--------------------------------------------------------------\ | One of my university professors met their partner, a clerk for the | | university computer, when submitting hole punch program sheets for their | | grad studies. | \------------------------------------------------------------------------------/ Like a program, a plan should not skip steps. Sure, the people involved may be able to infer steps that are skipped and do them anyway. But enough of those will add up to confusion, producing the wrong thing, or excessive or a surprising use of resources. [I1: Draw the rest of the owl] Like a mathematical proof, every step must be justified or given. And like making proofs, plans aren't fun for most people. [I2: An example mathematical proof] /[cendyne: confused]-----------------------------------------------------------\ | I was never all that gifted in math. But when it came to logical stuff I was | | able to work with that. My way was to visualize a network of conditional | | relationships and see if they connected right a whole. But once it was too | | big to fit in my head, I struggled with it. Thankfully, most solutions can | | be thought of with some abstraction. | \------------------------------------------------------------------------------/ Yet, if you think of it like a program instead of a mathematical proof, how does this change your approach? How does your perspective shift if you switch it to a language you're familiar with? /---------------------------------------------------------------[cendyne: math]\ | Even mathematical notation is a language invented to permit novel and useful | | ways of manipulating ideas in the domain of numbers and more. Or so I'm told | | on the internet, back in the day mathematicians used poems and spatial | | models to think about solving complex problems. Yet when it came to negative | | numbers they could not conceive of it. The language of 2d squares and 3d | | blocks could not support the ideas. | \------------------------------------------------------------------------------/ Another approach ^^^^^^^^^^^^^^^^ So if words like this aren't working out for you... [I3: An example task description] Then try something else before writing tasks. interface SawHorse {} interface WoodPlank {} interface WoodSurface {} interface Sander { void sand(WoodPlank plank); void sand(WoodSurface wood); } interface Jointer { void edge(WoodPlank plank); } interface RouterBit {} interface Router { void loadBit(RouterBit bit); void route(WoodSurface surface); } interface Clamp { void clamp(Object... objects); void removeClamp(); } interface WoodGlue { WoodSurface join(WoodSurface surface, WoodPlank plank); WoodSurface join(WoodPlank plank1, WoodPlank plank2); } interface Me { void put(Object above, Object below); void remove(Object object); void waitFor(long amount, TimeUnit unit); void flip(Object object); } class Plan { WoodSurface assembleSurface( Me me, Queue planks, Queue clamps, WoodGlue glue, Jointer jointer, SawHorse sawHorse1, SawHorse sawHorse2, Sander sander, Router router, RouterBit bevelBit, WoodSurface flatReferenceSurface) { // Prepare each plank so it can be used Queue edgedPlanks = new ArrayDeque<>(); for (WoodPlank plank : planks) { // Sand each plank so it is clean and smooth sander.sand(plank); me.flip(plank); sander.sand(plank); // Make the edges straight with the jointer jointer.edge(plank); me.flip(plank); jointer.edge(plank); // Add to a new pile edgedPlanks.add(plank); } // Set up a reference surface // This way when the glue hardens, it has the same flatness as the reference me.put(flatReferenceSurface, sawHorse1); me.put(flatReferenceSurface, sawHorse2); // Prepare the surface, glue each plank to the next WoodPlank firstPlank = edgedPlanks.remove(); Clamp firstClamp = clamps.remove(); // We need it to hold still firstClamp.clamp(firstPlank, flatReferenceSurface); // Create the first surface, consisting of only two planks WoodPlank secondPlank = edgedPlanks.remove(); WoodSurface surface = glue.join(firstPlank, secondPlank); // For the remaining planks, continue to glue them together // The last plank will be used too WoodPlank lastPlank = secondPlank; for (WoodPlank plank : edgedPlanks) { // Make the surface larger by adding to it. // In a way, this creates a new surface. surface = glue.join(surface, plank); // We will use the last plank later. lastPlank = plank; } // Now we clamp along the ends Clamp bigClamp1 = clamps.remove(); bigClamp1.clamp(firstPlank, lastPlank); Clamp bigClamp2 = clamps.remove(); bigClamp2.clamp(firstPlank, lastPlank); // And the center Clamp bigClamp3 = clamps.remove(); bigClamp3.clamp(firstPlank, lastPlank); // Then we add clamps on the remaining 3 corners to the reference surface. Clamp secondClamp = clamps.remove(); secondClamp.clamp(firstPlank, flatReferenceSurface); Clamp thirdClamp = clamps.remove(); thirdClamp.clamp(secondPlank, flatReferenceSurface); Clamp forthClamp = clamps.remove(); forthClamp.clamp(secondPlank, flatReferenceSurface); // It takes time for the glue to cure me.waitFor(4, TimeUnit.HOURS); // Remove all the clamps, you may finally see here how many we had to use. firstClamp.removeClamp(); // 1 clamp clamps.add(firstClamp); secondClamp.removeClamp(); // 2 clamps clamps.add(secondClamp); thirdClamp.removeClamp(); // 3 clamps clamps.add(thirdClamp); forthClamp.removeClamp(); // 4 clamps clamps.add(forthClamp); bigClamp1.removeClamp(); // 5 clamps clamps.add(bigClamp1); bigClamp2.removeClamp(); // 6 clamps clamps.add(bigClamp2); bigClamp3.removeClamp(); // 7 clamps clamps.add(bigClamp3); // But we're not done yet. Now we need to clean the surface. // Wood glue will seep out and it needs to be sanded off. // We no longer need the reference surface me.remove(flatReferenceSurface); me.put(surface, sawHorse1); me.put(surface, sawHorse2); // Remove the dried wood glue that seeped between the boards sander.sand(surface); me.flip(surface); sander.sand(surface); // Route each side of the top of the table router.loadBit(bevelBit); router.route(surface); // Left router.route(surface); // Right router.route(surface); // Back router.route(surface); // Front return surface; } } This exercise above highlights a few interesting resource needs. * I see that large clamps are required which can extend as long as the surface is deep * I need several more clamps to keep things in place. * I need a reference surface (actually more in reality). [I4: Joining the table with wood glue] Reality differed a little. For the reference surfaces, I used several boards clamped together. Some of these boards came from other projects (A book shelf) I had planned for a later time. Instead of saw horses, I actually used the finished frame of the table. Underneath, I used wax paper to catch the drippings from the wood glue. Anyway, this exercise of using a programming language allows us to do a bit more analysis and try a few more what-ifs. For example, what if we had a second person? Could sanding and jointing be done concurrently? Not on the same planks, but perhaps with a buffer between. Another spot might be that two people could glue up two halves of the table surface and join them at the end. More questions might be, what if we have two people, and two sanders? These resources can be negotiated upfront before the project begins. You'll look better executing plans on time and on budget, and it'll look even better if you set the budget and set the time. /--------------------------------------------------------------[cendyne: gendo]\ | I hear that venture capitalists and investors care more about a business | | reliably hitting projections and promises as opposed to exceeding | | expectations. If a business does not know why they are succeeding, then they | | probably don't know when they will start failing. | \------------------------------------------------------------------------------/ Of course, if your plan reveals that you're using too many resources and you cannot request as much budget or time or whatever that you need, then you need to make some compromises, adjustments, and so on. This program is a prototype that you can alter, that you can examine, and even peer review. It may be novel, it may be different, but a program language may be just the tool your peers need to understand what resources you need, what depends on what, and give feedback on the plan's soundness. When you are confident that: * You understand the User Story * A proposed solution satisfies the story * The proposed solution is possible * Milestones for the solution are defined * You have models and references for steps that support each deliverable * A reasonable sequence and dependency graph of steps to create each deliverable is drafted Then it is time to create tickets. This comes in the next post! The main takeaways of this post are: * Plans are procedures, which are composed of logical steps that consume resources * Programming languages map well to describing plans * With a draft plan written, examine the resources and begin negotiating for resources * Review the draft plan with peers and consider the soundness of its assumptions and design * Revise the plan with the resources available and resources promised -------------------------------------------------------------------------------- This post is the fifth of the series, part 6 on documenting a plan with tasks [L1] comes next. /[cendyne: excited]------------------------------------------------------------\ | You can succeed! If you're finding it hard to assemble your thoughts in one | | written medium, try another. Determining your resource consumption is a hard | | problem. That includes how much time you take! But if your bread and butter | | is solving problems in Java, C#, PHP, or Haskell then you can reorient | | project planning to your language of choice. | \------------------------------------------------------------------------------/ /---------------------------------------------------------------[cendyne: math]\ | Ever wondered how math proofs prove something is NP-Hard? They translate | | their problems into another known NP-Hard problem. Academics can be | | confident in declaring properties of new models by reorienting their chosen | | model to another well known and studied model. You can see plenty of this on | | StackExchange [L3]. | \------------------------------------------------------------------------------/ -------------------------------------------------------------------------------- [L1]: /posts/2021-11-11-project-planning-part-6.html [L2]: /posts/2021-11-09-project-planning-part-4.html [L3]: https://cs.stackexchange.com/questions/19228/np-hard-proof-polynomial- time-reduction [I1]: https://c.cdyn.dev/MZS5Nq67 [I2]: https://c.cdyn.dev/ZCYSb1in [I3]: https://c.cdyn.dev/ZvBlW64y [I4]: https://c.cdyn.dev/c4q8YORU