Talks

Coding with an Organized Mind

Coding with an Organized Mind

by Jason Swett

In his talk at RailsConf 2019 titled Coding with an Organized Mind, Jason Swett discusses the importance of mental organization in programming, arguing that many developers fail to achieve high productivity not because they lack technical skills, but due to disorganization. He contrasts the chaos associated with a disorganized mindset to the flow state achieved when coding is approached systematically.

Swett outlines three key phases to organizing work:

  • Defining Work: He emphasizes the importance of breaking projects into smaller tasks, utilizing methods such as user stories and usability testing to ensure that designs are sensible before development begins. By prototyping designs on paper and testing them with end-users, designers can avoid common pitfalls and misunderstandings that may arise later in the development cycle.

  • Setting Up Work: The necessity of maintaining clear to-do lists is highlighted. These lists should stem from user stories committed to in sprints, and include both personal and work-related tasks to ensure that developers know what they need to accomplish daily. The author encourages starting with broad objectives and drilling down to granular tasks to enhance clarity and focus.

  • Carrying Out Work: Swett advocates for focused work sessions, atomic commits, small short-lived branches, and small frequent deployments. By reducing distractions (like closing email or Slack), developers can enhance focus, while atomic commits simplify rollbacks and make tracking changes easier. Small, short-lived branches coupled with feature flags allow incomplete features to be deployed without impacting users. He concludes that frequent deployments reduce complexity, making it easier to maintain development and production environments in close alignment.

The concluding takeaways include:
- The necessity of usability testing to create coherent designs,
- The importance of precise user stories for project clarity,
- The requirement of maintaining an unambiguous to-do list,
- The benefits of working with small units to ensure manageability and efficiency.

For more resources and insights, Swett invites viewers to visit his website, code with Jason, and engage with him for questions post-presentation.

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.