
Code with Jason
Code with Jason
264 - Dan Moore, Principal Product Engineer at FusionAuth
In this episode I talk with Dan Moore from FusionAuth about authentication solutions, testing strategies, and when to skip tests based on risk and cost factors, then dive into philosophical discussions about experience versus knowledge, objective versus subjective programming practices, and imperative versus declarative coding approaches.
Hey, it's Jason, host of the Code with Jason podcast. You're a developer. You like to listen to podcasts. You're listening to one right now. Maybe you like to read blogs and subscribe to email newsletters and stuff like that. Keep in touch.
Speaker 1:Email newsletters are a really nice way to keep on top of what's going on in the programming world, except they're actually not. I don't know about you, but the last thing that I want to do after a long day of staring at the screen is sit there and stare at the screen some more. That's why I started a different kind of newsletter. It's a snail mail programming newsletter. That's right. I send an actual envelope in the mail containing a paper newsletter that you can hold in your hands. You can read it on your living room couch, at your kitchen table, in your bed or in someone else's bed, and when they say what are you doing in my bed, you can say I'm reading Jason's newsletter. What does it look like? You might wonder what you might find in this snail mail programming newsletter. You can read about all kinds of programming topics, like object-oriented programming, testing, devops, ai. Most of it's pretty technology agnostic. You can also read about other non-programming topics like philosophy, evolutionary theory, business, marketing, economics, psychology, music, cooking, history, geology, language, culture, robotics and farming.
Speaker 1:The name of the newsletter is Nonsense Monthly. Here's what some of my readers are saying about it. Helmut Kobler, from Los Angeles, says thanks much for sending the newsletter. I got it about a week ago and read it on my sofa. It was a totally different experience than reading it on my computer or iPad. It felt more relaxed, more meaningful, something special and out of the ordinary. I'm sure that's what you were going for, so just wanted to let you know that you succeeded, looking forward to more. Drew Bragg, from Philadelphia, says Nonsense Monthly is the only newsletter I deliberately set aside time to read. I read a lot of great newsletters, but there's just something about receiving a piece of mail, physically opening it and sitting down to read it on paper.
Speaker 1:That is just so awesome Feels like a lost luxury. Chris Sonnier from Dickinson, Texas, says just finished reading my first nonsense monthly snail mail newsletter and truly enjoyed it. Something about holding a physical piece of paper that just feels good. Thank you for this. Can't wait for the next one. Dear listener, if you would like to get letters in the mail from yours truly every month, you can go sign up at NonsenseMonthlycom. That's NonsenseMonthlycom. I'll say it one more time NonsenseMonthlycom. And now, without further ado, here is today's episode. Hey, today I'm here with Dan Moore, Principal Product Engineer at FusionAuth. Dan welcome. Hey, thanks for having me Jason.
Speaker 1:Thanks for being here. So tell me a little bit about FusionAuth.
Speaker 2:Sure. So FusionAuth is a downloadable authentication server. So if you're familiar with something like Auth0, it lets you add user authentication, user authorization and user management into your application or applications, and FusionAuth is in that same space and we differentiate a little bit because we are, as I mentioned, downloadable, which means people use us in their production instances or production applications, but also in their CI CD pipelines or in their development environments on their laptop. We also are API first and have a really great customization story in terms of being able to make your login pages look just like your application okay, um, I, about 10 years ago, worked, I did a certain amount of work with angular and that brought me into contact with auth zero.
Speaker 1:Um, and I had kind of a negative reaction to it because to me it felt kind of weird to have as my authentication provider this like third-party dependency, and part of what bothered me about it was testing, because it wasn't very clear how to involve it in my testing scenario. Um, and I guess it's not the fact that it was a third-party dependency exactly, it was that it was a third-party network dependency, because we have third-party dependencies all the time and that's that's not a problem, but the fact that it was like a network dependency. Um, since you mentioned ci, can you tell me a little bit about how it works into that picture?
Speaker 2:Sure, yeah, and I will say that it's always a trade-off, right.
Speaker 2:People that listen to your podcast may interact with Stripe or other kind of third-party network dependencies, and there are ways to work around that.
Speaker 2:And actually, on the Auth0 website there's suggestions around like using mocks, right, like mocking the calls to Auth0, because there are times when it makes sense to do full integration and then testing, and there's also times when you just want to like just test this one piece of your application and you want it to be quick and easy To get back to, kind of the way FusionAuth approaches it, which is being a downloadable product which also, by the way, will run for you in the cloud, and you can run in your own cloud, where basically a Docker image is one of the main ways people deploy us, and so we actually have a GitHub action out there that lets you.
Speaker 2:It stands up. Fusionauth, it configures it in a certain way within a GitHub action as a Docker container, and so you know again, if you want to just test, hey, can I log in, can I drive this login with Playwright or Selenium or something like that you can absolutely do that inside FusionAuth and then examine sorry, inside your application then, which then kind of goes over FusionAuth and then examine sorry inside your application, which then kind of goes over FusionAuth and then comes back right after it's posted, the username and password in the simplest scenario, and then you can kind of look at the results and see, you know, is there an HTML string in there that says, you know login successful, or something like that.
Speaker 1:Okay, I think I see what you're saying. Tell me if I have this right. So in a test suite maybe you have a dependency like Redis or something like that, and the way you would deal with that is in your CI configuration. You would have a Redis container that runs throughout the life of your CI run. The same way you can do that. You can have a FusionAuth container running and that's how you deal with that. You can have a fusion auth container running and and that's how you deal with that dependency. Do I have that right?
Speaker 2:yeah, I mean it's maybe a little more complicated because fusion auth itself has a dependency on postgres or mysql, but yeah, it's essentially the same thing. So we like to think about and this is something that took me a little while to get my hands around when I started at FusionAuth is you're never going to build an entire application just inside FusionAuth. It's always going to be an architectural component. So it's very similar to a database. How would you CIC stand up a database, and you know containers are certainly the easiest and most modern way to do that. If you have a different kind of like a jenkins setup or something like that, it might be a standalone server that gets wiped periodically or something like that got it okay.
Speaker 1:Yeah, and by the way, I'm I'm a little smarter now than I was 10 years ago, and I think if I were handed this problem today, I'd have a clearer idea of what to do about it. One of my consulting clients has an application that authenticates via I think it's Shibleth, which is used by universities. That's been my experience, and so they're like okay, we have this third-party network dependency for our authentication. How do we deal with this? And I helped them stub that so that basically, you just have to trick your Rails application into thinking that it's authenticated. So you just have to trick your Rails application into thinking that it's authenticated. So you just have to give it. You have to figure out a way to give your Rails application valid cookies and then before each test, you do that part, and so it's really not that much of an inconvenience at all.
Speaker 1:It's a bit of work up front to figure out how to make it work, but then that only has to be done once, and from there on out you're good.
Speaker 2:So yeah, so I might push back on that a little bit in a couple of ways. Right Like, I think that for the vast majority of the application code that is great. Right Like you want to like stub out, you don't care about the login process, you don't need to do that every time you're trying to test. You know action ABC. The two things that kind of come to mind are one at some point you might actually want to test that login flow.
Speaker 2:And shibboleth is another example of a server that you could run inside a container. Right, I think it's just a downloadable package as well. I'm not as familiar with Shibboleth, but I've definitely seen the name around. And the second thing, and the reason why you probably want to do that, that test against Shibboleth for real, rather than always relying on the cookies being set, is if Shibboleth gets upgraded or something changes, then you might need to change your cookie format, otherwise your production and your tests get out of sync. And so I totally agree that doing that kind of mock for 90% of your tests or maybe 99%, depending on your test coverage makes total sense sense. But you have to have that kind of real world use case at least a couple of times, because otherwise, if things change, your tests are going to merrily continue along like hey, things are fine when your underlying reality has changed.
Speaker 1:This brings up an interesting higher level question about testing strategy and stuff like that. One of the testing questions I get most often is when do you not write a test, and I have certain ideas about that. I'm curious for you, Dan do you have a way of deciding, like for any particular type of feature, like how you decide not to write a test? That's a great question.
Speaker 2:I would say that there's some things that are kind of easy to discard, right, like if you know the code is going to get thrown away.
Speaker 2:If it's like a scripting, something to load data or something like that, then doing full testing is a bad idea. I think that testing at interfaces or testing at kind of good places where your application is Well sorry, I'm skipping the question I would say over testing the implementation, is a bad idea, and I've definitely been guilty of that, right, like, I've done stuff where I've written a ton of tests, and I've seen this as well, and then you end up with this constriction where it feels like to make a single change, you have to change two lines of code in the code base and then 500 tests, and so now this is all in context of what problem you're solving is right, and with every application there's kind of core stuff and there's uncore stuff, and so if it's non-core, it may be okay to test lighter and test less to gain more fluidity, whereas if it's core, you know you may be willing to buy to pay the price of that slowness of change because it's so important that nothing goes wrong.
Speaker 1:Yeah, interesting, okay. So there's a lot in there that I would love to dig deeper into. So hopefully I can hold those points in my head, um, I want to come back to them after we after go a little deeper into the question of of what not to write tests for again, um, okay. So before I I share that, I want to share like a a mindset thing, cause it has a big bearing on the answer to this question.
Speaker 1:People often want to know how to do testing correctly. What's the right way to do testing? And you know, like, for a certain feature, like what's the right way to test this feature? And I think that that's not a great way to look at everything. It's more about costs and benefits, um, and so like, if you have a feature to test, um, there's there's not a single right way to do it. There are just different ways to do it, which make certain trade-offs and stuff like that. There are better and worse ways to do it, but there's not exactly a right or wrong way to do it. So, having said that, here's how I decide whether to write a test or not.
Speaker 1:One is the risk of silent failure, if something, and these are like several Boolean questions that I and together and like if the result of that is a yes, then I write a test, if it's a no, then I don't. So one of those Booleans is will it fail silently? And forgive me if I flip the Booleans, maybe it's ors, maybe it's ands, but anyway, will it fail silently? Um, and thinking about this shibboleth thing, um, I think that's something that would not not fail silently. If you break login and no one can log in, you'll hear about that. So that's one.
Speaker 1:Another question is like how severe is the in the case of failure? Would it be a big problem? And another question is how, if it were to fail, how frequently would this failure be likely to occur? Would it be frequent or not frequent? So, to take an example, like if there's a feature where it's only used by one person once a month and it wouldn't fail silently, they would totally notice. And the workaround is they would just have to do a little bit of manual work and instead of taking five seconds, it would take five minutes. Oh yeah, and the other question I ask, which is very significant is is the test expensive to write?
Speaker 1:Because if the test is very expensive to write and it's a low risk, low consequence, non-silent failure, then that's a case where I feel totally fine about skipping the test. Sure, so if any one of those is a I don't know if it's a yes or if it's a no but if any one of those answers is like the other way, like if the test is cheap to write but all those other things are the same way, then fine, I'll just do it. Or if it is something that would fail silently, then I write the test because I don't want a silent failure. So those are the questions that I ask myself.
Speaker 2:So this is really interesting to me, because one of the things I love tests for is they give you the comfort of knowing you can change things around in your software, and I didn't hear the ability to change or the likelihood of code changing at all in your criteria. So is that because it's kind of subsumed in some of those other things like the risk, or how does that work?
Speaker 1:Yeah, I'd say so. This opens up a really interesting question. You know, every test that you write is a bet. Something that frustrates me to no end is developers and managers desire for efficiency. People don't want to waste a single minute, which means, ironically, that they end up wasting weeks and months. Because, again, people are thinking in terms of right and wrong and black and white instead of more economic terms, costs and benefits and tradeoffs and also bets.
Speaker 1:A lot of things in programming are probabilistic and they involve unknowable futures, and so we can't know the right or wrong answer. We just have to make bets. It's like buying a stock. It's like I can buy a hundred stocks and I know that probably one of these businesses will go out of business in the next five years, but I don't know which one. So I can't answer the question for any particular stock Is this a good stock to buy? I can only say well, a policy of buying stocks is better than a policy of not buying any stocks. So, given that we can never know in advance well, loosely speaking, we can never know in advance whether any particular test will pay off All we can know is that a general policy of writing tests will pay off and a general policy of never writing tests will have a large negative payoff, and so every individual test is a bet.
Speaker 1:So that's an interesting concept to factor into the decision whether to write a test or not, cause if I choose not to write a test for something where the test is expensive and it's low consequence and all that, um, I think what I'm saying is that I'm making a bet. No, I'm not. I'm not even saying anything about the bet. I'm just saying this area is so unimportant that if I refactor something and this thing breaks sorry, I shouldn't just say unimportant, it's the combination of being unimportant. That's not even the right thing to say. It's low cost, you know, because if it's, if it's not a big deal if it breaks, and or if it breaks only very infrequently, like it's the frequency multiplied by the severity of when it breaks, um, so if that's a low number, um, and it's not going to fail silently, silently, because that's a very significant thing. Also, what I'm saying when I don't write a test is that I'm okay with this just breaking. Yeah, I want to be precise again.
Speaker 2:I'm okay with the risk of this breaking, yeah, and you're okay with making that tradeoff right, because you're not okay with it being broken of this breaking, yeah, and you're okay with making that trade-off right, because you're not okay with it being broken. Tests really are a way for you, as a developer, to be aware of breakage, right. And so you're saying, if you multiply the cost of breakage times, the frequency of breakage or the end times, the chance of missing breakage right, which is that silent piece the chance of missing breakage right, which is that silent piece, and they are low enough, then you're happy to take the manual means, right, because that person who's running that report might have to ping you on Slack or they might have to run through a document or something like that. That'll take them time, but that's different than if 100 million people or even a hundred thousand people can't log into your system and even though that's not silent, the cost is high and if the frequency is high, you're going to lose trust of your users, for example, example.
Speaker 2:So it's like I totally get it's a spectrum with like four or five dimensions and my question for you is other than experience, like there's no heuristic right, like you can kind of like guess on this stuff. But, like you know to me, I guess I'd be curious what your answer is in terms of, like, developing that intuition around, like hey, is this test worth writing or not, because the expensiveness I can see. That's something that you could probably tell right, like, oh, I have to stand up five services and you know it's gonna be complicated to mock or etc. But like, what do you think about those other aspects, like, how do you develop an intuition around them?
Speaker 1:yeah, that's a very good question. And one last comment on what I said before, because I gained some clarity just now. Um, I think it's not that I'm skipping a test. It's that I'm choosing to have a manual test in production instead of an automated test, which you kind of said. So I'm okay with the test being. Somebody uses it in production and then notifies me manually because that kind of test is cheaper than the automated test. So to answer your question of, like, how do you develop that intuition of whether the test is going to be expensive to write? Is that the question?
Speaker 2:No, I think that one is relatively straightforward to think about. I think it's those other things, right, Because you might not know if something's going to fail silently or what the frequency of failure or the cost of failure is, especially as a dev in the trenches right, Like as a consultant, you might have a bigger perspective. But, like when I'm a dev, how do I know? Is this test worth writing or not? Let's assume it's a low-cost test, because that's an easy thing to say. If it's high-cost maybe you talk to somebody else, but if it's low-cost, how do you determine whether or not it makes sense?
Speaker 1:Yeah. Well, again, if it's a low cost test, I just write it, because I won't skip a low cost test. I'll only skip a high cost test. Those other factors like will it fail silently? Only if I can be very confident that it won't fail silently Do I skip the test. So if your scenario is that you just don't know, in that case I would just bite the bullet and write the test because I couldn't be confident that it's a yes. And how do you figure that stuff out? I don't know. I guess it's a case-by Um. Yeah, I don't know. With the login thing, for example, that is a non-silent failure. That's kind of easy to put two and two together, that that you're going to find out about, that, um, but also, like you pointed out, it is a high consequence failure, and so if, if any of those things is a red flag, then that translates to a decision of I will write the test.
Speaker 2:Have you got a blog post about this? Because I think this would be great material for, like you know, a blog post, maybe a diagram or table or something like that.
Speaker 1:Yeah, I do have a blog post about this and I put it in my book. Um, I have a book called professional rails testing which is about rails testing. Um, so, yeah, it's out there. I think, if you search for like code with jason, because my site is code with jasoncom uh, code with jason when not to write a test, or something like that, I think think you'll find it and it lists those four criteria.
Speaker 2:Awesome.
Speaker 1:Awesome, Great, Okay, and let's see there are some other things that you said that were really worth digging into. Oh, you mentioned something that triggered me a little bit Use the word intuition, and I think either you said or I just thought about it the concept of experience. I read this book recently that I can't stop talking about, called the Beginning of Infinity by David Deutsch, and David Deutsch is just a maniac. He's such a smart guy and he does something that I haven't seen a lot of before is he takes like really fundamental ideas that we take for granted and he analyzes them and kind of asks like how do we know this is any good, or how do we know what this actually is, and stuff like that. The craziest one is in this other book. He wrote the Fabric of Reality. He went so far as to question numbers Like how do we know that one plus one equals two and that kind of stuff.
Speaker 1:And I'm just like what? Like how can you question something so fundamental? But he did and you like walked through it and stuff. Um, anyway, I've been doing that lately. Like, for example, um, what is abstraction?
Speaker 1:Abstraction is something we talk about all the time in programming. Yet if you go to a program and programmer and be like quick, what is abstraction? You might get kind of a long answer and it might be uh, might be kind of circuitous and it'll take a lot of figuring out and and eventually they might say something that's consistent with the truth. But I think there's real value in being able to say abstraction is and then have something right off the top of your head. So I've been taking those fundamental things and asking myself, like, what is this thing? So when I hear experience and intuition, I realize at some point that the idea of like, how do you learn this? Oh, it comes with experience. Like that is a total cop-out answer, because experience is just a way of gaining knowledge. And so when somebody asks how you learn something and somebody says it just comes with experience, basically what you're saying is, oh, you just get that by gaining knowledge.
Speaker 2:And that's not an answer. What is the?
Speaker 1:knowledge. That should be the question. Saying is oh, you just get that by gaining knowledge, um, and that's not an answer. What is the knowledge? That?
Speaker 2:that should be the question I might push back on that a little bit because, well, I think experience is a way of gaining knowledge, right, I'm not gonna argue with you there, just like reading a book. Um, I might argue that, like, experience is short for mistakes you've made the past, like the whole collection mistakes you've made in the past, like the whole collection of mistakes you've made in the past and how they've affected and scarred you. And you know I can read a book, I can work through code example, and I'm still not going to have the level of experience that I had when, or sorry, there might be this exact same lesson, right, that I read in the book or that I did in the code example, and it won't have seared in my brain, it won't be in my gut in the same way that it would if I had to give a presentation about it. Or there was something that was in that lesson that caused a website to fall over on live TV or something like that, right, which actually is an experience.
Speaker 2:I've had a website to fall over on live TV or something like that, right, which actually is experience I've had. And so maybe it's less about the knowledge itself, it's more about how rooted it is in your viewpoint, and that is valuable too. Right, because it's not enough to just know knowledge. You actually have to be able to apply it, know the context that it's applied in, know when not to apply it. As you kind of talked about with the testing, if you just say testing is good, I'm going to apply it all the time. You're going to run into problems downstream, so yeah. So I would say that experience is absolutely knowledge, and saying it comes with experience is kind of a cop out, but it is still.
Speaker 1:Um, there's knowledge and then there's like how you reflect and act on that knowledge, and they're almost two separate things yeah, that's a really interesting thing, um, because, on the one hand, um, whether you gain something, whether you gain knowledge through experience or by reading a book or something like that, everything enters our minds, through our senses, and it comes in the same way, no matter what. But if we take a really simplified example, like if you read that stoves are hot and you shouldn't touch one, that's one thing. But then if you actually touch a hot stove and burn your hand, that no pun intended gets seared into your memory much more deeply than if you just read about it. So what is the difference?
Speaker 2:I mean. So the knowledge is the same, right, like the concrete words are the same. I think that the context and your actions based on that knowledge are going to be different. Maybe I mean this feels weird to say, but maybe the experience is more real, right, than reading the knowledge, right? So there's like an aspect, like a dimension of reality that is important to making sure you act on. You know, in this particular case, not ever touching a hot stove again.
Speaker 1:Yeah, maybe you believe that you know it with a higher degree of certainty, because if I read that stoves are hot and so I never, ever touch one, I might have a feeling in the back of my mind like, are stoves really hot?
Speaker 2:right, yeah, well, there's also the other thing of like. If you read stoves are hot, you need to follow through a bunch of like think. Maybe in this case, not that much thinking, but like, okay, what does it mean? It's still hot. What does it mean? Oh, it means it will hurt me if I touch it. It means I shouldn't touch it. Right, there's like three layers of thought there, whereas you touch a hot stove and is, there's no thought involved, right, like it's all. Like, uh, autonomous nervous system, right, that's the thing that happens without us thinking about it. So it's almost a deeper level of knowledge, because you don't have to do the reasoning to get to the action, which really, to some extent, knowledge is great, but, like, the action you're going to take from knowledge is almost more important than, uh, knowledge itself yeah, yeah, you know.
Speaker 1:I feel like it should be said that, even though life feels like one continuous experience, that's not how it actually works. All we have is our present sensory inputs and our memories of the past. So all of our knowledge is just stored in our memory. Whether it came in experientially or by reading, it's stored the exact same way. But when we gain knowledge through experience, yeah, I think we believe it with a higher degree of certainty.
Speaker 2:Maybe that's not the only thing, but certainly that seems like it is a thing I 100% agree. Right, and anyone who's ever worked through a tutorial on any documentation ever versus just reading the tutorial you know experienced that right where, like, if you actually kind of work through the code, you understand it, you believe it, more than if you just read it on the page. And then obviously there's levels and levels of this with coding. But that to me is kind of the analogous to touching the hot stove.
Speaker 1:It's like there's two different levels yeah, and something we haven't touched on yet is the physical aspect of it. Reading a book is not the same physical experience as touching a hot stove, to use a different example like riding a bike. You can't learn to ride a bike by reading a book. You have to actually do it. And I wonder to what degree that comes into the picture with programming, because obviously programming is much less physical than riding a bike. It doesn't involve balance and stuff like that. But programming isn't completely unphysical. Agreed, you're taking actions and you're seeing the outcomes of those actions. The outcomes of those actions and a lot of the consequences of our actions are non-technical, like you mentioned something about an outage involving live TV or something like that.
Speaker 2:Yeah, it was an event on live TV that was responsible for a website and we had an outage during that event which still makes my skin cold when I think about it, which was definitely not I mean, there was a technical reason for it, but it 100% had non-technical downstream feedback and events, yeah, yeah, and so, yeah again, it's like the emotional component of it.
Speaker 1:I guess there's a couple of things like the hot stove thing. That was physical pain. And it must be that we have a really strong connection between physical pain and memories, between physical pain and memories, like if I ask you, hey, what kind of stuff hurts, you don't have to be like, hmm, what kind of stuff does hurt, like you know, right, right, yeah.
Speaker 1:And there must also be a strong connection between emotions and memories because a lot of things like you remember, things that you had a strong emotional reaction to, things that are emotionally neutral, are easy to forget.
Speaker 2:Right, yeah, I mean one thing I do want to not let go of the fact that programming is a lot mental, but there is absolutely a physical nature to it too, and this is actually someplace that I see newer devs struggle with is like, um, even just navigating the keyboard or navigating the file system, um, you know, with the mouse and things like that.
Speaker 2:And I think the first thing I do after I get any new computers I I turn on, like vi, key bindings in bash in my shell, because that's just how I have that muscle memory. And I'm not going to say that's an essential part of difficulty of programming, but it is 100% a part of slowing down other devs to not have that. And you could have key bindings for IntelliJ or whatever your IDE is, it doesn't matter what they are, as long as you know them and not having the ability to physically interact with a computer at a high level. Again, I'm not going to say that it makes you a bad programmer, I'm just saying that it allows the thoughts to stream more fluently from your brain to the the code than if you're like oh man, how do I, how do I move around this code, this file, right, like so there is definitely a physical nature of programming to some extent.
Speaker 1:Oh, definitely, and one of the ways that I like make judgments about whether somebody's a stronger programmer or weaker one is how how well they can manipulate their machine. Because there's a lot of programmers out there who have been doing it forever and like can hardly type and it's like wow, that's like, that's not good. I would not hire this person if you've been programming for 20 years and you still can't really type or like so many people like are just trying to switch among windows and stuff like that, and they they do it really slowly and like very often click on the wrong tab and stuff like that, and so that's, that's a big. I guess that's not a determinant of what makes you a better program or not. It's just a, it's a predictor, it's highly correlative. Good programmers are basically always also good at manipulating their machines.
Speaker 2:Sharpening their tools right, like, just like I think you know a good carpenter right To reach back to that thing that is so often analogized to programming Like a good carpenter is going to unlike me, they're going to have a sharp saw and sharp you know, sharp other tools, whereas I'm an itinerant, you know I am very. My best tool for fixing problems around my house is my phone that can call my handyman. But I've done some things right and so, but my tools are very much ad hoc and like, they're kind of messed up and so, yeah, it is really about like again, and I want to totally, be totally clear in my experience, you can be a good programmer without obsessing over your tools. But I think that I've definitely met great programmers who did obsess over your tools. But I think that I've definitely met great programmers who did obsess over their tools and thought about their workflows all the time.
Speaker 2:Sometimes I feel like people can over-focus on that. Right, it's almost like the carpenter who never builds anything. They just spend all their time polishing their tools and you don't want to shy away from that. But you know, if you had to pick between the person with the clean tools and the person with the crappy tools to do a job at your house. You'd probably pick the person with the clean tools who looked like they were organized and things like that. So yeah, definitely a factor.
Speaker 1:Yeah, and there's another part of it too, and people don't like to talk about this and it's uncomfortable. But, like, some, people are smarter than others and people with people who are more intelligent tend to be able to manipulate their computers a lot more fluently than people who are less intelligent, without any deliberate effort. They just it's easier for them because everything's easier for them.
Speaker 2:Just like it's easier for them to remember a book or get the the concepts out of a book right, like it's not. Yeah, I mean not that there aren't 10 different kinds of intelligence, and but yeah, I mean all the things being equal. Being able to be quicker to like, understand and read a concept is, you know, going to make you a better programmer.
Speaker 1:It's hard to argue with that yeah, um, another thing that's's interesting regarding Vim, and I've wrestled with this question a bit in the past. The question is is using an editor like Vim or Emacs or something that's keyboard based? Is that objectively better than not doing so? And I think the answer is yes, and I think the reason for that is because you can just objectively be faster by using the keyboard than having to switch between the keyboard and mouse. That doesn't mean that you're like any worse of a programmer for choosing not to use Vim. I don't think that's the case, but I do think it's objectively more efficient.
Speaker 2:I mean, I would probably make that, generalize that concept and say, you know, learning your keyboard shortcuts for whatever editor you are using or you're forced to use, because lots of times people don't have that choice. They're like, okay, I go to this job to use, right, because lots of times people don't have that choice. They're like, okay, I go to this job, we're using this editor. Um, that is a way to make yourself faster. Again, I want to be kind of super clear that, like, in my opinion, the hard part of programming is not actually the typing of the code. But if you can get that out of your way, then you can focus on understanding the problem. You can focus on, like communicating with people. You can focus on solving the problem. You can focus on, like communicating with people. You can focus on solving the right problem in the right way.
Speaker 2:But like it'd be, like if I again back to the house analogy like I may know what I need to do to my sink to like get it to not be clogged, but if I don't have the right tools or I don't have, you know my body's not flexible enough to do it, or you know I don't have the knowledge around it's going to, it's going to cause issues around that solving that particular problem.
Speaker 2:So it's like there's like essential and non essential skills and the essential skill, I would say, of a programmer like you could be a programmer and and hunt and peck and use the mouse all the time and if you have the essential skill of knowing how to solve a problem, knowing how to communicate that problem solution and knowing how to do it in an elegant way, you're going to be better off than the programmer who is super fast at typing but gets wrapped around the axle, doesn't have the bigger picture, is focused on their small thing instead of solving the global problem. Obviously, in an ideal world you have both right, like you want to be fast with your tools, with the non-essential pieces, and be good at the essential part of programming, but you can't and you can work on both of them and they're kind of different skill sets in my mind.
Speaker 1:Yeah yeah, that's a good point. Like the typing is never the bottleneck. Um, in fact I've said many times before uh, thinking is more expensive than typing, and I usually make that. I say that as an argument for long and clear variable names, as opposed to short and cryptic ones. Um, and I might, I might make an analogy.
Speaker 1:Like you know, programmers make a lot of money, so I'm not like obsessing over grocery store prices or anything like that, because that kind of stuff doesn't really matter that much. Like it's more a matter of like, what kind of house do you choose to live in? What kind of cars do you buy? Those will make the big difference. But having said that, if I'm at the grocery store and I'm gonna buy a can of beans, um, if there's one that's 150 and there's one that's two dollars and they're the same, I'm probably gonna reach for the one that's 150 instead of two dollars, just because why would I buy the one that's more expensive? For no reason. That's a little bit how I view Vim. It's like yes, typing is never the bottleneck, but when I want to get an idea from my head onto the screen, why would I choose to pay a higher price for that instead of the lower price?
Speaker 2:That's a great way to put it. It's like in both scenarios you end up with Can of Beans. It just took a little more effort, and if you add that up over years and years, or decades and decades, then that 50 cents matters over and over and over again, which is why, again, getting expertise in your keyboard shortcuts is going to pay off long term. Yeah, I agree.
Speaker 1:Yeah, and to be fair, I probably should have chosen an example of something that costs like $100 instead of $1 or something like that. But you get the idea Totally, as long as we're talking about some of these philosophical things because I get the impression that you enjoy talking about this kind of stuff, Something I've been thinking about lately and if this is too out there we don't have to go deep into it. But some things in programming are objective, Some of them are subjective, and how do we tell which is which? And there's two layers to this question. One is actually putting things into those different categories. Like we can tell that, I don't know, using Vim is objectively faster than not using Vim. That's objective. That's one thing, the categorization. But then the deeper question which I'm more interested in is how do you make that categorization for any particular thing?
Speaker 2:faced with like choices and the meta question is can I determine if this choice has an objectively better answer or is? Is an objective question which has a definitively better answer, or is subjective? Is that the idea?
Speaker 1:yeah, exactly like. Take the variable name thing, for example. Is it an objective fact that longer, clearer variable names are better than shorter, more cryptic ones, or is that subjective? Or is it a mix of the two? And if it's a mix, how do we make a judgment of what that mix is?
Speaker 2:roughly, yeah, so I would. I would actually advocate that. I think there's very few. I think there's very few 100% objective decisions, probably in life, but like in programming, even the variable name, one that you just kind of threw out there. You know, I can think of situations. I can make up a situation where it'd actually be a bad idea, right, one might be the variable names are way too long. One might be so they actually are more confusing than a shorter name might be.
Speaker 2:Well, don't mix up the the idea of objective versus subjective, with the idea of something being like universally, always true versus having nuances, because it can have those nuances but still be objective so you're saying that you could have a question that would have a nuance, but ignoring that nuance, or, in the majority cases, you know that this is the best answer, whereas there are other ones where it's legitimately. You're never going to have a solid answer, and that's the class of problems you're talking about. Is that a fair statement?
Speaker 1:and I think you're probably right that there's almost nothing that's 100 subjective sorry, 100 objective in programming, because you can always. It never ceases to be interesting to me how you can have something that seems like a rock solid belief and yet you can find somebody who's like no, I disagree. I think you know having one letter variable names is actually. I prefer that it's like okay, you're entitled to your opinion, I can't say you're wrong, so I guess that must be subjective.
Speaker 2:Yeah, it's really tough because you'd have to know the context and the experience back to how we learn, right? Why do they feel that way and in what situation are they doing that right? Is it like a certain but that gets? Are they doing that right? Is it like a certain, but that gets back to kind of the nuance, right? I mean, I think you could say with nuance that longer variable names that convey meaning are objectively better. Like you know, there may be constraints that you exist in that require you to have shorter variable names, but if you can, you know, set those constraints aside or with even within those constraints, the best variable name is the one that conveys the most meaning. That is accurate, right, like? I feel like that is an objective question. I I I have a hard time imagining when you take the opposite of that.
Speaker 1:Some people are crazy, sure, fair, fair yeah, and actually I take that back. I think maybe this particular thing, the variable question, is objective, and I think part of the question of what makes it objective or subjective is the explanation behind it. And I've asked myself a related question of for any programming practice, how do we know if it's any good or not? And I think the answer to that is the quality of the explanation behind it, and this was another inspiration from that David Deutsch book. Behind it, and this was another inspiration from that David Deutsch book, he said something that was very interesting to me and, contrary to what I previously believed, he said that the purpose of scientific theories is not prediction but explanation. And it's a little bit nuanced because you can have a theory that perfectly predicts. It predicts a certain phenomenon, you know, you can predict that the Sun is going to come up every day, but that's not the purpose of theories. The purpose is explanation. Um, why does the sun come up every day?
Speaker 1:it's because of the way the solar system works, um, and that like totally, uh, changed the way that I look at epistemology in general.
Speaker 1:And so now, when I'm thinking about programming stuff because David Deutsch said that this not only applies to science but also, like moral philosophy, for example, there is such a thing as objective morals and it depends on the explanations behind those moral beliefs.
Speaker 1:And so for any programming practice, I think people should demand an explanation, and I think different practices have different qualities of explanation. So what is the explanation for this proposition that longer, clearer variable names are better than short, cryptic ones? I think it's because clearer names are easier to understand and therefore understanding them costs less, and if the outcomes are equal, then things that cost less are better than things that cost more. I think that's the explanation. And then, of course, to put that nuance on it, like if you have a very small loop or something like that, short names are actually easier to understand than long ones, because a long name will introduce so much noise into that area of code that the burden is actually higher than when the variable name is one letter and therefore that is easier to understand. Does that seem like the right explanation?
Speaker 2:yeah, I think that, like, the introduction of cost is is an interesting concept, and I think that that ties back to what I was going to say, which is it always has to kind of be based on reality, and so the cost is is what you're doing to tie the concept to reality.
Speaker 2:So it's an explanation of how this um, you know thing, this concept, um, works, and it's always tied back to the results, right, um.
Speaker 2:So, so, yeah, I think that makes sense, and your counter example of the loop makes total sense, because you know and I could think of other situations where it might be throwaway scripts, or another example where it doesn't make sense to do long variable names, because there the cost is not, because it's confusing, because there's too much going on, it's more like I'm never going to look at this again, and so, therefore, using the variable name of I or J doesn't matter, right, doesn't matter right, and as soon as you start to to move it towards using it again, then you want to incur that extra, that, that upfront cost, to like lower the. It's almost like there's like an upward cost or runtime cost too, right, like there's a creation cost and like a read or like an execution cost, where execution is like execution of me in my mind for another developer, me in six months or you to like, reload all that context and reload that understanding into their brain.
Speaker 1:Yeah, and again, that part is one of the things in programming that's probabilistic. You can never know how many times you're going to have to look at a piece of code again in the future. We can only make bets and we don't know whether any particular bet will be a win or a loss, but we do know which way to bet in general, and so that's the way to do it. Yeah.
Speaker 2:Well, and to tie it back to the experience conversation we had right, or even to tie it back to the experience conversation we had right, or even to tie it back to using an authorization server. Like you know, you gain experience and so then you know the better way to make those bets, and that might be using an external database instead of writing your own database or writing a test. You know having a heuristic for writing tests, so we always want to be mindful of, like, the costs and to me you've said repeatedly like you can't know the future, so it's like your best estimate of the costs is basically the best we can do um to to solve the problem in the time and the space that we have.
Speaker 1:Yeah, part of the reason why I wanted to think about this question of how do we know what's a good programming practice or not is because, sadly, I see some fairly poor practices held in high esteem in the Ruby community and in programming in general, and I don't want the argument against those things just to be. I personally don't prefer these. That's a weak argument and I also don't think a popularity contest is the way to go, because there have been many times in history where the prevailing view of something is just wrong. And so, yeah, I wonder, if one were to put a bunch of practices through the test, maybe we could try one or two just right now for fun. Is it easy to explain why they're good or not good? Can we think of another example of some programming practice?
Speaker 2:Sure, I mean, I guess immutable infrastructure is kind of a more DevOps-y practice, but it's definitely out there and people are excited about it yeah, yeah.
Speaker 1:To me that seems like a pretty clear and compelling case.
Speaker 1:Um, because things that are immutable are easier to understand than things that have state and right if you, for example, have a server that was configured manually and you want to create another identical server, you know, not just configured manually but potentially mutated at some point during its life, not only it's not just expensive to replicate that server, it's impossible because you don't know how it might have been mutated during its life. So to me that's a pretty, pretty clear one. Is there something that's maybe more controversial?
Speaker 1:sure um it's more controversial oh, here's, here's one imperative versus declarative. Sure, yeah, do you have any thoughts on that one? First of all, just like your personal opinions on a preference.
Speaker 2:And you're talking about, for like configuration language or for like just programming in general?
Speaker 1:Yeah, just in general.
Speaker 2:Sure, I mean, I think that when you are doing declarative, you're outsourcing things to whoever is reading that declarative stuff.
Speaker 2:Right, that framework, whether it's like Kubernetes or I used to write Java many years ago and, like J2E, was all about declarative stuff, and so I'd lean towards that because it's a resource thing in two ways. One is I have to spend resources to do things, um, that I might be able to outsource to this, this other framework or this other thing, um. And the second is I I'm guessing and this again is a bet that someone who is building a system that does, you know, ingest declarative statements and take systems to a certain state or does certain things, is going to have more resources than I do, and so it's a way for me to get leverage by doing that. So that's kind of my personal take on it. I guess it also depends on whether I feel like it's my special sauce or not. If it's my special sauce, then I feel like that's where I need to have more control, and so imperative might make more sense. Is that making sense?
Speaker 1:I'd be lying if I said I followed completely, but maybe, maybe I can say a certain thing and then we can advance a little bit on that. So I've always had a very hard time explaining to people what imperative and declarative are, which is maybe a sign no, it's definitely a sign that I don't have that firm of a grasp on it myself. I can look at something and I can say that's an imperative style or that's a declarative style, but it's really hard for me to articulate the difference between the two. Um, but I realized something recently that might have something to do with abstraction. So my definition of abstraction is when you replace lower level ideas with higher level ideas in order to make something easier to understand, and with imperative versus declarative. Maybe declarative is at a higher level of abstraction than imperative. And what occurred to me just now while you're talking was with imperative, you are specifying the steps and leaving it up to the reader to infer the state. Versus with direct. With declarative, you are declaring the state and abstracting away the steps.
Speaker 2:Yeah, that's a great, I mean, and you could do it at all levels, right? Like I mean, whenever someone says declarative, I think about like Kubernetes and like saying, hey, I want this many servers running at this time. But even you could make a case that Ruby itself is declarative when compared to bytecode or when compared to like assembly. Right, like you are saying, hey, I want this variable to be an instance variable and this variable to be a class variable and this variable to be local, and you're not specifying exactly how that happens on the memory stack or anything like that, right? So something can be both imperative and declarative, depending on what level you're comparing it to, because there are different levels of abstraction yeah, yeah, because abstraction can have multiple nested layers and so maybe something that's declarative at one level is imperative at another level.
Speaker 1:Yeah, okay, interesting. I'll have to chew on that some more. Um, but I've been trying for like 10 years to figure out how to explain imperative versus declarative. Um, so hopefully that explanation that I just said is accurate. Um, because if it is, then I feel like that's a a more easily graspable way of explaining it. My, my historical way of explaining it is saying that, like if you ask somebody to take two pieces of bread and some peanut butter and jelly and put them together, that's imperative and decorative is saying I want a peanut butter and jelly sandwich but, that's not quite.
Speaker 1:That doesn't illustrate it that firmly to me, because it's still like yeah, I mean they're almost like.
Speaker 2:They're almost like co-explanations, right, because I think that the first one, the one you gave to me first recently, you know, five minutes ago, is super abstract in itself of like you know a series of steps, versus like saying how you want something to be, whereas the peanut butter sandwich is something that you know anybody can get and they can understand that you might go out and buy a peanut butter sandwich, right, that might be how someone delivers a peanut butter sandwich to you.
Speaker 1:Interesting.
Speaker 2:As opposed to making it.
Speaker 2:Or they might use three pieces of bread right in a peanut butter sandwich, and so they'd still be, you know, meeting your needs of a peanut butter jelly sandwich, but they wouldn't be doing it the exact way that you want jelly sandwich, but they wouldn't be doing it the exact way that you want.
Speaker 2:Um, to tie back to the objective subjective thing, like to me, it gets back to context, but I think declarative is almost always like it feels like declarative is objectively better based on cost, except for when you need something done a certain way, in which case then you want to fall back to imperative, right? Like if I really care that I use the strawberry jam and you know one piece of bread or two pieces of bread and one is the end of it, end of the loaf, then I probably need to go imperative as opposed to give me a sandwich. So it's really kind of more your needs, but, all the things being equal, the costs feel lower for saying hey, especially with software, give me a, you know, give me this thing in a state that I desire, as opposed to telling it how to get to that state.
Speaker 1:Yeah, yeah, I think there's a very strong argument to be made that with declarative there's a lighter burden of understanding, and that's making me realize something else, which is that declarative, I think. Tell me if this seems right or wrong. Declarative code tends to be less order dependent.
Speaker 2:I think you're just relying on the thing to sort it out, right, Whatever's reading the declaration and doing the thing. That can be actually exceptionally complicated, but for you, as a dev, you're leveraging that. So I think, maybe, but like it's, it's kind of there's stuff hidden behind, hidden behind the scenes, I guess.
Speaker 2:And that actually gets to one other point. Putting complexity real quick is like you and I have all had to dig down and all your, all your listeners had to dig down and like, pass that level of abstraction right. Like, because something wasn't working the way that you thought it would. That was declarative, and um, that is again. Again, you're taking a bet to see, to trust that the thing that reads the declaration that's going to bring you that sandwich is going to do it in the way that you actually want, you've specified it enough, or that your needs are, um, flexible enough to kind of take what comes back. Sorry, I'm mixing my metaphors like crazy, but like that is a cost that you need to actually think about bearing because it's not cost free.
Speaker 2:I have a blog post called Use Managed Services, please, that I contributed to a book and I was. You know, like stuff like RDS or Heroku or things like that are fantastic for accelerating your dev. There's always that cost of you know, when that abstraction breaks down, when you don't fully understand it, because you have used that managed service well, now you need to suddenly get speed or hire somebody to get speed on that thing, but you're taking a bet that 99.9% of the time it's going to actually fulfill your needs in a cheaper, faster way that lets you get more stuff done.
Speaker 1:Yeah, I totally agree with that. And back to the back to the order dependency thing. We were talking about declarative being easier to understand than imperative. To me, good code is code that's easy to understand and change, and order dependency makes things harder to change.
Speaker 1:Because if I expose to you the specific steps of making a peanut butter and jelly sandwich and you don't know of making a peanut butter and jelly sandwich and you don't know anything about a peanut butter and jelly sandwich, you might see okay, I put a piece of bread on the plate and then I put some jelly on the sandwich. Can I do it in the other order? Can I do the jelly first and then the bread? I don't know, and so you might be like I don't want to touch this because I don't know, um, and so you might be like I don't want to touch this because I don't know what the consequences would be of any change, um, whereas if the code is not order dependent, then you can change things around with a lot more confidence.
Speaker 1:Yeah, um, okay, we're. We're well past the hour mark here, so we should probably wrap up soon. We managed to talk about FusionAuth for about five seconds before we went into wildly different directions, which is par for the course on this show before we go. Is there anywhere you want to send people to learn more about FusionAuth?
Speaker 2:yeah. So we have a free community edition you can download. If you have Docker or we have a Homebrew install, all kinds of other options, it's just fusionauthio slash download. So if you are looking to learn more about OAuth or OIDC or you're looking for a user management system and what's in the rails world doesn't suffice, or even if you have multiple apps that you all want to, you want to integrate, I think fusion health is a great fit and we also have. Last thing I'd say is if you want to learn more about authentication in general, we have a really great article section that's vendor neutral and talks about oauth and ciam and and um, you know, jots and all kinds of good stuff. So and I'll make sure to get those links to you, jason, so you can add in the show notes if you choose great well, dan thanks so much for coming on the show thank you.
Speaker 2:It was a way more philosophical discussion than I was prepared for, but it was really enjoyable. Thank you. I was prepared for it, but it was really enjoyable, thank you.