Amos: Welcome to Elixir Outlaws, the hallway track of the Elixir community.
Chris: I want this keyboard so bad.
Amos: What keyboard?
Chris: The Moonlander.
Amos: Oh, I don't. I know, like, I don't like the, a the thumb switches.
Chris: I want this keyboard. I want this keyboard so badly.
Amos: It looks pretty.
Chris: It's so expensive.
Amos: I don't, that's cheaper than my keyboard.
Chris: I mean it's relative, to, I mean, as, I don't know, a single programmer who has not dealt with RSI at some point in their life.
Chris: So ergonomics are important. And when you factor in like what your time costs and ergonomics of that, and all those things, like this is definitely a business there's like, you could qualify this as a business expense. That's a lot of money.
Amos: I tell people when they come to me and they say they're developers and they're like in college or, uh, at their first job or they're going through some bootcamp program or just somebody who wants to become a developer, I tell them, go, go buy a good ergonomic keyboard. It, it will be worth it in the long run. It might seem like an idiot thing now. And they're like, this is too expensive. And like, yeah, I don't care. Uh, I know it's a month of your rent. You can just, I promise you, if you have my wrist pain, you will be very happy.
Chris: The worst RSI I ever had, I had just been laid off from a job and I needed to find work. And so I became a consultant. That was basically how I, how I got into consulting. And it's just like pure necessity. There wasn't anybody in Chattanooga who was hiring, who I thought was really interesting. And I had a couple of contracts just fall into my lap. And so I that's, after I got laid off, I just picked those up and started working on it. But the necessity of having to contract all the time when you're just on your own, you just take all the jobs because you don't know when more jobs are coming. And even at a certain rate, I was just always trying to get more work. So at one point I was, uh, I was programming like 60 hours a week and doing it all from my, we were living in like a real small apartment at the time and doing it all from a couch with a laptop. Uh, and I got, I developed RSI so badly that sort of tried towards the end of that when I was like trying to wrap everything up and start at Carbon 5, my first week at Carbon 5, I couldn't open my left hand.
Amos: Oh, man!
Chris: To like to type.
Chris: I like legitimately could not work my first week at Carbon 5. Cause I had, I, I had like killed myself, essentially like, like destroyed my arms and hands and wrists to like, try to do all that work.
Amos: Laptop keyboards are-
Amos: They are, they're all garbage. They're too close together. So it's bad on your back. It's bad on your wrists, it's it- Yeah. They're, they're just junk. And even, even if you're not used to working on a split keyboard, I always tell people like, just get used to it. If you can keep your arms shoulder width apart, you'll be a whole lot better. And a chair pick, get a good chair, or stand.
Just, just invest a little bit of time and invest a little bit of time in taking care of all of your, you know, ergonomic situation. It's important. You know, take care of yourself out there.
Amos: And do planks every morning.
Chris: You know, you're, you're gonna, you will benefit from that. If you're especially right now and everybody's working from home and stuff, invest a little bit of time in setting up, you know, a, a place where you can go where you can just be a programmer. That's important.
Chris: You'll find you're much happier when you do that.
Amos: And you do better work when you're happy. Yeah. I, so I do-
Chris: -You deliver the most value.
Amos: I never had Perfect. Now you sound like a consultant. Um, I've never had RSI, so like I'd never had an effect on whether I could open my hands or not, but I had an effect where my wrist would just hurt like crazy when I was typing and I couldn't carry a bag of groceries, even, not even a light, but like even a bag of bread was so it like just made my wrist hurt. And it would get that way and it would get a little swollen. So that's when I said enough is enough and I bought a nice keyboard.
Chris: Yeah. I, uh, I went hard into different ergonomic keyboards for sure. And overall ergonomics.
Amos: What's your favorite?
Chris: Oh, I don't know. I don't have one that really is a favorite yet, but this one could be it. That's the thing.
Amos: It could be your favorite, looking at this thing?
Chris: This could be the, this could be my favorite.
Amos: I, I don't like the thumb keys on it because you have that overlapping one. And those are, have always been really hard for me personally, to reach. I like, have to contort my hands to reach them or use a different finger because I always hit those other buttons that are in the front row with my thumb at the same time. Um, so that's why actually, why I picked the keyboard that I do have instead of, so that one has what, four buttons with then the red one behind it? And mine has five buttons on the thumb row and there's nothing to reach across. And that is really the only difference. And it was enough for me to say, this is the one I want because I tried, I tried all kinds of stuff. Uh, Kinesis Advantage, um-
Chris: -Yeah, I've, I've looked at all of these and I've never found anything that like really looks amazing. But this looks amazing.
Amos: It, it is very pretty, is a very pretty keyboard.
Chris: It's really? Yeah. I kind of want this. I don't need this. But I do want it. It's costly. It's costly.
Amos: Can I change subjects on you?
Chris: Absolutely. Please do.
Amos: You said something earlier, whenever you were talking about this, um, you said that like the, how you got into consulting, right? So I have never worked at a product company. Uh, well, Hmm. Well, I worked for the postal service for a year, and we had a product internally, but actually I would say that's, that's one of the shorter products I've worked on. Most of the time I work, I have like a lot of my products lasted years that I worked on and I've worked on greenfield and products that were pre-existing as, as like, um, I don't know, consultant seems like a bad word, like I'm coming in and telling people what to do and tell them how to fix their problems. And there's a little bit of that, but uh, just like a team building a product is what I did most of the time. Um, how does that differ from working for a product company? Cause I won't call it- the postal service is just different from everybody. I promise you. Cause it's government and-
Amos: -Yeah, right, exactly. Yeah.
Amos: They, they do a lot of ignorant things that they will never change because it's in their union contracts. Um,
Chris: Like there's a, or there's a, there's a law about it at some level. Right? Like, you know, somebody wrote a law one time, which is why like people still use fax machines for stuff.
Amos: Yeah. You must use CVS.
Chris: Right, right. Right.
Amos: Well, why? Well, because-
Chris: -It’s literally is the law.
Amos: Yeah. We have a contract that says that you have to, and, and that contract is legal, so.
Chris: Right, right. Right.
Amos: So what, what is, what is, what is different about a product company versus being a consultant, to you?
Chris: To me? Um,
Amos: In your experiences?
Chris: Sure. Yeah. So I've done both. I was in, I did independent contracting. I've done contracting with like a company, uh, because I was at Carbon 5, and I've worked at product companies before that. And I've, I've interacted at product companies with consultants and contractors as well. So what's the main differences? One of them, I think this is sort of the most important thing to realize as a contractor is as a contractor, you're always being brought in for a very specific reason. And it's always important to remember that if the company had the capabilities to do that job on their own, you would not be there. Which inherently means that there's something missing in that company. Sometimes it's just bodies. Like you just in your staff, augmentation, you just need more people in the room for whatever reason or, or the perception is that you need more people in the room.
Chris: Sometimes it's, you are really good at this technology. We don't have those capabilities. We need you to train us or we need to rely on your skills. And I think the other one, and this is probably the most complicated, is, there's some amount of dysfunction in the company that you're being brought into. And if they didn't have that dysfunction, you wouldn't be there. But, but it's, it's really important to remember that the company, in some ways doesn't really want you there and you ha and it, because it, you are necessarily taking over, um, a piece of you, you necessarily have a lot of autonomy as a, as a contractor and you need people to buy into that autonomy and basically trust you. You need to, you need to have a way to earn that trust. I guess maybe that's a better way to say it is they inherently don't trust you or they, they inherently don't want to give you that much power as a contractor because you aren't just there forever. Right? So you have to figure out really quickly how to earn that trust and earn that autonomy. And you can do that by either just being, so well-known about a certain thing, like having so many skills about a certain thing that they can't help, but trust you, like, you've just, you have too many crucial skills.
Chris: The other is that, you know, you can solve it in a, like a real back backhanded way. You just charge a lot of money. Like if you just charge enough money, uh, um, I'm not even kidding. Like if you just charge enough money, then like you weed out anyone who wouldn't, who just would want you to do like garbage work that they don't want to do immediately, like at the door, like you're buying into this entire premise. If all of a sudden it costs you, I'm going to throw numbers out there. But if, if a consultant is costing you $300 an hour, like you don't go into that deal lightly.
Chris: You need to know what you're getting.
Amos: You don't take their min- you don't take up their time in a meeting either. You're like, we're gonna run and get in and get out.
Chris: Yeah. And the, and they unblock you because you're the most expensive person in the room. So they want you to keep working. And this is, this is the big thing that most like contractors get wrong. When they first get started is they'll take any job for any money. And I certainly made that mistake, but there's a big difference between charging $40 an hour for a job and $140 an hour for a job. And in the latter case, you are necessarily walking into a situation where people are inclined to listen to you. So you can see you gain some amount of authority simply because you charge that much money. Because you charge more money. In any case I think, but I think that's, that's really complicated. And the main thing is like, because of that relationship as a contractor, you're never really in a position to enact really, really big change.
Chris: You can change things on sort of a small scale. And like maybe your team gets a little bit faster, but even that gets complicated in big companies. Because if your team gets a little bit faster in a big company, maybe you just caused a problem. Like there's plenty of times where you can, where you might speed up a team, you might make delivery a lot faster, but then now you're like bottle-necking ops or you're bottlenecking QA, or your bott- you know what I mean? Like there's all these downstream effects that happen in like big companies like that. So it's really hard to do that because you have to have a lot of political cachet to be able to make really big sweeping changes. And that goes back to the like If you were charging $500 an hour, then, then what that means is you're being brought in specifically to revamp their, the way in which they work. And that gets back into the whole notion of like the consultant, the like kind of consultants that nobody likes, you know, that gets you back to the Bobs, right? Like nobody wants to deal with the Bobs. So in any case, I think that's a big part of it. The other big problem is that, you know, companies don't outsource by and large companies really don't outsource their core competencies that often. And all of the interesting problems lie inside the core competencies.
Amos: So that's curious to me. So why, why do companies feel that as a contractor or consultant that you're not necessarily going to be there in the long run, but an employee is. Um, I've been, because personally I've been at plenty of companies where I've watched teams completely turnover-
Amos: -while I was still there. And, and their employees were actually the ones that were less about getting work done, doing a good job. And they were less loyal than the contractors were. And this is not just me as a contractor, but like other contractors that I worked with when I was at these companies.
Chris: Right. Yeah. I don't know. I mean, it's probably not a real thing. It's probably not a fair thing. Uh, but I think there a belief and it's probably not even correct, given the nature of programmers and salaries and the benefits of changing jobs as a programmer, the cold reality is that your options are almost always better leaving. There's no, there's no real incentive to stay at any given company for very long as a programmer. I mean we're obviously different than the rest of the world that, you know, we're privileged in that way. But I just mean that there's no, there's really no tangible benefit to staying at a company unless you just like it and you're comfortable.
Amos: Right. If you like the people, you like the product, you are happy. But if there's any sort of unhappiness even a little bit, you should, you should just leave. In our job.
Chris: No. Yeah, Yeah. In, in our, in the, yeah. That's why the advice of like, you should leave your job, like only really applies to people who have an abundance of job offers and that's that the people who are in that position are pretty few and far between, but all that to say, I think the notion, you know, the notion that a contractor is going to be less reliable, I think there that that may be wrong. Uh, at the same time, it's pretty hard to fire a employees, going through the process of becoming an employee is obvious is tends to be a more arduous than just signing up for a contract. And I think it's just the nature of the thing. Like, like the view is that the people who are employed here should own it, should own the knowledge about how this business operates at like sort of a fundamental level, as opposed to giving that over to a contractor. I think not every company is like that, but certainly a lot of companies take that approach. Like I don't want to give away my core competencies because that's the thing that makes me unique as a business.
Amos: Right. And I, I try to overcome that as a, as a contractor, by I work with your team. I pair with people. I, um, cause ultimately like my goal is to work myself out of a job there.
Amos: And, and I can't do that if I'm the only one who knows X sub system.
Amos: But I, I see other, other contractors that I've, I've had contractors before. Tell me, what do you mean your contract is over? It's like, I taught someone else to do it.
Chris: Yeah, no, like I like you and I agree. Yeah. You and I agree on that. Like I don't, I think it should be the mission of most contractors to get themselves up out of a job and then go onto the next thing simply because from a business perspective, it means you're just time and materials.
Chris: And that's like a better place to be sort of financially. It's like a much easier way to manage that. It's also a way to build goodwill. I'd say because why do employees not like contractors, right? It's, it's because they take over some part of their job, you know, they didn't, they just deliver, like everyone who's ever taken over some co something built by a contractor hates it, right. And it's largely because they weren't around when any of the decisions and trade-offs got made and they might've made those same exact trade-offs and decisions, but because they weren't in the room when they got decided upon, it's like, “Oh, this stuff sucks.” And like there's no communication, all that sort of stuff. And so I agree with your philosophy of, you need to, as a contractor, you need to embed yourself with that team so that they fully are bought in on every decision that's being made. And they own it at the end of it . Because you don't want to actually walk away and have to do maintenance. That's really not the position you want to be in.
Chris: Most of the time and, uh, in my opinion-
Amos: -And but, but still be happy to come back and work on the product. If you have to, right?
Chris: Right, yeah.
Amos: Like, leave the product in such a way, and in, in capable hands that if two years from now, you're asked to come back and work on it, you know, whose hands you left it in, and then that you can come back and be happy to do so.
Chris: Right. Yeah. I made the mistake of taking retainers from certain companies when I was starting out. I will never do that again, personally, because as an independent person, I simply couldn't keep up with all of the demands with people being able to just say, drop everything. I need you to work on this.
Chris: And those can be lucrative, like stuff like that can be lucrative if you set it up correctly. But I think by and large, it goes back to the idea that you can only really focus on like one thing at a time. You can only, at least like only one project at a time, you can't split your focus between the three projects and have any sort of good design or good code come out of that. It just doesn't happen.
Amos: It's much harder to be an independent contractor because of that, because you often can't get enough work unless you're splitting your time.
Amos: Where if you, if you have like a small contracting company, then you as an individual contractor often can get a project and just work on that project full-time for at least, you know, an extended period.
Chris: I think even that is pretty tricky. Um, certainly people build successful con contracting companies that many of them exist. The downside to it is just that you don't really make money in your sleep. Your, your money is so tied to billable hours. And it's basically so tied to head count that it gets really hard to grow a business like that. I mean, you know, this better than anybody like, and it also means that you essentially have to be profitable from day one. So to really be able to float long enough to do that.
Amos: The nice thing for anybody out there who thinks that they might want to be a contractor, is that in our line of work, your startup cost is often just a laptop. You may not even need internet at your home. You can to a coffee shop and work-
Chris: -Yeah, I mean, exactly.-
Amos: -or , um whatever. So our, our startup costs can be very low in this career field, which is amazing. Like our startup costs are less than a mechanic and we make more money than most mechanics.
Chris: Right. I mean, yeah. It's, it's, it's, it's, you know, many people have said lots of things about, about software and all that, right? Like, I mean, and it is true. Like yeah, you need a laptop and then you can begin to create things. That's pretty remarkable.
Amos: So I don't know, how many have you been at product companies that were starting up?
Amos: So what, what do you think are the keys to building a successful product from the start?
Chris: You need to make it better than Excel. I mean, that's, that's basically it,. The only thing that matters is being better than Excel.
Amos: What about the people you hire?
Amos: Or the, or the culture or anything?
Chris: Eh, it doesn't matter.
Amos: How do you,-it doesn't matter? Be better than Excel
Chris: No, I‘m being super flippant, because I, I don't know, man, I don't, I'm not good at that. I'm not good at picking which companies are going to succeed and which are going to fold and what you're going to fail and which ideas are worth pursuing. And so much of it is, it really is -I don't want to say luck, but so much of it is timing.
Chris: So much of it is having the right people in the right place with the right product, with the right market fit with the right marketing. And like, that's, you know, you got to get a lot of it right. For it just to work. And I think that that's really hard, I think. Yeah. I don't know. I don't, I don't know what, obviously, if I knew what it takes to build a successful business, I could be a lot, a lot wealthier than I am. Right. You know? It's.
Amos: Yeah. And you, you might be able to see what it takes and know what it takes and not necessarily want to do that though. Cause you can live comfortably where you are.
Chris: Mine- yeah. I don't really know that I want all of the stress of running a business, personally speaking. I'm very happy to work for, we've talked about this before. I'm really happy to work for other people, retaining some of my autonomy and help them build their thing. Cause I'm bad at it. I'm bad at guessing what's going to be a good fit for people and what's not, and I'm bad at guessing how things are going to be marketed. I mean, most of what makes a company successful is marketing. Most of what makes your products successful is marketing and marketing and UX. Honestly, that's, that's most of what makes your company successful and that's, and that getting back to the idea, that's what differentiate differentiates you from Excel.
Amos: No, not knowing UX very well is the reason why, I, uh, work for other companies.
Amos: Actually, I'm pretty good at UX. I am, uh, I, I, it's more of the design aspect of like picking colors, uh, that and putting stuff in the right place. But I can tell you whenever you have way too many steps to this process and where can we pull a button out? Where can we remove those- I'm good at that part of UX. But whenever you're like, which colors should we choose for this? I'm like, I dunno, which is what makes it pretty, right? Cause you, you that's part of the UX is it's gotta be pretty and it's got to work well.
Chris: Yeah. And I, yeah, I don't even know enough about all of it. I'm so unintelligent. I'm so unlearned about all of that to even to even know kind of where to start I'm bad at it. And I rely on people who are good at it and care about it, to do that part of it for me, because it's just, at the end of the day, I'm happy to rely on those people because I don't, that's not what I'm striving to get better at. That's not the kind of stuff I am working on getting better at and for my own personal career, it just isn't. So I I'm happy to delegate that work, but yeah, but, but in a big sense of what does it take to build a successful company, man? Like if you, you know, it's like, you just need to read the two books, everything they, they teach you at Harvard business school and everything they don't teach at Harvard business school. And then you'll have the sum total of the world's knowledge about how to run a business. I don't know. I don't know what it takes. I don't know that anybody really knows what it takes on a really on a really, really big level. I think there's a lot of really good ideas and smart business people out there. In terms of building something that's novel that changes the way people think about a problem, I think that is largely timing and marketing. So, that's my, that's my feeling on it. I do think that most startups grow too quickly. Like, you'd be shocked what you can get done with three people. Three people's kind of the maximum amount of people that can share a vision without having to really talk about it all the time. It's like the three, like three people is sort of that. Yeah. That's, that's, uh, that's more or less when you can just, that's where it stops, where the just you can have a conversation about what it is that you're trying to build and everybody can kind of get it and you can draw it on a whiteboard and everybody would like, get it. Any more than, four people that already breaks down, you can't do it anymore.
Amos: Well, and I, the, I want to go back to, you said, you said going too fast and that, that as a, as a consultant and working with a lot of startups too, that is what I see. They, they call me in, because they're, they're saying we're hitting a wall and I get there and I'm like, well, you tried to do too much too quickly. Uh, and your whole system is held together with duct tape and bailing wire. So when you, you wouldn't build your house that way. So let's, let's fill this, like you would your house, right.
Chris: You wouldn't download a car, you, you wouldn't build your house that way. It made me think of-
Amos: -Yeah. Like, but yeah, I agree. Well, quality of your backend code, it really hurts your long-term growth. If you try to cut corners and, you know, just hold the thing together with smoke and mirrors.
Chris: Yeah. I think so. Maybe, I don't know.
Chris: I like to think that, but I don't know that it's true. At some point it matters. Sure. But-
Amos: -Well, that's when your competitor beats you out.
Chris: Right. But often I think what happens is that your competitor beats you because they just do a lot less than you, but they do one thing better.
Amos: They, they found the thing, the thing about your product that everybody wants and then they make it better.
Chris: Yeah, I think that's really what it comes down to. I'm not sure that the quality of anything matters. I'd like to believe that it does. I think at a certain scale, it matters. And let's be clear what I'm talking specifically about. If you want to build a product that achieves, uh, that what's the right way to say it? If you're in early stages, I think it probably doesn't matter at all. Like quality doesn't matter at all. The only thing that matters is, will people pay money for this? And cause here's, here's the thing, here's the thing, startups, here's a novel idea. You should build a thing and then charge people money for it. And then if you do that, your company might make money. It's a novel idea. It's a, it's a contrarian opinion towards the normal Silicon Valley approach to things. But if you just build a thing that you didn't charge people money for it, that'll probably tend to work out for, you know-
Amos: -A lot of products out there have a free tier. And I think, I think that's a bad choice.
Chris: Yeah. I don't know. I just eat.
Amos: You almost never know if people will pay for it, if you have a free tier for a long time.
Chris: And that's the thing, like if you, if you, the only thing that matters when you're starting a new product is will people pay money for this? And you can actually determine that without building anything. Like I've definitely worked on contracts when I was at Carbon 5, that where literally the entire thing was concierge, like behind the scenes. There was no backend code. It was like a Squarespace site and it went and then like the form went into like a Google sheet and then like human beings just did it.
Amos: Just built it for you.
Chris: They just did it by hand. I'm, I'm not even kidding. And that was enough to figure out if they could actually build a real product around it.
Amos: That's a smart way to start.
Chris: I mean, not that doesn't work for everything. Obviously if you're building, if you're building a technology company, obviously something has to exist. But I don't know. I think you can away with a lot. I think you can get away with a lot less stuff. I'll say it that way. I also think you can get away with a total lack of quality up to a point. I think that's just the harsh reality of it. It's not fun to talk about that. It's not exciting. And it doesn't make me feel good as somebody who kind of cares about it. But I think up to a point, it doesn't matter.
Amos: Well, I think what kills you there again is your competitors. If you can get away with low quality, when you are one of few in the field and then you need one competitor could come in and say, Oh, I can do that and to do a quality job.
Chris: We should define what we mean by low quality. What are the low quality mean to you?
Amos: Regular bugs, bugs that come back, constant, new bugs, bad UX, but mainly like, like bugs where, you know, data's wrong. Errors are popping up all the time. Things are crashing and, and it's sad. I've seen companies where 50% of the requests that come in fail and you're like, half of your clients can't get to your website. Like can't use your service, whatever it is, half the people coming to it can't even use it. And whenever you are spending more money on your customer service department that's fielding phone calls than you are on your development team. And you, if you, you are watching customer service calls come in. And that that rate at which they come in is increasing, you probably have a quality problem, and you will have a competitor outpace you.
Chris: So I think that's the important thing. And that's the guy that's kind of the heart of it, which is that for me, everything is about ha retaining the ability to change. And that I think never, that never changes. That is, should always be the goal at any level of the system. You should always retain the ability to change. So what does that look like? Well, on a small scale, when you're first getting started, it means you have no idea what the product fit is going to be yet. If you just like throw something out there and start charging money for it, you have no idea if anyone's going to be willing to pay that money. And so when you learn what it is that people like, what's keeping people from paying you money, you then need to change and remove those barriers. You need to make it so people can pay you money.
Chris: And in order to do that, you necessarily have to change things about your application. If you've built your system in such a way that you can't change, now you're done. Now, that's when you get outpaced and anything that gets in your way of being able to change, whether it's bugs that are taking up your time, whether it's poor design and coupling, which is really the, the main coupling is the, is the biggest culprit of this. That's what's going to eat your lunch
Amos: On the longer that the longer that you live on top of that poorly designed system, the harder it is to go back and fix it too, and to make it so that you can change, right. Especially when that system is full of bugs on top of it. And every bug you fix just creates a new one somewhere else, because one thing was relying on that bug. But the other thing is not, this gets back into like your thing about changing code, right? And refactoring. But at some point you're like, well, this one piece is relying on this broken piece, but this other piece, if that remains broken now loses 5,000 records an hour. Well, that's probably a big problem. So then how do you, how do you deal with that? And when the more complex the system is, the harder that is,
Chris: I completely agree. And, and that, that is a constant. The need to be able to change the system is a constant. And that happens for new products and really well-established products. And so to me, when I talk about things like quality and like certain design patterns and those sorts of those sorts of goals, that's why I don't care about things like the format. You know, it's why I don't care about these trivialities, uh, that of programmers. And that's why I don't care about all the rules that people write about. You should pattern match on the struck type with, and, you know, lift all the keys out in the function heads so that you can use them inside. You shouldn't use like the dot syntax or you should write phone. It's like none of that matters absolutely. A hundred percent. None of that matters in the big, like in a, in a really, really big picture sense.
Chris: It matters in it as much as when you do that, you're creating coupling and you don't actually want to do that. So good job, but it doesn't matter. The only thing that matters is whether or not in terms of gauging quality is how easy it is to change the underlying, the underlying system. How easy is it to take it apart and put it back together in other ways. And it's also why I think contexts are a bad idea. It's like creating system, creating context, such that when I have this specific request that comes into this end point, or maybe not context, but I, why I think like the MVC structure, and then the context part that falls out of that is bad because you, you have you get these requests that come in, I'm going to do something with it. I'm going to put all this other logic over here, but now none of that logic is reusable.
Chris: It's like you jam all your repo calls and your queries and whatever into this other function. And like, now you can't do anything new with it. Now you can't, in order to take it apart, you have to take it apart in the five places you tried to reuse that one context function. And that, that kills you long-term. That coupling kills you because too many things are relying on it. So it almost certainly has to change at the call site. Same with errors. It's like, it's why I don't like the fallback handler and Phoenix. Your errors matter and changing the errors matter. And you don't want to go to a different module and change errors generically for everybody. You want to just do that at the call site, in place, because that's where it matters. And I think those things are conveniences but aren't leading you towards good design patterns. They're not leading you towards design patterns that allow you to change the system down the line.
Amos: Do you, do you think that putting the, the air handler up there was trying to decouple errors from, from, the call site?
Chris: I think it was, I don't know, I'm not going to speculate on what the reasons were for adding it. And I think,
Amos: I know I picked out one example there, but I didn't think-
Chris: -No, no. I mean, I think all that sort of stuff is trying to drive people towards a way to design systems that is theoretically reusable and theoretically split up. But I think it's all, I think it's all based on this premise on this sort of flawed premise. I think it's based on this like Cousin Robert view of the world where single line functions are really good and, you know, objects with a single responsibility are really good. Like, I don't know, like I just don't buy that stuff. I don't buy that that's a good design and I don't buy that that design is easier to change in the future and easier to compose in the future. I I've never seen that be true. I've never seen creating 30 objects for every single different controller action lead you to a place of good design. I just, I've never seen it work out that way, after a decade of programming.
Amos: Right. I agree with that.
Chris: And I think it's, I think it's all wrong. I think it's built on a flawed premise. I think MVC is built on a flawed premise. And I think if what you want to do is enable your, the ability to change. You have to really step back and think about what it is you're really doing. And how do you compose functions together in such a way that those functions are reusable, on their own, and can be changed where it matters, which is at the call site, everywhere.
Amos: Do you? Hmm. I'm trying to formulate this in my head. Do you think that there, but what are the things that you find that are reusable from system to system? Is there anything that like, uh, I dunno, I want to, I'm going to use the word pattern here, but not necessarily pattern, but are there things that you say yes, that, that does a good job of decoupling the system and everything that I've ever worked on or most things that I work on? Um, cause I think that's really, the goal is to come up with something that allows people to recognize coupling and pull it apart or places to do it.
Chris: Uh, the thing that I always, the biggest thing that I always get push back on, but it's the thing that I have found to be the most useful, is lifting everything in like lifting all the composition into a single place, if that makes sense. So in your traditional Phoenix application, that would mean putting a lot more stuff together in the controller. Having big controller actions. That has enabled me in the past and I, and I always get pushed back on it. Everybody always tells me I'm wrong. And then I change it because that's what the team wants to do. And then a month later we regret that decision. That lifting more things like inverting control, essentially inverting control back to the call site is the best thing you can do for- and composing things, is the best thing you can do, if what you want to do is enable people to change stuff in the future. Bar none.
Amos: My head is swimming now. I'm trying to like picture all of this. So, and I'm trying to think like, if, if I, if I agree or not, um-
Chris: -Which is fine.
Amos: Well, no, I'm I'm-
Chris: -You can not agree.
Amos: I know. I know. And, and I'm trying to think back through all the projects that I worked on too, and which ones worked really well and could change easily and which ones didn't and if they matched that, that pattern of bringing things up. Cause I I'm also like, also don't want too much in any function because I think in, in my experience that becomes hard to follow and hard to change too. So, so there's this fight in me that says, how can we, how can we shrink this thing? Um, and I think a lot of mine ends up breaking along the lines of concepts or communication. Like what can I do to make this code communicate what it's doing is far more important than how can I make this smaller, but often those, those are kind of together.
Chris: Okay. So let me make it, let me make this more concrete. So you generic generic Phoenix app.
Chris: You've got some controller, its going to get users. I don't know, whatever. I wouldn't necessarily call all of the Ecto repo query functions in the controller. I wouldn't be afraid to do that either, if it was simple, or rather if there was, if it was generic, like if it was just like one or two things, basically, typically what I would do is have functions on, I mean also caveat with, I don't use contexts. So I would just have a user module that defines like that schema. And then I would say, and then I have helper functions on that user module that can be used to compose Ecto queries. So you might say users dot all or something like that, or user dot all or user dot fine by or something like that.
Chris: And then you create you that just returns an Ecto query fragment and all those just become functions that you can then compose together. So that gives you your description of like, what kind of users are you going to find? And all those I attempt to remain pure, in the sense of they're just returning query fragments. And then I would just call repo directly, like in the controller, because again, you're just composing stuff and then you, and then you can do something with the errors because the errors that come back out of some context, they don't mean anything. In context of what do you want to do? What is the color care about? Meaning what is the user who initiated this request care about, or the API who initiated this request care about? And those errors matter. And they matter in that specific call site, they matter in that specific controller actions, they aren't generic. And you can't do any sort of generic thing with it because if that fails, maybe what I want to do is make a service call to a downstream thing, or go look in a Redis cache for a fallback, or I want to like put an error message into, uh, some sort of Kafka queue so I can like diagnose it later. I don't know. You want to do stuff with those errors. And so how, like there, isn't a generic way to talk about them. You want to turn them into something that is useful. And the other thing is that you want to turn them into something useful in a reusable changeable way, because down the line that might, that that goal might change, but it only changes at the call site. It doesn't change for the entire app. You don't want to change it for everyone. You want to change it there.
Amos: I am a hundred percent on board with you with errors. A hundred percent. Because I often see even, even very similar end points need to have very different ways to handle the exact same error. Where I don't know, I feel like, I feel like this is a little bit of a context thing, but like if I have user, right, that is the object, that object and the thing that knows how to build up queries. Right? And, and I might, I would still create, uh, an admin module maybe that knows how to get admin users. It probably uses user still. And I let the errors float up from user. And I feel like, I feel like that's the context thing. So to me, that's what a context is, is, is I have very specific things for admin. So I will create a module for admin, but again, I don't necessarily go create that module just because. If I have an end point that can just go straight to user because it's super simple, I probably will.
Chris: I think it depends on what you're trying to do. Any, any layer in the system that you create has to fully encapsulate the complexity of the layers below it. If it does not do that, that layer should not exist. So that's like, let's start with that as the premise.
Amos: So if I have admin that speaks to user and there's an error that comes out of user admin needs to encapsulate that error somehow.
Chris: Well, and I should never know what's beneath, as the caller, I should never know what's beneath admin. Or else the layer does not make sense. The layer is useless.
Amos: If you had a user struct, would you then wrap that or change it into an admin struck to pass up out of admin, if you decided to put an admin in?
Chris: I- it depends. But for instance, if you leak the idea that Ecto lives below this thing, that layer is useless, the interface can't, necessarily can't be Ecto.
Amos: Well, doesn't, doesn't user link that already?
Chris: Not necessarily. Cause because, because a user struct is just a map, it's just a map of stuff.
Amos: Well, but you're returning queries from like user dot, all that are usable and then passing those to repo.
Chris: Right. But in that case, the caller knows about all of that. Does that make sense? Like, you're dealing directly with the thing.
Amos: So what if-
Chris: -You're simply giving the thing a name, but the difference is that if you create a boundary in your system, like for instance, admin, and then you proceed to leak all the internals out of it, it hasn't bought you anything. Because by creating that boundary in your system, you, you have to hide- the only reason a boundary exists is to hide complexity.
Chris: Right. So if I have to care about the internals, if I have to touch the internals of the thing, then all the we've added is indirection-
Amos: -I guess w- where-
Chris: -And a name, around a thing, which doesn't buy you anything.
Amos: So, so for me, I might still have admin return queries. It's just that they're very specific to an admin. Like maybe the admin's queries don't don't need to check individual permissions or, or they pull back every user in the whole system, instead of just the ones that match their group ID or something like that. And then that's where, that's why I would create that. But it's, it's a facade, it's a name on top of a set of functions, but it's, you're still getting users out of it at the end of the day, I guess. So, so that's what my module would be for is just grouping a little bit of logic so that every controller that deals with admin don't need to then say admin true on, on their stuff or whatever they would need to.
Chris: I mean well, but. So sure. I buy, I buy that. Um, and I, and I think having functions, stateless functions like that, that can compose is a really good idea. And I wouldn't balk at that design. I would still, I think where it starts to fall apart is when you start dealing with side effects, and the side effects, I think you want to elevate, you want to invert control, like the caller wants to deal with the side effects directly. And that's, that's really where the context thing starts to fall apart. The only argument I would make then when it's kind of the thing that you said, which is, I don't want every controller action in this to have to call, uh, to, you know, to, to, to pipe everything into user dot admins only or whatever.
Chris: Well, you only have to do that because of MVC. Like you only have to do that because of, because controllers are a thing and because discreet actions are a thing. That's super worth noting, you only have to do that because your entire application is made up of these discreet parts that are split up in that way. There's no reason it has to be. There's no reason that you couldn't just say for all of these routes, as a function, compose that with the only get admin users function. Done.
Amos: I don't even think I know what that would look like. I want to know.
Chris: Yeah. it's just a- it's, I mean, you could, in theory, just have, I mean, it goes back to this idea that a request is just a map, a request is just a map with stuff in it. And if you set aside all of this nonsense about rest and controller actions and resources and crud and all this junk, all this junk, then what you're left with is a function that takes a request and returns a response. Or a series of functions that take a request and return a response. And that can just be modeled as functions. And so you could have a function that just says if the route is slash admin slash users transform that request into a query that, and start composing together other stuff with that query. And the query starts with a select some stuff from users where user dot admin equals true. Like that could just be function composition. So, I mean, I, this is kind of why I come back to this idea that I think these layers are pushing us in design to design patterns that are actually sort of net worse, then if you were to just compose functions together. And this is why I continually talk about sort of inverting the control back, like you want to be able to invert control for all your side effects back to the call site. So yeah. So if you have a, uh, a module that is admin users or admin dot user or whatever, or admin, and you get, you know, find users, whatever, whatever it is, and it just returns you Ecto fragments, that's fine. That's that is actually useful. Where it all starts to break down is when you do it, the side effects and you want to be able to control those directly at the call site. And model those correctly and compose those with other functions. I've never been upset doing that. I've always regretted trying to hide side effects within some other context module thing, and then compose it because the truth is that it doesn't compose. The cold hard reality is that it does not compose, uh, at least in Elixir systems because we don't have good ways to talk about that composition. What it amounts to is a series of imperative steps, none of which truly compose together.
Amos: Right. Yeah. It's hard to compose anything that's imperative together really. Once you're at that instruction level-
Chris: -Right? And so if you invert that control back to the caller and you make the caller deal with the ramifications of the side effects, it's already doing it anyway. It's just doing it through a bunch of layers. So just like do it in place. And when you do that, now, the controller is free to change. Like the one action can change. Other actions can change. Other actions can reuse all those same fundamental bits, but decide how they want to handle certain scenarios. And that empowers you to stay agile and to change your, the direction when you're building a system. Building all these layers, that does nothing for your ability to change. It does nothing for your ability to adapt to new information. And it actively, it is not only that it doesn't help you, it actively hurts you in your ability to continue iterating and finding better ways to build systems. Or to find a better way to serve your users or to build a better product. All of that stuff gets in your way. And valuing the ability to change above all else is, is like, I dunno, that's it. That's like, it for me. The flexibility and being able to just change and direction is the most key thing to me.
Amos: I agree. And I think a lot of the things that people are doing, MVC stuff like that is, is trying to, to get there, but has some, some flaws in, in, in it the way it's set up. So now I'm trying to think about composing everything at that top level like you're talking about it and what that looks like. And
Chris: Yeah, and I don't think it's that complicated. It's like, you know, have functions that you can compose together and then pipe to pipe into, to things that do side effects. G to G,
Amos: Right? So build up, build up the things you need to get the data, type them into something that gets the data, then do a bunch of compose, a bunch of things together that process the data and then pipe that into something that sends the results back.
Chris: Right. Exactly. And if you do that in some other boundary, I mean, if you here's, the thing is as you build the system long enough and you realize actually, yeah, there's this sort of fundamental set of side effects that we do all the time, and we need to do those. And we want to like, encapsulate that complexity, so we don't deal with the underlying bits of it anymore. Totally reasonable. That makes a lot of sense. Don't violate that by then, like returning a bunch of Ecto change sets out of the thing, because you've fundamentally not encapsulated anything at that point.
Amos: So at that point, what do you return out of it?
Chris: Well, I mean, you have to turn it into, you have to treat it like it's an actual library. Like you have to treat it like it's an actual fundamental thing. And I don't think your inner, like the benefit of that level of encapsulation, like for instance, if you have admin and you put all the side effects for fetching users in your admin module, it should either return you in a meaningful error that makes sense for that function call, or it should return you the user struct or map or whatever. And if it doesn't and if it returns, the problem is, is the only reason to do that is to hide the fact that you're going to a database at all.
Chris: So that your users never care. So if you all of a sudden decided, actually we're going to build the user microservice and extract that, and then I'm gonna start making, you know, RPC calls or whatever to go get users that your user doesn't care. But if you're leaking, Ecto out all over the place anyway, well, you can't do that. You still have to change all the call sites, but you've failed to encapsulate the inner workings of the thing, at which point, like, you've not bought yourself anything but indirection, like you have not bought absolutely anything.
Amos: And if you wrap every single error separately and differently, you haven't bought anything either because you have the same breadth of interface up above as you did below.
Amos: So like yeah. Shrink your interface. The only reason to encapsulate is to shrink an interface and hide and or hide something
Chris: You want to hide complexity. Yeah.
Amos: If you're hiding, you should be shrinking. Right. So,
Amos: So if you can say, I only need one type of error to come out of here because none of the others matter to me then it's probably worth wrapping. Maybe.
Chris: Right, if, but again, like that has to become your interface. Like you have to, you have to have a well-defined interface and you don't want to leak the internals of the thing out again, that's a bad API.
Amos: So when I see this out in the real world, cause I see it a lot, that original design of that and the thought about what you're shrinking and what you're doing, isn't well thought out. And so then later you're like, Oh, I do need this error. Oh. And so you add it. Instead of wrapping that one error, you pull it out separately and then you do that with another one. You do that with another one. And before you know it, you have, you know, three quarters of the errors that could come out of, out of Ecto up at the top, just rewrapped under a different name. Now you did shrink the interface a little bit, but if you had thought more, you might've completely written it in a very different matter.
Chris: Realistically, maybe you just didn't need that API at all. Maybe you didn't actually need that boundary. Maybe that boundary doesn't buy you anything it's only worth. I mean, complexity is a function for any given thing. Complexity is a function of its innate difficulty and also how often you have to interact with it. And if you don't need to interact with the thing that often, it's probably not worth encapsulating it. If you have to interact with a thing all the time, then it's worth encapsulating.
Amos: Like if you've got one call site, it probably doesn't matter.
Chris: Yeah. And that's the thing is like, if you've built a system long enough that you've gotten to that point where you're like, this is a fundamental thing that needs to happen in our application. Well then, yeah. Start to try to hide that, that complexity from people. If you're not there yet, don't do that. Like don't bother because all you're doing is making it harder for you to change things in the future. Especially if you don't get that boundary right. And most of the time you're not going to get boundary right by just going for it the first time.
Chris: You, you really want to wait until you have about three things, three disparate uses of that same fundamental thing. And then you can start to extract it and say, now how do we encapsulate this notion? How do we encapsulate this idea? This, this layer of complexity-
Amos: -And that probably takes more than just you. You should maybe be getting your team together to have a discussion about it whenever you want to do that.
Chris: Right. Well, and it necessarily means that you need to support a lot of disparate features, you know? And, and by that point you should have a really good grasp on what sort of the core thing that your application does. Don't rush to do that stuff.
Chris: Certainly have helper functions that compose Ecto query fragments together. Have named functions. Write more functions and compose them together. Those are all good ideas, but don't rush off to hide side-effects behind something, but behind some essentially facade thing, just cause. It's not buying you anything except more trouble. I don't know. I get pushed back. Every company I've ever worked at. Cause I always advocate for this. We always don't do it. We always wish we had done it. So that's been my experience with it.
Amos: Yep. Alright. You got me thinking.
Chris: Yeah. That's what I do. That's what I mean. I sharpen you like a knife.
Amos: That's the goal. That's the goal. Always be sharp.
Chris: Stay sharp.
Amos: San Diego? Uh we're over an hour. Yeah. Um, I'm hungry.
Chris: We've talked a lot about this.
Amos: Yes. And I think it goes back to our startup conversation or consultant conversation. All of that. I think it's all interconnected here. So-
Chris: -There's a grand unified field theory about this. We will invent it later.
Amos: We're really close. Like, like physicists in the thirties and forties. We are so close to solving all computer science.
Chris: Right. We're we're we're right on the precipice of greatness.
Amos: Nothing else to solve after this one. Last thing. Cool. All right, sir. Thank you. I'm going to go get some food.
Chris: Alright. Go eat.
Amos: Maybe do some interviews today.
Chris: Good luck.
Amos: Alright. Have a good one later. Thanks. Bye.