Software is never done — but that doesn’t mean you need to be stressed about constantly reworking it. The codebase architecture choices you make at the outset can set you up better for the future. This week, Chris and Gina share their tips on building for the future, from reusing code wherever possible to deciding what kind of technical debt you’re willing to take on to addressing accessibility concerns first instead of last.
Gina Trapani How do you do that? [Laughs.]
Chris LoSacco Oh my God.
GT Sorry. Put you on the spot.
[Intro music fades in, ramps up, plays 10 seconds.]
GT Hey Chris.
CL Hi Gina.
GT How are you doing today?
CL I’m doing great. How are you?
GT I’m doing alright. I’m doing alright. Have you ever had somebody ask you the classic question? The where do you see yourself in five years question.
CL Oof, where do I see myself in five months? [Gina laughs.] Like one step at a time, please.
GT Yes. Seriously. Don’t you just want to kick those people in the teeth? It’s true.
GT You and I are very similar in that. We’re like pretty—well, I think we’re similar. So I’m a pretty on-the-ground person. Like I could tell you what my to-dos are, what my meetings are for today. I know what I’m doing today. I know what I’m doing this week. I even maybe know what I’m doing for the next couple of weeks, but like, once you get into the months and year zone, hey, anything, anything can happen.
CL Anything can—I mean all bets are off.
GT All bets are off.
CL It gets very hazy as you look out into the distance.
GT Exactly. Exactly. But I’ve been thinking about this because one of the things that we ask our product managers to do in particular is to build a thing, like do a thing, right? And there’s a date, right? There’s a deadline and we have to deliver a thing. This is how we structure all our engagements with our clients.
CL Yep. Mhm.
GT We say, we’re going to deliver this thing and it’s going to be on this date. So everyone is super focused on the date and getting all the things done by the date. But the thing that we ask them to do in this process is to also think about like, what’s going to happen beyond the date, which is really hard.
GT It’s really hard to be in the weeds of delivering a thing by a date, but also thinking about what could be in the future. But you kind of have to do this with software, right?
CL Yeah. I mean this is the thing. Software is never done. It is both the most beautiful thing and the most frustrating thing about working on a software project. Because if you’re—if you’re like building a building or building a house, you build the house and then you’re done and you might add an addition or you might improve it in the future, but you’re done. You move into the house, you start living in the house. Like there is a very finite, you know, once you hit that deadline, you’re good to go. Software is different. It is, you know, you haven’t poured a concrete foundation. You haven’t, you know, erected the steel walls. It is by its nature—you are expected to continue to build it, to evolve it, to optimize it, to shore it up. There will always be a next phase when you’re working on a software project. You know?
GT Yes. Right. You don’t have that complete blueprint. This is where every single beam and wall is gonna go.
GT We say, okay, we’re going to build, you know, if you’re starting from scratch from nothing, we’re going to work our way to an MVP, minimum vial product. Just do the bare minimum. But if it’s good software and people like it and they want to continue to invest in it, right, which is the hope and you’re building for success, there’s going to be all these other releases, you know, V1, V2. There are certain product people who I’ve worked with in my career, who I would describe as like, as product visionaries. Like they could look at a simple feature or a function and blow out in their minds what this could mean at scale and what other things this could do and how it could integrate with other things. They just see this huge, big picture. And it always blew my mind as an engineer because I was always like, I gotta ship this ticket. I’ve got this ticket in front of me and I gotta ship this ticket. You are one of these people that can do this. Like I’ve seen you look at software that we’ve been building. You’re able to think ahead and have that sort of big-picture view of what’s possible. What, how does that work?
CL I mean, I can’t boil it down into like a sentence or two. I think it’s partially experience. And it’s, you know, I think having vision is thinking about, you are thinking about those next few phases, right? Or what’s coming beyond and you start to play out. You have to make some educated guesses about what your user behaviors are going to be and how they might evolve and change over time. Given the new powers you’re putting into someone’s hands. I would also add, I mean, much in the same way that you can have a product thinker or a designer who’s two or three steps ahead, I think there are some really important engineering choices that get made early on that can set up a platform, especially a new platform, for future growth and making the inevitable change and optimization that’s going to come a lot less painful rather than having to rework a bunch of ground that you already covered. You can do things in the beginning. And I’ve seen you do this firsthand as an engineering leader, is think about, okay, how do we make smart, pragmatic, future-looking choices that are not prematurely optimized, but are well set up for the future. And I’m curious, are there some of those things that we can share today as we think about like, okay, if I’m embarking on a new software effort, what are the choices that I make now that are going to put me in a much better position for 2.0?
GT Yeah, definitely. We should talk about those things. It’s funny because there’s a tension, right, because as engineers, you’re constantly told don’t prematurely optimize, don’t invest too much to build for traffic or users or problems that we’re never going to have. Like, let’s focus on getting it out the door. But I’ve also just, I’ve worked on projects, this has happened to me too many times in my career where you’re just trying to get something out the door, you don’t cut corners, but you’re not thinking about optimizing. Right? And then you go live and it’s a successful launch and a bunch of people hit it at the same time. I’ve seen this play out so many times and it’s slow or non-responsive, or the page doesn’t load, or it’s just slow. Right? Cause you didn’t plan for it.
CL Oh, I’m sweating just thinking about it.
GT Right? You’re sweating just thinking about it. Because you know that that person, that owner, that business owner, that stakeholder, that product person is like, this is—first impressions only happen once. Right? And we messed up, like, this is a bad experience because we didn’t think ahead and make this work for the success case. Right? So there’s this balance between don’t prematurely optimize, but be ready for success. And success is going to mean scale and change and needing to respond to bug reports fairly quickly. Like evolution pretty quickly. I think it’s really hard to be in these two mindsets: the mindset of like, I’ve got to deliver by my date, but also I have to make sure that I’m going to be ready for whatever that next next phase is. And I think there’s product thinking involved. I think that engineers sometimes get far in their own heads and think I want to optimize these things because they’re the best practice and the right way to do it versus like, this is what the future of this product or this product demands. And I think also you can spend too much time getting ready for, you know—you can miss your dates by focusing too much on getting everything perfectly. Right? So it’s a balance.
CL Totally. It is a balance. I wonder though, are there things that don’t cost too much upfront that you can start to do early on? So here’s an example that comes to my mind. We do a lot of work with AWS, Amazon web services and one of the things that’s great about AWS, and I know that some of the other, I mean, many of the other cloud providers have this, is it functions as a service as opposed to a monolithic backend. Right? So instead of writing a complete web server with a set of resources that you can call with HDP, you write modular functions that just do one specific thing, and then you can deploy them as standalone items. And the sort of beauty in that is that those functions, if you write them in an atomic encapsulated way, they can scale much easier and handle burst traffic much easier than if you have a monolith that you have to figure out how to separate and scale. And if you think about that from the beginning, you’re not really paying that much of a tax upfront. Right? But you are reaping the rewards on the other side. So I mean, to the point you made before so well: if you do have the success case, where you do get a lot of users very quickly, your platform has small bits that can ramp up very aggressively versus having to do a bunch of rework. So that’s one thing that comes to mind. I know there are a bunch of others.
GT Definitely. I mean, Amazon built their entire infrastructure so they could handle orders on Black Friday. Right? Like they built a burstable infrastructure that they made available to everyone. So picking serverless or functions as a service knowing that, and you’re only going to pay for as much as you use, but if you have that wonderful success case, which everyone hopes for, it’ll work.
CL Yeah. What about how you architect your code base? I mean, we mentioned separating services. Are there other things that you’ve seen, especially if you go back to your days as a lead engineer, where you feel like good architecture choices set you up better for the future?
GT Definitely. I mean, I think there are times when it’s right to focus on reusing code wherever possible. So a good example is if someone wants to build a mobile app—they’re building a new mobile app, they want to release on iOS and they want to fast follow with Android. Right? It’s a good idea to look at a technology like React Native, which is the same code that can run on both platforms. Because you can just double the impact of your engineering time and you’re not maintaining two separate code bases in two different languages. You’ve got one reusable code base. The opposite example is sometimes it makes sense to decouple parts of your architecture. So like your classic backend, which provides an API, which is one bit of the architecture, separated from your front end.
GT Which is just consuming the API. There’s a lot of advantages to separating those pieces of your architecture, right? Because you can have different engineers working on them at the same time with a contract defined about what the front end is going to expect from the back end. And you can parallelize a lot of that work and it’s very clean because you can troubleshoot and optimize each separately. So it’s really kind of a matter of knowing what’s best and knowing when to reuse versus when to separate and abstract things away. I’ve seen engineers over-abstract to the point where it was so complex that new engineers were like, I have no idea what’s going on here. So we’re just going to start over [laughs]. And then I’ve seen just this big monolith code base, which you had to just wade through thousands and thousands of files to understand what was going on. Instead of having the nicely defined contract API.
CL I mean, it’s such a good point. It’s often a judgment call. We worked on a project a few years ago with a client who shall remain nameless. And when we came into the client, they had defined a UI kit, a set of UI components that they intended to be used in their publishing platform, their front end and their CMS. But the reality was the current implementation of their system did not use these components. And they had made this UI layer in anticipation of rewriting parts of this code base, but it was the wrong order. Because they assumed that they knew exactly what they were going to need. And then when we actually got to building the interfaces, there was a mismatch between what was in the UI library and what was in the actual platform. What would’ve been, I think, a far better approach is to say, okay, we’re going to break ground to come back to the term you referenced before MVP, minimum viable product. We know we want to make the next version of this CMS. We’re going to break ground on that. And then once we have a really good outline of what the bones of this platform are, then we can start to abstract a UI layer, because then it’s the best of both worlds. You get speed of development upfront, but then you can leverage the reuse of these components. But once they’re well-defined. Because if you start with the building blocks and you don’t know what you’re building, you may build the wrong blocks. You know what I mean?
GT Yeah. It’s so true. I mean it’s funny, like, reusable components, like building the blocks versus the building—you’re right. Like the block should be driven by [laughs] what the building needs to be. Right? So it’s, it’s funny. It’s like, what should come first? I mean, classic design, you just design the entire screen. But in a design system situation, you’re designing those components. I think those things have tosort of feed one another. Right?
GT The system has to constantly get updated by the realities of what actually exists on the platform. But I think it’s worth investing in the system and updating the system and making it a system so that you can hand it to an engineer and you can quickly prototype new screens with your regular UI interface components, buttons, and fields, and add to cart, whatever it is, without having to bring in a designer and do a fresh new custom design every time. Because that’s how you wind up with platforms that have screens that look like they’re supposed to look like one another, but are a little bit off, you know?
CL Right, right.
GT You can tell like, oh, they redesigned this page recently, but this one not so recently.
CL [Laughs.] Yep, yep, yep. Or they pulled in this other open source, front-end library over here. And it doesn’t really fit with the rest of the system.
GT Yes, yes.
CL Yeah. I agree with you. That consistency is really important and the ability to not only speed up the development process, but in some cases allow non-developers and non-engineers to start putting things together. I mean, it’s a beautiful thing when the CMS itself can allow you to construct pages on the fly. because you’ve got a well-defined system of components of page components.
GT That’s right. And it frees up designers to think about the interesting problems, not the login button, you know, which every app has. Like they could think about the true, unique value that the platform is driving. Like the more interesting problems.
GT The other thing that I think is important from an engineering standpoint, and you said using an open-source library, which reminded me—I think it’s really important to use off-the-shelf and open-source components, proven ones, ones that are stable and proven. Not like bleeding edge stuff, not alpha beta stuff, but proven components. But take that stuff off the shelf and not build it from scratch. We spoke to a prospect who shall remain nameless recently and they were telling us about their e-commerce platform and how their engineering team just really wanted the whole entire experience to be bespoke. They wanted it to be exactly what they wanted it to be. So they built the entire e-commerce experience from scratch. And at first I was like, wow, that’s commitment. Wow. But it turns out it’s a couple of years later and they spend all their time updating the e-commerce system [laughs]. And there are people who can’t add new skews to the store—it involves a developer to add a new product to the store. And they were like, we just should have used Shopify or like an off the shelf e-commerce app, like Stripe. Then we could’ve focused on the other parts of the experience, which are more interesting to our customers. And I was like, oh yeah. I completely see how that happened. Right? There was something really attractive to me as an engineer. I was like, yeah, let’s innovate e-commerce let’s do that. Let’s do something new. And then it’s like, oh, but now we’re maintaining a shopping cart and credit card processing. Why?
CL That’s the thing. That is such a good instructive example of how getting in the business of the things where you want to have a differentiated offering and things where it’s going to be much more pain than profit. And that’s a prime example I think for that company. Building and maintaining a checkout experience was not a differentiator for them. And so they shouldn’t have done it.
GT Right. And then it’s like people get attached to this particular code base and they’re like, I’m an expert here. And there’s some cost fallacy of like, we put all this in here, we should be committed to it. And it’s like, oh no, it’s okay.
CL Yeah. I’ll give you another example that this is bringing to mind: rich text editing. I feel like it is a—every project that we have been involved with with a content management system, people are like: well, should we write our own rich text editor? Or should we go really minimal, really bare bones and get something that’s really close to the metal so that we have a ton of control over what that editing experience is? And 9 times out of 10, you’re going to want to leverage something that gets you most of the way there. Because we did it with parts of our MTA project because we wanted the subway bullets to appear in the compose experience. And it took a minute to get that right and get that feeling natural.
GT That’s right.
CL But in that example, that was core to the experience that we wanted to build. So it was worth it for us, but you have to constantly be asking yourself from the very beginning of the project, am I creating a maintenance burden that I’m going to have to think about for the second release, the third release and forever more, where if we can pull something off the shelf and not reinvent the wheel and get a huge head start, plus we’re relying on maintenance from the third party. If it’s an actively maintained library or offering or service, it just gets you a lot of the way there for what is very often a pretty minimal cost.
GT Yeah. It’s true. It’s true. I mean, you know, it brings with it—you are relying on a third party, if it’s open source, you can make changes and contribute them back. And it’s a virtuous cycle.
CL We’ve done that.
GT Yeah. We have done that. But there are some trade offs there, but the head start and there’s that burst of energy where you’re like, I really want to build this bespoke thing. And then at a certain point you’re like, I just don’t want to update this tech editor anymore, or this e-commerce—[laughs].
CL Something else that we’ve seen that you kind of alluded to with that checkout experience—we’ve seen clients who come to us, who had a very passionate team who built a really involved custom thing. And then they leave the company and now you’ve got to figure out how to go in. And it’s like, well, that was really Jim’s baby.
GT That was really Jim’s baby, yeah. [Laughs.]
CL He’s the only one who knows how to go in there and it’s just a world of hurt when you think about, okay, now I’ve gotta evolve this platform that is constantly evolving. The specialized stuff you should really invest in and make sure that it’s well-documented and clear and can evolve really seamlessly and naturally, and then the non-specialized stuff, you should figure out how to get it off the shelf if you can. Not just because it’ll give you a better head start, although it probably will, but because it makes your life a whole heck of a lot easier in the future.
GT Yep. I think another important thing about being sort of ready for the next phase, being future-facing about your platform is being really choosy about what kind of debt you’re willing to take on, whether that’s tech debt or design debt, right? When you’re under the pressure of a deadline, you have—things have to get cut, right? And there’s a list of choices of things you can cut. And there are times when you can make—we’re going to cut this corner, we’re going to do this not exactly the way we want to do it, but we’re going to do it just to get to launch. But there are certain kinds of technical and design debt that I think you shouldn’t wait on.
CL Like what?
GT Well, one that we talk about a lot at Postlight, our design team is especially passionate about this, is thinking about accessibility from the beginning and not afterward. You don’t want to learn on launch day that a large percentage of your users are colorblind, for example. And can’t tell the difference between these two colors or that most of your users are using one hand, holding onto the bar in the subway on their commute and not going to be able to get certain things done in your app. It’s very expensive to learn after the fact that your app isn’t accessible, and to go back and fix it than it is to kind of start off with accessibility concerns top of mind. I’ve seen similar things with SEO. Like we launched the website! Why can’t Google—oh. Because we didn’t think about it at all [laughs] like how it would show up. And even just like the performance example that I brought up earlier, like launch happens, there’s a big surge and the platform doesn’t stand up cause you just weren’t thinking about that success state of thousands of people hitting at the same time. So there are some corners that you have to cut, but there’s some debt that if you take it on, you’re really going to pay for it later. It just is gonna make V1 V2 that much slower, cause you’re going to have to pay down the debt first before you can get out the features and fixes that you’ve learned from the users who actually use the thing once it’s live.
CL Exactly. I have two more in this vein that I would add to the list: localization.
GT Oh, that’s a big one.
CL If you have to go back and retrofit and find all the strings that are in your code base and swap them out for grabbing from a file of localized text, it’s so much work and it’s annoying work. Where you’re like, oh, I’ve got to just command F everywhere in this project. It’s so frustrating versus if you know ahead of time that your app is going to be available in multiple languages, especially if they’re all left to right. It’s pretty easy to just put a call for a string instead of the string itself. So that’s a clear one. And the other one I would say is: navigation. This one is maybe a little more subtle, but oftentimes people will take on debt in how to get around the app because they are only thinking about what’s available right now at launch. And then the minute they introduce a new thing, they’ve got to rethink the navigation.
CL And the reason why it’s so painful, it’s not so much on the design and engineering side, although it is painful on the design and engineering side, but it’s a real pain for your users. And you’re passing off a real tax on them. And I personally hate this [laughs] as a user of many software applications when the core nav, the way that I get it—
GT Changes. Insulting. Yeah. It’s like you’re killing me here. [Laughs.]
CL Because you added a reporting section that wasn’t there before and now I have a hamburger menu instead of a top nav, like what’s going on here? So having a little bit, and you don’t have to think about like, oh, what are all the sections that we could possibly have in the next three years? It doesn’t need to be that broad. It just needs to be, what is the adjacent possible? What are the things that might come down the line and how do we make sure that we’ve got a logical home for them, even if we don’t know exactly what they are. And this is something that I’ve seen our design team do firsthand where they say, let’s make sure that we are thinking about an extensible navigation structure. It doesn’t have to cover every single case, but it goes a little bit beyond what’s in our MVP or what’s in our 1.0, so that we’re not boxing ourselves into a corner when we think about the future.
GT Yeah. It’s kind of going back to making it modular, like we can add more blocks here and here’s how they would look.
GT Some of this is hard to, you know, the modular piece, the reasonable component, some of this is hard to do. I mean, when you’re presenting to your stakeholders too, they want to see what the thing’s going to be. You have to balance how you communicate the value of these things, right?
CL That’s right.
GT One of our directors of product design, Kirsten Sorton, she wrote this great piece at the insight section of our website about user testing and the myths around user testing and how a lot of product folks or business owners will say, I know exactly what I want. Just please just build me this. And she’s making the case that it makes sense to invest in that ahead of time, because you probably don’t know what you want, or you’re going to learn something from your users that you didn’t know, or you think that all your stakeholders have the same vision, but you all aren’t reading each other’s minds. And it’s one of those things where I think another example of a way to be future-ready. You can learn what your users want before there’s a line of code written and after the whole thing is built and it’s out in the world.
GT Because it’s so much more expensive to change things then than it is to like, have some conversations and do actual user testing like at the get go. But I think for someone who’s excited to build software, they’re like, I don’t want to waste time talking to people about what I want to build. I’m excited. I want my thing, let’s start building the thing. Right?
CL Right. It’s easy to overlook how valuable that could actually be if you just put in not a ton of effort. You don’t have to invest in a two month research phase while you’re building that MVP. But a little bit of thought, a little bit of conversation early on, can be so, so valuable down the road.
GT Yep. Have you ever been in a position where you’re like, we have all this debt to pay down because we didn’t do this prep beforehand. [Laughs.]
CL Oh, of course.
GT And then you have to sort of represent the value of paying down debt, which is invisible kind of on the front end. When you’re a couple of releases in, part of this is like, it’s difficult to show the value of this upfront work cause a lot of it feels invisible, but you reap the rewards of it after when your velocity, when you’re release velocity is so much better. . And you’re responding to user needs so much faster. Like that’s actually what you’re buying by doing some of this prep work upfront and it’s always a balance, right?
CL Yeah. That’s beautifully said though. I mean, it’s easy—it’s harder to see the value when you’re not confronted with the three-month project where the goal line is nothing should be different. [Laughs.]
GT [Laughs.] Right.
CL Wow, we’re going to invest three months and we’ll know if we’re successful if you don’t know anything has happened. But sometimes you get in that situation and if you can avoid it upfront and save that future effort, that future value, that your team is going to spend, you’re so much better off. It’s just hard to see it sometimes in the beginning.
[Outro music fades in, ramps up.]
GT It’s true. We need easier ways, we being people who make products, we need ways to explain these things, to be like, it’s worth the investment for these reasons. And everything’s a trade off, you know?
CL Everything’s a trade off. That’s right. Well, if you’re listening to this and thinking I’m about to embark on a software effort and I would love to make sure I put myself in a good position for phase two, we’d love to talk to you.
GT Excellent segue.
CL Thank you. We are a full-service, digital strategy, design and engineering firm with a great product focus and we’d love to help you ship your thing. We really pride ourselves on putting real working software in the hands of users. And if you’ve got a project that you are trying to tackle or a thing that you’re thinking about kicking off, reach out: firstname.lastname@example.org. We’d love to talk to you.
GT We would. Thanks Chris.
CL Thanks Gina. This was fun.
GT Let’s get back to work.