You can listen to the podcast and read the show notes here.
Michael Smith: Back to the show. I'm here with Nolan, and he is gonna be telling us all about dependency injection, and various ways you can do it in ColdFusion, and why you'd want to do it, and what it is. And we're going to be looking in detail at that. He's giving a talk at Into the Box, coming up in about a month's time now. Exciting stuff. Nolan has been developing for nearly 20 years now, and he actually started off creating video games, and even worked on the Star Wars video game at Lucas Arts, and shook hands with George Lucas one time. Several times, in fact. Since then, he's been doing ColdFusion and a lot of object-orientated stuff, so welcome Nolan.
Nolan Erck: Thank you. Thanks for having me.
Michael Smith: Dependency injection. I know a lot of people don't really use it or aren't quite sure why they should use it, and yet when we did our recent State of the ColdFusion Union survey, 90 percent of people are using CFCs, but less than 50 percent are doing any dependency injection. So tell us what it is and why we should be using it.
Nolan Erck: Right. Yeah, I have seen similar stats before too. So I think a lot of people are using SF components as just a way to sort of dump CF functions into a little container and- not using components for much more than a glorified function library. Which is a good starting point for components, but there is a lot more you can do with them after that. So once you get comfortable with components and you have different CFCs that solve different types of problems, you might have one that handles talking to your user table in the database, you might have one for handling security in the application, making sure users are logged in and out, and that sort of thing.
The bigger your app gets, the more CF components you'll have, the more you run into cases where in order to build one component you might have to create three or four other components first and then stick them inside the main master component you're dealing with. For example, maybe something like a user component that handles everything that for a user in your app- that user might have to have a security system to take care of making sure they're logged in and out of the system properly, maybe some sort of permissions component that handles- not only is the user logged in, but which sections of the application are they or are they not allowed to deal with.
You might have some sort of logging mechanism in the app that handles- okay, as the application is being debugged, logs certain activity to a log file so we can check that out later and see if there are any problems in the app and so on. So the more components you get, the more you have cases like that, where one user component will depend on three, four, maybe five or six other components being created first and then handed to that user component so that they can all work together. You can do all of that manually in ColdFusion, calling the CreateObject function six, seven, eight, nine times, and connecting all those things together, but that gets very repetitive very quickly and adds for a lot of boilerplate code in your application.
So instead of doing it that way, you can use a dependency injection library like WireBox, and you just tell WireBox, “here are my components, here are the ways that they connect together to build a user bean”. So that way, rather than me manually writing the eight, nine, 10, 11 lines of code it takes to create a permission component, a logging component, everything else, and then handing them to the user bean before before I get my user bean that I actually want to use, I can just tell WireBox, “Hey WireBox, make me a user bean, please,” and WireBox will go off on its merry way, figure out which pieces need to be created first. It will take care of all of the CreateObject stuff behind the scenes and hands me back the user bean component.
So my boilerplate code that might have been 10 or 12 lines of code now gets reduced down to one line of code. Or I just say, “WireBox, go make this for me.” WireBox does its thing and it hands me back the variable that I'm actually interested in.
Michael Smith: And that has also the added advantage that if more components or different layers are added in the future, you don't have to change that code.
Nolan Erck: Exactly. Yes.
Michael Smith: It'll automatically pick up what the object dependency is, and also it figures out what order things have to be done in, because you have … you know, if you did them in the wrong order you're gonna end up with an error.
Nolan Erck: Exactly. Yeah. And if that order changes for some reason because you added a new piece of business logic into the code or if you add, like you said, more CF components into the mix, that boilerplate code can become more complex and the 10 or 12 lines of code might end up being 20 or 30 lines of code that you have to copy and paste everywhere in your app, and that's just not a good design idea. So you use dependency injection like WireBox instead, and it abstracts that problem out, off to the side. You don't have to worry about it any more in your application.
Michael Smith: That's great.
Nolan Erck: Yeah.
Michael Smith: So does that add a lot of overhead to the code, or …
Nolan Erck: A lot, no. I guess technically any time you add another thing in your application, there's technically more stuff going on, so there is technically more overhead, but it's not enough to actually worry about at a performance level. I've never seen an app that is too slow for use because you're using a DI library. It's just yet another function call that's doing some work, and the libraries are pretty good these days too about catching the parts of machinery that do have a little bit of overhead in them, so you might have a tiny bit of extra time on the first page load for the first user, but beyond that everything usually gets cached up pretty well and it's fine.
Michael Smith: Mm-hmm (affirmative). And I got why it was called dependency, but why injection? How does that word fit in there?
Nolan Erck: The injection happens with … I wish I had some code samples in front of me that I could help explain this with.
Michael Smith: Well, you'll have them in your talks, and then people-
Nolan Erck: I will. I'll have them.
Michael Smith: Everyone who listens to this has got to go to “Into the Box”, and I'll ask you why that is in a moment.
Nolan Erck: That's the idea. Yeah. So when you're building- to use the example earlier with the user beans and logging and so on- well, I can kind of just abstract that out. Say … let's make a simpler example, say with the user bean, users have typical properties that are set inside that component. First and last name, email address, maybe the city and state where they live, and so on. So typically what you would do is call CreateObject, create a user bean, and then call a handful or two handfuls of setter methods to set those properties at certain values, set first name and you pass a “Nolan”, set last name, pass it “Erck”. There might be 10, 12, 20 lines of boilerplate code for doing that sort of thing too. Not terribly bad when it's pretty simple properties like that, like first and last name, but it is a little bit repetitive, and if the objects all have the same default values that's a lot of repeating yourself with the code. Any time you repeat yourself, that's usually a sign there's a flaw in the design.
And we also have cases where that user bean might have not just the simple properties, first and last name and so on, that are getting passed in, but also maybe a logging component that we're passing in to handle logging everything that that user does. As the component is being run through the application, we can use a dependency injection library to take all of those things that would be boilerplate lines of code- set first name, set last name, set logging component- and move all of that out into a config of some sort. So that, much like when we call WireBox and say, “make a user bean”, and it will create the permissions object first and the logging object first and so on, we can also do things where it will inject default properties- not just first and last name, but also default objects, like a logging component and stuff, into the fully qualified user bean before we go and use it.
The nice thing about doing that is we can put all of that config default stuff in one spot, outside of the main block of code we're writing, and then it becomes much less like code that has to change any time we want to update those default values. It becomes more like a config file off to the side that changes, making it much easier to do things like swap in and out default values when you're going from the test server to the production server. Maybe you want to change an IP address, and you have an IP address that gets passed into that object. You can set one IP address for your test server, set a different one for your production server, and so on without having to actually change … it's technically code you're changing, but it's not code in the main meat of your application any more. It's now a config thing off to the side that's kind of separating your [crosstalk 00:08:12] better.
Michael Smith: Yeah, much better for maintenance then as well.
Nolan Erck: Yeah, exactly.
Michael Smith: And then you mentioned WireBox- I just shared the screen of the survey question from the ColdFusion State of the Union survey. WireBox is- I don't know if you can see the screen share, but WireBox is the most popular one there. About 22 percent of folks who took the survey are using that.
Nolan Erck: Right.
Michael Smith: And then some other popular ones are DI1 and ColdSpring. And then I don't know what people are doing for custom.
Nolan Erck: I don't know either. I've never done that myself.
Michael Smith: Some people are doing that. And then lots of people are just not doing any dependency injections.
Nolan Erck: Right. I don't think people realize the benefits to it. And dependency injection is one of those things where I think it's a little bit more of an abstract framework than, say an MVC framework is (Model-View-Controller), and there are a lot of what I'll call legacy ColdFusion apps that, or ColdFusion developers, that are still sort of learning the MVC process and getting used to that. And one thing that a lot of them know about MVC is that means that they kind of have to start from scratch again with their code base. They have to delete all of the CF include or custom based homegrown frameworks that they might have been using and start doing things the Framework 1 way, or the ColdBox way or whatever, and it does mean rebuilding a decent chunk of your original code base.
So I think that might might be part of why people have shied away from dependency injection libraries, is they think they have to reinvent the wheel and redo everything with dependency injection as well. And that's actually not the case. You can start using DI libraries right in the middle of a 20-year-old ColdFusion code base right now. You don't have to use ColdBox on top of it, you don't have to use Framework 1 or any of those other things. You can add, in this case WireBox, to your app, and then even if you have an app from 20 years ago that's one big long file with 10,000 lines of code in it, WireBox will happily sit there next to it and let you turn WireBox on and off in whatever spots in the file you want to sort of start incrementally adding dependency injection to your app, and hopefully-
Michael Smith: I hope no one is working on a 10,000 line ColdFusion app, spaghetti thing, but-
Nolan Erck: I hope so too. Sadly, I have seen those in the past, so I know they exist. But hopefully we're doing what we can to educate people and offer training at conferences like Into the Box and sessions like this, so people can understand there are better ways to build things and make their apps a little bit more modular and reusable without having to start from scratch.
Michael Smith: Great. You know, this is making ColdFusion more modern. It makes the ColdFusion language much more alive. You know, there's that ever-present thread, “ColdFusion is dying,” but really with stuff like this it's new and modern, and there's lots of cool stuff happening.
Nolan Erck: Exactly.
Michael Smith: So I know also in your talk you're going to talk a bit about aspects-orientated programming. Can you just briefly tell us what that is and why anyone should care?
Nolan Erck: Sure. So aspect-oriented programming, or AOP, is the idea that you've got a function call in your app, and the function can do anything at all. It can draw a sales report on the screen, connect a user to the data base, it doesn't matter what the function does. The idea is, I want to change an aspect of how that function is called. Not just running the function, but maybe running a block of code before or after that function, or maybe both. When I call my “draw sales report” function, I can either just have the function generate the sales report or I can have something happen before that function too, like maybe make sure that the current logged-in user has permission to actually run that sales report first. Maybe I have code that I want to run after that sales report is done. Say I want to log the fact that the sales report was generated out to a log file that I can examine later for error messages and such.
Let's say I call that “generate sales report” function at 20 different spots in my app, and I want to add this permission check before it and this logging after it in all 20 of those spots. Well, now I'm copy-and-pasting the same three chunks of code into 20 different places in my app. That's fairly repetitive- any time you're repetitively copy-and-pasting chunks of code everywhere it's more prone to human error. We might actually add more bugs in our application and so on. Let's say six months go by and I no longer need the logging that I added to the end of those 20 sections of code. I'd need to turn off the logging, but I'd still need that permission check that I did first to make sure the user is logged in and can run the sales report, then run the sales report but we no longer want the logging at the end of it. If I copy-and-pasted those 20 chunks of code across my app I have 20 different spots I have to change things. That's 20 more spots for human error, 20 more ways I might break the application.
You can use AOP to instead wire up that before-and-after functionality in one contained spot. And what I can do is I can tell WireBox in this case, or ColdSpring does it as well and some of the other frameworks too, I can say, “I want to change an aspect of my ‘generate sales report' function. So any time I call ‘generate sales report', before that function runs, do this other thing, in this case check permissions, and after that function is done do something- a third item, which is ‘log output to the log file'”. If I wire that all up in an AOP library, I only have to change- when I go to pull out that logging at the end after six months go by, I only have to pull that code out of one spot. I don't actually have to go through all 20 places that you generate the sales report- I could just go to my one AOP component, turn off the “after” methodology, and it's done.
So this would be a nice way to do group functions together and if I can dynamically add code that runs before or after it, that's one of the big things you can do with it. Another nice benefit is- and again this would be great- I'll have a slide on this in my talk and people can come watch that at Into the Box. Try catch blocks in ColdFusion. I'll often want to wrap CF functions- I'm sorry, CF queries- in a try catch block in production. That way, if the database goes down in production, I can catch that error and redirect the user to a nice friendly “we're sorry, something bad happened” sort of page where they do not see the actual error details. But in the case of development and QA servers, maybe I do actually want to see the raw error message on the screen so I can check what the problem was and fix the code that way.
Using AOP, not only can I run function calls before and after a chunk of code, but I could actually take that CF query and wrap a try catch block around it in production, and in development make sure that try catch block is not there at all. So I can do- doing that with traditional ColdFusion would mean a big IF statement. “IF in production do try catch, run the query, close try catch block, ELSE for development and QA, run the CF query again”. That means copy and pasting the same CF query into two spots in traditional ColdFusion.
If the query is just three lines of sequel, it's not that terrible of a thing. If the query is a real-world query, though, with 19 different joins, an aware clause and all different kinds of stuff, that's a great big chunk of code that I'm copying into two different places. If I have to fix a bug I have to fix it twice, and there's just more repetitive stuff that I can get rid of, that I'd like to get rid of. And AOP makes that much more easy to do, gets rid of a lot of the boilerplate, all the code duplication with the queries, and rather than calling the function directly I just tell my AOP library, “you call this function”, and it figures out where to put that try catch block, or it figures out where to put code before and after the function and does its thing.
Michael Smith: That sounds really great for improving maintenance, Nolan, and it kind of reminds me of events that get fired in some other languages. You know, when you create an object it fires an event or when you instantiate you get a pre-event and a post-event just adding on to that.
Nolan Erck: Yes, it's very similar.
Michael Smith: And what AOP library do you use?
Nolan Erck: I use whatever kind of makes sense for the project. I have a couple of apps that are using ColdSpring at the moment, but I like ColdSpring a lot, I'm a big fan of the XML config for that, so I'm probably not going to update those any time soon- just because I like them, even though I know ColdSpring is not quite as popular now as it was a couple of years ago. I started looking at AOP1 for a couple of upcoming projects. I like what that entails as well. And of course WireBox does lots of great things too, and we'll have WireBox demos of everything in the Into the Box presentation next month.
Michael Smith: Great. And then I also know you're gonna be touching on inversion of control, which I know the first time I met that I had to wrap my head around it to understand what it was like, so can you just explain to the listeners what that is and why you'd want to do it in your code?
Nolan Erck: Inverting the control- Yeah, what's a good way to explain this without looking at any code while we're doing the talk? That's the trick here. I guess the short of it would be, it's sort of the- there's a methodology in inverting called the Hollywood Principle, where you say “don't call us, we'll call you”, and the idea is with inversion of control- it's a similar idea to that, where rather than when I create a component, use the CreateObject function to start that component. And there may be seven or eight other things I have to do to actually make that component. Once that component's been created, I- what's a good way to explain this without- I'm used to doing this by staring at a line of code and going, “See this code here? We'll just move things over this way and this is what it does”.
Michael Smith: But instead of it being kind of top-down control, the children are controlling the parents is basically-
Nolan Erck: Yeah. Kind of the idea- that's a good way to explain it. It's just another way to write less code and have the code that's there be more compartmentalized and each little component knows how to take care of itself, and then it sort of updates the parent thing- “Okay, I'm done and ready to use”, and then the parent item knows. “Great, and now we can move to the next step and go from there”, and so yeah, rather than me writing CreateObjects and then calling 10 different setter functions in a row afterward, I can say, “Okay, CreateObject”, and then tell WireBox, “I created this thing”, and then if this thing has three different children inside it they will create themselves and return control back to the parent when they're done, and I can kind of go on from there to do the rest of the code that I want.
Michael Smith: So it saves you having to do it explicitly- again, makes better maintenance. That seems to be a theme in your whole talk- better maintenance of your code-
Nolan Erck: Yeah, that's kind of what the idea is with all the dependency injection and AOP libraries out there is. It gets rid of a lot of the boilerplate stuff that we have to remember to do. If you have a function you want to call, like okay, I can't call this function just by itself. I have to do these three things before it and these seven things afterward, and then it will actually do what I want it to do in my app. Well, rather than remember all those 10 or 11 steps every time I want to add some piece of functionality to my app, I can describe what that functionality should be in some sort of blueprint config section in my DI library or my AOP library or whatever.
And then I can just tell that thing, “Okay, I want to use this piece of functionality now”, and then in this case WireBox will be smart enough to know, “Oh, okay, Nolan called the ‘generate sales report' function”. I know that before that function runs we have to do these four, five, six different steps, and after the function is done I want to do these cleanup things that are also scripted out somewhere, and WireBox just sort of takes care of all of those processes for me.
Yeah, the idea is you've got more maintenance, less repetitive code, concentrated on the real detailed moving parts that we need to concentrate on, and less of the boilerplate stuff.
Michael Smith: Right. And then I know you're also talking about bean management. So beans are these components that are being created in your code.
Nolan Erck: Yes. A bean- really in Dependency Injection Land, a bean is just another term for a CF component. It's one of the components that your DI library understands how to build. So I might have a hundred different CF components in my app, just because they are components that live somewhere in any folder in my app does not make the dependency injection library aware of the component. WireBox, ColdSpring both have their ways that you initialize them and make the DI library aware of where certain components live. In the case of WireBox you basically put it in a certain folder and that's what does it. So the idea with- a bean really is just a shorthand name for a component that WireBox knows how to create.
Michael Smith: And I'm guessing that name “bean” probably comes from Java, which has that coffee symbol, so they're like beans of coffee in your Java app when that terminology was created many years ago.
Nolan Erck: Probably, yeah. And there's a- so in ColdFusion we have ColdSpring, and in Java they have the Spring library, which ColdSpring was based on. And Spring has the same concept of beans in there, and the terminology just carried over from Java Land like you said.
Michael Smith: So managing all these things you've talked about and having your talk are all to do with bean management.
Nolan Erck: Right.
Michael Smith: Just making maintenance easy. Cool. well, sounds like a really exciting talk-
Nolan Erck: I hope so.
Michael Smith: -and something that … yeah. Something I think a lot of people would benefit from learning about. So I know you code in ColdFusion. Why are you proud to program in ColdFusion?
Nolan Erck: I like ColdFusion because I'm a consultant for a living, so clients will call me and say, “Here's what we want to build- some sort of mobile app or Web app or what have you. What do you recommend we use to get the job done quickly, securely, write code that we can actually maintain moving forward”, and that sort of thing. And I try to be as objective as I can with clients when they call, and I look and, “Okay, what languages and tools are out there that would be the best solution for this client?” Nine times out of 10 it's ColdFusion. I get more done per line of code, out of the box, with a ColdFusion engine and code base, than I do any of the other similar options out there. It just does more out of the box for me.
Michael Smith: Yeah, I mean that it's not that you couldn't code it in PHP or Java, you just spend longer getting it done.
Nolan Erck: Exactly. Yeah, the syntax is just nice and concise, I get things done quickly, the platform itself has a lot of features baked into it that make what would be hassles in other languages or would require add-on packs in other languages, it just makes them very easy to do in just a couple of lines of code. So I tend to stick to ColdFusion for most of my projects whenever possible.
Michael Smith: All right. So what are you looking forward to at Into the Box this year?
Nolan Erck: Into the Box? I'm really looking forward to Brad's talk about CommandBox. I've seen a couple of demos he's done, different conferences, but I haven't had a chance to sit down and actually play with CommandBox for a significant period of time just yet, so- I'm really looking forward to checking that out and pestering Brad for a couple of days about all the different things you can do with CommandBox.
Michael Smith: He's a great guy. I'm sure he'll be happy to share all kinds of things. And it's a three-day event, so you've got plenty of time to reach out to him.
Nolan Erck: Yeah. I think he'll be sick of me before the end of those three days are done. “Brad, Brad, what about this, what about this? Can I do that?”
Michael Smith: So if people wanted to learn more about you, how could they find you?
Nolan Erck: They can find me on Twitter at “South Of Shasta”. They can also find me at southofshasta.com- that's my consulting business. I think I'm on GitHub as just Nolan Erck, and they can track down some projects I've been working on over there. And I try to make the rounds of the different ColdFusion conferences too. I'll be at Into the Box and I'll be at a couple of other events coming up, so they can contact me at any of those and say hi.
Michael Smith: Cool. Well, thanks so much for sharing all about dependency injection and beam management. It's exciting stuff.
Nolan Erck: My pleasure.