Summary
In this episode, we interview Trevor Ewen about his approach to software development, including the use of a functional core and imperative shell. He shares his experiences and insights on how to balance simplicity and complexity in software development.
Detailed Notes
Trevor Ewen is a software developer with a passion for creating reliable and efficient software. He shares his approach to software development, which emphasizes the importance of having a standard approach, using a functional core and imperative shell, and focusing on abstraction and testing. He explains the benefits of using a functional core and imperative shell, including improved code quality and reduced maintenance costs. However, he also acknowledges the challenges of implementing this approach, such as the need for careful planning and testing. Trevor also discusses the importance of abstraction in software development, explaining that it allows developers to focus on the core functionality of their software without getting bogged down in details. He shares his experiences with testing and code quality, emphasizing the importance of having a robust testing framework and regular code reviews. Throughout the episode, Trevor provides insightful and practical advice for developers looking to improve their skills and create better software.
Highlights
- The importance of having a standard approach to software development
- The benefits of using a functional core and imperative shell
- The challenges of implementing a functional core and imperative shell
- The value of abstraction in software development
- The importance of testing and code quality
Key Takeaways
- The importance of having a standard approach to software development
- The benefits of using a functional core and imperative shell
- The challenges of implementing a functional core and imperative shell
- The value of abstraction in software development
- The importance of testing and code quality
Practical Lessons
- Use a functional core and imperative shell to improve code quality and reduce maintenance costs
- Focus on abstraction to simplify software development and improve maintainability
- Implement a robust testing framework to ensure code quality and reliability
- Regularly review and refactor code to maintain a high level of quality
- Consider using open-source libraries and frameworks to simplify development
Strong Lines
- The importance of having a standard approach to software development
- The benefits of using a functional core and imperative shell
- The challenges of implementing a functional core and imperative shell
- The value of abstraction in software development
- The importance of testing and code quality
Blog Post Angles
- The importance of having a standard approach to software development
- The benefits of using a functional core and imperative shell
- The challenges of implementing a functional core and imperative shell
- The value of abstraction in software development
- The importance of testing and code quality
Keywords
- Software development
- Functional core and imperative shell
- Abstraction
- Testing and code quality
Transcript Text
This is Building Better Developers, the Develop-a-Noor podcast. We will accomplish our goals through sharing experience, improving tech skills, increasing business knowledge, and embracing life. Let's dive into the next episode. Well, hello and welcome back. We are into part four of our series of interviews with Trevor Ewen. This is in the middle of, or actually at the beginning of, a season of interviews. We're going to go out and interview a couple different people through the next several episodes, probably dozens of episodes. Most of them will be split up like this. We'll do multi-parters, trying to keep it roughly where we're at in the past, 15, 20 minute episodes. And so far, so good. In this last one, we really sort of continue from part three as we talk about extending software using libraries and frameworks and some of the challenges that can be involved with those. And sort of the how-to, not really specifically, but some things to avoid or to look out for when you do that, whether you are building your own library, whether you are using a library or even when you're introduced to one is how it relates to the core, whatever it is, language or application. So this one, we're going to sort of pick up right where we left off in the prior episode and then we'll swing back around. We'll wrap this up. But for now, we'll go ahead and dive right into it because it is a little bit longer than the prior ones. And here we go with Trevor. So a detour back to somewhere originally was what originally got me wanting to talk to you about is he mentioned, which actually this really goes back to some of the work you've done. We're talking about some of the integrations and things like that. There's a whole idea of a functional core and imperative shell. And this in particular has been not using those terms necessarily, but this has been one of those problems that I've struggled, I don't know if it's struggle with, but definitely have banged my head against a couple of times. And particularly in recent years is there's so particularly as we've gotten into the web world and there's so many visual things, but there's still a lot of stuff, a lot of software that's not and figuring out how to work within and test and sort of show off in those environments in a way. This is where he said you've used this in several places to some extent. So that's where I wanted to sort of see how you've approached it and how you've maybe built it in maybe from the start and how it's turned out. And particularly if you've got any warnings or great successes, the kinds of things where you say, hey, you always want to do this or you never want to do that, those kinds of things. Sure, sure. I am trying to rid myself of as much dogma as possible in the programming world because I've seen more than a few people be bit by that one. And I think, as you know, the wars over different styles and different frameworks and different tools can get semi-religious for some people too. So one of the things that I try and say is this is an approach that's worked for us and here's why it's worked. And the why is because we are willing to accept several of the trade-offs that come with that approach. And of course, the negative trade-offs. Everyone wants the positives. So, you know, if this approach is really good and fast and easy to hire developers, no one's going to complain about that. But the stuff they're going to complain about is the negatives. So talking about a little bit about this, this is one guiding principle we have, but I'm going to back out just a little bit and zoom the camera out, talk a little bit about the way we think about running our business. So we are working a lot with non-technical buyers, right, in small to medium-sized businesses. As I said before, usually it's a buyer whose product is not technology in and of itself. They're selling something else. We work with law firms, solar power companies, insurers, a sustainable LED lighting installer, just to give you an idea of different kinds of companies that is not really delivering technology at the end of the line, but has a lot of internal technical needs. And the big thing these users want is they want stability, reliability, and price, right? And they are not overly concerned about tools and tech. As a matter of fact, they want to hand that entirely over to us. And that's a big part of our model, is that we're going to own all those decisions. So having been an on-site contractor before, I've worked in several major finance institutions as well as HBO for a period of time. That's a totally different kind of engagement because you go in, you work by the hour with their team, and they are still making technical decisions and you're helping them implement them. And one of the things I notice is just small and medium businesses, our customers just don't really care about that, right? So they want us to own the technology and the technical solution. So we do that. And as a result, we have a pretty standard way we develop our software. As a matter of fact, I'm trying to standardize it so much that all the projects are exactly the same in terms of framework and setup. And this is not in a bid to stifle creativity. It's not in a bid to stifle a lot of the cool ideas our developers have. As a matter of fact, the developers we work with tend to push us forward because they'll introduce new ideas and patterns to the code base. And then slowly we'll just adapt that and say, okay, that's actually an official pattern at this point. And the reason we want to have that is we want to make it really easy to switch people from project to project and get a lot of stuff out the door. Because once again, we're dealing with stability, reliability, and price. And the way to get stability and reliability up is have things work pretty similarly. So we tend to know where the issues come from. We can build around those. We can work defensively. We can also build tools that just eliminate problems altogether. Right? Like we never have to figure out how to use our logging system ever again, because it's the same logging system for everything. It just works out of the box. And that's been a process of trying to develop the approach that allows us to be very high reliability but still high function. So now we can zoom down into where we got the functional core and imperative shell. And a lot of what we were seeing was the functional push in a lot of web software over the last few years. I attribute a lot of this to changing taste, but also the fact that functional programming is of big interest to a lot of people, given some of the more academic languages they were learning that were relying on it, like Clojure and Haskell. I think JavaScript works well with functional programming styles, because frankly, I think the initial versions of JavaScript, older versions, pre-typed script, just didn't really do classes very well. It was kind of confusing, the prototype interface and everything. So it lent itself well to functional programming. But then I saw data management patterns be very, very complicated at the top end for functional programming. So I really liked what I saw going on close to where the action is happening. But at the controller level of an application or manager, whatever you want to call it, all of a sudden I found people were jumping through a lot of hoops to do it. So that got us to functional core and imperative shell. It's something we've implemented a lot of on our platforms, which are just not the most amazing and most sexy platforms you've ever seen, but they're actually extremely reliable. It's stuff that all my developers know how to do and have pretty good confidence around. Fully typed script, React-based frontends, typed script, Node.js backends, RESTful services, haven't really found a big reason to integrate GraphQL just yet. Trying to do functional core and imperative shell. So there's management and a lot of more OO type processes happening at the top level, usually of the React application. And down at the lower levels, at the utility levels or helpers, everything is very functional. Trying to commit to some kind of immutability and just functions doing work that does not alter state. And I think the community has moved around this a lot. The React core team is trying to make the framework as functionally oriented as possible. So this has been easy for us because we're mostly just adopting stuff that's straight down the center. And the very last thing I'll say, and what is a very long blurb that you might end up wanting to split up, but we try to use the community standards as much as possible. So I have pumped the brakes a bit on introducing tons and tons of third parties into our codebase. Obviously, we use third party libraries for the things they're really good at, especially when someone's done an implementation that would take us a lot of time to do. But we've started to move away from some of the helper methods and tools that just replicate what's already available natively in JavaScript and now TypeScript more. And part of that is just because we are trying to deal less with the changing taste of the community and have the code be right down the center. So I'll stop there for a moment because that was a long bit. Let's ask some questions about it. I guess the first one is, but really it's like, how do you manage size and complexity of those functions? Do you have some rules there to sort of allow it? Do the developers sort of figure it out? Or is there maybe some rules of thumb that you've worked to find that those are the best ways to figure out essentially the granularity of functions that you're building at that core? This is an incredibly dumb rule, but it's actually done a lot for us. I'll still say it. One thing we have on all of our linters is we're just limiting files to 400 lines. And I'm doing some contributions on a Python project right now where apparently every file in a Python project is 8,000 lines long. So that's a little surprising for me. But that's been a really good thing is just to try and make people figure out, OK, I've got to structure this differently. I've got to maybe spread some of this logic across multiple places. I actually don't, and this is probably somewhat heretical, but we can talk about it. That's a podcast for a little good heresy every now and then. But I don't even mind a little bit of repetition in the code, particularly if we're separating out where different things are happening. Obviously I want to do something like number formatting, like really generic utilities. Obviously we shouldn't be replicating that. But if we say have two utilities that work in different parts of the application end up producing fairly similar results, I don't mind that stuff being separated out as well and tested separately. And part of that is just because you're lowering the footprint of super bespoke business logic type functions. And so you're saying stuff that's really observable, testable, easy to replicate across spaces, say currency formatting or something like that, we want to centralize all that kind of stuff. And so if we're going to go down to business logic side of it, I also want developers to have pretty independent leaves that they're operating on. And so if they end up replicating some functionality here and there, that's fine as well. And I think I've learned a lot from them. I mean, I think that's the ultimate lesson in organizational humility is if you think you know the whole architecture, you probably don't. And you're going to have some skilled developers who are able to better inform it. And I just want to make sure that it hits up to a couple benchmarks. I don't want to presume that I know everything that they're going to try and do, but I want to make sure, OK, what kind of new problems is this introducing? How testable is it? Do I understand it when I read it? Basic stuff like that. It's actually sort of funny because most of the places I've run into have something very similar to that. It's just sort of a very, almost random how they limit some of those things to size and complexity and things like that, which is often it is things like you can only have 50 lines of code in a function or you can only have an 8 kilobytes size file or some things like that, which to some extent does have some of those things have huge value, particularly when you start looking at microservices and some things you can do there because then you may be in or actually particularly if you go into hardware or something like that where you may have very limited size and space and memory and processing where you do need to really shrink those things down. And although I come from, I guess I'll join the heresy a little bit here is that I come from very much an almost religious object oriented kind of background that always loved it and the approach and the design around it, but also have found that like everything, it seems like there is a practicality to it where there's everything in moderation, I guess. And there are situations where I'll look at stuff and even all kinds of varied situations of code where I'll look at something and say, you know, it's probably better instead of us trying to make that function that's almost what we need in this other area, work in that other area, let's just essentially copy it and then edit it so that you have you do end up having code replicated to some extent, but sometimes that's the faster, easier way to do it than try to have one thing that solves, you know, essentially solves two problems. And sometimes it's one of those things too, that I've found a lot. It's sometimes maybe easier in the short run to go ahead and do that. It's just replicate it, just copy, change it, move on. And then you can come back, particularly if you're doing this across clients, where you can always come back and look at, you know, hey, we solve this problem for these five different clients. Let's take a closer look at those solutions. And maybe we can abstract out something that is more generically useful and that would work for all of those, or that would be a better starting point for client number six or seven or wherever we're at with them. You got me on the abstraction there. I mean, that's exactly what I like to do. And that's probably the moment when it comes together. And now we've got some, you know, true economies of scale starting to happen, right? And that's a process I find incredibly gratifying is to say, all right, we've let this sit for a while. We know this implementation is good. And, you know, by good, it don't just mean that I like the way the code looks, but actually users are using it, right? You know, potentially in some cases with some of our customers, hundreds, maybe even thousands of people have already run through this API. We try and time out specific periods when we're going to go back and take a look at the different patterns we've utilized to good effect and start abstracting those out. And that's a really fun process because, you know, I mean, first of all, there's just the feeling of being able to do it over again and make some different choices, maybe ramp up the testing a little bit. And then the sense, and I think it's a real sense that that investment is now some kind of investment in the future, you know, hoping that you can do something more with that. And we've had some really good luck with some of the stuff that's become standardized to all of our projects. I mentioned the logger pattern earlier, you know, nothing that exciting about that. I think our module for the logger is something like three or four files, but I mean, the mileage that thing gets because it's really in every single one, and we make some pretty minor updates to it, but we've got it all configured the way we want. And so we're not coming back to that problem over and over again. Another thing I've found too is there are now a number of systems we're integrating with that also, we have a very certain way of integrating with them. So one that comes to mind is actually QuickBase. And I don't know if you've used QuickBase or all it's kind of like a no code database. And we've had the kind of odd luck of a couple customers using it. And so we've been able to abstract away a lot of the standard stuff we do there that requires a lot of scaffolding if you just use the QuickBase APIs. And of course, we're sitting right on top of the QuickBase APIs. We've done nothing so amazing that it would make sense to do an open source release of it. But that is yet again, something that just translates from project to project. And one of the features I use more than anything with my developers, I mean, if they took away this feature, it would just destroy my work. But I love the GitHub has links to specific lines that you can put in the repo, and you could just quickly generate a link to a specific line of code. I mean, the amount of references I have across repos where I'm showing a developer, hey, just do it like this, do it like this implementation. And oftentimes, I'm referring them to a repo, especially if it's a new developer that they've maybe never seen before. But then they've got a great example that's feeding back into the main line. So I'm trying to identify more projects to do that modularization with. My one word of caution there is people like me, probably like you, people who are operationally minded like this, I think we tend to overdo it sometimes. So I've often jumped into libraries too quickly, and not really sat on it and said, is this really a problem I'm going to encounter that many times? So one of the things is it's almost like buying a firearm or something. I have a bit of a waiting period until I actually turn something into a library. So I force myself to just do it, just throw it into the project, see how well it works, tweak it, and then eventually reintroduce that as a library. And that's been a pretty good model for making sure I'm making the right decisions the second time around. Yeah, I think that's a good, again, that's a good rule of thumb. And actually, that's again back in my background, there was a company I worked for that they were primarily, actually, they were entirely a consulting company. And then they found that there were tools and things that the consultants were doing on a regular basis, particularly as they talked to each other, that they said, you know, it makes sense to pull these things out and just supply these to the new guys and gals that are coming in. So they've got it right away, or also for ourselves to use it in a way that we don't feel like we're reinventing the wheel every time. And that it does go to that abstraction where I think you get into these situations, and particularly when you've got, if you communicate well within your team, your group, that you find that, hey, we keep seeing this problem, we've solved this three or four times. Or you may even talk to somebody and say, hey, have you ever solved it? Like, oh, yeah, I've got this little repository over there. And at some point, you say, we've got this in four or five different places, maybe it is time to take a look at it, and see if there's a essentially, you know, library eyes, if that's even a word, but you know, turn into some sort of a library or a module or something that's very easy to reuse. And then, you know, maybe put a little documentation around or something so that you've got enough for somebody to pick it up that really, maybe doesn't understand much about that problem, but just say, hey, here's how you do the solution, here's how you implement it. And you're off and running and it allows them to go on and solve bigger and better problems instead of trying to do that one again. Yeah. And we like to, the stuff that we really like, we will green light for open source as well. Because I mean, I have no problem with that, you know, whether it's open source or not, I'm still going to just keep using it. And especially if I'm in control of the repo, I can certainly get pull requests in there quickly enough. So that won't be a problem. And that will wrap it up. I hope you enjoyed this series. This interview, this actually multi-part version of it. I think there's quite a bit to get out of it. There's a lot of food for thought, as I mentioned in the prior pieces that Trevor obviously has got some great experience to share, very willing to do so. And along those lines, there are links in the show notes, all the links that we talked about in this episode. If you want to get a hold of him, those will also be in the show notes. So you don't have to try to go back and re-listen to it several times to get your spelling or your .com kind of stuff straightened out. And I think he's more than happy to answer any questions you have. I am as well. You can always shoot either use the form at developerneur.com or shoot us an email, info at developerneur.com, and we'll get back to you with any questions, as well as a feedback that you have, or if you have suggestions for future interviews, or you want to be in a future interview, then let us know and we'll see how that fits in the general theme of building better developers. With this one going a little long, I think I'll wrap it up early. We'll be coming back next episode with a new interviewee, and it will be a little bit different, change of pace, a little different focus. But hopefully mixing this up will continue to give you some good ways to think about how to become a better developer yourself. That being said, go out there, have yourself a great day, a great week, and we will talk to you next time. There are two things I want to mention to help you get a little further along in your embracing of the content of Developineur. One is the book, The Source Code of Happiness. You can find links to it on our page out on the Developineur site. You can also find it on Amazon, search for Rob Rodhead or Source Code of Happiness. You can get it on Kindle. If you're an Amazon Prime member, you can read it from the source code of happiness. You can also find it on the website of the book. If you're an Amazon Prime member, you can read it free. A lot of good information there. That'll be a lot easier than trying to dig through all of our past blog posts. The other thing is our mastermind slash mentor group. We meet roughly every other week, and this is an opportunity to meet with some other people from a lot of different areas of IT. We have a presentation every time. We talk about some cool tools and features and things that we've come across, things that we've learned, things that you can use to advance your career today. Just shoot us an email at info at Developineur.com if you would like more information. Now go out there and have yourself a great one.