 Thank y'all for coming here to hear me speak. I'm very honored that y'all are here to see me. My name is Daniel Sherpeck. I go by Dash on the internets. You can find me on the Tritters and the Githubs and all that. I came all the way from Copenhagen to be here. Copenhagen is not usually like this. Usually it just rains. But I couldn't use a photo of that. That'd be sad. OK. So first of disclaimer, it's not going to be any JavaScript here. So I'm very sorry we thought that. We'll have something that will look a bit like mustache. So you'll feel familiar if you're looking for JavaScript. But I'm sure how many here do mainly like JavaScript front-ending? That's fucking not a lot. OK, great. So this is all server-side Ruby-generated views right now. It's more like classical EV stuff. So I'll get into all that later. I didn't want to disappoint too many people. I work at a place called Sendusk. We do customer support software. We are hosted platforms. So you'll get an email address that people can complain to. And it will give you an UI so your employees can manage support requests, all that stuff. This title, Curly, you're thinking of the view layer. I'm going to get into what Curly is. Curly is an open-source project that helps you write great views. However, I feel like there's a nice story behind some of the design decisions, why Curly looks the way it does. And I want to start out by sort of telling you that story. And then I'll talk about Curly and how it will make your lives a lot easier. So it all started with how we came to build a new template language. And why we did that. It's not something that you typically set out to do. It's sort of a pain in the ass. And once you did that, you have to write the actual templates in that language. And what if you then decide that it was a stupid language, then you have to rewrite all your templates. So it's something you really think long and hard about before you do it. And there were lots of options already. So why did we do it? Well, for the last three to four years, I've been working on a product that we call Help Center. It complements the main send us functionality, which is ticket support. It's a hosted knowledge-based and community site. And it integrates with Sentence. But it's sort of its own product. This was version two, basically, of an older product that we had. That was also a hosted knowledge-based and community site. But it had several shortcomings. And one of the big shortcomings was that it was very difficult to customize. We allowed our customers to upload a custom logo and change some background colors. But when users entered the knowledge base, it all looks sort of alike. And they definitely didn't look like the brand of our customers. And our customers were not happy with that, of course. So we then made the choice to allow them to inject JavaScript into their knowledge base and community site. And that worked. You can do a lot of stuff with JavaScript. And they did the added custom widgets, and the added text, the removed features they didn't like, and the reordered stuff, the change of colors, the fonts, everything so that it sort of looked like their brand. It was great, and they were somewhat happy. But that implementation had some shortcomings. Mainly, when you loaded the site, we would first render the default look and feel. And then once DOM loaded, hit, a bunch of JavaScript would be rendered, would render everything, and change everything, and things would move around and jump. It sort of felt weird and didn't feel that professional. Another big problem was that since our customers were using JavaScript to change things, they could depend on anything. Like, they used any class name, any sort of tag name to tie in behavior and to do selectors and move stuff around. And that, in turn, meant that we couldn't really change anything about the HMO without breaking lots of customer sites. And we had tens of thousands of customers. So it was impossible for us to know what would break for whom when we made a change. And in the end, it meant that we didn't really update that site, and we just let it sort of stagnate, because there's just too much pain to actually make changes. So it looks like something from the early 2000s, which is sort of bad when you're trying to sell to new customers also. So we decided that, for version two, among other things, we wanted to address that problem. We wanted to have a proper fix for it. And we had lots of discussions. But finally, we decided that we wanted direct support for theming and customizable templates. We wanted our customers to help define how the site should actually be rendered when we render things into HTML and should happen upfront, not as sort of a thing that happens after we deliver the site. So we had lots of discussions about how that feature should work, what kind of access should people have, how much responsibility should they have. And we had one extreme was that we just had a drag and drop thing, and the other extreme was that he did everything themselves. And we ended up somewhat in the middle. So the idea was that we provide a set of predefined components, and we have default templates that they can just use, and they look nice. And then the customers can go in and change all the HTML they want as long as they don't mess with the components. So the components are just something that they can move and remove if they want to. Maybe they can have multiple instances of them, but they can actually make changes to them. This allowed us to minimize sort of the API surface that we had to support to just those components, and it made things a bit more manageable for us. Since then, we've learned other things, and it's gotten a bit more complex. But in the beginning, that's what we wanted to do. So at that point, we had already ridden most of the site. It was functioning, and we had the knowledge base on the community. Everything was there. So we sat down and talked about how we wanted to actually implement it, like how should customers actually do this? We knew that they wanted to actually use HTML. We had to ask some of them, and there's no reason they shouldn't have access to the HTML itself. So otherwise, they'd just resort to JavaScript again. We didn't want that. So we looked at what we had. And what we had was ERB. All our views were written in ERB, and the views that we intended for the customers to customize, they were also written in ERB. So the simple thing would be to just allow customers to open a text field with the view in it, and just type ahead and save, and we would use that. And we thought of that for around 30 seconds, and then we realized that was the stupidest idea ever, and we didn't want to do that. So early on, we decided that customers should write templates. They shouldn't be programming. They're not necessarily programmers. They may be web developers, but mostly in terms of HTML and CSS, and maybe a sprinkle of JavaScript to use DHH terms. So we started looking at safe templating languages, and there are a few. We were already using liquid in other parts of our application, so we thought about using it here, too. So there were a few reasons that's why we didn't do that. Liquid is very cool, but it's also very granular. It feels almost like a programming language. It's safe to execute, but you still have to provide very granular data structures for it to be useful. So we would have to define this huge API of nested objects that would be passed to the customers, and there would be functions, and there would be loops, and all this stuff that was just too powerful and too advanced for what we wanted. We wanted something that was simple and approachable. We also looked at mustache. So mustache, if you do JavaScript programming, you probably know mustache or handlebars, which I think EmberJS uses. It has a very simple syntax, at least mustache. Handlebars has added a lot of bells and whistles. And it was actually pretty close to what we wanted. It's very declarative. There's no logic. There's no for loops. It's just simple. The main problem was that it was not well suited for rails. There was a Ruby implementation, but that was completely decoupled from rails. So we would have to go all in on mustache. We were not prepared to do that. We wanted something that we could use on just the outer layer of our views, just the things that our customers should be able to customize and nothing else. There are still lots of small portals and other views that we didn't want to convert. We just wanted to keep them as it were. We also wanted something that was baked into rails and used some of the niceties of rails, such as caching and whatnot, which also was a big deal for us. So we came up with a list of things that we wanted, but we couldn't really find any language that provided all of it. So we wanted the templates to be safe, of course, because we were running them and executing them on our service. We also wanted it to be declarative. We wanted our customers to signal their intent in terms of where they wanted to place stuff. They were not supposed to construct advanced stuff. And we wanted to keep all the logic in a separate place. We didn't want to expose that to our customers. They should just decide where to put stuff. But all that advanced stuff in terms of generating view related output, all that stuff, conditional stuff, we wanted to keep that out of the product. So we could have a symbol product and keep the complex out of it. And we wanted to be testable. This would be an API, and we would have people who depended on it to be stable. So if we made a change and it suddenly broke something for a customer, we would get complaints and they'd be unhappy. So we wanted to have regression tests in place so we could make sure that we respected our end of that working. And we also wanted to integrate well with our existing Rails app. So we decided to build Curly. It's heavily inspired by mustache, but it's different in some key ways. You keep all your HTML in templates, and you use the Curler Bracket notation to place around components wherever you want them. All the logic is kept in Precenders. And Precenders are just plain Ruby classes that reside in App Precenders. Those Precenders have full access to all the things you know from year B. So you have link helpers, path helpers, and form helpers. You can render partials, you can do whatever. And it can be used alongside AP and Hamel. So if you have existing fragments or partials, you can just render those directly from within Curly and the other way around. So it integrates completely into Rails. That was very important for us. This is what a pretty simple, but also very typical Curly template would look like. You have your components, as we call them. Which are just names surrounded by Curly brackets. And then you have your HTML. So it's very readable and very simple. And all the Precenders were placed in App Precenders. And they're just normal Ruby classes that inherit from Curly Precenders. So did you all attend Aaron's keynote this morning? Yes? Did you sleep in? So in it, he talked about the problem of not knowing which local's view is using. So if you render a partial template in Rails, the partial may use some local variables. And it's very difficult to know upfront what those are. So he talked about having to parse it self out. Actually in Curly, we decided early on that we wanted an explicit list of variables that a given template should accept. And we wanted it to just crash and complain if it didn't provide that, because we had run into issues previously where we were hit by issues around that. So we decided we wanted it to be explicit. So actually it's very easy in Curly to just ask a Precenter what do we need, and you'll get a list. So here we say, well, we expect there to be an article variable pass me. I'm presenting an article. And then you can just have a number of public methods. You can see that article is available as an instance variable. It's magic. So each component maps to a public method on the Precenter class. This is all done automatically for you. A lot of the stuff you could do manually, but Curly removes all the boilerplate and all the overhead. And it ensures that each public method there also has access to all the helpers that you need and to rendering stuff. And there's a simple naming convention where each template maps directly to a Precender. So we were happy. We used this. It was pretty generic, but we could store our templates in the database. We had some on disk. And then if a customer wanted to customize, we would store their templates in the database. And we were able to inject some resolution mechanism into Rails, meaning that we could actually get the templates from there. But we would reuse the same Precender. So that made things a lot easier for us, because we only needed to test the logic once. And it was safe. And it was very simple. Our customers were very happy. And we rolled it into our product. And you have an inline editor where you can go in. You can change your templates inside the product. You can preview changes. It also allowed you to edit CSS and JavaScript and all that stuff. And it was very cool. And I was very proud of it when we shipped it. And that's, I think, like two years ago, two and a half years ago. And it's been running ever since. So we were happy. And we sat back. We were proud of ourselves. We started thinking, you know what? We looked at these templates and the Precenders. And then we looked at the rest of our templates that we didn't convert, because they weren't customizable. And we started to wonder, maybe this curly thing is actually more useful than we initially thought. Maybe it's not just for customization. Maybe it's something that we want to use more broadly. So just to give you an example, this is actually a simplified version of an actual ERP template that I extracted a few years ago from our app. I think it's pretty typical. It's not overly simple, but it's not a hugely complex adder. You could definitely go in and make changes in ERB to make it simpler, but hopefully you've all seen sort of this kind of thing. So if you look at it, how much of this is actually structured? How much is it related to the ordering of things or the HML? I can help you out here. Not a lot. Most of this is actually Ruby code. It's logic that determines how some stuff should be looking. But it's very difficult for, say, a front-end developer to go in and if you're told, oh, we need to wrap the common form in a div and give it some class. Well, where's the common form? Well, in curly, it's a lot easier. Because all the logic has been extracted and identified, which is just as important, you can go in, you can see what is what, where is the common form. You can rearrange it, and you can suddenly see where all the HTML is. So that's a big deal, and our front-end developers are very happy about that, because it made their lives a lot easier, especially if you have big HTML pages containing a lot of markup. If you remove all the logic, all the Ruby from there, you left just the essence, just what they need. That was really cool. On the other hand, we back-end developers, because I'm not a very good front-end engineer, I should probably say that. We were left with Ruby classes, and we know them. There are things that we can deal in. We can use private methods to clean up stuff. We can use inheritance. You can do whatever you want. This is separation of structure and logic, and it really helped us to improve the state of affairs for our entire view layer, which was pretty big. And it basically meant that we could move at a much faster pace. We can start dealing with some of the complex logic that have been trapped inside year B. You have some in year B. It's like your option is keeping it there, or maybe extracting a partial, or maybe extracting a helper. But none of those options are always perfect. Now we can just use Ruby. One of the issues that we had previously was that we sometimes reused some views in multiple controllers, and you had to remember to include the same presenter classes in each controller because the view would need it. So that was sort of annoying, like the controller needed to know what the view needed. In curly, you don't need that, because you can just include a module. There's nothing magical about it. Helpers are not special. They're just methods inside a module. And you can use inheritance and whatnot. So that made a lot of sense here. So I talked about testing earlier. And testing is a big deal for us. We used RSpec, and we had used ViewTests previously. And it had been sort of a hassle. How many of you do view testing in your Rails apps? A few. So hopefully some of you know sort of what I'm talking about. But it can be a hassle. Basically, what you do is you want to test some specific piece of logic. And you just want to test that it's either this or that. But you have to pass all the needed variables to the view, then you need to render it. Then you're given back this huge blob of HTML. But you really want to interest it in just a slight, like a tiny part of it. So you try to use a library for parsing that HTML and getting out that specific tag that you're interested in, and that you can then make an insertion of just that. And we found that to be very brittle and error-prone. Sometimes you would test if something is empty, and you think that you're testing the right thing. But actually, you're just selecting the wrong thing. And it's always empty, so your tests will always pass. And it doesn't actually matter that you have a test. So we wanted to change that. So if you look at traditional view testing in a more graphical way, there are three parts. You have the test, you have a view, and you have a port step. And you have to go through this entire cycle. What we did in Curly was that we just cut out one part. We're not actually interested in testing the template itself. We're interested in testing view logic. So we just pass variables to the presenter class itself when we initialize it. And then we just call methods on it. There's nothing magical about it. You can literally just call a method, and you'll get back the result. And you can make assertions on just that piece. So that was huge for us. It meant that we could much more easily maintain the API and do specific unit testing. So what we wanted to do is test the logic. We didn't want to test the structure. You can test the structure by just looking at the template and seeing the things in the right order, right? Or just opening your browser. Next up is caching. Caching is also a big deal for us. We use Russian doll-style caching. How many do you use that? Caching, general? So quite a few. Basically, we have a lot of caches, and they're nested. So using the right cache keys is important for us. And typically, in year B, you'd have to specify the top level cache, and then the cache key, do, and then a bunch of stuff in there. And it means that everything is mashed together in this one file, and it's really difficult to test, too. So we wanted to have better support for caching and curly. And we found a pretty good way of doing it. Basically, if you have a cache key method in your presenter class, that view is going to be cached. If it returns a non-nil value, it will cache that view, the output, using that cache key. So that makes it very simple. You can have much more complex logic in your cache key, and you can use private methods and whatnot. It also means that you can actually start testing your cache keys. You can ascertain that if you pass in two different values for some variable, then the cache key will be different, which is actually a very nice way of testing that stuff. So what I'm getting at is sometimes it makes sense to use the best tool for the job. And there's definitely value in just having one size fits all thing. I think that's part of the real mantra. But in this case, I feel that Markov language is actually pretty cool. There's a reason we don't just have a precedual thing that renders pixels on a screen in the browser. You send back HTML. And HTML is nice, because it's Markov. You can see structure. It's very easy to identify the constituent parts. On the other hand, HTML is pretty bad for actual writing code. It's not actually possible. So you use your Ruby for that. But it feels like it makes sense to separate the two, because there are different things. So it's actually fun to see Aaron's talk this morning, because he went into some of the things that I've been looking at the last few years and been frustrated at. But he also talked a bit about caching views. And I'm not sure how much you know about the internals of action view. It took me a while to actually figure that stuff out. But I just want to show you basically how view rendering works and where curly fits into action view. So you probably only deal in action controller. You have a controller action, and it either implicitly or explicitly renders a view. So you can pass, you know, render some name. Or you can just let that name be the name of the action edit or show or something. So what action controller does is it passes that template name to action view. Action view will look around on the disk, and it'll try to find that probia template. It'll load that and wrap it in an object. It'll then find the appropriate template handler. Usually that's done by looking at the suffix, like dot ev or dot handle, or in our case, dot curly. It'll then pass the template object to that handler. And the handler is actually responsible for compiling that source code into Ruby. And it'll do that and then return it back to action view as a string containing Ruby code. So what action view does is it keeps an anonymous module around containing a bunch of methods. Each method corresponds to a view. And it'll take that Ruby code and it'll create a new method on that object named after the view. And it'll just put that source code in there and it'll e-ballad, and then it'll call a method. And the method will actually execute the Ruby code, and it'll return the HTML, and action view will return that back to action controller. So the nice thing is that the next time action view sees that template name, it doesn't have to actually compile it, because it can just call that method on the module. So that's what Aaron meant when he said caching abuse. And this is, of course, only done lazily and is done in each unicorn process if you're using this. So there are definitely issues, but it's a pretty clever implementation of this. So I've been talking about curly for a little while. So do I think that it's just awesome you should always use curly? Well, no. That's seldom the case. It's not an either or proposition. Curly has sold us out a lot, but we also tend to have some complex views. We still use ERB for a lot of cases. Like, if you have something as simple, ERB is great. Like, you don't care that things are mixed in a bit together. Ruby's not about being, you know, dogmatic. It's about using the best tool for the job. And if you have like a two line template, there's no reason to use curly for that. Just use ERB. Or if you're in the initial stages of building something and everything's in flux, ERB is great. You only have one file. You can easily move things around. You don't need to have a presenter class and a template match up together. But once you read some threshold of complexity, curly is a great way to actually start thinking of things in terms of a proper API and having a proper language for defining the structure. So I definitely encourage you to have a look. As for Hamel, I've talked to several Hamel people. I see Hamel as being sort of the same as ERB. It's just from a different perspective. So in ERB, you basically put lots of Ruby code inside your HTML. In Hamel, you put a lot of HTML code inside your Ruby. But it's basically the same things in terms of like design. You still cut things similarly. You don't separate the structure from a logic. You just blend them in in a different way. So this has been running in production for more than two years. And other companies are also using it. A bunch of people in Brazil are using it for some reason. I don't know. So it's been a huge success. And we've open sourced it as curly templates. Someone already took curly. It's a wrapper on a curl. You can just use curl, but OK. So it's called curly templates. And you can just drop it into your Rails app, and it will do nothing. So it's not going to break anything. But if you then change one of your templates to be dot curly instead of dot EAB, it will use curly. And you'll set up a presenter, and you'll extract code. And boom, just that one template will use curly. And you can use ERB for the rest. So it's very easy to try out and play around with. And I think it's actually pretty cool. So this was maybe a bit short. I think probably we have some time for questions if you want to. Just want to thank you again for coming. And you can go on GitHub, and you actually get this. It's open sourced and all that. And pull across the welcome. I really hope that some people will start looking at it and maybe contributing or finding useful purposes for it. So I think we have some time for questions if anyone wants? Yeah, so the question was, in our product, does the customers know what's available in terms of these components? So yeah, we have a nice documentation part, and we have auto-completion. So they can just type curly, curly, and it'll see a list. And we have descriptions and everything. So that's pretty cool. Yeah, exactly. Within the editor, we have sort of an ID kind of thing. So the question was, in this very astute observer, noticed that in one case, there was actually some HTML in the presenter in the form of a content tag. And that's right. And basically, I don't really care. I'm very pragmatic about that. And if you use any kind of link helper or form helper, that's basically the same thing. But I think you just want an API that says, I'll return a blob of HTML to you. And you'll actually create HTML in the presenter still. This is logic-driven HTML, right? So in that case, yeah, it doesn't bother me. It's still very simple. And if you want a very clean, logic-only layer, then you should create your own presenter, objects, or decorators outside of Curly that don't know about HTML at all. The benefit of Curly is that actually it knows form helpers. It knows link helpers. It knows all your paths. So you can actually do the clever view rendering stuff. It's view logic. It's not domain logic, right? Yeah, so the question was that if you want to render a collection, how do you do that? Basically, you can do it inline in Curly. You can use render a collection, something, something from the presenter, which will just use a normal mechanism, which is rendering a different template multiple times. So you have different options there. And you can also do it in the method itself if you want to just return HTML. That's probably messy. Yeah, oh, the question is what if you want to put like classes, if you're generating HTML in your presenter using, say, link to and you want to put like classes and stuff in there, whether that's like crossing some boundary in terms of where the frontend stuff should go. Well, I consider presenters to be the frontend also. They're just the view logic. But they're still view code, right? They're not back-end code. They're not domain logic. And if you have stuff that sort of smells like domain logic, that should probably go into the model or something. But yeah, it depends on your citation. Like if you have frontend developers who don't mind opening Ruby classes, then I would just do that. But if you have like a strict requirement of all UI stuff being in Curly, you can also do that. You can just like have, you know, article path, something, and it returns the path. And then you just do, you know, a ref equals and do the entire thing itself if you really want that. Like we do that in some cases where we want full access. So both are valid and both are supported. Cool.