Show Notes
02:53 - Nick Sutterer Introduction
03:31 - Trailblazer
- [GitHub] trailblazer
- 04:56 - Form Object
- “Operation”
07:28 - Validations
08:47 - Decoupling
09:45 - Namespace Reuse
- Concepts/Concerns
11:50 - Process Method => Procedural Code
12:54 - Inheritance
13:57 - Contracts
14:57 - How is Using Trailblazer Different?
18:17 - What Would DHH Think?
19:32 - Trailblazer as an Extra Layer
27:20 - Testing
28:35 - When Should You NOT Use Trailblazer?
29:53 - Moving to Trailblazer
36:03 - Rails 5 and Trailblazer
37:22 - Maintainers
38:44 - APIs
Deserialization
41:04 - Parts of Trailblazer
44:16 - Generators
Picks
A Gentleman’s Guide To Street Harassment (Saron)
Tor and HTTPS (Saron)
How it feels to watch a user test your product for the first time (Saron)
Humane Development (Coraline)
The Left Hand of Darkness (Coraline)
Star Wars: Episode VII - The Force Awakens (Chuck)
WorkFlowy (Chuck)
Ruby Rogues Episode #204: Limerence with Dave Thomas (Chuck)
JS Remote Conf Talks (Chuck)
Trailblazer: A New Architecture For Rails by Nick Sutterer (Nick)
[YouTube] Cinco Face Time Party Snoozer (Nick)
Tor and HTTPS (Saron)
How it feels to watch a user test your product for the first time (Saron)
Humane Development (Coraline)
The Left Hand of Darkness (Coraline)
Star Wars: Episode VII - The Force Awakens (Chuck)
WorkFlowy (Chuck)
Ruby Rogues Episode #204: Limerence with Dave Thomas (Chuck)
JS Remote Conf Talks (Chuck)
Trailblazer: A New Architecture For Rails by Nick Sutterer (Nick)
[YouTube] Cinco Face Time Party Snoozer (Nick)
Special Guest: Nick Sutterer.
Transcript
CHUCK:
We’ll call it dingo static.
[This episode is sponsored by Hired.com. Every week on Hired, they run an auction where over a thousand tech companies in San Francisco, New York, and L.A. bid on Ruby developers, providing them with salary and equity upfront. The average Ruby developer gets an average of 5 to 15 introductory offers and an average salary offer of $130,000 a year. Users can either accept an offer and go right into interviewing with the company or deny them without any continuing obligations. It’s totally free for users. And when you’re hired, they also give you a $2,000 signing bonus as a thank you for using them. But if you use the Ruby Rogues link, you’ll get a $4,000 bonus instead. Finally, if you’re not looking for a job and know someone who is, you can refer them to Hired and get a $1,337 bonus if they accept a job. Go sign up at Hired.com/RubyRogues.]
[This episode is sponsored by Codeship.com. Don’t you wish you could simply deploy your code every time your tests pass? Wouldn’t it be nice if it were tied into a nice continuous integration system? That’s Codeship. They run your code. If all your tests pass, they deploy your code automatically. For fuss-free continuous delivery, check them out at Codeship.com, continuous delivery made simple.]
[Snap is a hosted CI and continuous delivery that is simple and intuitive. Snap’s deployment pipelines deliver fast feedback and can push healthy builds to multiple environments automatically or on demand. Snap integrates deeply with GitHub and has great support for different languages, data stores, and testing frameworks. Snap deploys your application to cloud services like Heroku, Digital Ocean, AWS, and many more. Try Snap for free. Sign up at SnapCI.com/RubyRogues.]
[This episode is sponsored by DigitalOcean. DigitalOcean is the provider I use to host all of my creations. All the shows are hosted there along with any other projects I come up with. Their user interface is simple and easy to use. Their support is excellent and their VPS’s are backed on Solid State Drives and are fast and responsive. Check them out at DigitalOcean.com. If you use the code RubyRogues you’ll get a $10 credit.]
CHUCK:
Hey everybody and welcome to episode 206 of the Ruby Rogues Podcast. This week on our panel we have Jessica Kerr. Saron Yitbarek.
SARON:
Hey everybody.
CHUCK:
Coraline Ada Ehmke.
CORALINE:
Hello from Chicago.
CHUCK:
I’m Charles Max Wood from DevChat.tv. We’ve got a special guest this week and that’s Nick Sutterer.
NICK:
Hello and welcome America, from Australia.
SARON:
[Chuckles]
CHUCK:
I hope you’re on the beach. That’s all I have to say.
NICK:
I’m sitting right at the beach. My toes are actually in the water. And what you hear in the background is crocodiles, alligators, sharks, and dingoes.
CORALINE:
No [inaudible] bears? [Laughter]
CHUCK:
Kangaroos?
NICK:
No, the kangaroos… it’s too early for the kangaroo. They usually wake up after 10am.
CHUCK:
Oh, I see.
CORALINE:
Lazy kangaroos.
CHUCK:
Yeah. Do you want to introduce yourself really quickly?
NICK:
Yes. Hello, everyone. My name is Nick. I live in Australia. I’m from Germany. I write a lot of Ruby gems. And I just came back from a 12-week tour, world conqueror conference thing. And that’s why my voice is still a little bit rough.
CHUCK:
12 weeks? Wow.
NICK:
Yes. What was planned to be three conferences turned into seven conferences. And it was great.
And I met a lot of nice people, right Coraline?
CORALINE:
And you also met me.
CHUCK:
[Laughs]
NICK:
That’s what I just said.
CHUCK:
So, we brought you on today to talk about Trailblazer. Do you want to give us a quick rundown of what that is?
NICK:
Absolutely. Trailblazer is a collection of gems I wrote in the last couple of years and basically brings a high-level architecture to Rails. You’re wondering what’s a high-level architecture, and for me that’s everything that happens between the HTTP dispatch and the persistence. And this is where Rails leaves you completely alone. So, I wrote a lot of gems. And Trailblazer’s the umbrella gem to give you that high-level architecture or to give you a couple more abstraction layers to model applications.
CORALINE:
Nick, what was the overall problem with traditional Rails architecture you’re trying to solve with Trailblazer?
NICK:
So, the problem is in Rails apps we’re talking about conventions but actually the conventions are minimized to where do you put controllers, models, basically where to put files. But what happens in the files is completely up to the Rails developer. And that yields to every Rails app MVC component blowing up. And actually, every Rails app I’ve seen looks completely different. And so, I’m trying to, with Trailblazer I’m trying to introduce abstraction layers like form objects or representers to deserialize and render documents or view models and addressing the problem of where do I put this kind of code in Rails?
CHUCK:
So, I’ve done some of this. I’ve built my own form objects that pull in some of Active Model. And that way I don’t have to rely on Active Record while I do. But basically the form object does all the work as far as munging, validating, all that stuff. And then it uses the Active Record models as an interface to the database more or less. Is that part of the approach you’re taking there?
NICK:
Yeah, the form object is just one of the things in Trailblazer. The most important thing is that the entire business logic is taken out of the controller and taken out of the model. And it’s pushed into a new abstraction layer we call operation. And then within the operation you model your domain, your functions of the application. And every operation uses a form object. So, the whole point is that we have this higher level of abstraction in the Rails app. So, the form object is just one of the many things that help you to deal with every day Rails or web application problems.
CORALINE:
What kind of things go inside the operation class, the operation model?
NICK:
So, you have an operation per function in your application like, show me that shop, follow that person, give me a list of all the users that start with A. So, that goes into an operation and the operation is deserialization of the incoming data, authorization, and then validation, and then the business logic. And that all goes to different objects within the operation. The operation is just an orchestrating instance. And then the operation eventually uses models to persist data or to query data. The model layer is completely up to the user. Trailblazer doesn’t care if you use Active Record or whatever. Models are just one of the many objects used within an operation.
CORALINE:
So, operations are essentially separating business logic from persistence.
NICK:
Kind of, yes. So, one thing in Trailblazer is we have more or less empty controllers. Controllers are completely just reduced to HTTP endpoints. And models are empty and reduced to associations and finders, yeah? So, your business logic has to go somewhere else. And that is the operation. That’s exactly right. But the operation offers you several abstraction layers within the operation to structure your code. You know, like the form object. So for example validations go into the form object. But callbacks to be triggered after your business logic is run go into the operation as well.
CHUCK:
So, do the validations and other things that we’re familiar with from Active Record look a lot like Active Record?
NICK:
They look identical because we use Active Model validations in the form object. We also use… So, soon we’re going to have Lotus validations available in the form object as well. So, you can pick if you want to use Active Model validations or Lotus validations.
CHUCK:
Lotus validations?
NICK:
Lotus validations.
CORALINE:
So, Lotus is an alternative to Rails similar to, well, in the same way that Sinatra is an alternative to Rails. So basically, Trailblazer is agnostic to the underlying framework?
NICK:
It actually is. So, that’s one of the things in all my gems, is that they are completely decoupled from the actual framework. And there’s only a thin binding layer to use my gems in your respective frameworks. So for example, Roar which does document APIs has a separate gem, Roar-Rails, that provides the binding to Rails. The same with Trailblazer. So basically, an operation in Trailblazer could be run in any kind of environment because it’s completely decoupled from the framework. So, that’s one of my major points with my gems is to make them as agnostic as possible, which automatically results in better encapsulation.
SARON:
It makes me wonder. When you’re decoupling it from the framework, do you find that you’ve had to make any compromises or any sacrifices? Would it be better in any way if it was just made for Rails?
NICK:
Actually, the opposite is the case. So, the more you decouple or the more I decouple my stuff, especially from Rails, the easier it gets for me to deal with updates. And so, we are not really sacrificing functionality because we still use persistence. We still use all the awesomeness of Active Record. We still have controllers. We have all the stuff like responders and all that stuff. But we introduced really strong interfaces between those different layers. And I think it’s a good tradeoff between encapsulation and still using all the goodies from the framework. Because I love Rails, but I don’t want to deal with every update and I don’t want to follow Rails on GitHub and check out every little update they make. So, the more I encapsulate my own code with my gems, the luckier I am.
CHUCK:
So, one thing I’m seeing here is that you said you have an operation for every, basically every action or every operation I guess you perform in your code. And it looks like you create these classes that are, I don’t know what the right word is, but they’re contained within the Active Record base class. Is there a reason you would put them there instead of separating each one into its own thing?
NICK:
So, that’s a big misunderstanding with putting the operations into the Active Record model, namespace. Because what I do in Trailblazer is just, I reuse the namespace of the model. For example, Comment::create is an operation or Comment::update. But what I’m doing here is kind of a workaround, because I want to use the Comment namespace in Rails. But the Comment namespace is already taken by the model, yeah? So, that’s a workaround to reuse this namespace. But that does not couple the operation to the Active Record model, not at all.
CHUCK:
Right.
NICK:
That’s just really, not even a trick. It’s just a Ruby way to reuse a namespace. Don’t get confused and run away. Bear with me.
CHUCK:
No, I was just trying to understand why you would put it in there as opposed to just putting it in its own file, et cetera. But that makes sense. So, basically you’re concern…
NICK:
Well, it is a separate file.
CHUCK:
Yeah, it is. But your concern is named the same thing as your model, is what you’re saying. And so, since your area of concern is as comment and that is already taken up by the class name.
NICK:
In this case, yeah. But the thing is, in Trailblazer we have what we call concepts. So, you said concern. That’s a beautiful…
CHUCK:
Oh, a concept, yeah.
NICK:
No, concern is a beautiful name. But I don’t want to use it because people might think I use, I’m talking about Rails Concerns.
CHUCK:
Right.
NICK:
I’m not talking about this. So, we structure applications by concepts or concerns. And then often it happens to be the same name as the model. So, your concern or your concept can be called whatever you want.
CHUCK:
Right.
NICK:
When you start with a Rails app you start with CRUD operations. And that needs to have the same name, the model namespace.
CORALINE:
Nick, I noticed that in the operation models that you have a process method which is like the general method, the public interface for that operation model. Do you find that it’s really easy to turn that process method into procedural code? Or do you break things out into… are you supposed to break things out into multiple methods?
NICK:
So, you definitely break things out to multiple methods, or you even… you’re not limited to just putting your code into process. Process is just the only public dispatch method. So, you could definitely dispatch from there to, I don’t know, like a [PCI] oriented [chuckles] class or whatever. So, the process method should be small and declarative. So, Trailblazer tries to give you structure. But what you do inside process is still something we have to play with and we have to find out the best practices. Because I’m sure we can do more in this to give people even more structure. But so far, you’re supposed to split stuff into methods and maybe even dispatch to another object within this operation, the process method.
CHUCK:
So, one thing I’m seeing is that, say you create a Create class and then you create an Update class for your Active Record model. Isn’t there going to be a lot in common between the two?
NICK:
Between the Active Record model and what?
CHUCK:
No, between the Create class and the Update class.
NICK:
There are a lot of things in common. And that’s why we use inheritance. So, that’s another big thing in Trailblazer, is we actually use [chuckles], we start using inheritance again. Because that’s what we unlearned in Rails, is to use proper object-orientation. So, Trailblazer is designed to use inheritance to copy or to inherit form objects and [policies] and all that stuff to subclasses like update or show. And it’s also designed to make it really simple to override certain aspects of that original operation. For example, overriding properties in the contract, or disabling validations for update, or disabling a policy in the update method, in the update operation, all that kind of stuff.
CORALINE:
Can you talk a little bit about contracts?
NICK:
Yes, because I’m a lawyer. No, the contracts in operations are actually a separate gem. That’s the Reform gem. That’s a form object gem for Ruby and it’s really, really popular. So, a lot of people start breaking out their validation code into separate form objects. So, that’s Reform. So, the contract is basically, you define what fields does my form consist of? What input am I expecting? Title, email, a nested author with another email field. And then you define validations for those fields or you can even define validations, like arbitrary validations or dynamic validations, in that contract.
So, the contract wraps the model, deserializes the incoming input, delegates the input without touching the model, and then if you’re happy and if everything is valid you can write the fields, the content and the values, to the actual model. The contract doesn’t know anything about Active Record. And Active Record doesn’t know anything about the contract.
CHUCK:
So, what I’m wondering, and Jessica’s asked us to ask in the chatroom the same question. If I come into an app that’s using Trailblazer, how is it going to look different? How is the app going to change? Or, what she asked was when you add a feature, how many of these MVC + O typically change?
NICK:
Well, when you add a feature you definitely do not want to look into controllers and you definitely do not want to look into models, because it’s boring and it’s empty. So, you go check out the concepts, the concept directory, and you would start with looking at the operation. In the operation, you instantly see, okay, this is my input because we have the form object or the contract. And you definitely see this is what’s happening, because the business logic either sits directly in the operation or is dispatched from the operation.
So, you get away from this jumping through controllers back to model to view back to controller, because in Rails business logic is cluttered all over the MVC framework. In Trailblazer, it’s operation-oriented and you [inaudible]. And so, you start with the operation. And there’s a clear layering. So, you don’t have to guess, is the authorization happening in the controller, on the model? Where is the extra business logic? Where do you call that stuff, [inaudible] from the [inaudible] field or in the controller? No, you start with the operation, in the operation as a convention and well-defined abstraction layer. So, you don’t have to guess where stuff happens.
CORALINE:
So essentially, reducing the need for metaprogramming on the part of the developer as well?
NICK:
Are you talking about metaprogramming/DSL benefits in Trailblazer?
CORALINE:
Yeah, basically.
NICK:
The thing is, an operation basically gives you a really, really simple DSL tree. For example, to register callbacks that should happen after you update a comment or something and it gives you a simple DSL to define policies or authorization, because authorization in Trailblazer is a business logic, are there and not just something that happens [chuckles] maybe in the controller, maybe in the model, maybe in the view, or maybe everywhere. But the whole, an operation looks like a DSL but it’s actually just a composition of different classes. And every class has its own responsibility. There’s actually not too much metaprogramming happening in Trailblazer. It’s more about structuring. Here’s a place for your policies. Here’s a place for your business logic. Here’s a place for callbacks.
CORALINE:
So, you’re reducing the surface area that you have to interact with as you’re adding features to your application.
NICK:
Well, you add features to an application. And instead of, I don’t know, guessing where to put this kind of code, you start with an operation. And from there you have well-defined places to push your code to. And Trailblazer makes it very simple to start with a new concept or a new feature. And if it gets more complex, for example if your authorization code gets too complex, you’re free to introduce a new class or to dispatch to some other gem or whatever. So, Trailblazer is just identifying what’s happening in the web request, and that’s usually the points I mentioned earlier, like validation or authorization, all that kind of stuff. And then it still gives you a lot of freedom to structure your code for that particular layer or problem.
CORALINE:
Awesome.
CHUCK:
One other question that we got on Twitter was would DHH talk trash about Trailblazer? And if so, can you defend the objections you think he’d have?
NICK:
First of all, DHH is awesome because he keeps… so, we keep emailing about my gems, like Cells or Reform or Trailblazer. And he definitely had a look at it. And so, I made a joke because he had this blogpost saying that, I don’t know, I think it was the ‘TDD is dead’ or something. And he uses the term ‘a complex web of indirections and abstractions’ or something like that. So, I made a joke saying, okay for you, Trailblazer I guess is a complex web of indirections. And he said, “Absolutely. But I can see where this could help in applications.” He’s not going to use it but he is definitely interested and he was keen to learn more about it.
And so, there are a couple of other people from the Rails core team. So, we had a panel at Tropical Ruby with Rafael França and Carlos Antonio. And Celso Fernandes, but was on the Trailblazer side. And they were really, really interested in a lot of things in Trailblazer. So, it’s not like I’m building something against Rails. This is like, “Here’s Rails. Rails is awesome. But let’s make it better.”
CHUCK:
Got it. It does seem like there is a lot of indirection here. You’ve got, you’re essentially creating classes where you would just put your logic into models before. That’s not exactly a fair characterization of what’s going on. But I can see people thinking that. So, what is, besides encapsulating the behavior of particular forms and things like that and having that isolated and having those concepts well-contained, why would you need this extra layer of indirection on these different pieces of your application?
NICK:
Well, there are several points. So, my main thing is that I wrote a lot of gems like form object or view models or data or information objects and all that kind of stuff. And a lot of people love them. So, because it makes it really easy to understand what is happening because we have little objects with a limited scope.
So, you don’t have a beast like Active Record and all your logic sits in this model and you have to understand every aspect of Active Record. No, what happens is you would deserialize incoming data. That happens in a separate object. And you have your data object. Then you run validations which happen in another object. After your validations are run, you do the business logic. And if one of the steps fails or if you need to dive into something, you don’t have to learn everything. You just have your limited object with a limited scope. And it makes it very easy to understand what’s going on, even though you have more objects. This is actually a client-object orientation to limit abilities, the capabilities, and the responsibility of objects, and make them do one thing and not 500 things.
And also, it is easier to replace layers of your workflow. So, if I want to do my authorization with another gem, it is really easy to swap that layer. And one thing actually, so a lot of people are really, really afraid of introducing objects and classes because of performance. But what people do not understand is that every string, every bloody string in your Rails app is an object. And Ruby doesn’t care if it’s a string or if it’s a form object or if it’s a view model. So, objects in Ruby are cheap.
CORALINE:
Especially when you get the benefit of knowing exactly where an individual piece of code, where an individual piece of logic lives.
NICK:
Exactly. And this is… So, I started using Rails and the first thing I hated was that everything is distributed over the entire stack. So, deserialization happens, it happens in model, it happens in the controller. Validation might be in the controller and the view and the model. And so, you have no idea where this actually happens, because within Rails core they also have this fear of the class as I call it. They don’t even use separate objects for validation. It all happens in the Active Record Model. And it is incredibly hard to understand what’s going on. And if you use a well-defined workflow with separate encapsulated objects, it is incredibly simple to understand what’s going on, once you understand the individual objects.
CORALINE:
I want to coin a new term here for what Trailblazer seems to enforce. And I’m going to call it Single Responsibility Principle.
CHUCK:
I’ve never heard of it. I like the term, though. [Chuckles]
SARON:
It has a nice ring to it.
NICK:
Yeah. I have no idea what this guy is talking about, Single Respo-… what? [Chuckles]
CHUCK:
So, one other thing that I worry about is basically, and I hear this argument for other frameworks and other types. But the argument is people understand Rails. And if they come in here then they’re going to have to figure out how to use Trailblazer. So, it adds this extra layer of complexity or another layer of APIs that I have to understand in order to use Trailblazer in my application. So, I can’t just hire any Rails developer to do this work.
NICK:
This is a thing I don’t see the way you see it, because I have seen many, many Rails app. And every Rails app looks completely different. Some people use this, some people use that, some people use presenters, decorators, some use form objects. Some use service objects and then the service objects have different APIs. So, people say that Rails has structure and convention but it does not. Because it doesn’t… I know where controllers sit and I know where models sit and I
know how views are supposed to look like. But it’s incredibly hard if you get a new developer. They still have to learn how you structure your Rails app because in the company they worked before it might have been completely different.
And Trailblazer is addressing exactly that. It’s introducing standards and conventions for the highlevel application code. So, in the end of course you have to learn what is a form object, what is an operation? But once you’ve got it, it’s easier to, if you go to another company and they use Trailblazer, you will find your way through the code way faster than if it’s just another Rails app with, I don’t know, our own service object and here’s our own decorators and all that stuff. So, it is all about keeping conventions for my application code.
JESSICA:
Nick, I think that’s a great point. Because in my experience if you find yourself asking yourself, which clearly everyone who uses Rails does, does this logic belong here or here? Usually the answer is neither. It belongs someplace entirely new. And it sounds like Trailblazer is providing this logic finally has someplace to belong.
NICK:
Exactly, well said. Because [chuckles] I keep repeating that phrase, but Trailblazer is all about where do I put this kind of code? Because that’s what I hear from all the development teams I’ve worked with is, okay, now we’ve got Rails. Now we’ve got the controller and the model. So, does that go into the controller or does that go into the model? So, it usually ends up in the model. But as you said, the right answer is, this is not model logic. This is not persistence and this is not HTTP-related. So, give it a new object. And this is certainly what Trailblazer brings. So, we basically identified what’s missing, what layers are missing. Authorization, view objects, validation, all that kind of stuff. And once you understand the different layers, and it’s not like we introduced 25 new layers. It’s three, four, five new layers. Once you understand them, you instantly know where to put code.
CHUCK:
Yeah, and I think that’s where the struggle comes in, and what Jessica said and what you said really comes in for me. Because usually what we’re saying is, does this go in the model or does this go in the controller? And the answer is neither. And then it’s like, okay, well we don’t have a convention for that. And that’s what Trailblazer gives you.
NICK:
Yeah, exactly. Trailblazer is a collection of gems that have been around for years. And a lot of gems in Trailblazer are really popular because they give you a new place for code for a particular concern or for a particular area of solving a problem. And that’s what I’m missing in Rails. It’s still missing in Rails. And no one talks about this. And a funny thing is that DHH in his keynote on the RailsConf, he was talking about monoliths and how awesome monoliths are and I agree. Because I don’t think we need several different Rails apps to solve one problem.
A monolith is, for DHH or for vanilla Rails, is an excuse to clutter your code and push all the different responsibilities in these three pockets, MVC. Whereas in Trailblazer you still have a monolith if you want that. But you have a clearly separated abstraction of solving problems. So, a monolith is, for DHH, is an excuse to not introduce abstraction layers. And that’s exactly what Trailblazer addresses, is you can have one Rails app but you have a beautiful structure to solve all kinds of problems in your web application.
CORALINE:
So Nick, one of the problems with monoliths is that they’re notoriously difficult to test. How does Trailblazer address testing? And what are good test strategies for Trailblazer?
NICK:
Ah, testing, my favorite area. So in Trailblazer, so since we structure code into operations you basically test your operations. And you test all kinds of edge cases using operations. You can still have unit tests for separate objects. Let’s say you have an invoice generator that generates a pdf. So, you can write separate unit tests. But your actual high-level functions in Rails, you test using operation tests. And you also don’t use factories anymore, arbitrary factories. But you use operations to create a test environment. And that gives you a production-close, or an identical environment to the production code.
And this is something I’ve been… that drove me crazy in a lot of Rails apps, is that people mock and use factories and create some application state that might be similar to the production code but might not be because they mock this and that. And in operations, if you run an operation it creates the identical environment that it creates in production. It is slower, but that is not a problem.
Because you throw more RAM [inaudible] and more CPU at the test.
SARON:
So, I have a question. So, it sounds like you’re making a really good case for Trailblazer and all the awesome things that it does. And I’m wondering. Is there a use case for not using that? Are there any very clear situations where it’s much better for me to just stick with the regular Rails?
NICK:
No. Always use Trailblazer. [Laughter]
CHUCK:
There’s never a tradeoff, ever.
SARON:
[Laughs]
CHUCK:
Writing code. [Chuckles]
NICK:
[Chuckles] You need the complex web of indirections everywhere. No, the thing is, and I say this in the Trailblazer book and on the readme as well, is Trailblazer is what I call non-intrusive. So, you can use Trailblazer where you find it’s necessary. But if you start with a really simple app, you’re happy, you’re fine to use, just use your model and just use your controller. But after five lines of code you will see, “Hmm. I don’t want this sitting in my controller.” And that’s where you introduce the operation and all the goodies it brings. But I’ve written a couple of apps with Trailblazer. I’ve seen a lot of apps because it’s actually already in use in a lot of production apps. And people stick to the operation structuring right from the get go. So, I haven’t seen… once people use an operation, they use it everywhere. And that’s pretty interesting.
CHUCK:
So, if I have some big, gnarly Rails app that is a complete mess, is like the canonical example of a poorly managed monolith, the ones that people are like, “Ugh. I need to break this up into services or I need to just go and rewrite this as another monolith,” how instead would you work on making the transition into this and watching it solve your problems?
NICK:
So, you have an existing legacy Rails app and you want to change it to a better structure? So, usually you start replacing functions or controller actions with introducing an operation for that very function or action. And it’s a bit tricky at the moment because you’re supposed to move out validations, existing validations, from models into operations or into the contract. And you’re also moving business logic from controller and model into operations. So, I think there are still problems, because sometimes people still need the validations in the model and all that kind of stuff. But Trailblazer or Reform tries to solve that by copying validations into the contract instead of making you move them physically. And so, software development is always tricky. So basically, what you do is you start to introduce concepts and operations where it was models and controller code. Does that answer your question?
CHUCK:
I think so. I think what I’m hearing is that you start toward the outside, things like your controller actions, and you start building operations to handle those controller actions. And then you just work your way down so that your business logic that’s encapsulated in both the controller and the model including validations and other things, wind up in the operation. So that the next time that you deploy or the next time that it’s handled, it’s still handled by mostly the same code. It’s just that it’s been arranged in a place where you can easily find it and modify it, and maintain your app a little bit more nicely.
NICK:
Yeah, absolutely. So, if you just replace one action or one controller action and all the associated functionality into one operation, you might not see the benefit yet because you basically, as you just said, you’re just moving code to new abstraction layers. Once you use a form object, you never want to go back to having the validations in the model. So usually, the code shrinks already because of the form object.
And then once you use callbacks and once you remove the callbacks from your model and put them into the operation, this is where you start to really understand how Trailblazer helps you to reduce conditionals and all that kind of stuff. Because validation and callbacks in models are horrible because they get triggered in every context. And sometimes, you reuse a model in different contexts. And in Trailblazer this is handled in different operations or with inheritance and polymorphism. And that’s where you start to realize, “Wow, this saves me actually a lot of code and gives me a lot of structure, because I don’t have to introduce conditionals and deciders in my models, in my controllers. But I just use polymorphism within my operations.”
CORALINE:
So, the callbacks would just go to operations?
NICK:
Yeah, exactly. So, what makes me [chuckles] what drives me crazy about models and callbacks is they get triggered, and sometimes they get triggered and you don’t want them to get triggered because I don’t want to, I don’t know, when I update I don’t want them to send out emails or that kind of stuff. And in Trailblazer you introduce a separate operation class if you need that function. If you need to update without sending out callbacks you introduce a new operation where you disable the callbacks or where you disable a certain callback, because the callbacks are defined on the operation, not on the model anymore. The model is just stupid persistence. It’s awesome. I love it.
CHUCK:
Right. So, you get all the flexibility that you want basically in a sense by subclassing or building around… well, let me back up. So, you’re getting different behaviors for different ways of accessing your model, so to speak, by creating different operations for different situations.
NICK:
Exactly. So, what you call situation is what I call context. For example, a logged in admin user might have different behavior or might expect different behavior when updating than a signed in user and all that kind of stuff. So, I call it context. And contexts are handled with subclassing and polymorphism instead of cluttering your code with ifs and else and deciding whether or not to run this code leg or run that validation or run this and that method. So, this is… and people are, the first time they see that they are shocked about, “Oh my god. You’ve created a new class.” But in Trailblazer classes map to contexts. And in Rails, contexts map to conditionals. And conditionals suck.
CORALINE:
If that’s not enough of a selling point right there, I don’t know what is.
CHUCK:
Yeah, no kidding. If you fought those, just the complexity of, okay when does this happen? How does this happen? Okay, under these circumstances but not this other… once you get more than two, three, four branches in there, it’s just, okay how do I keep all this in my head? And just by saying, “Oh, it just follows this process,” then it’s just one set of behaviors that define the entire process.
NICK:
Yeah. Maybe that’s a good way of putting it, is an operation is a set of behavior for a certain context. And if you want to change that behavior, because the context changes, you use… you can still have ifs and else in your operation and you just use one monolithic operation for all kinds of context if you want that. But I hate that. So basically, every operation class maps to a different set of behaviors which maps to a separate context.
CHUCK:
So, I have to ask one other thing and that is that Rails 5 is coming out. I don’t know exactly when. But it’s coming. Have you been working on Trailblazer to get it to play nicely with Rails 5? Or is there just not a lot you have to do there?
NICK:
[Chuckles] The thing is, nothing has changed in Rails since 1.2.3. We still have no high level architecture. And that’s good for Trailblazer, because every time Rails brings us a major upgrade, in my opinion, and I’ve been working with Rails since 1.2.3, is that all we get is new features like [inaudible] or Action Cable, or I don’t know, the asset pipeline. But that’s all unrelated to my application code. So, Rails does not give us application code as structure, which is good for me because I don’t have to worry about fixing that or making that compatible with Trailblazer.
Trailblazer’s completely decoupled from Rails. The form object doesn’t know about Rails.
And Rails 5 in my opinion, nothing has changed when it comes to application code. Because we still don’t have any abstraction. So, that’s great for me because [chuckles] it’s less work. But Rails 5, I think we’re already running tests against the release candidates or against the master code. So, nothing has changed.
CORALINE:
So, that leaves me to a question, Nick. What does the team of maintainers look like for Trailblazer? Is it just you or do you have associates you’re also working with?
NICK:
Well, that’s, oh. I think working on all those gems, Cells or Reform or Roar, for I would say the last decade [chuckles] it’s basically a one-man army with some people who’ve supported me for a couple of years. Like for example, one of the two people I want to mention are seuros and Celso Fernandes. So, those guys have been helping me for years now. But still, a lot of… because I’m really opinionated on structuring my gems, so usually when I get a pull request I usually, I merge it but then I restructure it internally to fit into the architecture or to extend the architecture. I would say there are at least a hundred contributors across all the gems. But in the end, I have to do all the hard work.
And it’s a bit frustrating because it’s shitloads of work. I got 21 gems and I have to work on all those gems. And I have to write documentation and I have to write the book and I have to, also I have to work on a daytime job because I’m not Aaron Patterson, or not DHH or someone who gets paid for open source yet.
CORALINE:
So, APIs are pretty much a hot thing now with the move to service-oriented architectures. How good is Trailblazer at… how appropriate would it be to use it for building an API?
NICK:
So, Trailblazer is actually perfect if you want to write an application for a document API because… so, we also use the Roar gem which is really popular for APIs, because Roar does both ways. It does not only render documents like Active Model serializer. It also does parse incoming documents into object graphs. And so, what’s the plan or what’s actually working in Trailblazer is you can… so, the parsing and rendering works with what we call representers. And the representer can be inferred from the contract, because the contract usually has the same structure than the actual document.
And so, you can infer the representer automatically from the contract. You can extend it. You can add hypermedia and all that kind of stuff, all the cool stuff, to the representer. And then, so you deserialize incoming data using the representer. You delegate it using the form object. And then you run your business logic. And that’s all integrated in Trailblazer in a really simple way, because we still use separate objects to do all the different tasks like deserialization or validation. And in the end, it basically feels like you’re working on an HTML form but it’s actually code to handle a JSON API or whatever. So, that’s a big selling point for Trailblazer, is how we handle document APIs.
And we use the same code for rendering and for parsing, which is something I completely miss in Rails, because rendering happens using AMS. And then parsing happens in the middleware somewhere, in the parser. And then you deserialize an object graph in your controller. You add nested authors to the comment and all that kind of stuff. And this all happens in Roar. This all happens using the representer. And I think the code is way cleaner and you have way less manual work to do with document APIs. Because parsing incoming documents is a big problem in API code. API code is not only about rendering JSON. We have great gems for that. The problem is how do we deserialize code. And that’s what Trailblazer or Roar addresses in a really clean and again encapsulated way.
CHUCK:
So, let’s say that somebody isn’t sold on Trailblazer and they just want to use some of these pieces. Can you talk about what the different parts of Trailblazer are and what they do?
NICK:
So Trailblazer basically consists of the operation. And the operation currently sits in the actual Trailblazer gem, because the gem name Operation is already taken. And if the author of the Operation gem listens to this podcast, please give me that gem name. And the form object or the contract in Trailblazer is Reform. It’s handled by Reform. So, Reform is a separate gem as I said earlier for handling forms, for defining forms and validating forms and syncing or saving the fields to models. Reform is in the process of becoming 2.0, because I’m restructuring the way Reform works. And it’s going to be less, less code, and again better structuring.
And then the thing I just mentioned, Roar is an optional part of Trailblazer. So, Roar helps you to define representers for document APIs. So, it helps in rendering JSON or XML or YAML or whatever you want, because YAML APIs are awesome. [Chuckles] And it also helps you to deserialize incoming data into object graphs. That’s again, a completely separate gem. And Reform doesn’t know anything about Roar and all that stuff.
And then another gem we use extensively which is also optional is Cells, which is view models for your view. We didn’t talk about the view layer yet. But again, view layers in Rails end up usually in a partial helper filter nightmare. And view models in Cells give you a new abstraction layer where you have objects that represent widgets in your UI. And those widgets are Ruby classes. And they don’t know anything about Action Controller and Action Controller doesn’t know anything about the widgets. So again, strong encapsulation. And it’s really, really popular. It just reached half a million downloads on RubyGems. I’m just shaking my own hand. [Chuckles]
So, most of the gems in Trailblazer are optional. So, you don’t have to use representers and you don’t have to use Trailblazer if you don’t like the way, I don’t know, form objects work. So, the point of my architectural idea is, make stuff optional. Make it well encapsulated so that different layers don’t know about each other. Or if they know about each other, then there’s only one direction of knowledge and not bidirectional. And this yields to, this yields in a really clean setup for Trailblazer and also in a really nice way of selling people to Trailblazer by just [inaudible] to Reform or to Cells. And suddenly they use Reform and Cells. And suddenly they use Reform and Roar and Cells. And then they ask me, okay, where do I put the actual business code? Because it’s like, all the new stuff is cool but there’s still something missing. [Chuckles] And then I show them the operation pattern and so on.
So, by maintaining all those workflow steps in different gems, I make it easy for people to dive into the architectural pattern without having to learn everything from the get go.
CHUCK:
So, one last question, and this is related to Rails. One of the features that a lot of people I talk to either love or hate are generators. So, are there generators that will generate the models and all of the other pieces of Trailblazer when I do rails generate scaffold or
rails generate model or rails generate operation maybe?
NICK:
Yes, and no, because I think… I’m not sure actually. I think there’s a pull request sitting out there. I couldn’t go and work on those gems for the last 12 weeks because I’ve been speaking and [inaudible]. So, we got generators. But the whole point of Trailblazer is to make generators a redundant concept, because lots of the code, a lot of code can be automatically inferred or can be convention-driven. So for example, my ideal vision is we don’t need controllers anymore. We don’t need standard views anymore. All that kind of stuff can be inferred from your operations. So, you can still have a generator for an operation. But Trailblazer aims to make you write less code. So, I’m not the biggest fan of generators.
CHUCK:
Alright. Well, let’s go ahead and do picks, then. Saron, do you want to start us with picks?
SARON:
Sure, so I have, I think I have three that I like. One is tech related, two are not really. So, the first one is this blogpost that I really, really like called ‘A Gentlemen’s Guide to Street Harassment’. And it’s by a guy. And he explains it and talks about it in just a really, really smart way. And I’ve never really heard or read anyone describe the problem and the issues around street harassment quite the way that he did. And it was just very, very well done. So, if you’re wondering what the big deal is and why does it matter that a guy told me I’m cute on the street, read this and it will all make sense to you.
My other one is called ‘Tor and HTTPS’. And this one is from the Tor Project. And it’s a really, really good, I guess diagram that explains what happens to your information when you use Tor, when you use HTTP, and when you use HTTPS. And it talks about what someone in your Wi-Fi network gets to see, what the NSA gets to see, what your ISP gets to see. And it’s a really nice, clean visual that tells you what happens to your information and who gets access to what based on what you use. And I really like that one.
And my last one which is just for fun is, oh my god it’s so funny. It’s called ‘How it feels to watch a user test your product for the first time’. And it’s this [chuckles] it’s a gif of a guy trying to drink from a cup of water but he doesn’t know how to use the cup of water. So, he just looks ridiculous. And it’s just so accurate when you put the product out for the first time and you’re trying to, you’re watching it and you don’t want to say how it’s supposed to work because it should be intuitive. So, I think a lot of developers would really appreciate it. That’s all I got.
CHUCK:
Very nice. Coraline, what are your picks?
CORALINE:
Sure. My first one is a new website called HumaneDevelopment.org. It’s based on a series of talks that Ernie Miller has been giving at several conferences. It’s essentially a manifesto. Its core principle is that we are humans working with humans to develop software for the benefit of humans. It states the need for development organizations to embrace four basic principles. Those are empathy, honesty, trust, and autonomy. And how by doing so, that makes the workforce and our feelings about our jobs much, much more productive, more happy, more effective.
My second pick is ‘The Left Hand of Darkness’ which has just been released as a radio program on BBC Radio. It’s a radio dramatization of Ursula Le Guin’s novel from 1969. If you haven’t read it, ‘Left Hand of Darkness’ was very groundbreaking in its approach to gender. And it’s very relevant, just as relevant today as it was 45 years ago. It’s really great sci-fi with incredible humanity from a really brilliant feminist writer.
CHUCK:
Very cool. I’ve enjoyed some of her other books. So, I’ve got a couple of picks. The first one is I watched a trailer for Star Wars VII. I’m super excited. So yeah, so I’m going to pick that. I think you just go to StarWars.com or something and see it.
And then I’m also going to pick a utility I’ve been using called WorkFlowy. I have tried just about every task management for my personal to-do’s under the sun. And none of them seem to really fit. And WorkFlowy seems a little bit more freeform which I think is going to be helpful. So, I’m going to pick that.
And I also just want to pick the episode that I wasn’t on with Dave Thomas about limerence. I just, I
loved that episode. And so, I’m going to pick that as well.
And finally I want to let everybody know that the JS Remote Conf talks are up. So, if you’re interested in ES 6 or Angular we had the Angular core team do a Q&A. If you’re interested in all kinds of web development stuff, there’s a talk on Ember. There’s another talk on Angular. I talked about freelancing. John Sonmez who was on the show before talked about marketing yourself as a software developer. Just a bunch of great talks. So, I’ll put a link to that playlist on YouTube in the show notes and you then you can go check it out. But definitely go check out Jessica’s talk, because it was awesome, too. So yeah, so those are my picks. Nick, what are your picks?
NICK:
So, my first pick is obviously the Trailblazer book which is on Leanpub. And it’s six chapters and it’s going to have a couple of more chapters soon because I’m back from my conference trips. If you want to support my stuff, please buy it now, not in five years.
And my second pick is the Cinco Face Time Party Snoozer which is a commercial, a fake commercial on the internet about a mask you put on and it gives five distinct voice responses at a party. So, you can sleep and the mask answers the people. And once you watch the commercial you will use those [chuckles] distinct voice responses in your everyday life. So, my last pick is the Cinco Face Time Party Snoozer, really popular amongst Ruby developers.
CHUCK:
Very cool. If people want to know more about Trailblazer or about you and what you’re working on, how do they do that?
NICK:
They friend me on Skype and call me. Or they visit me in Byron Bay or in Sydney. Or they meet me at conferences. Or they just email me. And that’s apotonick@gmail.com.
CHUCK:
Alright. Well, thanks for coming. We’re going to wrap up the show. We’ll catch everyone next week.
[This episode is sponsored by MadGlory. You’ve been building software for a long time and sometimes it’s get a little overwhelming. Work piles up, hiring sucks, and it’s hard to get projects out the door. Check out MadGlory. They’re a small shop with experience shipping big products. They’re smart, dedicated, will augment your team and work as hard as you do. Find them online at MadGlory.com or on Twitter at MadGlory.]
[Hosting and bandwidth provided by the Blue Box Group. Check them out at Blubox.net.]
[Bandwidth for this segment is provided by CacheFly, the world’s fastest CDN. Deliver your content fast with CacheFly. Visit CacheFly.com to learn more.]
[Would you like to join a conversation with the Rogues and their guests? Want to support the show? We have a forum that allows you to join the conversation and support the show at the same time. You can sign up at RubyRogues.com/Parley.]
206 RR Trailblazer with Nick Sutterer
0:00
Playback Speed: