https://adamzerner.bearblog.devAdam Zerner2024-03-19T09:40:48.168390+00:00adamzernerhiddenpython-feedgenHi, I'm Adam
I'm a software developer and entrepreneur
I live in Portland, Oregon.
Email | LinkedIn | GitHub | StackOverflow | LessWrong | IndieHackers | Goo...https://adamzerner.bearblog.dev/pursuing-the-right-tech-stack-for-me/Pursuing the right tech stack for me2022-11-26T01:50:20.288173+00:00adamzernerhidden<p><em>Meta: This post is journal entry-like. It's not well thought out, researched or refined.</em></p>
<p>I'm a programmer and I like to work on my own projects. Sometimes for fun, sometimes for profit, sometimes for something in between. So then, I need a tech stack.</p>
<p>Yes, the most appropriate tech stack will depend on the app — SSG would probably be appropriate for a blog or marketing site whereas a SPA would probably be appropriate for a heavily interactive and dynamic app like website — but I think that there is also something to be said for sensible defaults. I think a lot of apps actually have pretty similar needs. At least the ones I would pursue. This makes me think that coming up with a sort of default tech stack would be a worthwhile pursuit.<sup class="footnote-ref" id="fnref-1"><a href="#fn-1">1</a></sup> I could always tweak it for the project at hand.</p>
<h2 id="programming-language">Programming language</h2>
<p>Let's try to start with shorter, quicker discussions and save the longer discussions for later in the post.</p>
<p>This will be a quick one here. I want to use JavaScript.</p>
<ul>
<li>I like to program in a functional style. <a href="https://adamzerner.bearblog.dev/classes-often-arent-the-simplest-tool-for-the-job/">Classes make me gag</a>. Especially when they're written with <a href="https://www.youtube.com/watch?v=m4-HM_sCvtQ">Java</a>.</li>
<li>You have to use JavaScript on the client, and I like not having to context-switch and use a different programming language on the server.</li>
<li>It's what I'm good at. After turning 30 recently, I am officially an old man who is set in his ways. In my 20s I spent some time messing around with Clojure and Haskell, but they're not quite for me. At least not at this point in my life. Hopefully later in life I'll dive into them more deeply.</li>
</ul>
<p>Err, actually I should have said TypeScript, not JavaScript. That's what the cool kids are using now, right?</p>
<p>In all seriousness, I do like the autocomplete and being able to hover over some code in my text editor and see it's shape. In opening up an old JavaScript project I hadn't touched in some time, I found myself having to <code>console.log</code> everywhere to see the shape of my data. Yuck. I'd much rather hover over stuff.</p>
<p>I guess there's also the benefit of catching bugs earlier. From what I gather, that's the main selling point of type-safe code. I guess that's helpful. Personally, thinking about the time I've spent coding in JavaScript vs the time I've spent coding in TypeScript, I don't really feel like it's something that helps me all that much. I wonder how common that is. I wonder if it is helping me a lot and it's just hard to notice.</p>
<p>One thing I will say is that I think it makes sense to be pragmatic with TypeScript. There are tradeoffs at place with respect to how hard you push the type safety thing.</p>
<p>As an example, think about numbers. You could say that something is a number. But you could also get more specific and say that it is rational number, or an integer, or a positive integer, or a positive even integer, or a positive even integer between 20 and 86. You see? You can get stricter and stricter and stricter. Well, in TypeScript I'm not really aware of a way to do that but I know in Haskell there are a million different ways to get more specific about the type of a number.</p>
<p>Anyway, the point is that there is trade off with types. It is more effort and complexity to get stricter. My opinion is that you should be pragmatic, think about the tradeoffs, and do what makes the most sense. Which implies that <code>any</code> or <code>@ts-expect-error</code> is sometimes the way forward. That might seem obvious, but other people say to make your types as specific as possible. Smart people who I respect. I disagree, but reserve the right to change my mind as I get more experience.</p>
<h2 id="ui-framework">UI framework</h2>
<p>Earlier this afternoon I was reading <a href="https://www.smashingmagazine.com/2022/05/you-dont-need-ui-framework/">You Don’t Need A UI Framework</a>. Um, yes I do.</p>
<p>Something like Bootstrap. Except not Bootstrap.</p>
<p>I have this "signals of seriousness" theory. Imagine that there's a website that sells widgets. It might be an awesome place to buy widgets, but when it is your first time on the site, how do you know that? Think: first impressions. It takes time to research and investigate to see how good a product actually is, so instead users rely a lot on snap judgements and heuristics. If the site is kinda ugly and obviously not designed by an actual designer, you assume that it's not "serious", and not a good place to buy widgets. A site built with Bootstrap is a pretty good indicator of that. So for my projects, I'd really like something that is a step up.</p>
<p>And I'm willing to pay for it too. A good amount of money. Thousands of dollars. If a UI framework helped me design sites that are a step up, that's worth a lot to me. However, I actually have had a really hard time finding a good one.</p>
<p>There's a lot of random paid ones that just don't look very good. <a href="https://tailwindui.com/">Tailwind UI</a> is the first one I came across that I thought looked really good. I actually bought it, but subsequently asked for a refund. I realized that they don't really give you pre-built components. Take a look at <a href="https://tailwindui.com/components/application-ui/application-shells/stacked">this</a>. You have to kinda dig through their code and create components yourself. I don't want to do all of that. I want to have pre-built components.</p>
<p>I gave up looking after that. Then months later I picked back up. Again I wasn't having success, but eventually I came across <a href="https://chakra-ui.com/">Chakra UI</a> and fell in love. It's exactly what I'm looking for. Pretty much. There's tons of components. It looks great. It's not (too) generic looking. The documentation is great. There's an active team and community behind it. So yeah, I think Chakra is the winner. For my projects, I want to use Chakra.</p>
<h2 id="database-orm">Database + ORM</h2>
<p>This is a topic that is a weak point of mine, but I'll give it a stab.</p>
<p>One question is whether to use a relational or document database.<sup class="footnote-ref" id="fnref-2"><a href="#fn-2">2</a></sup></p>
<ul>
<li>Document databases talk about how they're easy to scale because they can scale horizontally whereas relational databases can't, at least not easily. I'm not worried about this though. My memory from reading various blog posts and stuff on HN is that vertical scaling can actually take you quite, quite far.</li>
<li>Another selling point to document databases is that, being JSON-like, it maps more closely to your application code. That makes a lot of sense to me and is what got me into document databases initially, but to my surprise I actually haven't found this to be much of a help in practice.</li>
<li>Similarly, I haven't found the schema flexibility to be much of a help in practice either. I'm a big fan of optimizing for making fast iteration easy, so you'd think that schema flexibility would be an important thing, but for whatever reason I haven't found it to be.</li>
<li>I've seen people warn against document databases. That they work great until they don't sort of a thing. I don't totally grok this, but it seems plausible, especially given how battle-tested relational databases are.</li>
<li>Relational databases seem like they do a little bit of a better job in terms of data accuracy and reliability. This doesn't feel like too big a deal though. I'd assume that for document databases if you use a big name provider like MongoDB you wouldn't have many reliability problems at all.</li>
</ul>
<p>All things considered, I don't feel strongly, but relational seems like the way to go. And Postgres seems like a good choice for a relational database.</p>
<p>That brings us to the question of ORMs. For that, I am quite happy with <a href="https://www.prisma.io/">Prisma</a>. I've found it to be pretty easy to use, but what I'm most impressed with is the documentation. Wow. Incredible. Some of the best I've ever seen. That makes me really happy, and gives me trust that developer experience will in general be pretty good.</p>
<p>I have heard that the SQL it generates could be problematic at times, but I think that's only in pretty complicated situations, and if you run into it you could always just write raw SQL yourself, so I don't see it as a concern.</p>
<p>I will say, my one gripe with Prisma is that there isn't an equivalent of <code>rails console</code> that you get with Active Record. I used to love being able to type <code>rails console</code> and mess around, especially in sandbox mode.</p>
<p>Oh, there's also the question of GraphQL. I used it for a few months at one job and didn't particularly like it. I found it a little overly complicated and difficult to work with. I like just sending an HTTP request to whatever RESTful endpoint.</p>
<h2 id="rapid-fire">Rapid fire</h2>
<p>There's a bunch of things that don't require much discussion. Yes, this is a pretty broad interpretation of "tech stack".</p>
<h3 id="version-control">Version control</h3>
<p>Git. It's what I've always used and what most people use. Even if something else is better I don't expect it to make me notably more productive — the benefits are more likely to be marginal — so familiarity and popularity win out.</p>
<h3 id="repository-management">Repository management</h3>
<p>GitHub wins out over BitBucket and GitLab. At this point I've actually used all three in different jobs, and GitHub just feels like it provides the best UX. It used to not offer free private repos which was a problem, but now it does, so it's the winner.</p>
<h3 id="text-editor">Text editor</h3>
<p>VSCode. Seems like the best one if you're working in JavaScript. I used to use Atom but ran into issues with it being slow and with it being hard to get jump to definition stuff working.</p>
<h3 id="code-formatting">Code formatting</h3>
<p>Prettier. I love being able to just not think about it.</p>
<h3 id="end-to-end-testing">End-to-end testing</h3>
<p>Cypress. I'm a believer in using it sparingly because e2e tests are notoriously flaky, but Cypress is the best framework I've used. Previously I used Nightwatch.js and hated it.</p>
<h3 id="unit-testing">Unit testing</h3>
<p>Meh, I don't care. Jest, Testing Library, Mocha. They all feel like they're basically the same thing to me.</p>
<h3 id="analytics">Analytics</h3>
<p>Google Analytics is the most popular, but fuck that. I don't like the privacy issues. I don't like how it hurts page load times. I don't like how it forces you to have a cookies popup.</p>
<p>Then again, I don't feel like paying for analytics for a project that doesn't have at least a moderate amount of revenue yet. Which unfortunately is, err, every project I've ever pursued. I've searched for tools with a nice free tier but haven't been able to find any.</p>
<p>So I think my plan is to just forget about analytics early on — you could always look at your database for a more informal approach to analytics — and if my project has enough revenue I'd use <a href="https://plausible.io/">Plausible</a>. Plausible looks fantastic.</p>
<p>Oh, and they have a great blog post about how server-side analytics basically don't work because of bots. Good to know.</p>
<h3 id="payment-processing">Payment processing</h3>
<p>It's been some time since I've investigated this, and I think I'd just go with Stripe. They're the big player, and so presumably pretty reliable. Their docs are good. I like the founders. There's tons of tutorials.</p>
<p>OTOH, it feels a bit maximalist for my purposes. I just need something simple and minimal. In my experience using it you do have to sift through stuff that is excessive and/or not relevant to you in order to accomplish your task. If there was a more minimal tool that is also good and comparably priced, I'd be interested.</p>
<p>I have seen some concerning stories on HN about people getting screwed by Stripe unfairly and not being able to get in touch with customer support. Hopefully those are rare, but it's something to keep an eye out for.</p>
<h3 id="build-tool">Build tool</h3>
<p>Webpack is too slow. Cold starts are often 10+ seconds, and I start my dev server frequently. Maybe because I'm paranoid about HMR not actually working.</p>
<p>Vite is pretty awesome. I'm happy with Vite. Turbopack is intriguing. The idea that you don't even need a build tool in the first place with Deno is doubly intriguing.</p>
<h2 id="web-framework">Web framework</h2>
<p>Ah, finally, the meat of the post.</p>
<h3 id="client-vs-server-side-rendering">Client vs server side rendering</h3>
<p>When I was first learning to program, I did some server side rendering with both Cake PHP and Rails. Maybe the first year or so. Pretty soon after that I learned Angular. That lead to be building SPAs for the next nine years or so, in Angular, Backbone, Vue and React.</p>
<p>Then we started using Remix at work about three months ago. That (re)opened my eyes to server-side rendering. To my surprise, I really liked it!</p>
<p>For one, I was still able to use React to build views. I never liked templating engines like handlebars or ERB in Rails. OTOH, React components and JSX are both really nice IMO. I think I had previously been conflating that with liking SPAs. Previously, I had a preference for SPAs, and I think that preference was more about the view layer than actually rendering on the client.</p>
<p>Another thing I was surprised to love is doing the data fetching on the server. With SPAs you have to hit the API to request the data, and then use the response to build the page. With SSR, well, you still kinda have to do the same thing, but it happens on the server. Ie. client makes request to server, server hits database to load data, that data is used to construct the HTML, and the HTML is sent back to the client. It's not conceptually that different, but something about it is just much nicer IMO.</p>
<p>Maybe it's the separation of concerns? With JavaScript based SSR frameworks you usually fetch the data in a separate place from the React component. You can still do that in a traditional React SPA though, you just have to use smart components for the data fetching and dumb components for the presentation. That feels messy to me though, and leads to huge amounts of nested components which is a little ugly.</p>
<p>I also like the routing in server-side rendered apps. It's a little less work.</p>
<p>So yeah, I think I like SSR better. That said, I can still definitely see a use case for SPAs. I think they are a better choice for highly interactive and dynamic apps.</p>
<h3 id="performance-vs-simplicity">Performance vs simplicity</h3>
<p>For what follows, there's a lot of tradeoffs regarding performance vs simplicity. I have the feeling that frameworks are leaning too heavily towards performance. Some apps need the performance, but others don't. So I guess it's ok for a framework to optimizie for performance, but others should optimize for simplicity, and I think that is the part that is missing.</p>
<p>Maybe this is a good analogy. Let's say that a studio apartment is just a plain Apache server that serves HTML. A one bedroom apartment is a SSG. A two bedroom apartment is just a vanilla SSR framework that handles requests, hits a database, and returns HTML. Then 3+ bedroom houses start to incorporate features like filesystem based routing, partial hydration, client side navigation after the on subsequent navigations, deciding between SSG and SSR per route, etc.</p>
<p>I feel like I am looking for a two bedroom apartment, but there are non available in the market. It's all four and five bedroom houses that are listed. Ok, I guess there are some two bedroom apartments that are listed. I actually found <a href="https://github.com/saltyshiomix/react-ssr">one</a> and got really excited at first, but on closer inspection it was old and unmaintained and had various warts.</p>
<h3 id="ssg">SSG</h3>
<p>With SSR, the request comes in, the server parses it and generates HTML by running stuff through some sort of view layer or templating engine, and then sends that HTML back as the response. With SSG, the HTML is basically generated at build time instead of runtime. So when the request comes in, the HTML is already there. It doesn't need to get generated when the request comes in. So SSG saves you the time it takes to generate the HTML.</p>
<p>I don't really care though. I can't imagine this actually improves performance all that much, so I'd prefer if SSG just wasn't a feature that was offered in the first place.</p>
<h3 id="client-vs-server-side-navigation">Client vs server-side navigation</h3>
<p>I'm not sure if this is actually the right vocabulary or not, but let's distinguish between rendering and navigation. Rendering is the first time you visit the site and navigation is subsequently when you click a link. So like if you visit example.com for the first time, it is rendered, and then when you click "About" to navigate to example.com/about, it is a navigation.</p>
<p>Frameworks are moving towards server-side rendering with client-side navigation. So initial page load is server rendered (unlike SPAs) whereas subsequent navigations happen client-side.</p>
<p>I see the same tradeoff of performance vs simplicity. Client-side navigation helps with performance, but at the cost of simplicity. To me, I default to simplicity and put the burden of proof on performance to change my mind. Here, I don't feel like performance has made a strong enough argument. Sending a request to a server and getting back the full page in HTML is fine. It seems like it is fast enough for the great majority of situations, so it is my personal preference.</p>
<h3 id="partial-vs-full-hydration">Partial vs full hydration</h3>
<p>With server side rendering, the server responds with HTML. But what about interactivity? Event listeners and stuff? That's where hydration comes in. After the server responds with HTML, some JavaScript is then loaded that goes through the DOM and attaches event listeners and stuff. That might be a slightly inaccurate description, but I think it's sufficient for now.</p>
<p>You could traverse through the whole DOM to do hydration stuff, but frameworks like Astro and Fresh utilize the <a href="https://www.patterns.dev/posts/islands-architecture/">islands architecture</a> and say "Hey, we know that the navbar is the only interactive part of this web page, let's only traverse through that part of the DOM to do hydration stuff". So basically, it lets you avoid unneeded work.</p>
<p>But again, this doesn't come for free. It comes at the expense of complexity. And to me, the performance gains are much too small to justify the added complexity. Few sites need that level of performance.</p>
<h3 id="filesystem-based-routing">Filesystem based routing</h3>
<p>This I don't see as a performance vs simplicity thing actually. I guess it's more of a personal preference. My personal preference is to not have filesystem based routing, although it's not a strong one.</p>
<ul>
<li>I want to colocate my components. If I have <code>src/pages/about/index.tsx</code> that uses <code>src/pages/about/helper.tsx</code>, I don't want <code>/about/helper</code> to render anything. I want it to give the user a 404. Some frameworks let you do something like <code>(helper).tsx</code> or <code>_helper.tsx</code> to denote this, but others don't and you have to figure out some sort of workaround.</li>
<li>Sometimes you don't want the URL structure to map to your directory structure. An example that comes to my mind is with posts on Substack. A URL looks like this: https://astralcodexten.substack.com/p/semaglutidonomics. <code>/p/:post-name</code>. I doubt developers would want a <code>p</code> directory underneath <code>src/pages</code>.</li>
<li>You often want to include middleware in your routing. ExpressJS does a fantastic job at this. I'm not sure how that'd work with filesystem based routing. I'm not sure if there is a solution. I'm not aware of any.</li>
</ul>
<p>In short, filesystem based routing potentially leads to headaches, and the benefits are either unclear and/or small, so I'd just prefer to avoid it.</p>
<h3 id="options">Options</h3>
<p>So with all of that said, let's see if we could find a framework that fits my needs.</p>
<h4 id="react-ssr">react-ssr</h4>
<p>All I really want is to have a Node + Express backend, Express would handle the routing, and you'd be able to do something like <code>res.render('account', { user: user })</code> which would render <code>src/pages/account/index.tsx</code>. And there'd also be full hydration so we can have interactivity wherever we want. Yeah. That's all I actually want from a framework I think.</p>
<p>Well, this little framework <a href="https://github.com/saltyshiomix/react-ssr">react-ssr</a> with only 240 GitHub stars offers that.</p>
<p>I messed around with it though and ran into some issues. It hasn't been maintained for 2+ years so various packages are old. This gave me some headaches getting set up. I was able to get past most of them, but not all, including not being able to get Chakra working. I need to have Chakra, and depending upon an unmaintained framework scares me, so as much as it pains me to say this, I don't think <code>react-ssr</code> is the answer.</p>
<h4 id="fresh">Fresh</h4>
<p><a href="https://fresh.deno.dev/">Fresh</a> from Deno looked quite cool to me at first. But after looking more closely, there are issues.</p>
<ul>
<li>Chakra can't be used with Deno, which probably makes this a a non-starter for me.</li>
<li>I don't want the partial hydration and islands architecture stuff. And their implementation is particularly limiting. Anything interactive needs to be in the <code>/islands</code> directory, so colocating your files is hard, and island components can't take functions as parameters. Wut.</li>
<li>Deno is really cool, but the NPM support looks like it's still pretty iffy. They say so themselves. That's pretty limiting. You never know when you'll need a certain NPM library. In particular I need Prisma. It's supposed to work with Prisma, but I'm skeptical.</li>
<li>I'm not sure if there are any good auth libraries for Deno.</li>
</ul>
<h4 id="astro">Astro</h4>
<p>Like Fresh, I really like how <a href="https://astro.build/">Astro</a> doesn't try to mess around with client side navigation. It's just straight SSR. Cool. But they also use that islands architecture with partial hydration, which comes with similar issues.</p>
<p>And you need to at least start off using these <code>.astro</code> files that use a sort of custom version of HTML. From there you could import React components, but things have to start with with <code>.astro</code> file. This is pretty limiting to me. Chakra needs to be with React, so basically I'd have all of these <code>.astro</code> files that are just light wrappers around React components. It's just excessive and ugly to me.</p>
<h4 id="remix">Remix</h4>
<p>We use Remix at work. It's ok, but I don't love it. I don't want the client-side navigation. I don't like <code>useFetcher</code> and other hooks they want you to use to make HTTP requests. Their version of filesystem based routing is pretty limiting.</p>
<h4 id="solid-start">Solid Start</h4>
<p><a href="https://start.solidjs.com/getting-started/what-is-solidstart">Solid Start</a> seemed really cool at first. No messing around with client-side navigation or partial hydration. They have filesystem based routing, but their specific implementation seems better than others. Everything is just pretty straightforward.</p>
<p>But then I realized that Chakra doesn't work with Solid. I also realized that Solid can actually be pretty <a href="https://www.youtube.com/watch?v=Lygh1pYLz9A">annoying</a> to work with due to components only rendering once. I'd just prefer React. Sigh.</p>
<h4 id="nextjs">NextJS</h4>
<p>This leaves us with what I've been trying to avoid: NextJS. Next just feels too bloated to me. They try to offer all of these little performance optimizations in ways that feel overly complicated to me. They don't deal with partial hydration so that's good, although they kinda do now in Next 13 with server vs client components. There's some complexity there. And they really go hard with client-side navigation. They try to do SSG by default and you have to opt out of it if you want to. Another thing for you to keep your minds eye on. And like almost every other framework, it offers filesystem based routing that I'd prefer to avoid.<sup class="footnote-ref" id="fnref-3"><a href="#fn-3">3</a></sup></p>
<p>But there are also good things about Next. It is super popular and well maintained. The docs are pretty good. It works with Chakra. It works with Prisma. Well. The docs for both are excellent. It uses Turbopack as a build tool which is supposed to be super fast and awesome. And <a href="https://next-auth.js.org/">NextAuth.js</a> is supposed to be pretty awesome.</p>
<p>I'm sad because I wasn't able to find a framework that gives me that radical simplicity I was looking for, but being pragmatic, I think Next is probably the winner.</p>
<hr/>
<p>If you have any thoughts, I'd love to discuss them over email: adamzerner@protonmail.com.</p>
<p>If you'd like to subscribe, you can do so via <a href="/subscribe/">email</a> or <a href="/feed/">RSS feed</a>.</p>
<section class="footnotes">
<ol>
<li id="fn-1"><p>Plus it'd be fun! Not to offer fake wisdom, but being fun is something that is both important and underrated.<a class="footnote" href="#fnref-1">↩</a></p></li>
<li id="fn-2"><p>Well, usually that's the question. If you have some sort of specialized needs you might want to use something more niche like a graph database.<a class="footnote" href="#fnref-2">↩</a></p></li>
<li id="fn-3"><p>I'm also turned off by how sales pitch-y their <a href="https://www.youtube.com/watch?v=NiknNI_0J48">Next 13 Keynote</a> was. Gross. It genuinely could have passed for a The Onion skit making fun of Apple.<a class="footnote" href="#fnref-3">↩</a></p></li>
</ol>
</section>
2022-11-25T03:39:25.588242+00:00https://adamzerner.bearblog.dev/onboarding-and-taxi-driving/Onboarding and taxi driving2022-08-18T09:17:56.526660+00:00adamzernerhidden<p>I just started a new job. Naturally, that means learning my way around a new codebase. Here is an analogy for how that feels.</p>
<p>Imagine that you are a taxi driver in Chicago. You have been doing it for six years and you know your way around pretty well. But then you get a new gig in New York, so you move there.</p>
<p>You get your first request for a ride. A client wants you to take them from point A to point B. But here's the thing: you don't know how to get from A to B! You're new in town!</p>
<p>And here's the other thing, there aren't any maps! So what do you do? You mess around. Before your first ride it'd be good to spend a little time riding around town, getting a feel for the layout, slowly building up your own little map in your mind. Kinda like how in those video games the map only starts to become visible for places that you've walked through before.</p>
<p><img alt="" src="https://i2.wp.com/www.starcomnexus.com/wordpress/wp-content/uploads/2018/02/diablo_map1.jpg"/></p>
<p>But you can't really afford to build a complete map. That would take too long. There are clients who need things done for them. So you build up a partial map yourself a little bit, you go through a little onboarding where they describe the layout to you, you chat with your coworkers and ask for tips, but ultimately you don't have a complete picture for your first ride, and so going from A to B will take you longer than usual. You'll go down some false paths, make mistakes, and update your model. As time goes on, there will be fewer and fewer false paths. Fewer and fewer mistakes.</p>
<p>There are also parallels with software design and urban design. In good urban design, getting around is as intuitive as possible. Eg. the grid structure of Manhattan + how a lot of the streets are numbered. If you are on 34th and 7th and need to get to 42nd and 8th, that is pretty easy to do even if you are new to town. Going from 34th street to 42nd street just means going north eight blocks. And going from 7th to 8th avenue means going west one block. It's the same thing with good software design. It can be done in such a way where things are as intuitive as possible.</p>
<p>The following might be stretching the analogy a little bit, but let's try it. Imagine a city that is very large. That'll mean a lot of your routes are just going to be long. Even if the city is designed well, distance is distance. Perhaps that is analogous to the inherent complexity in a codebase. If there is a ton of code and a ton of features, there is only so much you can do to make it easy to navigate quickly. Cue the people who preach about the <a href="https://basecamp.com/gettingreal/05.3-start-with-no">virtues of saying no</a>.</p>
<p>I'm sure you could continue taking this analogy further and further, but I'll leave it here.</p>
<hr/>
<p>If you have any thoughts, I'd love to discuss them over email: adamzerner@protonmail.com.</p>
<p>If you'd like to subscribe, you can do so via <a href="/subscribe/">email</a> or <a href="/feed/">RSS feed</a>.</p>
2021-12-12T01:01:19.612180+00:00https://adamzerner.bearblog.dev/what-are-pure-functions/What are pure functions?2022-08-18T09:17:56.526660+00:00adamzernerhidden<p>I've seen lots of people describe what pure function are. Most of them are ok, but there is one in particular that really clicked with me, and I'd like to share it with you. I got it from <a href="https://lispcast.com/">Eric Normand</a>.</p>
<p>Consider the following function.</p>
<div class="highlight"><pre><span></span><span class="kd">function</span><span class="w"> </span><span class="nx">sayHello</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="s2">"Hello, "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">name</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>Here is how we can visualize it if it is called with an argument of <code>"Alice"</code>.</p>
<p><img alt="" src="https://i.ibb.co/J2TdHN4/Screenshot-2021-12-11-at-3-53-58-PM.png"/></p>
<p>But now imagine that we have some sort of global state representing the language.</p>
<div class="highlight"><pre><span></span><span class="kd">const</span><span class="w"> </span><span class="nx">language</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"spanish"</span><span class="p">;</span>
<span class="kd">function</span><span class="w"> </span><span class="nx">sayHello</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">language</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s2">"english"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="s2">"Hello, "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">name</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">language</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s2">"spanish"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="s2">"Hola, "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">name</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>Maybe we can visualize it like this?</p>
<p><img alt="" src="https://i.ibb.co/zfTLHQm/Screenshot-2021-12-11-at-3-59-31-PM.png"/></p>
<p>I'd caution against that. There is something categorically different about the two inputs, and the visualization above implies otherwise.</p>
<p>Eric Normand says that <code>name</code> is an explicit input, whereas <code>language</code> is an implicit input. I really, really like that concept. <code>name</code> is explicitly being passed in to <code>sayHello</code>. You can see this clearly in the function's signature. But <code>language</code> is more implicit. Let's visualize it like this.</p>
<p><img alt="" src="https://i.ibb.co/54nBBB6/Screenshot-2021-12-11-at-4-03-42-PM.png"/></p>
<p>Let's take things even further. Imagine that we want to create a record in our database when they say hello. So in addition to returning the string, we hit our API as well.</p>
<div class="highlight"><pre><span></span><span class="kd">const</span><span class="w"> </span><span class="nx">language</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"spanish"</span><span class="p">;</span>
<span class="kd">function</span><span class="w"> </span><span class="nx">sayHello</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nx">greeting</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">language</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s2">"english"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">greeting</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Hello, "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">name</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">language</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s2">"spanish"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">greeting</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Hola, "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">name</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="nx">axios</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">"/greeting"</span><span class="p">,</span><span class="w"> </span><span class="nx">greeting</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">greeting</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>Now our function is doing two different things. 1) It is returning a string. 2) It is hitting our API. Maybe we can represent that like this?</p>
<p><img alt="" src="https://i.ibb.co/TLCRyQq/Screenshot-2021-12-11-at-4-08-51-PM.png"/></p>
<p>No. This has the same issue as before. There is something different about these two things: one is implicit, and the other is explicit. I'd visualize it like this instead.</p>
<p><img alt="" src="https://i.ibb.co/xMj0syn/Screenshot-2021-12-11-at-4-11-28-PM.png"/></p>
<p>Finally, with all of that out of the way, we are at the point where I can explain what a pure function is. A pure function is just a function with no implicit inputs or outputs. The only inputs are the arguments to the function. The only output is the return value. Pretty simple, right?</p>
<p>Now you might be having a lot of thoughts. Why would we want to avoid implicit inputs? Why would we want to avoid implicit outputs? Is doing so even possible? Practical?</p>
<p>Answering those questions is beyond the scope of this post. Sorry. It would be a pretty big rabbit hole to dive into, and I think it makes sense to separate the "what" from the "why". I can point you to some resources though. Check out this <a href="https://www.youtube.com/watch?v=_oifJWkO_so">video on side effects</a> and this <a href="https://www.manning.com/books/grokking-simplicity?a_aid=lispcast&a_bid=72596968">book on functional thinking</a>.</p>
<hr/>
<p>If you have any thoughts, I'd love to discuss them over email: adamzerner@protonmail.com.</p>
<p>If you'd like to subscribe, you can do so via <a href="/subscribe/">email</a> or <a href="/feed/">RSS feed</a>.</p>
2021-12-12T00:22:07.622108+00:00https://adamzerner.bearblog.dev/classes-often-arent-the-simplest-tool-for-the-job/Classes often aren't the simplest tool for the job2022-08-18T09:17:56.526660+00:00adamzernerhidden<blockquote>
<p>Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
— John Carmack</p>
</blockquote>
<p>When programming, you should reach for the simplest tool for the job.</p>
<p>Well, that's not entirely true. Using the simplest tool for the job often helps in making the code clean and easy to understand, but that isn't <em>always</em> the case, and that isn't your <em>only goal</em>. Still, I think it is a very good rule of thumb, so let's run with it and see where it takes us.</p>
<h2 id="printing">Printing</h2>
<p>Suppose you want to print "Hello world" to the screen. I think the simplest tool for the job would be something like <code>console.log("Hello world")</code> or <code>print("Hello world")</code>.</p>
<p>On the other hand, in some languages like Java, you are forced to create a class in order to complete this task.</p>
<div class="highlight"><pre><span></span><span class="kd">class</span> <span class="nc">HelloWorld</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="n">String</span><span class="o">[]</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="s">"Hello world"</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
<h2 id="functions">Functions</h2>
<p>Let's continue to pick on Java. Suppose you wanted a function that says hello to a specific person. Like "Hello Alice" or "Hello Bob". More generally, "Hello {name}". What is the simplest tool for the job here?</p>
<p>A function! It isn't a trick question.</p>
<div class="highlight"><pre><span></span><span class="kd">function</span><span class="w"> </span><span class="nx">sayHello</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">"Hello "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">name</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<p>Well, in Java there are no first class functions, so you'd have to use a class.</p>
<div class="highlight"><pre><span></span><span class="kd">class</span> <span class="nc">SayHello</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">toPerson</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">name</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="s">"Hello "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">name</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
<h2 id="namespaces">Namespaces</h2>
<p>Suppose you want to namespace stuff. What would be the simplest tool for the job here? Again, not a trick question: a namespace! Here's how it'd look in Clojure.</p>
<div class="highlight"><pre><span></span><span class="p">(</span><span class="kd">ns </span><span class="nv">currentUser</span><span class="p">)</span>
<span class="p">(</span><span class="k">def </span><span class="nv">email</span><span class="w"> </span><span class="s">"alice@example.com"</span><span class="p">)</span>
<span class="p">(</span><span class="k">def </span><span class="nv">login</span><span class="w"> </span><span class="p">(</span><span class="k">fn </span><span class="p">[]</span><span class="w"> </span><span class="nv">...</span><span class="p">))</span>
</pre></div>
<p>Not all languages have such pure namespacing though. For example, in JavaScript, you'd have to use an object.</p>
<div class="highlight"><pre><span></span><span class="k">export</span><span class="w"> </span><span class="k">default</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">email</span><span class="o">:</span><span class="w"> </span><span class="s2">"alice@example.com"</span><span class="p">,</span>
<span class="w"> </span><span class="nx">login</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">}</span>
<span class="p">};</span>
</pre></div>
<p>Still, an object is a lighter weight thing than a class, so I'd prefer it as a namespace over a class with static methods and/or properties.</p>
<h2 id="creating-objects">Creating objects</h2>
<p>Suppose you want to create objects. Say, an employee with a <code>firstName</code> field and a <code>lastName</code> field. What is the simplest tool for the job here?</p>
<p>Some might say a class. I think we're getting close to the point where a class is the simplest tool for the job, but we're not there yet. A <a href="https://medium.com/javascript-scene/javascript-factory-functions-with-es6-4d224591a8b1">factory function</a> is a simpler tool for the job here.</p>
<div class="highlight"><pre><span></span><span class="kd">function</span><span class="w"> </span><span class="nx">createEmployee</span><span class="p">(</span><span class="nx">firstName</span><span class="p">,</span><span class="w"> </span><span class="nx">lastName</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">firstName</span><span class="o">:</span><span class="w"> </span><span class="nx">firstName</span><span class="p">,</span>
<span class="w"> </span><span class="nx">lastName</span><span class="o">:</span><span class="w"> </span><span class="nx">lastName</span><span class="p">,</span>
<span class="w"> </span><span class="p">};</span>
<span class="p">}</span>
</pre></div>
<h2 id="creating-objects-with-shared-characteristics">Creating objects with shared characteristics</h2>
<p>Suppose you have different types of employees. There are full time employees, contractors, and hourly employees. And all three have first and last names. You could use three separate factory functions like this:</p>
<div class="highlight"><pre><span></span><span class="kd">function</span><span class="w"> </span><span class="nx">createFullTimeEmployee</span><span class="p">(</span><span class="nx">firstName</span><span class="p">,</span><span class="w"> </span><span class="nx">lastName</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">firstName</span><span class="o">:</span><span class="w"> </span><span class="nx">firstName</span><span class="p">,</span>
<span class="w"> </span><span class="nx">lastName</span><span class="o">:</span><span class="w"> </span><span class="nx">lastName</span><span class="p">,</span>
<span class="w"> </span><span class="nx">generatePayCheck</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// logic for full time employees... }</span>
<span class="w"> </span><span class="p">};</span>
<span class="p">}</span>
<span class="kd">function</span><span class="w"> </span><span class="nx">createContractor</span><span class="p">(</span><span class="nx">firstName</span><span class="p">,</span><span class="w"> </span><span class="nx">lastName</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">firstName</span><span class="o">:</span><span class="w"> </span><span class="nx">firstName</span><span class="p">,</span>
<span class="w"> </span><span class="nx">lastName</span><span class="o">:</span><span class="w"> </span><span class="nx">lastName</span><span class="p">,</span>
<span class="w"> </span><span class="nx">generatePayCheck</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// logic for contractors... }</span>
<span class="w"> </span><span class="p">};</span>
<span class="p">}</span>
<span class="kd">function</span><span class="w"> </span><span class="nx">createHourlyEmployee</span><span class="p">(</span><span class="nx">firstName</span><span class="p">,</span><span class="w"> </span><span class="nx">lastName</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">firstName</span><span class="o">:</span><span class="w"> </span><span class="nx">firstName</span><span class="p">,</span>
<span class="w"> </span><span class="nx">lastName</span><span class="o">:</span><span class="w"> </span><span class="nx">lastName</span><span class="p">,</span>
<span class="w"> </span><span class="nx">generatePayCheck</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// logic for hourly employee... }</span>
<span class="w"> </span><span class="p">};</span>
<span class="p">}</span>
</pre></div>
<p>But that involves writing a lot of repeated code for the first and last names. Looks like factory functions aren't really a tool that gets the job done here. So perhaps a class is the simplest tool for the job in this scenario.</p>
<div class="highlight"><pre><span></span><span class="kd">class</span><span class="w"> </span><span class="nx">Employee</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kr">constructor</span><span class="p">(</span><span class="nx">firstName</span><span class="p">,</span><span class="w"> </span><span class="nx">lastName</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">firstName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">firstName</span><span class="p">;</span>
<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">lastName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">lastName</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
<span class="kd">class</span><span class="w"> </span><span class="nx">FullTimeEmployee</span><span class="w"> </span><span class="k">extends</span><span class="w"> </span><span class="nx">Employee</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">}</span>
<span class="kd">class</span><span class="w"> </span><span class="nx">Contractor</span><span class="w"> </span><span class="k">extends</span><span class="w"> </span><span class="nx">Employee</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">}</span>
<span class="kd">class</span><span class="w"> </span><span class="nx">PartTimeEmployee</span><span class="w"> </span><span class="k">extends</span><span class="w"> </span><span class="nx">Employee</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">}</span>
</pre></div>
<p>Be careful though. One thing to think about is whether "is a" or "has a" better describes the relationship. Here it makes sense to say that a contractor "is a(n)" employee, but for "has a" relationships, <em>composition</em> is the <a href="https://stackoverflow.com/a/49016/1927876">preferred way</a> of dealing with the shared characteristics.</p>
<h2 id="wrap-up">Wrap up</h2>
<p>I want to keep the scope of this post narrow. I don't want to start getting into the weeds about the pros and cons of using classes vs using alternatives to classes. My goal here is just to point out that simpler alternatives often do exist. Hopefully that perspective can help better inform the decisions you make when writing code, and the opinions you form about programming languages.</p>
<hr/>
<p>If you have any thoughts, I'd love to discuss them over email: adamzerner@protonmail.com.</p>
<p>If you'd like to subscribe, you can do so via <a href="/subscribe/">email</a> or <a href="/feed/">RSS feed</a>.</p>
2021-10-12T09:33:51.258038+00:00https://adamzerner.bearblog.dev/code-as-a-closet/Code as a closet2022-08-18T09:17:56.526660+00:00adamzernerhidden<p>Alice: How have things been at your programming job?</p>
<p>Bob: Terrible.</p>
<p>Alice: How so?</p>
<p>Bob: Well, imagine that you had this weird job where you had to go into a closet and put together outfits for someone.</p>
<p>Alice: Hm, ok.</p>
<p>Bob: Imagine that this closet hand thousands and thousands of different shirts, shorts, pants, socks, hats, etc. And you'd be given a request from your boss to pick out a very specific outfit. Eg. the yellow shirt with the pink polka dots paired with the teal pants, metalic sombrero, and brown socks.</p>
<p>Alice: Ok. So basically, a request for an outfit comes in and my job is to go into this enormous closet and get the outfit?</p>
<p>Bob: Exactly.</p>
<p>Alice: Ok, I'm with you so far.</p>
<p>Bob: Now imagine that the closet is a complete mess. Everything is just carelessly thrown around.</p>
<p><img alt="" src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fmedia.istockphoto.com%2Fphotos%2Fpile-of-dirty-laundry-clothes-disorganized-messy-bedroom-closet-picture-id871012892%3Fk%3D6%26m%3D871012892%26s%3D612x612%26w%3D0%26h%3DB3rTuQXS31ORjIJN3eien6uSO2T7PbyeNvAdndjimRE%3D&f=1&nofb=1"/></p>
<p>Alice: That sounds terrible. Why would I do this job again?</p>
<p>Bob: They pay you six figures.</p>
<p>Alice: Ok, I guess.</p>
<p>Bob: Anyway, that's how I feel a lot of the time.</p>
<p>Alice: I think I understand the analogy. You're given a programming task, and it's hard to do the task because the code is disorganized?</p>
<p>Bob: Yeah.</p>
<p>Alice: So why don't you just clean it up as you go? Like, using the analogy, next time you're in the sock drawer, instead of just taking the socks out, take some time to organize that drawer so that next time you're there, it'll be easier.</p>
<p>Bob: Well, sometimes you can, but there are various reasons why I often can't. The biggest one is probably a lack of time. They have this big backlog of outfits that need to be picked out. It's really important that my boss gets all of these outfits very soon. And cleaning up drawers is a non-trivial task. It takes time. I could do it if they wanted me to, but they'd prefer me to get them the outfits in the backlog as quickly as possible.</p>
<p>Alice: Wait, that doesn't make sense. I mean, maybe it does if these next couple of outfits in the backlog are super essential, but in the long run it'll be faster if you just clean out the closet.</p>
<p>Bob: Exactly! Maybe it takes three months to clean out the closet. But once I clean it up, I'll be able to pick out outfits so much faster! Maybe it moves me from two outfits a day to five outfits a day. In the long run, the investment will pay for itself.</p>
<p>Alice: Yeah, for sure. So why don't you just kinda go off by yourself and do it? Maybe put in extra hours if you have to. In the long run it'll make your life easier.</p>
<p>Bob: I'm not sure how true that is. Maybe this analogy is breaking down a bit. In reality, I'm working in a codebase with dozens and dozens of other people. If I clean out a corner of this "closet", the next person to work in that corner will be grateful, but chances are I personally will be working in a different corner, and won't reap the benefits.</p>
<p>Alice: Well won't your coworkers realize this and promote you?</p>
<p>Bob: Not really. The people who do the promotions are upper management. The same people who put in requests for outfits. They don't really have visibility into how the gears turn. They only have visibility into how many outfits each person is successfully churning out.</p>
<p>Alice: Hm, sounds like that is a really misleading way to evaluate people.</p>
<p>Bob: Yeah. And what makes matters worse, they also kinda judge you on how nice your outfits are.</p>
<p>Alice: Huh? I thought they were the ones who tell you what outfits to pick out? Like that one you mentioned earlier with the pink polka dots, it sounded kinda ugly to me but if that's your task are you supposed to tell them it's ugly?</p>
<p>Bob: No, not really. Some obvious things you can point out, but for the most part I'm just supposed to do what they tell me. They're the fashion people, I'm the operations person.</p>
<p>Alice: So then how can they judge you on fashion?</p>
<p>Bob: I think it's just human nature. Like if I am continuously churning out beautiful outfits, even if I'm not part of the fashion, it just kinda feels like I'm doing a good job, y'know?</p>
<p>Alice: Yeah, I see what you mean. It reminds me of the halo effect.</p>
<p>Bob: Yeah, that's a good point. I agree.</p>
<p>Alice: So maybe it'd be a good idea for you to be a little opinionated about the outputs they give you?</p>
<p>Bob: It's complicated. The fashion people don't really see me as someone who understands fashion. Sometimes they're open to feedback, but for the most part they just want me to get their vision out there. Plus, fashion is another thing that takes time to formulate. Time that I don't have.</p>
<p>Alice: I see. That's quite a pickle you've got yourself into. I'm not really seeing a way out. Other than, I guess, well, actually leaving the company.</p>
<p>Bob: Unfortunately, that doesn't really work.</p>
<p>Alice: Why not?</p>
<p>Bob: Well, for the most part, all companies operate like this.</p>
<p>Alice: Ugh, that's so frustrating.</p>
<p>Bob: Tell me about it.</p>
<p>Alice: Well how difficult is it to find the ones that operate the right way?</p>
<p>Bob: I don't know. It's kinda hard to say. You could go to their websites and look at the careers pages and stuff, but they all say the same thing. No one actually comes out and says, "we don't give a shit about keeping our closet organized". They all <em>say</em> they like to be organized. But talk is cheap. And then the interview process doesn't really help much either. It's the same problem of talk being cheap. Plus the whole thing only lasts a few hours. You kinda have to actually work at the company to find out.</p>
<p>Alice: Hm. Are there any companies where there does happen to be some sort of strong signal? All it takes is one!</p>
<p>Bob: That is true. And yes, there are some I have in mind. I'm not 100% sure, but I do get a good vibe from them. The problem is that it's not easy to get a job there.</p>
<p>Alice: Yeah, that makes sense. I'm sure those jobs are in high demand.</p>
<p>Bob: Not quite as high as you'd expect, but yeah, they're not easy to get. The whole hiring process is a separate mess itself.</p>
<p>Alice: Don't tell me. It's a review site!</p>
<p>Bob: I was thinking more along the lines of what it's like having to find a doctor, but close enough!</p>
<hr/>
<p>If you have any thoughts, I'd love to discuss them over email: adamzerner@protonmail.com.</p>
<p>If you'd like to subscribe, you can do so via <a href="/subscribe/">email</a> or <a href="/feed/">RSS feed</a>.</p>
2021-06-23T07:29:03.404696+00:00https://adamzerner.bearblog.dev/code-quality-interviews/Code quality interviews2022-08-18T09:17:56.526660+00:00adamzernerhidden<p>I've been through a lot of coding interviews in my life. I've had four jobs, and thus have been through the job search process four times. Each time I took the "quantity over quality" approach, and basically mass-applied to as many companies as I was able to. Maybe something like 150-200 companies each time. To a variety of web-related programming roles. From there, I'm not sure how many interviews I had each time, but it was probably something in the ballpark of "dozens".</p>
<p>I can think of four main categories of interview questions I've been presented with:</p>
<ol>
<li>Data structures and algorithms</li>
<li>Real world problem solving</li>
<li>Behavioral</li>
<li>Domain-specific knowledge (eg. "How does prototypal inheritance work?")</li>
</ol>
<p>A fifth category is "product thinking". Eg. "What would you do to improve this landing page?" or "What features should we add to better address customer's needs?". I've only encountered that a few times though.</p>
<p>A sixth category would be <a href="https://github.com/donnemartin/system-design-primer">system design</a>, but I've never really had one of those in an interview.</p>
<p>In this post, I want to talk about a seventh category: code quality interviews. By "code quality", I am roughly referring to the sorts of things that Bob Martin talks about in his book <a href="https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882">Clean Code</a>.</p>
<p><img alt="" src="https://images-na.ssl-images-amazon.com/images/I/41yafGMO+rL._SX376_BO1,204,203,200_.jpg"/></p>
<p>Arguing that code quality is important is beyond the scope of this post. This post is intended for people who are already on the bandwagon. The questions I want to address here are:</p>
<ol>
<li>Is there a practical way to test candidates on their ability to write clean code?</li>
<li>Is writing clean code a skill, or is it just a matter of want-to?</li>
<li>Is the ability to write clean code predictive of other useful skills?</li>
</ol>
<h2 id="is-there-a-practical-way-to-test-candidates-on-their-ability-to-write-clean-code">Is there a practical way to test candidates on their ability to write clean code?</h2>
<p>I'm not sure, but here's an idea I feel pretty optimistic about: have candidates review a pull request. Let me elaborate...</p>
<p>Check out this <a href="https://github.com/ryanmcdermott/clean-code-javascript"><code>clean-code-javascript</code></a> repo on GitHub. It basically goes through Bob Martin's book Clean Code and gives examples of what is good and what is bad.</p>
<p><img alt="" src="https://i.ibb.co/3sN7K2t/Screenshot-2021-04-25-at-3-28-06-PM.png"/></p>
<p>So, what I envision is a PR that has various "bad" examples scattered throughout, and you'd be hoping that the candidate identifies them as bad and proposes a better alternative.</p>
<p>That's how it'd look in broad strokes anyway. I haven't had a chance to actually put this to the test, so I expect that things would be a little rough around the edges, but overall I am optimistic.</p>
<p>I also think that this would serve as a great conversation starter. Hopefully it would lead to larger conversations, eg. about how <a href="https://www.youtube.com/watch?v=_oifJWkO_so">side effects</a> can be problematic, or about how following <a href="https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)">the rule of three</a> is a good way to avoid abstracting things prematurely. If a candidate can dive into one of these conversations and speak intelligently about it, that's probably a pretty good signal.</p>
<p>I've actually had one interview where I did this! I thought it was fantastic! The way this one was structured, I reviewed the PR on GitHub and left comments, just like you would in real life. Then I had a Zoom call where I talked everything through with the interviewer.</p>
<p>Personally, I suspect that it would be a good idea to do the initial code review via a Zoom call so you can observe the candidates initial thought process, but I'm not sure. Maybe the mix of async and sync was good. After all, it can be hard to collect your thoughts and offer your best comments during the pressure of a live interview. Regardless, if the big picture I'm trying to paint is a good one, I'm sure these sorts of details can be figured out.</p>
<p>Let me end this section by trying to be honest about where I stand here. As I've gotten older, I've moved more and more towards being skeptical of ideas that haven't been battle tested. They look pretty at first, but when you actually put them into practice they usually start growing warts. This idea has not been battle tested, and so I (am trying to!) have a degree of skepticism about it. However, I'm also not one of those people who think ideas mean nothing. Ideas are <a href="https://www.lesswrong.com/posts/pgEHv3oq8q3hcssfF/write-a-business-plan-already">simulations</a>. It's hard to simulate perfectly, but that doesn't mean you can't simulate <em>usefully</em>. What I'm trying to say is that it's not a black or white thing, and my optimism here is perhaps a 7/10.</p>
<h2 id="is-writing-clean-code-a-skill-or-is-it-just-a-matter-of-want-to">Is writing clean code a skill, or is it just a matter of want-to?</h2>
<p>I have mixed feelings about this. On the one hand, given my experiences working with dozens of developers throughout my career, the idea that it is "just a matter of want-to" does <em>not</em> pass the smell test. There is clearly a difference in ability, and I think that most other developers would agree with this.</p>
<p>But on the other hand, if you're in an interview where you <em>know</em> you're being evaluated on your ability to write clean code, you're going to make sure you think about using good variable names, creating the right abstractions, commenting things appropriately, etc.</p>
<p>Here's a concrete example. I've seen people use <code>Array.map</code> in JavaScript before instead of <code>Array.forEach</code>. Eg.</p>
<div class="highlight"><pre><span></span>users.map(user => {
api.user.update(user);
});
</pre></div>
<p>If they were in an interview where they are explicitly being tested on code quality, I expect that they would realize "I don't understand <code>map</code> too well, that might be a bad practice, let me just use <code>forEach</code>." But... and here's the key point... such a thing is not at <em>the front of their minds</em>. And in practice, when these sorts of things aren't at the front of your mind, you resort to the "bad" technique instead of the "good" one. So to some extent, interview candidates can "game the system".</p>
<p>But that is true of other types of interviews too! For example, if you're in an algorithms interview, you'll be laser focused on big O, whereas in real life you may not have a deep enough understanding for inefficient algorithms to "pop out" to you.</p>
<p>However, there is only so much that you can fake in an interview. If you don't know what a priority queue is, you don't know what a priority queue is. And, circling back to code quality interviews, if you don't realize that <a href="https://github.com/ryanmcdermott/clean-code-javascript#functions-should-only-be-one-level-of-abstraction">functions should only be one level of abstraction</a>, that's not the kind of thing that you can sidestep.</p>
<p>So then, the question becomes, to what <em>extent</em> can you sidestep in code quality interviews? Like always, reality isn't black or white, and the difficulty is finding the right point on the spectrum. That's a difficult thing to do here though. I guess I'll just say that I personally suspect that it'd be something like a 6 or 7 out of 10, where a 10/10 is "impossible to sidestep". I wish I could do better than just offering my opinion, but it's a hard thing to dive deeper into, and my goal in this post is really just to be posing questions.</p>
<h2 id="is-the-ability-to-write-clean-code-predictive-of-other-useful-skills">Is the ability to write clean code predictive of other useful skills?</h2>
<p>Algorithms questions are really divisive. One camp says that they're stupid and you never have to do that sort of stuff in the real world. A second camp says that you do. But then, a third camp admits that you don't, and instead, argues that such interview questions identify candidates with a high <em>aptitude</em>, and say that if the candidates can understand such complicated algorithms, they're going to be able to learn all of the other things as well.</p>
<p>Personally I have a pretty big heap of skepticism for the third camp, but let's not talk about that here. Instead, let's talk about whether code quality interviews have the same benefit.</p>
<p>I don't think they are (too) predictive of that sort of high IQ aptitude that algorithms questions try to get at. But I do suspect that they'd be predictive of someone who has a talent for <em>communication</em>. The ability to express oneself clearly, and for that matter, the ability to think clearly about a problem in the first place. Like everything else in this article, I don't say this with a high degree of confidence, but it is something I feel optimistic about. Food for thought.</p>
<hr/>
<p>If you have any thoughts, I'd love to discuss them over email: adamzerner@protonmail.com.</p>
<p>If you'd like to subscribe, you can do so via <a href="/subscribe/">email</a> or <a href="/feed/">RSS feed</a>.</p>
2021-04-25T23:26:40.584817+00:00https://adamzerner.bearblog.dev/call-stacks-in-everyday-life/Call stacks in everyday life2022-08-18T09:17:56.526660+00:00adamzernerhidden<p>Call stacks are a thing in programming, but they're also a thing in everyday life. Realizing this seems, at best somewhat useful, and at worst interesting to think about.</p>
<h2 id="conversations">Conversations</h2>
<p><a href="http://www.youtube.com/watch?v=n5CgGTziQ4Y" title="Louis CK - Women Horrible Storytellers"><img alt="IMAGE ALT TEXT" src="http://img.youtube.com/vi/n5CgGTziQ4Y/0.jpg"/></a></p>
<p>In the video, Louis CK tells the audience about how his wife is bad at telling stories.</p>
<p>Speaking of Louis CK, have I ever told you how much I <a href="https://adamzerner.bearblog.dev/why-i-love-stand-up-comedy/">love stand up comedy</a>? It's really one of my favorite things in the world. When done well. Going to the Comedy Cellar in NYC was one of the best experiences of my life.</p>
<p>Speaking of NYC, I might end up moving there for a job. That'd be interesting. Coming back to the town where I grew up. Well, I grew up on Long Island technically.</p>
<p>Speaking of white lies, I'm kind of a fan of them. They can be problematic, but they also have their uses. For instance, the distinction between me having been raised on Long Island versus NYC wasn't relevant to you, and pretending that I grew up in NYC made the sentence flow better, so why bring it up in the first place?</p>
<p>Was that last use of the word "it" clear? Maybe I should be more specific.</p>
<p>Wait, what were we talking about again?</p>
<hr/>
<p>I have a small problem. In conversations like these, I usually want to "hold on to" the structure.</p>
<ul>
<li>You're talking to me about this Louis CK video. Ok.</li>
<li>Now you're going on a tangent about stand up comedy. Cool. We'll finish that and then come back to the video.</li>
<li>Oh, now you're talking to me about NYC? Hm, ok. Let's discuss that, then return to stand up comedy, then return to the video.</li>
<li>Wait now you're talking about white lies? This is getting hard to keep track of.</li>
<li>The word "it"? Really?</li>
</ul>
<p>I don't know why I do this. I think the natural thing is to just "let the conversation flow", but I use up mental resources holding the structure in my head. I've been known to actually answer questions like "How did we end up talking about X?". "Well, we were talking about A, which lead to B, which lead to C..."</p>
<p>Anyway, we're not here to talk about my problems. We're here to talk about call stacks.</p>
<p>The conversation can be represented like this:</p>
<div class="highlight"><pre><span></span>it
white lies
nyc
standup
video
</pre></div>
<p>First we were talking about <code>video</code>. Then we started talking about <code>standup</code>, so we put <code>standup</code> on top of <code>video</code>. Then <code>nyc</code>. Then <code>white lies</code>. Then <code>it</code>.</p>
<p>Imagine a stack of plates. You can't just take out the bottom plate and use it (unless you're really good at Jenga). Here, if we want to return to the conversation about <code>video</code>, we have to finish talking about <code>it</code>, then finish <code>white lies</code>, then <code>nyc</code>, and then <code>standup</code>. Then, and only then, can you return to your conversation about <code>video</code>. If you skip a step, the gods of recursion will find you.</p>
<h2 id="tasks-in-general">Tasks in general</h2>
<p>It's not only conversations where this sort of thing happens. It's with daily activities too.</p>
<p>For example, before writing this article I was getting my dog ready for a walk.</p>
<p>But then I realized that the kitchen needed to be cleaned, so I started doing that.</p>
<p>Then I got inspired to write this article, so I started doing that.</p>
<p>Then I got a text from my brother.</p>
<p>I just responded to my brother.</p>
<p>Now I'm going to finish up the article.</p>
<p>After that I'll finish cleaning the kitchen.</p>
<p>After that I'll finally go and walk my dog.</p>
<p>Again, if you don't proceed through the tasks in precisely this order, the gods of recursion <em>will</em> have your neck.</p>
<h2 id="wikipedia-rabbit-hole">Wikipedia rabbit hole</h2>
<p><img alt="" src="https://imgs.xkcd.com/comics/the_problem_with_wikipedia.png"/></p>
<p>Surfing the web is particularly prone to big call stacks.</p>
<h2 id="in-programming">In programming</h2>
<p>Maybe I should talk about what this looks like in programming. I'll try to make it accessible for those who aren't programmers.</p>
<p>Imagine that we want to get the user with the id of 42. To do that, we need to know which database to look at. To know that, we need to know what time of day it is.</p>
<div class="highlight"><pre><span></span>get_time_of_day
decide_which_database 42
get_user 42
</pre></div>
<p>Once we know what time of day it is, we're back to <code>decide_which_database</code>.</p>
<div class="highlight"><pre><span></span>decide_which_database 42
get_user 42
</pre></div>
<p><code>decide_which_database</code> tells us that since it's the morning and we're looking for a user with the id of 42, we should look in database #7.</p>
<div class="highlight"><pre><span></span>get_user 42
</pre></div>
<p>Now that we know what database to look in, we can grab the user and finish the execution.</p>
<p>More generally, the idea is that the situation looks like this:</p>
<blockquote>
<p>I want to do A, but to do A I have to first do B, and to do B I need to do C, but to do C I need to do D. So I do D. Now that I finished D, I can do C. Now that I finished C, I can do B. Now that I finished B, I can, finally, do A.</p>
</blockquote>
<p>Hopefully this way of thinking will be a useful <a href="https://jamesclear.com/mental-models">mental model</a> for you.</p>
<hr/>
<p>If you have any thoughts, I'd love to discuss them over email: adamzerner@protonmail.com.</p>
<p>If you'd like to subscribe, you can do so via <a href="/subscribe/">email</a> or <a href="/feed/">RSS feed</a>.</p>
2021-04-16T05:43:59.477603+00:00https://adamzerner.bearblog.dev/using-obscure-features-of-a-programming-language/Using obscure features of a programming language2022-08-18T09:17:56.526660+00:00adamzernerhidden<p>There is a coversation that I had about five years ago where I'm really disappointed with myself.</p>
<p>I was working at a job where we were using Rails and Angular 1. I was a front-end developer there. I was pretty comfortable with Angular and had been using directives heavily, sometimes venturing into some of the more obscure features of directives. One day my boss had a conversation with me about it.</p>
<p>He told me not to use them. He said that they violate the normal expectation one would have of a MVC architecture. In particular I think he was referring to the fact that in Angular you can do something like this:</p>
<div class="highlight"><pre><span></span><div ng-controller="MainController as main">
<fancy-directive></fancy-directive>
<h1>Page header</h1>
<p>Lorem ipsum dolor</p>
</div>
</pre></div>
<p>When something happens inside of <code><fancy-directive></code>, the directive can handle it. Eg if you click a button to toggle some sort of state, it can all be handled inside of the directive and never touch <code>MainController</code>. In fact, this was the Angular Way. However, it violates the expectation one might have that it'd be handled by <code>MainController</code>.</p>
<p>At the time, I thought it was totally crazy that he'd propose that I shouldn't use <em>directives</em> in <em>Angular</em>! Directives are like... one of the most fundamental parts of the framework. They say that the three D's of Angular are directives, dependency injection and data binding. And the reason why it's called "Angular" is because HTML elements have angular brackets − <code><</code> and <code>></code> − and Angular lets you create your own things with angular brackets.</p>
<p>Furthermore, I took an uncharitable perspective of focusing on the fact that my boss was a Ruby dev without much front end experience in general, let alone with Angular or single page apps. It felt to me like he had a huge shortcoming in his knowledge and that he wanted to take a shortcut and sidestep this shortcoming. If we're using Angular, it seems reasonable to expect that the developers know the fundamental concepts of the framework. If they don't, then we either picked the wrong developers or picked the wrong framework.</p>
<p>Let me give you some more context of where I was coming from. There's a stereotype about how developers go through phases with best practices over the course of time.</p>
<ol>
<li>In the beginning, you don't know what they are and your code suffers from this lack of knowledge.</li>
<li>Then you learn what they are and start to follow them blindly.</li>
<li>Then you realize that they don't apply to every situation, and start to apply them intelligently.</li>
</ol>
<p>This is oversimplified, but I think it points at something that is roughly correct. Anyway, at the time of this directives debate, I was a little bit over a year into my career, coming from a coding bootcamp background, and I was pretty firmly in that second phase of following best practices blindly.</p>
<p>I didn't <em>know</em> that I was doing this. I just knew that I read things from all of these experts on how you should write your code. The experts seemed like really good programmers and highly trustworthy. So it just felt like I was choosing to listen to the experts instead of listening to Joe Shmoe.</p>
<p>I think the main place where this goes wrong isn't that the experts are <em>wrong</em>. If you sat down and talked about it with them, they'd usually agree that their advice is a guideline not a rule, and you have to think about whether it makes sense to apply it. But it's often hard to express such caveats when you're teaching or arguing something.</p>
<p>I experienced something like this in my journey as a poker player. There's a book I read called <a href="https://www.amazon.com/Course-Serious-Strategy-Smart-Players/dp/1511768320">The Course</a>. It makes a lot of generalizations about how poker players play. There's a friend I have who I discuss poker hands with, and we'd often have disagreements where he says one thing and I say, "The Course says the opposite and I trust the author more than I trust you". Then I actually <em>met the author</em> one day and he totally acknowledged that his advice doesn't always apply and that his book was meant to help beginners take their first steps.</p>
<p>I think the same thing happens in programming when experts talk about best practices. I think they know that they don't always apply, but a lot of times that caveat gets lost in translation. It was lost on me anyways at that point in my career. To me it just felt like, "Super smart experts say X, Joe Shmoe says Y, I think I'll go with the super smart experts."</p>
<p>Let's get back to the Angular example. I had spent a lot of time reading through all of these books and courses and stuff about Angular. So in my mind I had this repository of knowledge that all of these experts imparted on me. And my boss was telling me to violate that. It really suck out to me how much what he was telling me goes against everything I've been reading.</p>
<p>However, as I sit here today writing this, I disagree with my former self and agree with my former boss. In the particular situation we were in, I think it would make sense to ditch the weird directives. Or at least only use them for presenational stuff, and not keep state inside of them.</p>
<p>Here's the thing. On that team, I was really the only one who was an "Angular guy". We had one other guy who was an "Angular guy", but he actually didn't work in the same codebase. He mostly worked on this Django codebase. The other devs were Rails devs. Some were better with Angular than others, but in general I think that given the makeup of the team (and what we anticipate about how the team will look in the future), it'd make sense to avoid the weird parts of Angular.</p>
<p>There's a tradeoff with using obscure features. The benefit is that they can be powerful, make your code cleaner, whatever. The cost is that people who aren't familiar with them will have trouble understanding them. I think the job of an organization is to figure out how to navigate that tradeoff.</p>
<p>Maybe you want to be really careful about hiring domain experts who know all about the obscure features. Maybe you want to have non domain experts on your team, and just have them take their time learning all of the obscure features. Or maybe you just want to punt and shove all those obscure features off to the side. It depends on the situation.</p>
<hr/>
<p>If you have any thoughts, I'd love to discuss them over email: adamzerner@protonmail.com.</p>
<p>If you'd like to subscribe, you can do so via <a href="/subscribe/">email</a> or <a href="/feed/">RSS feed</a>.</p>
2021-02-24T04:23:30.297090+00:00https://adamzerner.bearblog.dev/code-isnt-the-only-thing-that-needs-to-be-maintained/Code isn't the only thing that needs to be maintained2022-08-18T09:17:56.526660+00:00adamzernerhidden<p>When I was working on <a href="https://premiumpokertools.com/">Premium Poker Tools</a>, it took me a while to launch. I wanted to make absolutely sure that there were no bugs. Even if I launched a free version, I reasoned that bugs would still be catastrophic.</p>
<p>The software tells you things like, "pocket jacks will win 66% of the time against ace five suited". Imagine if the software told you that the number is 56% instead of 66%? You'd lose trust, right? And once you lose trust, you wouldn't want to use the product, right? The whole point of the thing is to tell you what the numbers are. If you can't trust it to give you the right numbers, well, then why use it?</p>
<p>And so, I proceeded to write tests. Lots, and lots, and lots, and lots, of tests. My unit tests took a few minutes to run. Minutes, not seconds.</p>
<p>I also had end-to-end tests. Those took about 30 minutes to run.</p>
<p>To put that in perspective, at my current job where there are maybe 30 engineers and the company has been in business for ~4 years, the tests take a similar amount of time to run.</p>
<p>Part of why I wrote so many tests is also because I was just excited to do so. You see, I learned that testing was this super important thing, but at my first two jobs, I never got to write tests. It was something people acknowledged would be good in theory, but in practice there were always things higher on the priority list to tackle. So, no tests were written in either company.</p>
<p>Then in my side projects, the scope had always been small enough where writing tests seemed sorta silly.</p>
<p>But now I had a sizable project I was working on, where tests were business critical and very appropriate. I wanted to get experience with them. So, I wrote them. Lots, and lots, and lots of them.</p>
<p>"What's the harm?", I asked myself. Ok, maybe some of the tests aren't necessary and I could move a little faster if I avoided writing them. That's ok though, at least I'm getting valuable learning experience and becoming a better developer. Anything for education! Right?</p>
<p>Well, I did learn some valuable lessons, but they weren't about being better at writing tests. They were about being better at <em>not</em> writing tests.</p>
<p>Here's what happened. I reached a point where I would make a change to the code, and all sorts of tests would break. So I'd have to then go through all of those tests and augment them so that they work with my new code change. In the beginning it wasn't so bad, but as the codebase grew and grew, it started to become a bigger and bigger problem. At the end I reached a point where I was afraid of refactoring. That's not a point you want to reach.</p>
<p>That's kinda funny, right? Conventional wisdom is that writing tests gives you the confidence you need to refactor without worrying about breaking things, but my experience was the opposite. I was worried about refactoring because it'd mean I'd have to spend hours and hours going back and augmenting old tests.</p>
<p>I don't want to speak too badly about testing though. I still think of myself as someone who is pro-testing. It's definitely an important thing that has it's place. However, you do have to acknowledge that it comes at a cost. Traditionally people think the <em>upfront</em> cost of writing the tests in the first place. However, I think they often ignore the long term cost of <em>maintaining</em> all of those tests.</p>
<p>Maybe I shouldn't speak for others. I'm not sure what others think. What I can say is that I myself didn't see tests as a thing that needs to be maintained. I knew that <em>code</em> is something that needs to be maintained! I read Bob Martin's book Clean Code and really made an effort to keep my code clean. I knew that when you don't write clean code it comes back to bite you later on.</p>
<p>But <em>tests</em>? That's not the same thing as code. The book isn't called Clean Tests.</p>
<p>When articulated explicitly like this, these thoughts do seem pretty silly. I think the problem is that the questions didn't occur to me. "Should I write clean and maintainable tests?" just wasn't something I consciously thought about. I just assumed that stuff only applied to code, not to tests.</p>
<p>Well, it turns out I was wrong. Tests, like code, need to be maintained.</p>
<hr/>
<p>Recently I had a similar experience, this time with documentation instead of tests. Premium Poker Tools taught me that tests need to be maintained, but I failed to recognize that the same ideas apply to documentation as well.</p>
<p>Throughout the previous 12 months, I started two different jobs. Ramping up and onboarding as a developer is always tough. I often found myself tempted to think, "we need documentation for this". README's, Confluence docs, Draw.io diagrams − whatever. Just something I could read through to understand what's going on, instead of having to Slack someone or sift through a ton of code. I'm not the only one who is confused, it happens to all new devs getting onboarded. So wouldn't it be more efficient to write it all down once rather than having new devs always asking the same questions?</p>
<p>In theory, yes. But did you notice the mistaken assumption I made?</p>
<blockquote>
<p>write it all down once</p>
</blockquote>
<p>There it is! That key word "once"! As the codebase evolves, documentation and diagrams grow stale. Just like how test suites also grow stale as the codebase evolves. When things grow stale, you have to update them. And that takes <em>time</em>.</p>
<hr/>
<p>I hope the takeaway from this article isn't "Boo tests!" or "Boo documentation!". I'm still "pro tests" and "pro documentation": I think each are very often underutilized.</p>
<p>The point of this article is just to point out that there are costs associated with both of them. Namely, that they need to be updated and maintained. I think that many people, when they think about costs associated with tests or documentation, they think about those upfront costs of initially writing the specs/docs. What doesn't occur to them, and what didn't occur to me, is the fact that you need to update them when they grow stale, and that over time, this cost will probably end up being larger than the upfront cost.</p>
<p>So then, be smart about when you choose to write tests and when you choose to write docs. Try to get a sense of what the overall, long-term costs will be, and weigh that against the benefits.</p>
<hr/>
<p>If you have any thoughts, I'd love to discuss them over email: adamzerner@protonmail.com.</p>
<p>If you'd like to subscribe, you can do so via <a href="/subscribe/">email</a> or <a href="/feed/">RSS feed</a>.</p>
2021-01-25T05:07:40.352994+00:00https://adamzerner.bearblog.dev/conversation-event-loops-and-error-handling/Conversation, event loops, and error handling2022-08-18T09:17:56.526660+00:00adamzernerhidden<p>My previous post <a href="https://adamzerner.bearblog.dev/debugging-the-student/">Debugging the student</a> got me thinking about conversations. Particularly conversations where one person is trying to explain things to the other person. In that post I talked about some ways I see this go south. In this post I want to expand on these ideas with some analogies from programming.</p>
<p>To summarize the previous post, imagine someone trying to explain differential equations to a random person on off the street. Silly, right? A random person off the street won't be able to follow. But I think something analogous happens all of the time. The "teacher" starts babbling about something to the student when the student doesn't have nearly enough background information or context to keep up.</p>
<p>In that post one of the commenters <a href="https://www.lesswrong.com/posts/SfsZAitvivsTFBQnX/debugging-the-student?commentId=dGZxZFNqGbW4GwEkp">proposed</a> that the issue is teachers assuming too much of their students. <a href="https://www.lesswrong.com/posts/SfsZAitvivsTFBQnX/debugging-the-student?commentId=titFj2L9rNDQnqb5Y">My response</a>:</p>
<blockquote>
<p>That was a hypothesis of mine too, but it seems to only scratches the surface. If teacher stops to reflect, they'll usually realize that it was silly to try to teach differential equations to someone off the street. It's not that they "actually" think there's a short inferential distance, it's that they didn't ask themself the question of what the inferential distance is in the first place.</p>
</blockquote>
<h2 id="event-loops">Event loops</h2>
<p>There is something called an event loop in web browsers. If you're interested, this video explains it and is one of my favorite videos:</p>
<p><a href="http://www.youtube.com/watch?v=8aGhZQkoFbQ" title="What the heck is the event loop anyway? | Philip Roberts | JSConf EU"><img alt="What the heck is the event loop anyway? | Philip Roberts | JSConf EU" src="http://img.youtube.com/vi/8aGhZQkoFbQ/0.jpg"/></a></p>
<p>And if you're not interested, well, I guess I'm going to explain it anyway.</p>
<p>A web browser executes code. But while it's busy executing its code, when you click something, you need it to execute <em>other</em> code for <em>you</em>. "Hey, could you stop what you're doing and check the most recent score of the basketball game please?" You're interrupting!</p>
<p>As an analogy, imagine your accountant sitting at his desk doing taxes. There's a three inch stack of papers on his desk that he's working on. And now you walk in and just have a measly two papers you need him to fill out for you. You interrupt and see if he would mind stopping what he's doing to help you.</p>
<p>Nope! Not gonna happen! That shit on his desk, he's in the zone working his way through it and nothing's gonna get in the way of that!</p>
<p>But if you want, there's another desk in the back with a good 20 inches of papers he also needs to get to. You could put your stuff on <em>bottom</em> of that, and he'll get to it when he's ready. First come first serve. You're last.</p>
<p>The three inch stack on his desk is like the browsers main call stack, and the 20 inch stack in the back is like task queue. (I'm trying to make this accessible but it might be easier if you watch the video, and I'm not sure if this will actually work for non-programmers.)</p>
<p>The way the event loop works, is it continuously polls the task queue, and whenever the main call stack empties, it puts another chunk onto the main call stack. Like the accountant finishing his 3 inches and taking another 3 inches from the 20 inch stack in the back.</p>
<p>Now imagine that you want your accountant to be responsive to clients. Well, you can't put too much stuff on his main call stack. And you also can't put too much stuff on his task queue. This is exactly how it works for web developers. If you do either of those things, the browser won't be responsive to the user. When the user clicks it'll be really laggy.</p>
<p>Ok, so problem solved? Not quite. Now your accountant is responsive to clients, but he isn't getting any work done! His just sitting there all day waiting patiently for clients and not doing anything productive in the downtime.</p>
<p>Here's what I'd propose. Only put like one inch of papers on your main desk at once. That way if a client comes, they'll never have to wait too long for that to clear. From there, that task queue/desk in the back with 20 inches of papers, give your clients the priority. Let them jump to the front of the line. Do away with "first come first serve".</p>
<p>Consider how this would play out. In a normal day, the accountant might have 0.4 inches of paper on his main desk, 17.5 on his background desk, a client comes in, the accountant says to put their stuff at the top of his papers on the background desk, skipping the line, the accountant quickly finishes the 0.4 inches on his current desk (inches wasn't the most realistic analogy...), then his event loop pulls another 1 inch from the background table, gets to work on it, and since the client jumped to the front of the line it's already their turn!</p>
<p>So big picture, the accountant is only doing short bursts of work at a time and is constantly cognizant of the needs of clients, ready to pull in new tasks from them pretty quickly.</p>
<p>Similarly, this is how you want to structure your websites. Don't block the main callstack with stuff that takes a long time. Only do a little at once. That way, the event loop will be constantly looking for input from the user so that it can respond quickly.</p>
<p>With this background information out of the way, I can finally make my point: <em>this</em> is how conversations should work.</p>
<p>Imagine that I'm explaining something to you. I say a couple sentences. Then I <em>pause</em> and check if you have anything to say. No? Then I say a couple more. Followed by another check. My event loop is constantly running, seeing if there are any inputs from you before I proceed. And I only do a little bit at once. Contrast this with something like going on a 90 second long rant where I am caught up with what I am saying and not cognizant of you wanting to interject. A one-way lecture instead of a two-way conversation.</p>
<p>In real life, the way I envision this is not <em>actually</em> pausing every few sentences and saying, "Do you have any comments? No? Ok. I'll continue." In reality it's much more subtle than that. Much more nonverbal. Pausing is still probably a good idea, and sometimes it can also be a good idea to verbally check in with the student, but other times it's more practical to just take cues from their body language and stuff.</p>
<p>But yeah, anyways... when you're the teacher, you want to keep your main call stack short. And you want to constantly have your event loop running. Looking to pull from the task queue so that the student has the chance to say something.</p>
<p>Let's talk about that task queue actually. I don't know about you, but sometimes when I'm talking my mind really starts running and I have like 10 things I want to say that are "waiting in line". And I can't seem to get them out of my mouth fast enough. Using our analogy, it'd be good to put like 2 of them on the main stack and the other 8 in the background in your task queue. But, you also want to give the other person access to the task queue, and you want to let them jump to the front of the line, skipping past the 8 items you have there.</p>
<p>Here's how that'd play out. You've got 2 on the main stack and 8 in the task queue. You say your first thing. Now there's 1 on the main stack. You get a signal from the other person that they have something to say. They add an item to the task queue. It jumps to the front of the line. There are 9 items in the task queue now. You proceed to finish the last item on the main stack. Now the event loop runs and takes that item from them at the top of the task queue, puts it on the call stack, and excutes it, giving the other person a chance to say what they want to say.</p>
<p>Then from <em>there</em>, you don't just execute their item and throw it away. You pay attention to what the result is! Depending on that result, you may want to add a few more items to the task queue and have them jump the line.</p>
<p>Maybe you realize they don't know what a derivative is so you add "teach them what derivatives are" to the top of the task queue, ahead of "teach them more stuff about differential equations". Or better yet, you add "spend some time asking about their math background" instead. It would be similarly foolish to just start blabbing about derivatives for the same reason it's foolish to blab about differential equations in the first place.</p>
<h2 id="error-handling">Error handling</h2>
<p>Another programming analogy that I think fits here is error handling. Consider the following code:</p>
<div class="highlight"><pre><span></span>let n = 0;
n += 2;
n += 5;
n -= 3;
n += 1;
fetchAndDisplayCatImages(n);
n -= 4;
fetchAndDisplayCatImages(n);
n += 2;
n -= 3;
console.log(n);
</pre></div>
<p>We have a value <code>n</code>. We're adding and subtracting from it. We're using it to get cat images to display to the user. And finally, we're logging the value of <code>n</code> at the end.</p>
<p>But what happens if <code>fetchAndDisplayCatImages</code> fails? Maybe the API changed on us. In practice, what we'd want to do is check to see if there are any errors, and if so, have a pop up box or something tell the user and fail gracefully. We don't want the whole thing to just crash. That's ugly. And perhaps harmful. So we can instead do this:</p>
<div class="highlight"><pre><span></span>let n = 0;
n += 2;
n += 5;
n -= 3;
n += 1;
let firstResponse = fetchAndDisplayCatImages(n);
if (firstResponse.error) {
showErrorPopup("Problem trying to get the first batch of cat images.");
} else {
n -= 4;
let secondResponse = fetchAndDisplayCatImages(n);
if (secondResponse.error) {
showErrorPopup("Problem trying to get the second batch of cat images.");
} else {
n += 2;
n -= 3;
console.log(n);
}
}
</pre></div>
<p>Make sense. But what about the <code>n +=</code> and <code>n -=</code> lines? What if <em>they</em> fail?</p>
<p>Well, they almost certainly won't. Some lines of code we're so confident in that we don't bother checking for errors. Actually, that happens more often than not. Usually we only check for errors when we do something complicated enough where things might actually go wrong.</p>
<p>I think it makes sense to take a similar approach to conversations. Suppose you're tutoring a student in college on differential equations. You've been tutoring him for a while so you don't need to spend time diagnosing where his math skills are like we did in the previous example. So then, you're sitting in the library explaining stuff to him. Things are going smoothly. But then you get to a concept that is particularly tricky. What do you do? Error handling!</p>
<p>You've just made a statement that has some complexity to it, and it's possible that it caused stuff to go wrong. You have to check to see if an error was thrown before moving on. It would be imprudent to just continue rambling along. If an error was thrown, you need to handle it.</p>
<p>In this case, I guess an error being thrown would usually mean the student not understanding what you said. That'd mean you'd have to pause and address their confusion (by trying to <a href="https://adamzerner.bearblog.dev/debugging-the-student/">debug</a> together).</p>
<p>But not necessarily. Maybe they would just like to paraphrase back to you to make sure they understood. Or maybe they have an interesting comment to make!</p>
<p>I should have talked about <em>exception</em> handling instead of <em>error</em> handling. In programming, usually we're worried about errors, but sometimes there are other exceptional things that happen that we want to be aware of and handle properly. Same with conversations. I think it's probably true that we're most worried about the student "throwing an error", but sometimes the exception that they throw isn't actually an error, and yet it's still exceptional enough that we want to interrupt and handle it.</p>
<h2 id="social-conversations">Social conversations</h2>
<p>So far I've mostly been focused on an example of a more educational type of conversation between a student and a teacher. Makes sense that this stuff would apply to that type of conversation. But what about more fun and social types of conversations?</p>
<p>Well, I guess it depends on your idea of fun. Personally I pretty much always prefer my conversations to have error handling and short call stacks, but I've came across people with different preferences. However, I think that those preferences usually only apply to certain contexts, and as a default people prefer error handling and short call stacks. I'll leave you with this <a href="https://youtu.be/7x3knxMBHco?t=140">Seinfeld clip</a> as an example.</p>
<hr/>
<p>If you have any thoughts, I'd love to discuss them over email: adamzerner@protonmail.com.</p>
<p>If you'd like to subscribe, you can do so via <a href="/subscribe/">email</a> or <a href="/feed/">RSS feed</a>.</p>
2021-01-08T08:04:44.227523+00:00