Go offline with the Player FM app!
421: The Idealistic vs. Pragmatic Programmer
Manage episode 410125338 series 1401614
Stephanie revisits the concept of "spiking"—a phase of exploration to determine the feasibility of a technical implementation or to address unknowns in feature requests—sharing her recent experiences with a legacy Rails application. Joël brings a different perspective by discussing his involvement with a client project that heavily utilizes the dry-rb suite of gems, highlighting the learning curve associated with adapting to new patterns and libraries.
Joël used to be much more idealistic and has moved to be more pragmatic. Stephanie has moved the other way. So together, Stephanie and Joël engage in a philosophical discussion on being an idealistic versus a pragmatic programmer. They explore the concept of programming as a blend of science and art, where technical decisions are not only about solving problems but also about expressing ideas and building shared understandings within a team.
- Spike tasks episode
- dry-rb
- Working with Maybe talk
- Problem solving with maybe
- Programming as Theory Building
- The Pragmatic Programmer
Transcript:
JOËL: Hello and welcome to another episode of the Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville.
STEPHANIE: And I'm Stephanie Minn, and together, we're here to share a bit of what we've learned along the way.
JOËL: So, Stephanie, what's new in your world?
STEPHANIE: So, a few weeks ago, we did an episode on spiking in response to a listener question. And I wanted to kind of revisit that topic for a little bit because I've been doing a lot of spiking on my client project. And for those who are not familiar, the way that I understand or define spikes is kind of as an exploration phase to figure out if a technical implementation might work. Or if you have a feature request with some unknowns, you can spend some time-boxed spiking to figure out what those unknowns might be.
And I'm working on your typical legacy Rails application [laughs]. And I think one thing that we talked about last time was this idea of, at what point does spiking end up being just working on the feature [laughs]? And I think that's especially true in an older codebase, where you kind of have to go down a few rabbit holes, maybe, just to even find out if something will trip you up down the line.
And the way I approached that this time around was just, like, identifying the constraints and putting a little flag there for myself. Like, these were rabbit holes that I could go down, but, you know, towards the initial beginning phase of doing the spiking, I decided not to. I just kind of bookmarked it for later.
And once I had identified the main constraints, that was when I was like, okay, like, what kind of solutions can I come up with for these constraints? And that actually then helped me kind of decide which ones we're pursuing a little bit more to get, like, the information I needed to ultimately make a decision about whether this was worth doing, right?
It kind of kept me...I'm thinking about, you know, when you are bowling with those safety guards [laughs], it keeps your ball from just rolling into the gutter. I think it helped with not going too deep into places that I may or may not be super fruitful while also, I think, giving me enough information to have a more realistic understanding of, like, what this work would entail.
JOËL: Would you say that this approach that you're taking is inspired or maybe informed by the conversation we had on the episode?
STEPHANIE: I was especially interested in avoiding the kind of binary of like, no, we can't do this because the system just, you know, isn't able to support it, or it's just too...it would be too much work. That was something I was really, like you said, kind of inspired by after that conversation because I wanted to avoid that trap a little bit.
And I think another really helpful framing was the idea of, like, okay, what would need to be done in order to get us to a place where this could be possible? And that's why I think identifying those constraints was important because they're not constraints forever. Like, we could do something about them if we really wanted to, so kind of avoiding the, like, it's not possible, right? And saying like, "It could be. Here's all the things that we need to do in order to make it possible." But I think that helped shift the conversation, especially with stakeholders and stuff, to be a little bit more realistic and collaborative.
So, Joël, what's new in your world?
JOËL: So, I'm also on a new client project, and a thing that's been really interesting in this codebase is that they've been using the dry-rb suite of gems pretty heavily. And I've seen a lot about the suite of gems. I've read about them. Interestingly, this is kind of the first time that I've been on a codebase that sort of uses them as a main pattern in the app. So, there's been a bit of a learning curve there, and it's been really interesting.
STEPHANIE: This is exciting to me because I know you have a lot of functional programming background, also, so it's kind of surprising that you're only now, you know, using something that explicit from functional languages in Ruby. And I'm curious: what's the learning curve, if not the paradigm? Like, what are you kind of encountering?
JOËL: I think there's a little bit of just the translation. How do these gems sort of approach this? So, they have to do a couple of, like, clever Ruby things to make some of these features work. Some of these also will have different method names, so a lot of just familiarizing myself with the libraries. Like, oh, well, this thing that I'm used to having called a particular thing has a slightly different name here or maybe not having all of the utilities. I was like, oh, how do we traverse with this particular library? Then you have to, like, look it up.
So, it's a lot of like, how do I do this thing I know how to do in, let's say, Elm? How do I translate that into Ruby? But then, also, some of the interplay of how that works in code that also does some very kind of imperative side effecty things also written by a team that is getting used to the pattern. And so, you'll sort of see things where people are pulling things in, but maybe you don't fully understand the deeper underlying approach that's meant to be used.
STEPHANIE: Have you noticed any use cases where the dry-rb patterns really shine in your application?
JOËL: A thing that's nice is that I think it really forces you to think about your edge cases in a way that sometimes Ruby developers play very fast and loose with "Yeah, whatever, it will never be nil." Push to production immediately start getting NoMethodError in your bug tracker. I never do this, by the way, but you know.
STEPHANIE: [laughs].
JOËL: Speaking from a friend's experience [laughs].
STEPHANIE: Asking for a friend, yeah [laughs].
JOËL: I think a thing that I've sort of had to figure out sort of every time I deal with these patterns in different languages is just the importance of good composition and good separation. Because you're adding these sort of wrapper context around things, if you're constantly wrapping and unwrapping, you're like, check things inside, and then do the next thing, and then unwrap again and branch and check and do the next thing, that code becomes really clunky in a way that you just sort of expect to do if you're just writing code in regular Ruby with a nil. But it doesn't really work with a dry-rb maybe or a result.
So, the pattern that I have found that works really well is to extract sort of every operation that can be, let's say, that could fail so that it would give you a result back. Extract that out into its own separate function that will construct a success or a failure, and then have your sort of main code that wants to then do a bunch of these things together.
All it does is use some of the dry-rb helper methods to compose all of these together, whether that's just some sort of, like, do notation, or binding, or fmap, or something like that, which allows you to have sort of individual chunks that can fail, and then one sort of aggregator piece of code that just finds a way to combine all of them nicely. And that avoids you having to do all this repetition.
STEPHANIE: Yeah, that makes a lot of sense.
JOËL: It's a pattern, I think; I had to learn the hard way when I was working with Elm. Because if you're taking a potential nullable value and then you want to do things with it but then that potential operation is also nullable because the input was potentially null, and then that just sort of propagates all the way down the chain. So, my whole chain of functions now is doing checks for nullability. And in Ruby, I could just be like, no, I checked it in the first function. I can then just trust that it's not null down the chain.
Elm doesn't do the like, trust me, bro. The compiler will force you to validate every time, and then the code just blows up, and it gets really painful. So, I had to start thinking about new models of thinking that would separate out code that actually needs to care and code that doesn't need to care about nullability. And I wrote an article about that. That turned into actually a conference talk as well. And these sort of ideas have served me really well at Elm. And I think these translate pretty well to dry-rb as well. That's something that I'm exploring, but the principles seem like they're not tied to a particular language.
STEPHANIE: Yeah, and it's kind of cool that you experienced all of that in working with Elm, where a compiler was there to yell at you [laughs] and kind of forcing you to...I don't know if do the right thing is the right word, but kind of think in the way that it wants you to think. And I can see people who are coming from Ruby and starting to experiment with dry-rb maybe needing a bit of that since it's not built-in in the tooling, just in a recoder view or just in conversations among devs.
JOËL: [inaudible 09:26] Beyond just the idea of wrapping your values and making sure you check them all the time, there are patterns that make that easier or more painful. And even in something like Elm, the compiler would yell at me would make sure I could not have a runtime error by forgetting to check for nullability. It did not prevent me from writing monstrosities of nested repeated conditionals checking if nil, if nil, if nil. That I had to figure out some sort of, like, higher-level patterns that play nicely with that kind of software.
And I think these are things that people have to sort of encounter, feel the pain, feel the frustration, and then move into those better patterns after the fact. And sometimes that's not easy because it's not obvious why that's a valuable pattern to approach.
STEPHANIE: Yeah, I agree completely. Speaking of following patterns and kind of arriving at maybe an ideal version of [chuckles], you know, what you'd like your code to do, you know, to build what you are looking to build [laughs]...this is my very poor attempt at a smooth transition that Joël [laughter] manages to be able to do [laughs] whenever we're trying to shift into the topic of the episode. Anyway, today, we were hoping to talk a little bit about this idea between being an idealistic programmer and a pragmatic programmer and the different journeys that we've each been on in arriving kind of how to balance the two.
JOËL: Yeah, you know, I think neither of these are absolutes, right? It's a spectrum. You probably move around that spectrum from day to day, and then probably, like, more general trends over your career. But I'm curious, for you today, if you had to pick one of those labels, like, which sort of zone of the spectrum would you put yourself in? Do you think you're more idealistic or more pragmatic?
STEPHANIE: I think I'm in a more of an idealistic zone right now.
JOËL: Would you say you're kind of like middle trending idealistic or kind of, like, pretty far down the idealistic side?
STEPHANIE: Middle trending idealistic. I like that way of describing it. I want to know where you are. And then I kind of wanted to try to take a step back and even define what that means for both of us.
JOËL: Right, right. I think the way I'd probably describe myself is a recovering idealist.
STEPHANIE: Oof. Yeah [laughs].
JOËL: I think there was a time where I was really idealistic. I really like knowing sort of underlying theory of software construction, broader patterns. By patterns here, I don't mean necessarily, like, you know, the Gang of Four, but just general sort of approaches that work well and using that to guide my work. But I've also been trending a lot more into the, like, pragmatic side of things in the past few years.
STEPHANIE: So, could you kind of tell me a little bit about what does pragmatic mean for you and what does ideal mean for you?
JOËL: So, I think the pragmatic side of me it's about delivering working software. If you're not shipping anything, you know, the most beautiful piece of art that you've created just warms your heart is useless. So, I think I'm sort of at the extreme end of pragmatism, right? It's all about shipping and shipping fast. And, in the end, that's generally the goal of software.
On the more idealistic side, the sort of doing everything kind of perfect or by the book, or, you know, maybe in a way that brings you personal satisfaction, oftentimes, at the expense of shipping and vice versa. Sometimes shipping comes at the expense of writing absolutely terrible code, but, of course, you know, there's value in both. Shipping is what actually delivers value to your users, your company, yourself if you're using the software.
But if you're not following patterns and things, you're often stuck in a really short-term thinking loop, where you are maybe delivering value today at the cost of being able to deliver value tomorrow or writing code that is unreadable or code that is difficult to collaborate on. So, more than just me shipping an individual feature, I've got to think about, while I'm working with a team, how can I help them be able to ship features or build on top of my work for tomorrow? So, that's sort of how I visualize the field. I'm curious what the words idealism and pragmatism mean to you.
STEPHANIE: Yeah. I agree with you that pragmatism is, you know, this idea of delivering working software. And I think I have seen it very, you know, kind of condensed as, like, moving quickly, getting stuff out the door, basically, like, end result being, like, a thing that you can use, right?
I think I've personally been reassessing that idea a lot because I'm kind of almost wondering like, well, what are we moving quickly for [laughs]? I sometimes have seen pragmatism just end there being like, okay, like, it's all about velocity. And then, I'm kind of stuck being like, well, if you write working software for, you know, completely the wrong thing, is that still pragmatic? I don't know. So, that's kind of where I'm at these days with–I'm feeling a little bit more suspect of pragmatism, at least wanting to make sure that, especially with the people that I'm working with day to day, that we're agreeing on what that means and what success means.
And then, as for idealism, I think also, actually, I now have a little bit of duality in terms of how I understand that as well. One of them being, yes, definitely, like, by the book or, like, by the ideas that we've, you know, some very smart people [laughs] have figured out as, like, this is clean or good quality, or these are the patterns to, you know, make your code as, again, as clean, I don't know, kind of putting air quotes around that, as possible.
And then, I actually like what you really said about code that warms your heart [laughs] that you feel, like, really moved by or, like, just excited about or inspired by because I think that can also be a little bit different from just following theories that other people have defined.
The more I spend doing this stuff, the more I am convinced that writing software is actually a very creative practice. And that's something that I've, like, definitely had to balance with the pragmatism a bit more because there are days when it's just not coming [chuckles], you know, like, I just stare at a blank, new file. And I'm like, I can't even imagine what these classes would be because, like, that creative part of my brain just, like, isn't on that day. So, that's kind of where I'm sitting in terms of, like, what idealistic programming kind of seems to me.
JOËL: There's definitely an element of programming that feels like self-expression, you know, there are parameters around that. And working with a team, you probably all sort of, like, move towards some average. But I would definitely say that there is some element of self-expression in coding.
STEPHANIE: Yeah, 100%. Have you heard about this paper called Programming as Theory Building?
JOËL: The name sounds vaguely familiar, but I can't place the main idea in my mind right now.
STEPHANIE: It's, like, an academic-ish paper from the 80s. And I'll link to it in the show notes because I can't remember the author right now. But the idea is writing code is actually just one way of expressing a theory that we are building. In fact, that expression doesn't even....it's like, it's impossible for it to fully encapsulate everything that was involved in the building of the theory because every decision you make, you know, you decide what not to do as well, right? Like, all the things that you didn't encode in your application is still part of this theory, like stuff that you rejected in order to interpret and make abstract the things that you are translating from the quote, unquote "real world" into code.
That really stuck with me because, in that sense, I love this idea that you can create your own little world, right? Like, you're developing it when you code. And that is something that gets lost a little bit when we're just focused on the pragmatic side of things.
JOËL: Where things get tricky as well is that when you're working with a team, you're not just building your own little world. You're building a shared world with shared mental models, shared metaphors. That's where oftentimes it becomes important to make sure that the things that you are thinking about are expressed in a way that other people could read your code and then immediately pick up on what's happening. And that can be through things like documentation, code comments. It can also be through more rigorous data modeling.
So, for example, I am a huge fan of value objects in general. I tend to not have raw numbers floating around in an app. I like to wrap them in some kind of class and say, "Hey, these numbers that are floating around they actually represent a thing," and I'll name that thing so that other people can get a sense that, oh, it is one of the moving parts of this app, and then here are the behaviors that we expect on it.
And that is partly for sort of code correctness and things like that but also as a sort of way of communicating and a way of contributing to that shared reality that we're creating with the team in a way that if I just left a raw number, that would be almost, like, leaving something slightly undefined. Like, the number is there. It does a thing, but what it does is maybe a little bit more implied. I know in my mind that this is a dollar amount, and maybe there's even a comment above it that says, "Dollar amount." But it makes it a little bit harder for it to play in with everybody else's realities or view of the system than if it were its own object.
STEPHANIE: Yeah, I like what you said about you're building a shared world with your fellow colleagues. And that helped explain to me why, as some people say, naming is the hardest part about building software because, yeah, like you said, even just saying you are wanting to make a method or class expressive. And we talked about how code is a way of expressing yourself. You could, like, name all your stuff in Wingdings [laughs], but we don't. I actually don't know if you could do that. But that was, for some reason, what I imagined. I was like, it's possible, and you could deliver software in complete gibberish [laughs].
JOËL: In theory, could you say that naming your variables as emoji is the most expressive way? Because now it's all emotions.
STEPHANIE: A picture is worth a thousand words, as they say.
JOËL: So, this variable is the frowny face, upside-down smile face. It doesn't get more expressive than that.
STEPHANIE: At a former company, in our Slack workspace, I had a co-worker who loved to use the circus tent emoji to react to things. And, like, I'm convinced that no one really knew what it meant, but we also kind of knew what it meant. We were just like, oh yeah, that's the emoji that she uses to express amusement or, like, something a little bit ironic. And we all kind of figured it out [laughs] eventually. So, again, I do think it's possible. I bet someone has done, like, a creative experiment with writing an application in just emojis. This is now going to be some research I do after this episode [laughter].
JOËL: It is fun when you have, like, a teammate. You know they have the signature emoji that they respond to on things.
STEPHANIE: Yep. Absolutely. So, you know, we kind of spent a little bit of time talking about idealism. I actually wanted to pull back to the idea of pragmatism because, in preparation for this episode, I also revisited my copy of The Pragmatic Programmer. Are you familiar with this book? Have you read it at all?
JOËL: I have read it. It's been probably ten years. We did, I think, a book club at thoughtbot to go through the book.
STEPHANIE: I was skimming the table of contents because I was curious about, again, that, like, definition of pragmatism. You and I had kind of talked about how it can be short-sighted. But what I was actually pretty impressed with, and I imagine this is why the book holds up, you know, after decades, is success for them also means being able to continue to deliver quality software. And that idea of continuity kind of implied, to me, that there was an aspect of, like, making sure the quality meets a certain threshold and, like, incorporating these theories and doing the best practices because they're thinking about success over time, right? Not just the success of this particular piece that you're delivering.
JOËL: I would say most people in our industry are sort of balancing those two objectives, right? They're like, we want to have a decent velocity and ship things, but at the same time, we want to be able to keep delivering. We want a certain threshold of quality.
In between those two objectives, there is a sea of trade-offs, and how you manage them are probably a little bit part of your personality as a developer and is probably also, to a certain extent, a function of your experience, learning sort of when to lean more into taking some shortcuts to ship faster and when to double down on certain practices that increase code quality, and what aspects of quality value more than others because not all forms of quote, unquote, "quality" are the same.
I think a sort of source of danger, especially for newer developers, is you sort of start on almost, like, a hyper-pragmatic side of things because most people get into software because they want to build things. And the ultimate way to build is to ship, and then you sort of encounter problems where you realize, oh, this code is really clunky. It's harder and harder to ship. Let me learn some elements of code quality. Let's get better at my craft so that I can build software that has fewer bugs or that I can ship more consistently. And that's great.
And then, you sort of run into some, like, broader sort of theories of programming: patterns, structures, things like that. And it becomes very easy to sort of blindly copy-paste that everywhere to the point where I think it's almost a bit of a meme, the, like, intermediate programmer who's read Clean Code or the Design Patterns book and is just now, like, applying these things blindly to every piece of code they encounter to the annoyance of the entire team.
STEPHANIE: I think you just about described my trajectory [laughter], though hopefully, I was not so obnoxious about [laughs] it for my team having to deal with my, like, discovering [laughs] theories that have long been used.
JOËL: I think we kind of all go through that journey to a certain extent, right? It's a little bit different for every one of us, but I think this is a journey that is really common for developers.
STEPHANIE: Yeah. One thing I frequently think about a lot is how much I wished I had known some of that theory earlier. But I don't think I have an answer one way or another. It's like; I'm not sure if having that knowledge earlier really would have helped me because I've also definitely been in...I'm just thinking about, like, when I was in college in lectures trying to absorb theories that made no sense to me because I had no, like, practical experience to connect it to. It's almost, like, maybe there is, like, that perfect time [laughs] where it is the most valuable for what you're doing. And I don't know. I kind of believe that there is a way to bridge that gap.
JOËL: I mean, now we're kind of getting into an element of pedagogy. Do you sort of teach the theory first, and then show how to apply it to problems? Or do you show problems and then introduce bits of theory to help people get unstuck and maybe then cap it off by like, oh, these, like, five different, like, techniques I showed you to, like, solve five different problems, turns out they all fit in some grand unified theory? And, like, here's how the five things you thought were five different techniques are actually the same technique viewed from five different perspectives. Let me blow your mind.
STEPHANIE: That's a Joël approach [laughter] to teaching if I've ever heard one.
JOËL: I'm a huge fan of that approach. Going back to some of the, like, the functional programming ideas, I think that's one that really connected for me. I struggled to learn things like monads, and functors, and things like that. And I think, in my mind, these two approaches is like the Haskell school of teaching and the Elm school of teaching.
Haskell will sort of say, "Hey, let me teach you about this theory of monads and all these things, and then, we'll look at some ways where that can be applied practically." Whereas Elm will say, "No, you don't need to know about this. Let's look at some practical problems. Oh, you've got null values you need to check. Here's how you can, like, handle nullability in a safe way. Oh, you've got a bunch of HTTP requests that might resolve in random order, and you want to, like, deal with them when they all come back. Here's some tips on how you can do that."
And then, you have three or four things, and then, eventually, it just sort of lets you say, "Wait a minute, all of these problems are sort of all the same, and it turns out they all fit in some unified theory." And then, the light bulb goes off, and you're like, "Ooh, so now when I'm dealing with unknown blobs of Jason trying to parse data out of them, I'll bet I can use the same techniques I used for chaining HTTP requests to dig multiple dependent pieces of JSON."
STEPHANIE: Yeah. And that's so satisfying, right? It really is kind of leveling up in that Galaxy Brain meme sort of way.
JOËL: Yeah. And that's maybe to a certain extent even a value of idealism because if you build your system in such a way that it follows some of these patterns, then insights and intuitions that people have in one part of your code can then carry to other parts of your code, and that's incredibly powerful.
STEPHANIE: Yeah. And I almost wonder because you also mentioned kind of where you end up on the spectrum is a function of your experience. I wonder if us, you know, being consultants and seeing patterns across many applications also kind of contributes to the striving for idealism [laughs].
JOËL: It's kind of both, right? Because there's very high incentive to ship pretty rapidly, especially if you're on a shorter engagement or if you're on a project that has a shorter timescale. But also, yes, because you've seen so many projects, you've seen how things can go wrong. Also, you've seen the same problem from 20 different perspectives that are all slightly different. And so, some of those broader patterns can start emerging in your head.
STEPHANIE: Yeah, honestly, I think that's kind of the work that I enjoy the most in consulting because a lot of clients bring us on when they're like, "Hey, like, we've reached a point where our velocity has slowed down. Like, can you help us unstick our developers?" And that's actually when I've found that leaning on the theories and maybe a little bit of idealism is actually really useful because I'm kind of providing those tools to developers at this time when they need it. That's kind of why I have been saying trending idealism because I have found that particularly useful at work.
JOËL: There's an element here of, like, looking at a bunch of different use cases and then finding some sort of unifying model or theory. And that's a word that I think programmers have a love-hate relationship with: Abstraction. I don't know about you, but designing abstractions is a lot of fun for me. I love designing abstractions. I have always loved designing abstractions. It's not always the best use of my time, and it's not always the best thing for a codebase.
STEPHANIE: Ooh, okay, okay. This was a good transition. I hear you that, like, yeah, love-hate relationship. It's hard. That's kind of where I've ended up. It's really hard. And I think it's because it requires that creative thinking.
JOËL: It requires that creative thinking. And then also, like, it requires you to sort of see more broadly, a more broad picture. What are the things that are connected, the things that are disconnected, even though they seem related? And, like, being able to sort of slice those similarities from each other.
STEPHANIE: Yeah. I agree. And the interesting part is that, like, a lot of the time you just don't know yet. And you kind of have to come back to reality and admit that you don't know yet, you know, got to come back to earth, take a look around, and, yeah, you can go through the thought exercise of thinking [laughs] about all of the possibilities, and I imagine you could do that forever [laughs].
JOËL: I mean, that's why we have heuristics like the rule of three that says, "Don't abstract something out or attempt to DRY code until you've seen three use cases of it." So, maybe leave a little bit of duplication or a little bit of maybe not perfectly factored code until you have a couple of more examples. And the sort of real picture starts emerging a little bit more.
STEPHANIE: So, I think we are kind of at this topic already, but was there a moment or was there something that kind of helped you realize, like, oh, I can't be in that space of imagining abstractions [laughs] forever when I have to deliver software? Like, what changed for you to be the, as you said yourself, recovering idealist and having to maybe employ some more pragmatic heuristics?
JOËL: And I think, for me, it's partly being a consultant and being in a lot of projects and having that pressure to work with deadlines and sort of not having an infinite canvas to paint with, having to sort of fit some of my grand ideas into the reality of, we've got a week or two weeks to get this thing done, and also working with a team, and some ideas don't work well with every team. Every team is kind of at a different place.
And abstractions sort of only serve you as well as they are useful to not only you but the team at large. So, if a team is not comfortable with a set of abstractions, or it's sort of, like, too far down a path, then that can be really challenging. And that's where something like the dry-rb set of gems, which has some really fun abstractions like a mental model for doing things, depending on the team, that can be a really heavy lift. And so, as much as I like those patterns, I might think long and hard before I try to push this on a whole team.
STEPHANIE: Yeah, I kind of had to navigate a situation like that recently, where I was doing a code review, and I had left some suggestions about refactoring to encapsulate some responsibilities better. And then, I was like, oh, and then I noticed another thing that we could do to make that easier. And it, you know, definitely can start to spiral. And the author, you know, kind of responded to me and said, "Hey, like, I really appreciate these comments, but we are a bit tight on deadline for this project. So, is it okay if I, like, revisit this when we've delivered it?"
And, you know, I was just like, "Yeah, it's totally up to you." At the end of the day, I want whoever's authoring this code to have, like, full agency about how they want to move forward. And it was really helpful for me to get that context of, like, oh, they're a bit tight on the deadline because then I can start to meet them where they're at. And maybe I can give some suggestions for moving towards that ideal state, but ones that are lower left, and that is still better than nothing.
JOËL: That sounds awfully pragmatic.
STEPHANIE: [laughs]
JOËL: Moving in a positive direction, we're getting halfway. It's better than nothing. That's very pragmatic.
STEPHANIE: Hmm. Wow. But it's pragmatically moving towards idealism.
JOËL: [laughs]
STEPHANIE: If that is even possible [laughs].
JOËL: Uh-huh.
STEPHANIE: That's maybe the book that I'm going to write, not The Pragmatic Programmer, but The Pragmatically Idealistic Programmer [laughs].
JOËL: The Pragmatic Idealist.
STEPHANIE: Ooh, yeah, I like that. Okay. Watch out for that book coming 2030 [laughter], written by me and Joël.
JOËL: So, I think you brought up a really interesting point, which is the idea of pragmatism versus idealism when it comes to code review. Do you find that you think about these ideas differently when reviewing somebody else's code versus when you write your own?
STEPHANIE: Oooh, yeah. I'm not sure exactly why, but definitely, when I'm reviewing someone else's code, I'm already in the headspace of, you know, I have some separation, right? Like, I'm not in the mode of thinking very hard [laughs] about what I'm creating. I'm just, like, in the editing kind of phase. And then, I can actually pull more from different theories and ideas, and I find that actually quite easier. When I'm writing my own code, it's just whatever comes out, right? And then, hopefully, I have the time to revisit it and give it a scan, and then start to integrate the, like, idealistic theories and the patterns that I would like to be using.
But it definitely...for patterns that I feel a lot more confident about or more familiar with, they just come out mostly kind of oriented in that way if I have the time, or sometimes I will make the time, you know. I'll just say, "It's not done yet," because I know it can be better. I think that could be another, like, pragmatically idealist way of handling that.
JOËL: [laughs]
STEPHANIE: Right? It's just telling people, "I'm not done." [laughs] It's not done until I do at least give it an attempt.
JOËL: So, it's kind of a two-phase thing when you're writing your own code, whereas it's only a single phase when you're reviewing somebody else's.
STEPHANIE: Yeah. Yeah. But, like I said earlier, it's like, I also really believe that I don't want to impose any of my ideas [laughs] onto others. I really believe that people have to arrive at it on their own. So, it used to bother me a little bit more when I was just like, oh, but this way is better [laughs]. When people wouldn't get on board, I would be sad about it. But as long as I know that I, like, left that comment, then I can give myself a pat on the back for trying to move towards that ideal state. What about you [laughs]?
JOËL: I think this is probably also where I'm, like, now a recovering idealist. There was a time where I would leave a ton of comments on someone's PR. I almost had a view of like, how can I help you get your PR to be the best it can possibly be? And sometimes, if you start with something that's very rough around the edges, you're leaving a lot of comments. And I've been that guy who's left 50 comments on a PR. In retrospect, I think that was not being a good teammate.
STEPHANIE: Hmm.
JOËL: So, I think maybe my mental model or my, like, goal for PR review has changed a little bit. It's less about how can I help you make your code the best it can possibly be? And a how can I help you get your code to mergeable? And it's possible that mergeable means best that it can possibly be, but that's usually not the case. So, I'm going to give you some feedback: some things that confuse me, maybe raise one or two patterns that are existing in the app that maybe you weren't aware of that you should maybe consider applying. Maybe I'll raise a couple of ideas that are new, but that apply here.
And those might just be a, "Hey, let's just think about this. Maybe we don't want to do this in this PR, but maybe we want to look at them at some point. Or we should be thinking about this in a sort of rule of three situation. If we see this come up another time, maybe consider introducing a strategy pattern here, or maybe consider making this a value object, or separating these side effects from these pure behavior." But it's more of a dialogue about how can I help you get your PR to the point where it is mergeable?
STEPHANIE: Yeah. Another thing I thought about just now is both are meaningful or, like, both can provide meaning in different ways, and people ascribe different amounts of meaning to both; where I had worked with someone, a client developer before, who was not super interested in doing any kind of refactoring or, like, any, you know, second passes for quality. Because, for him, like, he just wanted to ship, right? That was where he found meaning in his work.
Whereas that actually made my work feel a lot more meaningless [chuckles] because I'm like, well, if we're just kind of hands on a keyboard, like robots shipping code, I don't know, that doesn't feel particularly motivating for me. You know, I do want to employ some of that craft a little bit more.
JOËL: And, I guess, yeah, idealism versus pragmatism is also...it's a personal individual thing. There's an element where it's a team decision, or at least a sense of, like, how much quality do we need at this point in the life cycle of the project? And what are the areas where we particularly want to emphasize quality? What are our quality standards? And that's, to a certain extent, consensus among the team that it's individual members. And it's also coming from team leadership.
STEPHANIE: Yeah. Yeah, exactly. I mentioned that, you know, just to, I think, shed a little bit of light that it's usually not personal, right [laughs]? There's that part of understanding that is really important to, yeah, like, keep building this shared world of writing software, and, hopefully, it should be meaningful for all of us.
JOËL: I think a few takeaways that I have would be, one, the value of, like, theory and idealism. These things help you to become a better developer. They help you to spot patterns. It's probably good to sort of have in the background always be learning some new thing, whether that's learning a new set of patterns, or learning some mental models, thinking about, oh, the difference between side effects and pure code, learning about particular ways of structuring code. These are all things that are good to have in your back pocket to be able to apply to the code that you're doing, even if it's a sort of after-the-fact, hey, I've done a similar task three different times. Is there a broader principle?
But then, also, take the time to really make sure that you're focusing on shipping code, and maybe that's learning to work in smaller chunks, working iteratively, learning to scope your work well. Because, in the end, delivering value is a thing that is something that we could all probably benefit from doing more of.
And then, finally, taking some time to self-reflect, a little bit of self-awareness in this area. What are the aspects of pragmatism and idealism that you find personally meaningful? What are the elements that you think bring value to your work, to your team? And let that sort of guide you on your next code writing or PR review.
STEPHANIE: On that note, shall we wrap up?
JOËL: Let's wrap up.
STEPHANIE: Show notes for this episode can be found at bikeshed.fm.
JOËL: This show has been produced and edited by Mandy Moore.
STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter.
STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email.
JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week.
ALL: Byeeeeeeee!!!!!!
AD:
Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us.
More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
439 episodes
Manage episode 410125338 series 1401614
Stephanie revisits the concept of "spiking"—a phase of exploration to determine the feasibility of a technical implementation or to address unknowns in feature requests—sharing her recent experiences with a legacy Rails application. Joël brings a different perspective by discussing his involvement with a client project that heavily utilizes the dry-rb suite of gems, highlighting the learning curve associated with adapting to new patterns and libraries.
Joël used to be much more idealistic and has moved to be more pragmatic. Stephanie has moved the other way. So together, Stephanie and Joël engage in a philosophical discussion on being an idealistic versus a pragmatic programmer. They explore the concept of programming as a blend of science and art, where technical decisions are not only about solving problems but also about expressing ideas and building shared understandings within a team.
- Spike tasks episode
- dry-rb
- Working with Maybe talk
- Problem solving with maybe
- Programming as Theory Building
- The Pragmatic Programmer
Transcript:
JOËL: Hello and welcome to another episode of the Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville.
STEPHANIE: And I'm Stephanie Minn, and together, we're here to share a bit of what we've learned along the way.
JOËL: So, Stephanie, what's new in your world?
STEPHANIE: So, a few weeks ago, we did an episode on spiking in response to a listener question. And I wanted to kind of revisit that topic for a little bit because I've been doing a lot of spiking on my client project. And for those who are not familiar, the way that I understand or define spikes is kind of as an exploration phase to figure out if a technical implementation might work. Or if you have a feature request with some unknowns, you can spend some time-boxed spiking to figure out what those unknowns might be.
And I'm working on your typical legacy Rails application [laughs]. And I think one thing that we talked about last time was this idea of, at what point does spiking end up being just working on the feature [laughs]? And I think that's especially true in an older codebase, where you kind of have to go down a few rabbit holes, maybe, just to even find out if something will trip you up down the line.
And the way I approached that this time around was just, like, identifying the constraints and putting a little flag there for myself. Like, these were rabbit holes that I could go down, but, you know, towards the initial beginning phase of doing the spiking, I decided not to. I just kind of bookmarked it for later.
And once I had identified the main constraints, that was when I was like, okay, like, what kind of solutions can I come up with for these constraints? And that actually then helped me kind of decide which ones we're pursuing a little bit more to get, like, the information I needed to ultimately make a decision about whether this was worth doing, right?
It kind of kept me...I'm thinking about, you know, when you are bowling with those safety guards [laughs], it keeps your ball from just rolling into the gutter. I think it helped with not going too deep into places that I may or may not be super fruitful while also, I think, giving me enough information to have a more realistic understanding of, like, what this work would entail.
JOËL: Would you say that this approach that you're taking is inspired or maybe informed by the conversation we had on the episode?
STEPHANIE: I was especially interested in avoiding the kind of binary of like, no, we can't do this because the system just, you know, isn't able to support it, or it's just too...it would be too much work. That was something I was really, like you said, kind of inspired by after that conversation because I wanted to avoid that trap a little bit.
And I think another really helpful framing was the idea of, like, okay, what would need to be done in order to get us to a place where this could be possible? And that's why I think identifying those constraints was important because they're not constraints forever. Like, we could do something about them if we really wanted to, so kind of avoiding the, like, it's not possible, right? And saying like, "It could be. Here's all the things that we need to do in order to make it possible." But I think that helped shift the conversation, especially with stakeholders and stuff, to be a little bit more realistic and collaborative.
So, Joël, what's new in your world?
JOËL: So, I'm also on a new client project, and a thing that's been really interesting in this codebase is that they've been using the dry-rb suite of gems pretty heavily. And I've seen a lot about the suite of gems. I've read about them. Interestingly, this is kind of the first time that I've been on a codebase that sort of uses them as a main pattern in the app. So, there's been a bit of a learning curve there, and it's been really interesting.
STEPHANIE: This is exciting to me because I know you have a lot of functional programming background, also, so it's kind of surprising that you're only now, you know, using something that explicit from functional languages in Ruby. And I'm curious: what's the learning curve, if not the paradigm? Like, what are you kind of encountering?
JOËL: I think there's a little bit of just the translation. How do these gems sort of approach this? So, they have to do a couple of, like, clever Ruby things to make some of these features work. Some of these also will have different method names, so a lot of just familiarizing myself with the libraries. Like, oh, well, this thing that I'm used to having called a particular thing has a slightly different name here or maybe not having all of the utilities. I was like, oh, how do we traverse with this particular library? Then you have to, like, look it up.
So, it's a lot of like, how do I do this thing I know how to do in, let's say, Elm? How do I translate that into Ruby? But then, also, some of the interplay of how that works in code that also does some very kind of imperative side effecty things also written by a team that is getting used to the pattern. And so, you'll sort of see things where people are pulling things in, but maybe you don't fully understand the deeper underlying approach that's meant to be used.
STEPHANIE: Have you noticed any use cases where the dry-rb patterns really shine in your application?
JOËL: A thing that's nice is that I think it really forces you to think about your edge cases in a way that sometimes Ruby developers play very fast and loose with "Yeah, whatever, it will never be nil." Push to production immediately start getting NoMethodError in your bug tracker. I never do this, by the way, but you know.
STEPHANIE: [laughs].
JOËL: Speaking from a friend's experience [laughs].
STEPHANIE: Asking for a friend, yeah [laughs].
JOËL: I think a thing that I've sort of had to figure out sort of every time I deal with these patterns in different languages is just the importance of good composition and good separation. Because you're adding these sort of wrapper context around things, if you're constantly wrapping and unwrapping, you're like, check things inside, and then do the next thing, and then unwrap again and branch and check and do the next thing, that code becomes really clunky in a way that you just sort of expect to do if you're just writing code in regular Ruby with a nil. But it doesn't really work with a dry-rb maybe or a result.
So, the pattern that I have found that works really well is to extract sort of every operation that can be, let's say, that could fail so that it would give you a result back. Extract that out into its own separate function that will construct a success or a failure, and then have your sort of main code that wants to then do a bunch of these things together.
All it does is use some of the dry-rb helper methods to compose all of these together, whether that's just some sort of, like, do notation, or binding, or fmap, or something like that, which allows you to have sort of individual chunks that can fail, and then one sort of aggregator piece of code that just finds a way to combine all of them nicely. And that avoids you having to do all this repetition.
STEPHANIE: Yeah, that makes a lot of sense.
JOËL: It's a pattern, I think; I had to learn the hard way when I was working with Elm. Because if you're taking a potential nullable value and then you want to do things with it but then that potential operation is also nullable because the input was potentially null, and then that just sort of propagates all the way down the chain. So, my whole chain of functions now is doing checks for nullability. And in Ruby, I could just be like, no, I checked it in the first function. I can then just trust that it's not null down the chain.
Elm doesn't do the like, trust me, bro. The compiler will force you to validate every time, and then the code just blows up, and it gets really painful. So, I had to start thinking about new models of thinking that would separate out code that actually needs to care and code that doesn't need to care about nullability. And I wrote an article about that. That turned into actually a conference talk as well. And these sort of ideas have served me really well at Elm. And I think these translate pretty well to dry-rb as well. That's something that I'm exploring, but the principles seem like they're not tied to a particular language.
STEPHANIE: Yeah, and it's kind of cool that you experienced all of that in working with Elm, where a compiler was there to yell at you [laughs] and kind of forcing you to...I don't know if do the right thing is the right word, but kind of think in the way that it wants you to think. And I can see people who are coming from Ruby and starting to experiment with dry-rb maybe needing a bit of that since it's not built-in in the tooling, just in a recoder view or just in conversations among devs.
JOËL: [inaudible 09:26] Beyond just the idea of wrapping your values and making sure you check them all the time, there are patterns that make that easier or more painful. And even in something like Elm, the compiler would yell at me would make sure I could not have a runtime error by forgetting to check for nullability. It did not prevent me from writing monstrosities of nested repeated conditionals checking if nil, if nil, if nil. That I had to figure out some sort of, like, higher-level patterns that play nicely with that kind of software.
And I think these are things that people have to sort of encounter, feel the pain, feel the frustration, and then move into those better patterns after the fact. And sometimes that's not easy because it's not obvious why that's a valuable pattern to approach.
STEPHANIE: Yeah, I agree completely. Speaking of following patterns and kind of arriving at maybe an ideal version of [chuckles], you know, what you'd like your code to do, you know, to build what you are looking to build [laughs]...this is my very poor attempt at a smooth transition that Joël [laughter] manages to be able to do [laughs] whenever we're trying to shift into the topic of the episode. Anyway, today, we were hoping to talk a little bit about this idea between being an idealistic programmer and a pragmatic programmer and the different journeys that we've each been on in arriving kind of how to balance the two.
JOËL: Yeah, you know, I think neither of these are absolutes, right? It's a spectrum. You probably move around that spectrum from day to day, and then probably, like, more general trends over your career. But I'm curious, for you today, if you had to pick one of those labels, like, which sort of zone of the spectrum would you put yourself in? Do you think you're more idealistic or more pragmatic?
STEPHANIE: I think I'm in a more of an idealistic zone right now.
JOËL: Would you say you're kind of like middle trending idealistic or kind of, like, pretty far down the idealistic side?
STEPHANIE: Middle trending idealistic. I like that way of describing it. I want to know where you are. And then I kind of wanted to try to take a step back and even define what that means for both of us.
JOËL: Right, right. I think the way I'd probably describe myself is a recovering idealist.
STEPHANIE: Oof. Yeah [laughs].
JOËL: I think there was a time where I was really idealistic. I really like knowing sort of underlying theory of software construction, broader patterns. By patterns here, I don't mean necessarily, like, you know, the Gang of Four, but just general sort of approaches that work well and using that to guide my work. But I've also been trending a lot more into the, like, pragmatic side of things in the past few years.
STEPHANIE: So, could you kind of tell me a little bit about what does pragmatic mean for you and what does ideal mean for you?
JOËL: So, I think the pragmatic side of me it's about delivering working software. If you're not shipping anything, you know, the most beautiful piece of art that you've created just warms your heart is useless. So, I think I'm sort of at the extreme end of pragmatism, right? It's all about shipping and shipping fast. And, in the end, that's generally the goal of software.
On the more idealistic side, the sort of doing everything kind of perfect or by the book, or, you know, maybe in a way that brings you personal satisfaction, oftentimes, at the expense of shipping and vice versa. Sometimes shipping comes at the expense of writing absolutely terrible code, but, of course, you know, there's value in both. Shipping is what actually delivers value to your users, your company, yourself if you're using the software.
But if you're not following patterns and things, you're often stuck in a really short-term thinking loop, where you are maybe delivering value today at the cost of being able to deliver value tomorrow or writing code that is unreadable or code that is difficult to collaborate on. So, more than just me shipping an individual feature, I've got to think about, while I'm working with a team, how can I help them be able to ship features or build on top of my work for tomorrow? So, that's sort of how I visualize the field. I'm curious what the words idealism and pragmatism mean to you.
STEPHANIE: Yeah. I agree with you that pragmatism is, you know, this idea of delivering working software. And I think I have seen it very, you know, kind of condensed as, like, moving quickly, getting stuff out the door, basically, like, end result being, like, a thing that you can use, right?
I think I've personally been reassessing that idea a lot because I'm kind of almost wondering like, well, what are we moving quickly for [laughs]? I sometimes have seen pragmatism just end there being like, okay, like, it's all about velocity. And then, I'm kind of stuck being like, well, if you write working software for, you know, completely the wrong thing, is that still pragmatic? I don't know. So, that's kind of where I'm at these days with–I'm feeling a little bit more suspect of pragmatism, at least wanting to make sure that, especially with the people that I'm working with day to day, that we're agreeing on what that means and what success means.
And then, as for idealism, I think also, actually, I now have a little bit of duality in terms of how I understand that as well. One of them being, yes, definitely, like, by the book or, like, by the ideas that we've, you know, some very smart people [laughs] have figured out as, like, this is clean or good quality, or these are the patterns to, you know, make your code as, again, as clean, I don't know, kind of putting air quotes around that, as possible.
And then, I actually like what you really said about code that warms your heart [laughs] that you feel, like, really moved by or, like, just excited about or inspired by because I think that can also be a little bit different from just following theories that other people have defined.
The more I spend doing this stuff, the more I am convinced that writing software is actually a very creative practice. And that's something that I've, like, definitely had to balance with the pragmatism a bit more because there are days when it's just not coming [chuckles], you know, like, I just stare at a blank, new file. And I'm like, I can't even imagine what these classes would be because, like, that creative part of my brain just, like, isn't on that day. So, that's kind of where I'm sitting in terms of, like, what idealistic programming kind of seems to me.
JOËL: There's definitely an element of programming that feels like self-expression, you know, there are parameters around that. And working with a team, you probably all sort of, like, move towards some average. But I would definitely say that there is some element of self-expression in coding.
STEPHANIE: Yeah, 100%. Have you heard about this paper called Programming as Theory Building?
JOËL: The name sounds vaguely familiar, but I can't place the main idea in my mind right now.
STEPHANIE: It's, like, an academic-ish paper from the 80s. And I'll link to it in the show notes because I can't remember the author right now. But the idea is writing code is actually just one way of expressing a theory that we are building. In fact, that expression doesn't even....it's like, it's impossible for it to fully encapsulate everything that was involved in the building of the theory because every decision you make, you know, you decide what not to do as well, right? Like, all the things that you didn't encode in your application is still part of this theory, like stuff that you rejected in order to interpret and make abstract the things that you are translating from the quote, unquote "real world" into code.
That really stuck with me because, in that sense, I love this idea that you can create your own little world, right? Like, you're developing it when you code. And that is something that gets lost a little bit when we're just focused on the pragmatic side of things.
JOËL: Where things get tricky as well is that when you're working with a team, you're not just building your own little world. You're building a shared world with shared mental models, shared metaphors. That's where oftentimes it becomes important to make sure that the things that you are thinking about are expressed in a way that other people could read your code and then immediately pick up on what's happening. And that can be through things like documentation, code comments. It can also be through more rigorous data modeling.
So, for example, I am a huge fan of value objects in general. I tend to not have raw numbers floating around in an app. I like to wrap them in some kind of class and say, "Hey, these numbers that are floating around they actually represent a thing," and I'll name that thing so that other people can get a sense that, oh, it is one of the moving parts of this app, and then here are the behaviors that we expect on it.
And that is partly for sort of code correctness and things like that but also as a sort of way of communicating and a way of contributing to that shared reality that we're creating with the team in a way that if I just left a raw number, that would be almost, like, leaving something slightly undefined. Like, the number is there. It does a thing, but what it does is maybe a little bit more implied. I know in my mind that this is a dollar amount, and maybe there's even a comment above it that says, "Dollar amount." But it makes it a little bit harder for it to play in with everybody else's realities or view of the system than if it were its own object.
STEPHANIE: Yeah, I like what you said about you're building a shared world with your fellow colleagues. And that helped explain to me why, as some people say, naming is the hardest part about building software because, yeah, like you said, even just saying you are wanting to make a method or class expressive. And we talked about how code is a way of expressing yourself. You could, like, name all your stuff in Wingdings [laughs], but we don't. I actually don't know if you could do that. But that was, for some reason, what I imagined. I was like, it's possible, and you could deliver software in complete gibberish [laughs].
JOËL: In theory, could you say that naming your variables as emoji is the most expressive way? Because now it's all emotions.
STEPHANIE: A picture is worth a thousand words, as they say.
JOËL: So, this variable is the frowny face, upside-down smile face. It doesn't get more expressive than that.
STEPHANIE: At a former company, in our Slack workspace, I had a co-worker who loved to use the circus tent emoji to react to things. And, like, I'm convinced that no one really knew what it meant, but we also kind of knew what it meant. We were just like, oh yeah, that's the emoji that she uses to express amusement or, like, something a little bit ironic. And we all kind of figured it out [laughs] eventually. So, again, I do think it's possible. I bet someone has done, like, a creative experiment with writing an application in just emojis. This is now going to be some research I do after this episode [laughter].
JOËL: It is fun when you have, like, a teammate. You know they have the signature emoji that they respond to on things.
STEPHANIE: Yep. Absolutely. So, you know, we kind of spent a little bit of time talking about idealism. I actually wanted to pull back to the idea of pragmatism because, in preparation for this episode, I also revisited my copy of The Pragmatic Programmer. Are you familiar with this book? Have you read it at all?
JOËL: I have read it. It's been probably ten years. We did, I think, a book club at thoughtbot to go through the book.
STEPHANIE: I was skimming the table of contents because I was curious about, again, that, like, definition of pragmatism. You and I had kind of talked about how it can be short-sighted. But what I was actually pretty impressed with, and I imagine this is why the book holds up, you know, after decades, is success for them also means being able to continue to deliver quality software. And that idea of continuity kind of implied, to me, that there was an aspect of, like, making sure the quality meets a certain threshold and, like, incorporating these theories and doing the best practices because they're thinking about success over time, right? Not just the success of this particular piece that you're delivering.
JOËL: I would say most people in our industry are sort of balancing those two objectives, right? They're like, we want to have a decent velocity and ship things, but at the same time, we want to be able to keep delivering. We want a certain threshold of quality.
In between those two objectives, there is a sea of trade-offs, and how you manage them are probably a little bit part of your personality as a developer and is probably also, to a certain extent, a function of your experience, learning sort of when to lean more into taking some shortcuts to ship faster and when to double down on certain practices that increase code quality, and what aspects of quality value more than others because not all forms of quote, unquote, "quality" are the same.
I think a sort of source of danger, especially for newer developers, is you sort of start on almost, like, a hyper-pragmatic side of things because most people get into software because they want to build things. And the ultimate way to build is to ship, and then you sort of encounter problems where you realize, oh, this code is really clunky. It's harder and harder to ship. Let me learn some elements of code quality. Let's get better at my craft so that I can build software that has fewer bugs or that I can ship more consistently. And that's great.
And then, you sort of run into some, like, broader sort of theories of programming: patterns, structures, things like that. And it becomes very easy to sort of blindly copy-paste that everywhere to the point where I think it's almost a bit of a meme, the, like, intermediate programmer who's read Clean Code or the Design Patterns book and is just now, like, applying these things blindly to every piece of code they encounter to the annoyance of the entire team.
STEPHANIE: I think you just about described my trajectory [laughter], though hopefully, I was not so obnoxious about [laughs] it for my team having to deal with my, like, discovering [laughs] theories that have long been used.
JOËL: I think we kind of all go through that journey to a certain extent, right? It's a little bit different for every one of us, but I think this is a journey that is really common for developers.
STEPHANIE: Yeah. One thing I frequently think about a lot is how much I wished I had known some of that theory earlier. But I don't think I have an answer one way or another. It's like; I'm not sure if having that knowledge earlier really would have helped me because I've also definitely been in...I'm just thinking about, like, when I was in college in lectures trying to absorb theories that made no sense to me because I had no, like, practical experience to connect it to. It's almost, like, maybe there is, like, that perfect time [laughs] where it is the most valuable for what you're doing. And I don't know. I kind of believe that there is a way to bridge that gap.
JOËL: I mean, now we're kind of getting into an element of pedagogy. Do you sort of teach the theory first, and then show how to apply it to problems? Or do you show problems and then introduce bits of theory to help people get unstuck and maybe then cap it off by like, oh, these, like, five different, like, techniques I showed you to, like, solve five different problems, turns out they all fit in some grand unified theory? And, like, here's how the five things you thought were five different techniques are actually the same technique viewed from five different perspectives. Let me blow your mind.
STEPHANIE: That's a Joël approach [laughter] to teaching if I've ever heard one.
JOËL: I'm a huge fan of that approach. Going back to some of the, like, the functional programming ideas, I think that's one that really connected for me. I struggled to learn things like monads, and functors, and things like that. And I think, in my mind, these two approaches is like the Haskell school of teaching and the Elm school of teaching.
Haskell will sort of say, "Hey, let me teach you about this theory of monads and all these things, and then, we'll look at some ways where that can be applied practically." Whereas Elm will say, "No, you don't need to know about this. Let's look at some practical problems. Oh, you've got null values you need to check. Here's how you can, like, handle nullability in a safe way. Oh, you've got a bunch of HTTP requests that might resolve in random order, and you want to, like, deal with them when they all come back. Here's some tips on how you can do that."
And then, you have three or four things, and then, eventually, it just sort of lets you say, "Wait a minute, all of these problems are sort of all the same, and it turns out they all fit in some unified theory." And then, the light bulb goes off, and you're like, "Ooh, so now when I'm dealing with unknown blobs of Jason trying to parse data out of them, I'll bet I can use the same techniques I used for chaining HTTP requests to dig multiple dependent pieces of JSON."
STEPHANIE: Yeah. And that's so satisfying, right? It really is kind of leveling up in that Galaxy Brain meme sort of way.
JOËL: Yeah. And that's maybe to a certain extent even a value of idealism because if you build your system in such a way that it follows some of these patterns, then insights and intuitions that people have in one part of your code can then carry to other parts of your code, and that's incredibly powerful.
STEPHANIE: Yeah. And I almost wonder because you also mentioned kind of where you end up on the spectrum is a function of your experience. I wonder if us, you know, being consultants and seeing patterns across many applications also kind of contributes to the striving for idealism [laughs].
JOËL: It's kind of both, right? Because there's very high incentive to ship pretty rapidly, especially if you're on a shorter engagement or if you're on a project that has a shorter timescale. But also, yes, because you've seen so many projects, you've seen how things can go wrong. Also, you've seen the same problem from 20 different perspectives that are all slightly different. And so, some of those broader patterns can start emerging in your head.
STEPHANIE: Yeah, honestly, I think that's kind of the work that I enjoy the most in consulting because a lot of clients bring us on when they're like, "Hey, like, we've reached a point where our velocity has slowed down. Like, can you help us unstick our developers?" And that's actually when I've found that leaning on the theories and maybe a little bit of idealism is actually really useful because I'm kind of providing those tools to developers at this time when they need it. That's kind of why I have been saying trending idealism because I have found that particularly useful at work.
JOËL: There's an element here of, like, looking at a bunch of different use cases and then finding some sort of unifying model or theory. And that's a word that I think programmers have a love-hate relationship with: Abstraction. I don't know about you, but designing abstractions is a lot of fun for me. I love designing abstractions. I have always loved designing abstractions. It's not always the best use of my time, and it's not always the best thing for a codebase.
STEPHANIE: Ooh, okay, okay. This was a good transition. I hear you that, like, yeah, love-hate relationship. It's hard. That's kind of where I've ended up. It's really hard. And I think it's because it requires that creative thinking.
JOËL: It requires that creative thinking. And then also, like, it requires you to sort of see more broadly, a more broad picture. What are the things that are connected, the things that are disconnected, even though they seem related? And, like, being able to sort of slice those similarities from each other.
STEPHANIE: Yeah. I agree. And the interesting part is that, like, a lot of the time you just don't know yet. And you kind of have to come back to reality and admit that you don't know yet, you know, got to come back to earth, take a look around, and, yeah, you can go through the thought exercise of thinking [laughs] about all of the possibilities, and I imagine you could do that forever [laughs].
JOËL: I mean, that's why we have heuristics like the rule of three that says, "Don't abstract something out or attempt to DRY code until you've seen three use cases of it." So, maybe leave a little bit of duplication or a little bit of maybe not perfectly factored code until you have a couple of more examples. And the sort of real picture starts emerging a little bit more.
STEPHANIE: So, I think we are kind of at this topic already, but was there a moment or was there something that kind of helped you realize, like, oh, I can't be in that space of imagining abstractions [laughs] forever when I have to deliver software? Like, what changed for you to be the, as you said yourself, recovering idealist and having to maybe employ some more pragmatic heuristics?
JOËL: And I think, for me, it's partly being a consultant and being in a lot of projects and having that pressure to work with deadlines and sort of not having an infinite canvas to paint with, having to sort of fit some of my grand ideas into the reality of, we've got a week or two weeks to get this thing done, and also working with a team, and some ideas don't work well with every team. Every team is kind of at a different place.
And abstractions sort of only serve you as well as they are useful to not only you but the team at large. So, if a team is not comfortable with a set of abstractions, or it's sort of, like, too far down a path, then that can be really challenging. And that's where something like the dry-rb set of gems, which has some really fun abstractions like a mental model for doing things, depending on the team, that can be a really heavy lift. And so, as much as I like those patterns, I might think long and hard before I try to push this on a whole team.
STEPHANIE: Yeah, I kind of had to navigate a situation like that recently, where I was doing a code review, and I had left some suggestions about refactoring to encapsulate some responsibilities better. And then, I was like, oh, and then I noticed another thing that we could do to make that easier. And it, you know, definitely can start to spiral. And the author, you know, kind of responded to me and said, "Hey, like, I really appreciate these comments, but we are a bit tight on deadline for this project. So, is it okay if I, like, revisit this when we've delivered it?"
And, you know, I was just like, "Yeah, it's totally up to you." At the end of the day, I want whoever's authoring this code to have, like, full agency about how they want to move forward. And it was really helpful for me to get that context of, like, oh, they're a bit tight on the deadline because then I can start to meet them where they're at. And maybe I can give some suggestions for moving towards that ideal state, but ones that are lower left, and that is still better than nothing.
JOËL: That sounds awfully pragmatic.
STEPHANIE: [laughs]
JOËL: Moving in a positive direction, we're getting halfway. It's better than nothing. That's very pragmatic.
STEPHANIE: Hmm. Wow. But it's pragmatically moving towards idealism.
JOËL: [laughs]
STEPHANIE: If that is even possible [laughs].
JOËL: Uh-huh.
STEPHANIE: That's maybe the book that I'm going to write, not The Pragmatic Programmer, but The Pragmatically Idealistic Programmer [laughs].
JOËL: The Pragmatic Idealist.
STEPHANIE: Ooh, yeah, I like that. Okay. Watch out for that book coming 2030 [laughter], written by me and Joël.
JOËL: So, I think you brought up a really interesting point, which is the idea of pragmatism versus idealism when it comes to code review. Do you find that you think about these ideas differently when reviewing somebody else's code versus when you write your own?
STEPHANIE: Oooh, yeah. I'm not sure exactly why, but definitely, when I'm reviewing someone else's code, I'm already in the headspace of, you know, I have some separation, right? Like, I'm not in the mode of thinking very hard [laughs] about what I'm creating. I'm just, like, in the editing kind of phase. And then, I can actually pull more from different theories and ideas, and I find that actually quite easier. When I'm writing my own code, it's just whatever comes out, right? And then, hopefully, I have the time to revisit it and give it a scan, and then start to integrate the, like, idealistic theories and the patterns that I would like to be using.
But it definitely...for patterns that I feel a lot more confident about or more familiar with, they just come out mostly kind of oriented in that way if I have the time, or sometimes I will make the time, you know. I'll just say, "It's not done yet," because I know it can be better. I think that could be another, like, pragmatically idealist way of handling that.
JOËL: [laughs]
STEPHANIE: Right? It's just telling people, "I'm not done." [laughs] It's not done until I do at least give it an attempt.
JOËL: So, it's kind of a two-phase thing when you're writing your own code, whereas it's only a single phase when you're reviewing somebody else's.
STEPHANIE: Yeah. Yeah. But, like I said earlier, it's like, I also really believe that I don't want to impose any of my ideas [laughs] onto others. I really believe that people have to arrive at it on their own. So, it used to bother me a little bit more when I was just like, oh, but this way is better [laughs]. When people wouldn't get on board, I would be sad about it. But as long as I know that I, like, left that comment, then I can give myself a pat on the back for trying to move towards that ideal state. What about you [laughs]?
JOËL: I think this is probably also where I'm, like, now a recovering idealist. There was a time where I would leave a ton of comments on someone's PR. I almost had a view of like, how can I help you get your PR to be the best it can possibly be? And sometimes, if you start with something that's very rough around the edges, you're leaving a lot of comments. And I've been that guy who's left 50 comments on a PR. In retrospect, I think that was not being a good teammate.
STEPHANIE: Hmm.
JOËL: So, I think maybe my mental model or my, like, goal for PR review has changed a little bit. It's less about how can I help you make your code the best it can possibly be? And a how can I help you get your code to mergeable? And it's possible that mergeable means best that it can possibly be, but that's usually not the case. So, I'm going to give you some feedback: some things that confuse me, maybe raise one or two patterns that are existing in the app that maybe you weren't aware of that you should maybe consider applying. Maybe I'll raise a couple of ideas that are new, but that apply here.
And those might just be a, "Hey, let's just think about this. Maybe we don't want to do this in this PR, but maybe we want to look at them at some point. Or we should be thinking about this in a sort of rule of three situation. If we see this come up another time, maybe consider introducing a strategy pattern here, or maybe consider making this a value object, or separating these side effects from these pure behavior." But it's more of a dialogue about how can I help you get your PR to the point where it is mergeable?
STEPHANIE: Yeah. Another thing I thought about just now is both are meaningful or, like, both can provide meaning in different ways, and people ascribe different amounts of meaning to both; where I had worked with someone, a client developer before, who was not super interested in doing any kind of refactoring or, like, any, you know, second passes for quality. Because, for him, like, he just wanted to ship, right? That was where he found meaning in his work.
Whereas that actually made my work feel a lot more meaningless [chuckles] because I'm like, well, if we're just kind of hands on a keyboard, like robots shipping code, I don't know, that doesn't feel particularly motivating for me. You know, I do want to employ some of that craft a little bit more.
JOËL: And, I guess, yeah, idealism versus pragmatism is also...it's a personal individual thing. There's an element where it's a team decision, or at least a sense of, like, how much quality do we need at this point in the life cycle of the project? And what are the areas where we particularly want to emphasize quality? What are our quality standards? And that's, to a certain extent, consensus among the team that it's individual members. And it's also coming from team leadership.
STEPHANIE: Yeah. Yeah, exactly. I mentioned that, you know, just to, I think, shed a little bit of light that it's usually not personal, right [laughs]? There's that part of understanding that is really important to, yeah, like, keep building this shared world of writing software, and, hopefully, it should be meaningful for all of us.
JOËL: I think a few takeaways that I have would be, one, the value of, like, theory and idealism. These things help you to become a better developer. They help you to spot patterns. It's probably good to sort of have in the background always be learning some new thing, whether that's learning a new set of patterns, or learning some mental models, thinking about, oh, the difference between side effects and pure code, learning about particular ways of structuring code. These are all things that are good to have in your back pocket to be able to apply to the code that you're doing, even if it's a sort of after-the-fact, hey, I've done a similar task three different times. Is there a broader principle?
But then, also, take the time to really make sure that you're focusing on shipping code, and maybe that's learning to work in smaller chunks, working iteratively, learning to scope your work well. Because, in the end, delivering value is a thing that is something that we could all probably benefit from doing more of.
And then, finally, taking some time to self-reflect, a little bit of self-awareness in this area. What are the aspects of pragmatism and idealism that you find personally meaningful? What are the elements that you think bring value to your work, to your team? And let that sort of guide you on your next code writing or PR review.
STEPHANIE: On that note, shall we wrap up?
JOËL: Let's wrap up.
STEPHANIE: Show notes for this episode can be found at bikeshed.fm.
JOËL: This show has been produced and edited by Mandy Moore.
STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter.
STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email.
JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week.
ALL: Byeeeeeeee!!!!!!
AD:
Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us.
More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
439 episodes
All episodes
×Welcome to Player FM!
Player FM is scanning the web for high-quality podcasts for you to enjoy right now. It's the best podcast app and works on Android, iPhone, and the web. Signup to sync subscriptions across devices.