Dependency Management

The Selfish Programmer

Using Ruby at work is great… but sometimes it feels like a job!

This year, I rediscovered the joy of writing Ruby apps for nobody but myself—and you can, too! Solo development is a great way to learn skills, to find inspiration, and to distill what matters most about programming.

Building an entire app by yourself can be overwhelming, but this talk will make it easier. We'll start with a minimal toolset that one person can maintain. You'll learn how many "bad" coding practices can actually reduce complexity. You may be surprised how selfish coding can make you a better team member, too!

RubyKaigi 2019 https://rubykaigi.org/2019/presentations/searls.html#apr20

RubyKaigi 2019

00:00:00.000 Hello everyone, welcome to my talk named 'The Selfish Programmer.' In this presentation, I want to explore what you can learn by writing software for yourself, as opposed to working on a team or as part of a larger organization.
00:00:10.200 My research shows that the three most important traits of a successful solo programmer are being antisocial, egotistical, and irresponsible. We're going to talk about all three traits. You may know me by this old picture that doesn’t really look like me or by my username 'searls' on GitHub and Twitter, which I pronounce as 'Sade Zoo' when I'm here in Japan because it's easier.
00:00:26.789 I work for a company called Test Double, where we have software developer teams that join other organizations to help them get things done, as well as to search for general ways to improve. I'm here today because I've been struggling with learning Japanese for years, and I found it really challenging. A couple of years ago, I discovered an application called WaniKani, which helps teach kanji and vocabulary memorization.
00:00:57.930 Its interface is like a flashcard game where you see Japanese characters and have to provide the reading, such as 'tsunami' for 津波, and it marks you right or wrong based on your responses. Additionally, it gives you the English meaning. This app's ability to teach me kanji was excellent; however, I found it lacked when I was trying to express concepts in Japanese that originated in English.
00:01:15.479 So, I built a companion app to WaniKani, which I called 'Kamisama.' This app works in reverse; it provides an English prompt, and using a Japanese keyboard, you have to provide the correct answer. It also has a feedback mechanism similar to WaniKani to help reinforce the learning process.
00:01:36.360 Building this app taught me a lot about selfish programming, which I believe can be beneficial for programmers. I would like to discuss why it can be beneficial to be a little bit antisocial. First, let's talk about why the selfish programmer is unambitious.
00:01:54.030 It’s easier to stay motivated when our goals are incremental and achievable. When goals are too ambitious, we run the risk of exhausting ourselves without making real progress, which might eventually lead to quitting. In contrast, at work, our applications are large and involve many components, where we can rely on others to cover various areas. The problem with large systems is that our brains can’t contain them all, and switching between contexts can be time-consuming.
00:02:26.100 For that reason, many developers specialize in just one part of a system at any given time. I get nostalgic when I remember starting to use Ruby in 2005. Back then, Ruby was known for enabling individuals to create small, useful applications quickly. Ultimately, Ruby allowed me to keep my entire application in my head, so I was much faster.
00:03:10.320 Fast forward 14 years, I attempted to create a new solo Ruby app. After several days of effort, I completed only a small part of the app that turned out to be useless on its own, which discouraged me and made me think about how much longer it would take to finish the complete application. Over these 14 years, I feel I had unlearned how to create small, useful things.
00:03:44.370 As a result, I established a personal rule: if I cannot release a project by Sunday night, I won’t even start it. This one-weekend rule is liberating because it forces me to shrink the scope of my app, and I find that it fits within my brain, allowing me to work more quickly.
00:04:19.110 For my initial project, I thought of a simple and small feature: a gem that tells me whether my WaniKani flashcard reviews are ready or not. It’s just a command-line interface that runs and tells me when to come back to check on my reviews.
00:04:58.140 The code is straightforward; it uses Net::HTTP and JSON. With a given API key, it fetches a response and checks for errors. If there are reviews available, it informs me immediately, effectively making it super easy to test and retain in my mind.
00:05:35.820 What’s crucial is that this initial project gave me the experience of working with WaniKani's API, which helped with the larger application I eventually wanted to build. My next project involved creating an English to Japanese flashcard game, but it turned out to be too complicated since it involved a user interface and various game rules.
00:06:20.580 Thus, I decided to focus only on the game logic, wrapping it in a simple command-line interface for practice. Over weeks, I would get the logic right by practicing with correct and incorrect answers, adapting for synonyms and implementing timers.
00:07:01.550 To my surprise, I ended up with real code that could build a review queue for me, score my answers, and track progress effectively. That weekend project was a resounding success and became the foundation for the current web application. Such incremental accomplishments keep me motivated and moving forward.
00:07:37.440 So the selfish programmer is unambitious, shrinking their goals until they are easy to accomplish. The next point to mention, stage two, is how the selfish programmer is ungrateful about open-source dependencies.
00:08:08.330 When unmanaged, dependencies can create an unmaintainable mess. I like to think of applications as triangles: original application code at the top, with various gems and dependencies below. In a corporate setting, the marginal cost of adding one more gem is low, but in solo projects, each additional gem increases the maintenance burden.
00:08:43.660 Instead of arbitrarily limiting myself, I categorize dependencies based on how much I trust their maintainers. For example, I trust the Rails core team to curate their dependencies closely, which allows me to include Rails in my projects.
00:09:14.300 Conversely, I consider the smaller gems carefully before adopting them, especially if I don’t trust their maintainers. While at work, I have been conditioned to never reinvent the wheel, in solo projects I might choose to write code even if another gem could do the same thing.
00:09:50.860 Sometimes I find gems that are too cumbersome to learn. If a gem overwhelming me leads to quitting a solo project, I’d rather take the time to create my solution than give up. For instance, I’ve never been responsible for building authentication features at work, but for Kamisama, I needed to figure it out. I faced my fear of using existing solutions like the Devise gem, and I started with a basic password field.
00:10:30.220 As a result, my solution utilized bcrypt and Rails’ 'has_secure_password' feature, which worked perfectly. This foundational implementation lasted five months before I expanded to include more complex features.
00:11:13.430 Eventually, I added features like changing passwords, verification emails, and so forth. Even though those custom functions were likely more complex than using Devise, my pride comes from having created them myself, resulting in a deeper understanding of my application’s workings.
00:11:50.210 Kamisama provided me the opportunity to practice a skill where I lacked confidence previously. So now I can engage comfortably in conversations about authentication because I developed this understanding myself.
00:12:28.480 Nonetheless, solo programmers must consider the ease of adding dependencies and the long-term issues that may arise from using them without careful thought. Therefore, they must critically weigh the trade-offs of each dependency they add.
00:13:06.940 Moving on to stage three, the selfish programmer's code is often ungenerous and doesn’t focus on making code reusable. In a work environment, I've learned to share code to benefit the team, but this can inadvertently slow progress as code reuse leads to higher maintenance costs.
00:13:42.270 That's why I prefer to keep my code isolated, focusing on implementing it close to the feature it serves, instead of storing my logic in shared locations. By soundproofing my code, I avoid the complications that come with extensive reuse.
00:14:18.840 I treat my models as simple value types, focusing on functionality and keeping model responsibilities clear. For example, if a controller performs two distinct tasks, I make sure to separate those functionalities to maintain cleaner and prioritized code.
00:14:51.100 Soundproofing my code allows me to change it aggressively since it is only invoked in one context, while I ensure the more generalized utility code remains lean, as it will be called in multiple places. Additionally, I avoid adding custom logic to Rails subclasses, treating them primarily as configuration and keeping the package size minimal.
00:15:31.240 This approach has served me well. For example, I initially built Kamisama as a sentence search engine without any need for further changes when I adapted it, which underscores how keeping code simple can eases modifications.
00:16:08.110 This careful separation of code ensures that some areas are viewed as valuable assets within workplaces, leading teams to believe that maximizing reuse enhances speed. Still, this can create dependency nightmares, which is why the selfish programmer embraces writing just enough code for flexibility.
00:16:45.680 Now, let’s discuss the virtues of being egotistical. At stage one, the selfish programmer is delusional, often believing that their code is ready to ship even when it’s still rough around the edges.
00:17:21.110 In my case, pushing messy but functional code allows me to observe performance and behavior over time, which helps me refine the product based on actual use. This iterative refinement enables me to be confident that changes presented in the end result meet my expectations.
00:18:00.160 Initially, I was running too many queries for my application’s API response. However, when addressing response times, I transitioned to using PostgreSQL views to aggregate data effectively, improving the application’s overall performance.
00:18:37.620 To sum up, I encourage shipping code quickly, observing the output, and refining as necessary before returning to optimize. The pressure to produce perfect code can hinder actual project progression.
00:19:10.370 The second stage of egotism is narcissism, where the selfish programmer considers only personal benefit when evaluating activities. In collaborative environments, tests enhance communication by clarifying intents and ensuring everything functions correctly across different sections of an application.
00:19:49.880 However, these testing benefits don’t always extend to solo projects. When working alone, you manage the direction entirely, and it’s easier to assess specific tasks without employing comprehensive tests.
00:20:30.730 For my project Kamisama, I adopted AI testing, which simply looks at recent code changes and only runs relevant tests. This method enhances efficiency, cutting the testing time significantly.
00:21:03.120 Truthfully, my AI testing means I often executed tests manually without writing formal code-based tests because it just didn't seem like a smart return on investment.
00:21:43.650 Thus, while traditionally automated testing pays off on teams, with solo projects, you need to assess the cost-benefit relationship since you’re only investing your time when managing tasks.
00:22:25.850 In programming, a balance must be struck between preventing issues upfront or minimizing repair time later on. My career primarily focused on maximizing the prevention of problems, yet now I find value in learning about monitoring and debugging.
00:23:07.300 So, although automated testing can seem indispensable, solo programmers like myself must be judicious about their time investments. This brings us to the third stage, where the selfish programmer is domineering and used to asserting their personal vision.
00:23:41.700 When you’re solo, you advocate for your own priorities without needing to navigate multiple stakeholders' needs. The complexity of managing various demands contrasts starkly when you’re simply focusing on a personal project. Hence, I opted to launch Kamisama for free, making me my only customer.
00:24:12.250 With that came the freedom to make decisions based solely on personal preference without external pressure. However, as development progressed, I began to run out of ideas and turned to community boards for inspiration.
00:24:51.900 This enabled me to solicit ideas for improvement. While responding to feature requests, some were good, others weren’t worth prioritizing due to personal disinterest. A notable example was a suggestion for color-coding. A colorblind user expressed difficulties with subtle distinctions.
00:25:31.890 Initially, I hesitated to act as it didn’t affect me; however, once I reviewed their feedback in context, I realized a simple solution could significantly enhance accessibility. So, I implemented straightforward validations for the kanji inputs.
00:26:07.850 This modified validation had multiple benefits, and a feature inspired by a user’s experience enriched my application positively. It became more apparent that selfish programming can yield benefits for others even when it begins from a personal need.
00:26:43.030 At work, we may forget to voice our perspectives, yet a successful selfish programmer takes control over their priorities while remaining flexible to community feedback.
00:27:16.920 Now shifting to stage one in the next world, the selfish programmer actively detaches from operational responsibilities, enabling their application to run with minimum involvement.
00:27:55.970 Many apps come with operational burdens ranging from security to performance monitoring. Originally, 'DevOps' implicated developers being responsible for operational tasks; however, it has morphed into something demanding full-time positions resembling traditional systems admins.
00:28:32.770 As a proponent of 'no ops,' my ambition is to focus solely on coding without routine operational work. My strategy included reducing dependencies and leveraging services like Heroku, which eliminate much of the operational overhead.
00:29:11.310 Heroku allows me to produce a simple configuration defining how my server functions and automating necessary tasks like migrations directly during pushes. This exemplifies effective service management.
00:29:46.240 Offering remarkable value, platforms like Heroku can outperform significant investments in custom infrastructure by streamlining the developer experience for minimal cost.
00:30:22.670 However, there are growing pains, as companies tend to resist adopting standardized operational solutions, clinging to their unique processes despite the efficiency of outsource operations. Why not collaborate with those specializing in specific operational needs?
00:30:59.280 The selfish programmer discards operational burdens to focus purely on writing code. As such, the second stage here reveals the fickleness of the selfish programmer, reflecting how personal whims and creativity can alter opinions and preferences frequently.
00:31:35.390 In shared coding environments, consistency standardizes practices, enhancing readability and manageability. Solo coding allows for greater freedom; each change can lead to inconsistency across projects, which complicates maintenance.
00:32:11.270 Tools like RuboCop help enforce rules consistently, yet each implementation may generate large, non-standardized configurations. To combat this, at Test Double, we created 'Standard'—a package that encapsulates best practices, providing consistency while minimizing decision fatigue.
00:32:49.000 Standard addresses syntax and formatting decisively, allowing one community style to prevail while maintaining quality across teams. Utilizing such tools can help maintain focus and consistency in programming.
00:33:27.470 Finally, the last stage of our exploration involves unhelpfulness. The selfish programmer aspires to solve problems once rather than revisiting the same issues repeatedly.
00:34:04.870 In organizational settings, support staff commonly mediate queries, relaying repeats and workarounds for complex issues to developers who are shielded from user feedback. Yet, the solo programmer is constantly exposed to user responses.
00:34:43.290 When I encountered a troubling bug stemming from browser behaviors, I learned quickly through user feedback and direct engagement how essential it is to refine the client code proactively.
00:35:23.650 To mitigate potential repetitive tasks, I developed a gem named 'To Do or Die,' designed to remind me of messages I needed to address or tasks to delete.
00:36:01.320 This preventative tool boosting accountability resulted in significantly fewer recurring bugs. In summary, the selfish programmer's focus on preventing issues is evident: they understand that if no one is seeking help, it implies they’ve succeeded.
00:36:39.150 This leads us back to the exploration of selfish programmers as being antisocial, egotistical, and irresponsible. If you have any comments or questions, feel free to tweet or send a DM. I’ll also be available throughout the day for discussions.
00:37:13.740 You can check out Kamisama at kamisama.com. Additionally, feel free to grab a copy of the background artwork linked here. If your teams need developers who won’t mind speaking largely in English, I’d love to discuss opportunities at Test Double.
00:37:40.990 Thank you once again for joining me today, and I hope this talk encourages you to adopt a more selfish approach in your solo coding endeavors.
00:38:23.250 Unfortunately, we do not have time for questions.
00:38:32.110 If anyone has questions, please approach the microphone to ask.
00:39:08.450 Thank you for the presentation! I appreciate your motivating story about developing your application. I am not a programmer myself; I work in instructional design. Do you think your experiences could benefit programming training?
00:39:41.920 Thank you for your question! I believe the best method for beginners to learn programming is to pursue something they genuinely want to create and to go through the necessary work to make it happen.
00:40:23.260 [Further questions about programming differences in solo vs. workplace projects]. Certainly, maintaining a library differs greatly from running a live service application. My experiences taught me a lot about expectations and capabilities when it comes to running applications.
00:40:51.380 [End of Q&A session]. Thank you for attending this session and for sharing your valuable questions!