Thursday, March 19, 2020

Tech Book Face Off: Rails AntiPatterns Vs. The Rails 5 Way

It's been a while since I've cracked open a Ruby on Rails book, and there were still a couple of these books that I've been meaning to read. So far the Rails books I've read have been beginner's books and tutorials. With this latest pair of books, I wanted to go deeper into Rails and learn how to program fluently in the framework. The first book, Rails AntiPatterns: Best Practice Ruby on Rails Refactoring by Chad Pytel and Tammer Saleh, was published way back in 2010 when Rails 2.3 was cutting edge. I took a chance that the book would focus more on timeless advice than version-specific tips and tricks. The opposing book, The Rails 5 Way by Obie Fernandez, was published much more recently at the end of 2017 and should be at less risk of being out-of-date. Although, it looks like Rails 6 will be out soon. One thing's for sure: technology doesn't stand still, but that shouldn't matter too much if the books take that into account. Let's see how they fare.

Rails AntiPatterns front coverVS.The Rails 5 Way front cover

Rails AntiPatterns


Most programming books will tell you the right way to do things and give examples of how to implement that advice. This book takes a different tack and instead shows you what not to do, with examples of how to refactor those mistakes into clean Rails code. This change in approach is refreshing for the intermediate to advanced programmer because over time we develop certain habits as we try to discover how to do things in a language or a framework, and they're not always the best (or even very good) ways of doing those things. Having a book to help identify where our code has gone astray and how to fix it is a helpful tool indeed.

I was a bit worried about reading a book specifically about Rails that was written so many versions ago, being that Rails 2.3 was out at the time and we're now heading into Rails 6.0. I normally don't mind reading older books about programming in general, since those books have been filtered by time and tend to contain plenty of wisdom that has survived current fads. However, this is a book about a specific web framework, so if it is over eight years old, how could it possibly still be relevant? I needn't have worried. Most of the book focuses on general good programming practices within the context of the Rails environment. Such advice is still as valid in Rails 6.0 as it was in Rails 2.3, even if some of the implementation details have changed.

The structure of the book works well, with ten chapters each focusing on a different topic of the Rails framework. These topics range from the obvious models, views, and controllers on which the Rails architecture is based, to the related services, testing, and databases that are all a part of web application programming. Each topic covers a few antipatterns with descriptions of a common programming mistake and why it's wrong, followed by one or more solutions that fix up the antipattern into beautiful, DRY code. The obvious solutions—like that views should contain strictly display logic, controllers should be thin, and models should contain all of the business logic, but broken out into helpers and plain Ruby objects—are covered along with a number of less obvious antipatterns. Some of the more extended solutions are quite satisfying to follow as the refactorings morph an ugly hack into a pretty Rails implementation.

Throughout these refactored antipatterns the authors relate clear reasons for why things should be done a certain way and sound advice on how to choose between competing options. For example, when discussing whether or not to use scopes to create chainable filters on models, they say:
There are downsides to this approach, including problems with readability and simplicity, as well as abuse of the Law of Demeter. Whether you use this approach is a judgment call on your part. Will you use the added flexibility? Is it better than defining a handful of separate finders? Like many advanced refactorings, this one has no easy answer and depends greatly on your tastes.
I appreciate the honesty of this advice. In programming, as in most things in life, not all rules are hard and fast. Multiple good options can and do exist, and in these cases it comes down to a judgement call from the programmer, given the context of the specific situation. Experience and taste will develop into a programmer's style, and as long as they're not making a poor choice for the wrong reason, it's okay to prefer one viable option over another.

The authors aren't always so amenable to choice in correcting antipatterns. They do discourage attempts at divining the future, as in this example:
Developers new to the template pattern tend to want to err on the side of flexibility. This is a form of future-proofing, and it's a mistake—especially when working in a language as geared toward agile development and the refactoring cycle as Ruby.
It's almost always better to spend time fixing real problems in the here and now instead of trying to predict and head off future problems that may never happen.

The whole book was full of insights like these, and it was all packaged in easy-to-read prose and concise, relevant examples of how not to write Rails code, followed by how to fix it. I found it to be a quite enjoyable way to learn better Rails programming practices, and it reminded me of an old chess book that had followed a similar format: How Not to Play Chess. Seeing the mistakes that can be made and their consequences clearly laid out can prove quite helpful in identifying our own mistakes and seeing the path to correcting them. This teaching method was expertly executed in Rails AntiPatterns, and I highly recommend giving it a read if you do any programming in Rails.

The Rails 5 Way


This was definitely the longest book on a programming language or framework that I've read in a while. Weighing in at over a thousand pages, it definitely achieves tome status, and strives to be a comprehensive map of the Rails 5 framework. The forwards and introduction recommend reading it straight through at least once to get the lay of the land and see everything that's available in Rails before using it as a reference.

I would agree that knowing what tools are available in any given language or framework is half the battle when attempting to develop solutions as efficiently as possible. If you know that something you want to do is possible and you know where to look to research how to do it, then you're already ahead of the game in reaching an optimal solution. However, I was not going to read all the way through this book, considering the last third of it is a pure reference listing of the Active Model and Active Support APIs. That's skim-worthy material at best.

At least another third of the non-appendix part of the book is also reference listings of various APIs in the Rails framework. The trouble with this reference material is that it is interspersed with actual guidance on how to use the different parts of Rails. That makes it much harder to skim through the boring, tedious method descriptions without missing tidbits of more useful information, so most of the book was kind of a slog.

Obie Fernandez took a slightly unconventional approach to covering Rails, and instead of starting with Active Record, he started at a high level by covering the Rails configuration and environments, then followed the flow of a request by going into routes, REST, resources, and controllers before getting to Active Record. After five chapters of the various aspects of Active Record, he continued with Action View, helpers, and Haml, followed up by an assortment of short chapters on session management, security, Action Mailer, caching, background processing, Ajax, Turbolinks, Action Cable, and testing with RSpec. Whew. Like I said, comprehensive, and even if some things couldn't be included in depth, they were at least mentioned so that the reader could be aware of them and do more research on their own.

Some chapters were quite useful and informative, like the main chapters on the MVC architecture of Rails. These chapters contained a fair amount of good advice and recommendations that can save developers a lot of trouble, such as:
Rails' schema definition provides the authoritative record of truth for the latest version of your database schema. If you need to recreate your database on another server, you should be using db:schema:load, not running all the migrations from scratch.
Anyone who's tried to run a long chain of migrations while setting up an application on a new machine can attest to the futile debugging situation you end up in when one of the migrations inevitably fails halfway through. Using the schema is definitely the way to go. I also found the chapters on security, caching, and Turbolinks to be quite helpful, and I learned a bunch of great things that will help me build better Rails applications.

On the other hand, there were large swaths of the book that were pure drudgery. Most of the helpers chapter was like this with page after page of very similar method descriptions:
11.3.1 asset_path(source, options = {})
Computes the path to asset in public directory. If :type options is set, a file extension will be appended and scoped to the corresponding public directory. All other asset *_path helpers delegate through this method.

<...code example...>

11.3.2 asset_url(source, options = {})
Computes the full URL to an asset in the public directory. This will use asset_path internally, so they behave the same way. If the :host option is set, it overrides the global config.action_controller.asset_host setting normally set in config/environments/production.rb.

asset_url "application.js", host: "http://cdn.example.com" # => http://cdn.example.com/assets/application.js

Also aliased as url_to_asset.
Ugh. This kind of stuff is much easier to search for in the online Rails documentation when you need to look it up, not by paging through a giant book. I was also surprised at how much of these method descriptions ended with comments about how useless they were. Maybe 20% of the methods would have a description of what they did with a code example, and then Fernandez would end it with saying he had never found a use for this method or you would never want to do things this way because some other method was much better. That got more than a little frustrating as the book dragged on.

It may sound a bit strange to criticize this book for including ways not to do things in Rails, having just praised a book whose entire structure was showing how not to do things and then showing the right way, but this is different. In Rails AntiPatterns, the author was showing common mistakes when programming in Rails and how to fix those mistakes by using Rails the right way. My complaint with The Rails 5 Way is that time is spent describing irrelevant methods that may have been included in the framework for completeness or for a specific, uncommon use case, but are hardly ever used in practice. When those things are included in a book whose title asserts that this is how things should be done, it muddies the waters.

Between the appendices, the long lists of method descriptions, and the inclusion of dozens of methods that are rarely used, this book is probably three to four times longer than it needs to be, all for the sake of being comprehensive. It was light enough on actual recommendations for how to use Rails, focusing more on every single thing that's available, that a more appropriate title would simple be The Rails 5 Documentation.


I much prefer reading programming books that directly address the 'how' and 'why' of programming, like these books I previously reviewed on how to use Rails. The Ruby on Rails Tutorial is especially good and the latest version is also up-to-date with Rails 5.  Even Rails AntiPatterns is still relevant nearly a decade later because it addresses the fundamentals of developing in Rails. I would rather leave the 'what' of programming to the online documentation where it is easily searchable and stays updated to the latest version of the tools. In that respect The Rails 5 Way falls flat. It would have been a much more compelling book if it had stripped out all of the drab documentation and focused on showing the right way to program in Rails and explaining why that was the best way to do it. As it is, reading through Rails AntiPatterns and referring to the online documentation is the more productive path.

No comments: