For several years we have witnessed a small revolution in the world of network applications. The concept of returning ready HTML documents is being replaced by dynamic JS applications generating client-side views. This does not mean, however, that the traditional approach is completely obsolete. In fact, it is still a huge part of web services. Today we will compare two such solutions. 

A few years ago, when generating views on the server side was the most common practice, the template mechanisms were considered the best and most modern solution. In the world of JVM we have two classic and official standards - JSP and JSF. JSP was widely disliked and criticized mainly due to its mess of HTML and Java code. Their successor - JSF - was tightly integrated with the rest of JEE, which was replaced on the market by Spring, so that the JSF itself did not gain much popularity. It seems to me that the architectural specificity also contributed to this. In SpringMVC, each HTTP request corresponds to one controller method (request-based MVC), which makes it easy for the developer to manage the authentication and logic of the request and to debug it - everything is in one place. JSF is a solution based on distributed ManagedBeans components (component-based MVC) - interesting but also much less convenient. Few know that Oracle in JEE 8 (2017) also presented the request-based approach (JSR 371 - JEE MVC), but it did not gain much popularity. These solutions, although they can still be found, have been quite effectively replaced by unofficial technologies such as FreeMarker or Thymeleaf - especially in combination with Spring MVC. Although generating views on the server side is losing popularity, they are still common standards.

Templates have been the standard for creating server-side views for several years. Nobody is going to concat strings in the controller, right? Solutions generating HTML code using objects representing HTML elements have always had marginal popularity due to the low convenience of their use and dissimilarity to HTML code. Or rather it was so until the introduction of the Kotlin DSL.

If someone does not know what Kotlin DSL is, I will explain it briefly. In general, Domain-Specific-Language is a language specific to a given, narrow use - as opposed to general purpose languages ​​(GPL). Examples include AWK or even the REGEX. HTML itself is also a DSL as well as template languages. Kotlin DSL is, however, internal DSL, i.e. the domain language within the general-purpose language which is Kotlin. Therefore, it is not a separate language, but rather a subset of it for a specific application. Or at least that's what its creators define it, because in my opinion they are simply interesting syntax sugars that allow to convenient creation of objects: extension functions, lambdas with receivers and lambdas outside of method parentheses. As a result, many different "DSL" can be created for specific applications. Anyway, look at this banal and simplified example:

data class Document(var attribute: String? = null, var subElement: SubElement? = null)
data class SubElement(var subattribute: String? = null)

fun document(block: Document.() -> Unit): Document {
val document = Document()
block(document)
return document
}

fun Document.subElement(block: SubElement.() -> Unit): Unit {
subElement = SubElement().apply(block)
}

// example of use
document {
attribute = "A"

subElement {
subattribute = "B"
}
}

The key elements of this solution are, of course, the "block" parameters of the Document.() -> Unit and SubElement.() -> Unit types. They are simply lambdas with receivers that can be called on Document and SubElement objects (in fact taking such an object as a parameter). Thanks to this simple trick, composing objects (e.g. HTML page representatives) looks almost as good as a template (it resembles JSON syntax) and we stay in the programming language with all its benefits. Well, let's see some real example. The home page of Hex.log is currently created using such a template:

<!DOCTYPE html>
<html th:lang="${#locale}">
<head th:replace="head.html :: head"></head>

<body onresize="resize_posts()">
<header th:replace="header.html :: header"></header>
<div class="main-body">
<br>
<!--/*@thymesVar id="posts" type="java.util.List<domain.Post>"*/-->
<div class="post" th:each="post, stat: ${posts}">
<!--/*@thymesVar id="post" type="domain.Post"*/-->
<button th:id="${post.id.value}" class="post-header openable" onclick="toggle_collapse(this)" th:onauxclick="|window.open('${#locale}/post/${post.id.value}')|">
<p>
<span th:text="${#temporals.format(post.createDate, 'dd.MM.yyyy')}" class="post-date"></span>
<span th:text="${post.title}" class="post-title"></span>
</p>
<p th:text="${post.shortcut}"></p>
</button>
<div class="post-panel"></div>
</div>
<br>
</div>
</body>
</html>
The equivalent of this in the Kotlin DSL is the following code:

fun mainPage(language: Language, posts: Array<Post>): HTML.() -> Unit = page(language) {
br()
posts.forEach { post ->
div("post") {
button(classes = "post-header openable") {
id = "${post.id?.value}"
onClick = "toggle_collapse(this)"
attributes["onAuxClick"] = "window.open('/${language}/post/${post.id?.value}')"
p {
span("post-date") { +post.createDate.formatted() }
span("post-title") { +post.title }
}
p { +post.shortcut }
}
div("post-panel")
}
}
}

And how it looks like to you? In my opinion, it is quite bearable, although it also has its cons so let's compare both solutions:

There is one more argument - for the template approach you always need to have a full set of data, the collection of which may be difficult and not necessarily required if their use is conditionally. Of course you can use lazy wrappers, but it is another nuisance. In such cases, various templates are often written. There is no such problem in KDSL where verything can be conditionally invoked while composing.

So how does the comparison of both solutions looks like? I personally prefer KDSL. Although it is usually a bit uglier, it gives me more freedom to compose and better flow control. I am glad that the developers of ktor-html-builder have made it possible to insert custom attributes. Without it, it would not be possible on Hex.log to conveniently implement opening a post in a new window by clicking the middle button on the title bar (did you notice this functionality?)

Should we announce the end of templates then? Contrary to Betteridge's law of headlines, I believe so. Not only for HTML generators, but in fact all such documents - XML, JSON, YAML, etc. Of course it will not happen immediately - templates are not a horrible solution, but there are better alternatives. I think they will become obsolete over time, and programming with XML and templates will be seen on a par with the GOTO instruction. 

I am also making this change on Hex.log. I make a pull request of the Thymeleaf exchange for ktor-html-builder on Github. Review it and let me know what do you think. I would also like to thank my friends from the Hex.log Reviewers group: Gosia and Grzesiek for their help. If you want to join them and help in the development of this blog, write to me