Domain-specific languages (DSLs) – are they worth the hype? In a recent investigation, our Berlin-based Android Team were looking to further optimize Wayfair’s Android app, and were looking around for options. With the inconvenience of creating a UI in XML, and the appeal of a language that focuses on a specific aspect of an application, our team chose to give Anko Layouts a try.
Theoretically, domain-specific languages should be understandable enough that non-technical people can read and understand them. This was a core reason why we started looking into Anko Layouts. On the inconvenience side, the
Anko Layouts wiki states that XML is:
- Not typesafe
- Not null-safe
- Forcing you to write almost the same code for every layout you make
- Is parsed on the device, wasting CPU time and battery
- Doesn’t allow code reuse
Anko Layouts were actually part of our production code for a short period of time last year. Due to some problems with blank screens on older operating systems, we decided to revert back to XML in that case. It was now time to revisit history.
About the Wayfair App
You might already be familiar with Wayfair’s Android app – if not, our previous look into Kotlin and JaCoCo gives a good overview. To paraphrase, we have weekly releases to support what might be characterized as your usual e-commerce app, with our architecture a hybrid of VIPER and Clean. This combination allows for a separation of responsibilities between “layers” and increases the code coverage of our unit tests.
For the purposes of our Anko Layouts investigation, we’re using a simplified version of our production code. The actual code is provided at the bottom of the article. Let’s get started.
Diving into Anko Layouts for a Second Time
As I mentioned, we had previously dabbled with Anko Layouts but returned to XML in that instance. Here, we decided to give Anko Layouts a second try: We built two simple apps, one using Anko Layouts, the other using XML. We used this approach in order to create realistic benchmarks for future consideration and use.
The Layout is Code
With Anko, you create UI programmatically by using DSLs, which should bring about all it’s noted advantages. However, If you aren’t careful, nothing prevents you from adding other responsibilities into this code. That would be against the single responsibility principle. In contrast, XML prevents you from adding any kind of code – this is great! The layout should only define a structure for a user interface in your app without any additional logic. Out of the box, there is a clear separation of concerns.
Time for a warning: When using Anko, your code could crash if you need to support older versions of Android’s operating system. In order to define margins, you would have to do the following:
In this example, your IDE would complain if you don’t define correct margins for different OS versions, but with this, your code could get ugly:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
marginStart = dip(16)
} else {
leftMargin = dip(16)
}
In the examples your IDE wouldn’t complain, but the app will crash with an older OS – if you aren’t careful enough you could run into production crashes with older Android versions:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
foreground = ctx.getDrawableFromAndroidAttr(android.R.attr.selectableItemBackground)
}
……
relativeLayout() {
val txv = textView() {
id = R.id.profile_text_viewholder
textSize = 6f
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
txv.lparams(width = wrapContent, height = wrapContent) {
alignParentStart()
}
}
else {
txv.lparams(width = wrapContent, height = wrapContent) {
alignParentLeft()
}
}
}
Code ugliness is something we can control by using extension functions, but IDEs are not yet smart enough to prevent us from causing errors like this.
Preview in Design Time
A very important aspect of UI development time is a preview. Developers should be able to access a preview, in a speedy way, of all the changes they’ve made without building the whole project over again. We achieve this with the XML Preview Tool from Android Studio, but unfortunately, this functionality isn’t available for Anko Layouts.
There is an Anko Layout plugin available, but we found it very unstable and incredibly difficult to use. At the moment of writing we’d been using Android Studio 3.2.1, and the Anko Layouts plugin was broken at the time. Also, we couldn’t find a way to use the tools namespace for Anko Layouts, so the preview option isn’t so great in design time; it can be frustrating when you have to run your code every time when you want to see the UI changes you’ve implemented.
Impact on CPU Time and Battery
On the Wiki page for Anko Layouts there is a claim that “XML is parsed on the device, wasting CPU time and battery”. Using Anko sounded like a great improvement to delivering the best user experience in our app by saving the user battery.
We took all of our measurements on the Android Emulator Pixel 2 API 26. We compared this with Android Profile CPU usage in between the two versions of layouts. Our finding was that there was no big difference in CPU usage, however, some slightly better performance with XML Layouts.
XML Layouts:
Anko Layouts:
We also measured the time needed for the onCreateViewHolder method to execute inside the RecyclerView adapter.
Anko:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
val timings = TimingLogger(HomeRecyclerAdapter::class.java.simpleName, "onCreateViewHolder")
val itemView = AnkoViewHolderListUI().createView(AnkoContext.create(parent.context, parent))
timings.addSplit("onCreateViewHolder done")
timings.dumpToLog()
return ListViewHolder(itemView)
}
XML:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
val timings = TimingLogger(HomeRecyclerAdapter::class.java.simpleName, "onCreateViewHolder")
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.image_text_view_holder, parent, false)
timings.addSplit("onCreateViewHolder done")
timings.dumpToLog()
return ListViewHolder(itemView)
}
All of the measurements we took were very similar, as noted below:
This data seems to point in favor of Anko as being faster. It seems that Anko beats XML in fifteen cases, and XML beats Anko in four cases. When Anko does take longer, however, it does so for a specific reason that we have yet to be able to investigate.
The graphical representation of this data is below:
The results on first glance look as though XML Layouts have much better performance, more than twice over, in fact. If we ignore the best and the worst results, the numbers will be in favor of Anko.
We are not exactly sure why Anko sometimes takes a longer time, but it looks like Anko Layouts are slightly faster than XML. We hope to investigate this further in the future.
Build Time
As you already know, a slower build time means using more of a developer’s hours. Build time is important to us, and we’re always trying to save some time in the build process. As part of our investigation, our team also compared build times for these two implementations. Low and behold, the Anko version turns out to be slightly slower. We looked at clean builds versus incremental ones in order to compare and take note.
Clean builds:
Incremental builds:
Our Conclusion
Here at Wayfair, we are very curious about how DSLs will be used in the coming years. We are excited that with Kotlin you can create your own DSL, allowing you faster development and more readable code across teams, whether team members are technical or not.
With Anko Layouts, we can gain a variety of improvements: View rendering time is shorter, plus less CPU and battery usage. However, we’re also concerned about Anko Layouts due to the following:
- The separation of concerns for your layout is not clear
- There are problems with UI previews at development time
- It looks like build time would really go up for bigger projects
- Finally, there are issues with older OS versions
The above considerations are why we wouldn’t replace XML with Anko Layouts at this moment in time for production projects. It was great to explore this possibility; perhaps using Anko Layouts in places where you have to do so programatically could work – we’ll keep the blog updated as we continue to experiment. We can’t wait to see how this will evolve in the future!
For a look at the projects we used, see the links below – thanks for reading!