Recently I read a very good book about SQL Antipatterns. What I did expected was a whole bunch of good advices about how to write bad sql and how to avoid it. I was surprised to find the ActiveRecord in the application specific antipatterns section and it inspired me to some thoughts that I would like to dump here.
But first of all, a small review of the book: It is divided in 4 chapters:
Logical Database Design Patterns
This chapter contains guidelines how to solve logical design problems in your DB. The most inspiring one for me was how to save a tree in a relational DB. I always created parent-child associations but now I know that there are a lot of (better) choices.
Physical Database Design Pattern
Typical problems with rounding, wrong indexes and cases where you reference a file by name in the database and store it elsewhere(its called phantom files). In the latter case you should just store the file as BLOB.
Do not use queries with wildcards in it, since you they aren´t refactoring save. Do not use like expression for complex search queries and avoid complex queries which try to solve evereything. Use multiple ones instead. Interesting stuff if you have to write your SQL for yourself. Mentioned lucene/solr as search engine alternatives.
Application development antipatterns
It´s about readable passwords in the db(does anyone really do this?), SQL Injection and other stuff that was not really interesting except the last part about the ActiveRecord antipattern.
Maybe nothing new for some out there, but for me it was great to recap the reasons why ActiveRecord is an antipattern:
- it leads to an anemonic design because you get CRUD methods on the public interface
- objects are difficult to test, you need the complete framework or mock a shared context
- it violates the single responsibilty principle
Since ActiveRecord is one of the core concepts of Rails, it is easy to get fat controllers with to much logic in it.
But even hibernate has issues: typically you call some repository for CRUD actions. This is better, since you have a shallow object, less dependencies and no magic stuff from the upper class.
But what about situations were calling a repository inside the domain object could lead to more intelligent entity objects?(DDD likes that)
AspectJ? Why? What you get is a technical burden and a quite more complicated test setup, because you need the framework in the test setup as well.
Hibernate Interceptors? Maybe simpler than aspects, but why solving this design issue with more complicated technical stuff? Why not just following the plain old KISS principle?
BTW that´s the reason why I can´t agree with some points of DDD since they are too theoretical, not pragmatic, and introduces just a lot of new layers into the system.