00:00:21.830
I've worked with a lot of different programmers in my career so far. Some programmers I've worked with have been super productive, while others, although just as smart, are not nearly as productive. This made me ask: why is that? Why are some programmers super productive and others aren't? The answer that I've been able to come up with to that question is the topic of my talk today.
00:00:35.030
First, I'm going to talk about the consequences of coding with a disorganized mind, contrasted with the benefits of coding with an organized mind. Then, I'm going to discuss three phases of organizing your work. The first is defining your work by breaking a project into small, discrete tasks. The next is setting up your work, mainly using to-do lists and similar tools. Lastly, after you've defined your work and set it up, we will discuss how to actually carry out your work.
00:01:07.410
First, a little bit about me. My name is Jason Swett. I'm a consultant and I've been working with Rails for about eight years now. I host a podcast called the Ruby Testing Podcast and another one that's coming out soon called Rails with Jason. I also wrote a book called Rails Testing for Beginners, and all my content can be found at codewithjason.com, which is mostly focused around Rails testing.
00:01:58.020
Now, let's talk about organized versus disorganized coding. When you're disorganized, basically everything sucks. Things are chaotic, you aren't achieving tasks in a reasonable period of time, and everything feels stressful. You may experience what’s called psychic entropy, a state of mental chaos where you cannot focus. I learned about this from the book 'Flow' by Mihai Csikszentmihalyi. It's like trying to read a book and watch a TV show at the same time—you aren’t truly engaged with either.
00:02:20.459
Conversely, when you have order, you are successful. You can sit down to build a feature without getting lost in dead-end paths. You enter a flow state—this state of enjoyment where you become immersed in the work and lose track of time.
00:02:38.300
So how do we take a project and break it down into discrete tasks? I’m going to talk about two things: breaking a project into user stories and then breaking those stories down into tasks.
00:02:55.410
There’s a common problem with designs that programmers receive, which is that the designs often don’t make sense. Has anybody experienced this? Someone says, 'Hey, build this,' but when you look at it, you think, 'Well, I can't build this; it doesn’t make sense.' So, at the risk of stating the obvious, the designs have to make sense before you can start the work or even start estimating.
00:03:18.590
But how do you ensure that the designs make sense? There’s a methodology I’ve been using for years: usability testing. Usability testing forces your designs to be valid. When you go through this process, design defects have no place to hide. The way I conduct it is by drawing out designs on paper—simple pen and paper prototypes—and sitting down with someone representative of the target user. I won’t just ask them what they think of the design; instead, I lay out a series of tasks they need to accomplish using the design to see if they can navigate it successfully.
00:04:10.340
If they can’t accomplish the tasks, that’s a sign of a design defect. This approach has led me to discover that during the first round of usability testing, my designs are almost always way off, despite my confidence as a UI designer. This is likely true for many, including professional designers.
00:04:46.500
After identifying flaws, we need to rework the design and bring it back for another round of usability testing—possibly two or three rounds—until it makes sense and can be implemented. This process creates several benefits: the design will make sense to everyone involved, and it completely eliminates miscommunication. Have you ever built something and returned only to find people weren’t expecting that? Usability testing prevents those surprises.
00:05:27.410
The best part is that it eliminates unnecessary conversations about preferences. I think the field should look like this, and another thinks it should look like that. Usability testing gives you a definitive answer through user feedback, removing the debate over what’s better.
00:06:11.500
Here’s an example usability testing scenario: let's say I'm building an appointment scheduling system. A user would try to schedule an appointment for 2:00 p.m. on Monday. If they get stuck without help, that indicates a design defect.
00:06:27.410
Once you’ve completed usability tests for several screens within your project, the scenarios can be translated into user stories. For those unfamiliar, when I say 'user story,' I mean something like an issue or ticket in your issue tracker.
00:07:06.360
Attributes of a good user story may seem obvious, but I've seen many stories that violate these principles. Each story should have a clear and descriptive title, like 'Ability to Schedule Appointment,' rather than a vague 'Appointments.' The stories should clearly indicate when they are complete, meaning someone not familiar with the project should understand what 'done' looks like.
00:08:01.570
For every story, you should also define what 'done' means. Is it completed when it’s code complete, ready for QA, or deployed to production? Additionally, stories shouldn't take more than a few days to complete because long stories can drag on unnecessarily. If a story is supposed to take a day but extends to three, that’s a red flag.
00:09:06.170
Now that we have defined our work, let’s talk about how to set it up for execution. At the risk of stating the obvious, I’m going to talk about to-do lists. The purpose of a to-do list is to clarify exactly what you’re trying to accomplish at any given moment.
00:09:53.740
This realization inspired me to give this talk. When working with colleagues, I noticed many couldn't answer the question: 'What exactly am I trying to accomplish right now?' My to-do items come from user stories for my projects. I usually work in sprints of one or two weeks.
00:11:01.930
At the beginning of each sprint, we pick user stories to commit to, creating the starting point for my daily to-do list. But then I also reflect on my life goals: what do I want to accomplish this year, this month? If I don’t keep these in mind, I might find myself years down the line thinking, 'Wait, I wanted to achieve so much with my life, but I didn’t.'
00:11:55.870
I keep a list of annual goals visible, aligning my daily tasks with them. I also break down my user stories into finer granularity because while a user story may sound clear, it is often too broad to start working on effectively. If the user story is to schedule an appointment, I can break it down further into tasks like adding a patient to the appointment. This approach requires examining specific UI aspects and laying out details for implementation.
00:12:54.520
My daily draft to-do list has personal and work sections. For example, I might plan to work on my RailsConf talk, get an oil change, or order something online. For work, I would set specific goals like saving or canceling appointments. This structure isn’t exhaustive but enough to kickstart my day.
00:13:43.790
Consequently, I avoid wasting time being indecisive or distracted. Different people have their ways of working, but starting early generally leads to increased productivity. That first hour of the day is often called the 'rudder of the day,' as getting off to a proactive start tends to set the tone for the rest of the day.
00:14:42.170
However, if you start the day in a state of mental chaos—checking social media, emails, and notifications—your thoughts remain jumbled and unproductive for the entire day.
00:15:05.810
Continuing throughout the day, I maintain my to-do list. I expand my items, ensuring they are actionable. For instance, rather than saying, 'ability to save an appointment,' I break that down into specific tasks, such as listing the tests I want to write for this feature.
00:16:02.780
Now that we’ve defined our work and set up to-do lists, how do we carry out our tasks swiftly and efficiently? I’ll mention four key points: focused work sessions, atomic commits, small short-lived branches, and small frequent deployments.
00:16:51.740
First, during focused work sessions, I close distractions like email and Slack. I may check them occasionally—like once an hour—so I can avoid interruptions throughout the day. This method allows me to concentrate, emphasizing that most incoming messages aren't as crucial as they seem.
00:17:06.760
It’s advisable not to have notifications from social media platforms. I don’t keep Twitter or Facebook on my phone. After a year without them, I realize they added no significant value to my life and merely distracted me.
00:17:53.690
On top of reducing distractions, you should clearly state your current goal and any related tasks using the previously discussed levels of granularity. Next, talking about atomic commits—commits should represent a single piece of work.
00:18:43.830
Atomic commits are beneficial because if an error arises, rolling back becomes much simpler. I generally commit every five to fifteen minutes, allowing me to clear my mind afterward; it's no longer something I need to think about.
00:19:32.490
This method is also helpful for debugging. If you ever need to use `git bisect` to identify the introduction of a bug, smaller commits facilitate that process. I highly recommend getting familiar with `git bisect`.
00:20:16.750
Regarding short-lived branches, long-lasting branches create risk and confusion. They diverge from the master branch, complicating merges and increasing the potential for conflicts.
00:20:44.720
A common argument against short-lived branches is that features can’t be released until completely finished. This can be managed through feature flags, which separate deployment from release. This way, you can deploy partial functionality while keeping it invisible to users, managing risks effectively.
00:21:25.630
While maintaining these short-lived branches, aim to merge them back into master promptly after completion. This simplicity enhances clarity, reducing overhead and confusion that arises when multiple branches linger.
00:22:24.100
Lastly, small frequent deployments reduce the risks associated with larger deployments and enable you to fix issues as they arise before they compound.
00:23:01.590
These strategies help keep the development environment and the production environment in close alignment, potentially reducing those tricky bugs that only appear in production.
00:24:01.540
To conclude, I want to summarize a few takeaways from this talk. First, when defining your work, iron out the flaws in designs through usability testing to ensure they make sense. Every user story should be crisply defined with a clear title that outlines what 'done' looks like.
00:24:57.540
Always document your tasks, and maintain clarity on your current objectives. Working in small units with atomic commits, regular integrations, and frequent deployments promotes efficiency and clarity in your work.
00:25:48.680
If you want to learn more about these concepts and other Rails topics I write about, please visit codewithjason.com or email me at [email protected]. I won’t be handling Q&A up here, but I’ll be hanging around after the talk if anyone wants to chat about any questions you may have.