{"id":56,"date":"2008-05-23T19:55:00","date_gmt":"2008-05-23T19:55:00","guid":{"rendered":"https:\/\/karwin.com\/blog\/index.php\/2008\/05\/23\/activerecord-does-not-suck\/"},"modified":"2008-05-23T19:55:00","modified_gmt":"2008-05-23T19:55:00","slug":"activerecord-does-not-suck","status":"publish","type":"post","link":"https:\/\/karwin.com\/blog\/index.php\/2008\/05\/23\/activerecord-does-not-suck\/","title":{"rendered":"ActiveRecord does not suck"},"content":{"rendered":"<div>I&#8217;ve been reading a few blog postings such as Kore Nordmann&#8217;s\u00a0<a href=\"http:\/\/kore-nordmann.de\/blog\/why_active_record_sucks.html\">ActiveRecord sucks<\/a> and Mike Seth&#8217;s\u00a0<a href=\"http:\/\/blog.mikeseth.com\/index.php?\/archives\/4-ActiveRecord-sucks,-but-Kore-Nordmann-is-wrong.html#extended\">ActiveRecord sucks, but Kore Nordmann is wrong<\/a>.<\/div>\n<p><\/p>\n<div>ActiveRecord is fine. \u00a0It is a tool that does just what it&#8217;s designed to do. \u00a0What sucks is when developers try to make it do other things than what it&#8217;s intended to do.<\/div>\n<p><\/p>\n<div>I worked for Zend, managing the Zend Framework project through its 1.0 release. \u00a0I also completed the implementation and documentation of <a href=\"http:\/\/framework.zend.com\/manual\/en\/zend.db.html\">Zend_Db<\/a>\u00a0and its related components. To set the record straight, Zend_Db does not implement the <a href=\"http:\/\/martinfowler.com\/eaaCatalog\/activeRecord.html\">ActiveRecord<\/a> pattern.  It implements the <a href=\"http:\/\/martinfowler.com\/eaaCatalog\/tableDataGateway.html\">Table Data Gateway<\/a> and <a href=\"http:\/\/martinfowler.com\/eaaCatalog\/rowDataGateway.html\">Row Data Gateway<\/a> patterns, which taken together offer similar value as the ActiveRecord pattern.<\/div>\n<p><\/p>\n<div>I totally agree with Mike Seth that MVC should not be taken as &#8220;ActiveRecord-View-Controller.&#8221;  I tried to make this point in documentation, screencasts, conference presentations, and in many mailing list messages, but I met with little success.<\/div>\n<p><\/p>\n<div>Unfortunately, the Ruby on Rails drumbeat that <a href=\"http:\/\/wiki.rubyonrails.org\/rails\/pages\/Models\">Models are simply database table wrappers<\/a> has established momentum. \u00a0The term &#8220;Model&#8221; has (incorrectly) become synonymous in many developers&#8217; minds with &#8220;ActiveRecord.&#8221; \u00a0Since Models by this definition are tied to database access and largely implementing various query techniques, Ruby on Rails development forces you to write a large amount of code in the controller classes that should properly be written in Model classes.<\/div>\n<p><\/p>\n<div>This has a few consequences. Unit-testing controller classes becomes very complex, since that&#8217;s where the majority of your application code resides. \u00a0To test a controller class you need to mock HTTP requests, and sift through HTML output. \u00a0This is fine, but it results in more work since testing the controller class is so important and complex. \u00a0If the application code were separated into a true Model, then unit-testing the controller would simply be testing whether the HTTP request had been communicated to the Model correctly. \u00a0Testing the behavior of the Model would be much more straightforward unit-testing of a class API in isolation, requiring no mock HTTP requests or scraping HTML output.<\/div>\n<p><\/p>\n<div>Also, unit-testing Rails-style Model classes is difficult, since the Model is coupled with the database. \u00a0We start to see unfortunate things like <a href=\"http:\/\/www.floehopper.org\/articles\/2006\/06\/27\/rails-fixtures-help-or-hindrance\">database fixtures<\/a> as being necessary before you can execute the simplest tests against your Model class. \u00a0This makes testing Models time-consuming, error-prone, and run slowly.<\/div>\n<p><\/p>\n<div>If developers were to separate Models and Controllers properly, and separate data access components from Models, unit-testing all of these classes could be done more simply, and with greater isolation from other classes. \u00a0This makes it easier to diagnose defects, when they occur. \u00a0Isn&#8217;t this the point of unit tests?<\/div>\n<p><\/p>\n<div>A Model is a class that provides a logical component of your application domain. \u00a0Models are products of OO design, which is a development activity I see get very little attention in the developer blogosphere or the developer tools market. \u00a0Developers seem more enchanted by evangelizing their favorite code editor or debugger, or by squeezing more performance out of their database, than by mental analysis to make sure their OO architecture is modeling its application requirements well.<\/div>\n<p><\/p>\n<div>A single Model class <span style=\"font-style: italic;\">may<\/span> be backed by a database table, or <span style=\"font-style: italic;\">multiple<\/span> database tables, or perhaps even <span style=\"font-style: italic;\">no<\/span> database tables. \u00a0Data persistence should be an internal implementation detail within a Model; the external API of the Model class should reflect its logical OO requirements, not the physical database structure.<\/div>\n<div><\/div>\n<div>(<span style=\"font-style: italic;\">update<\/span>) What I often tell people is that the relationship between a Model and an ORM class should be &#8220;HAS-A&#8221; rather than &#8220;IS-A.&#8221; \u00a0The latter is the assumption of Rails and other frameworks who are enticed by ActiveRecord. \u00a0If the Model <span style=\"font-style: italic;\">uses<\/span> ORM objects instead of inheriting from ORM classes, then you can design the Model to contain all data and code for the domain it&#8217;s supposed to model &#8212; even if it takes multiple database tables to represent it.<\/div>\n<p><\/p>\n<div>Many developers have complained that Zend Framework provides no base Model class. Of course it doesn&#8217;t provide a base Model class!\u00a0<span style=\"font-weight: bold;\">That&#8217;s <\/span><span style=\"font-style: italic;\"><span style=\"font-weight: bold;\">your<\/span><\/span><span style=\"font-weight: bold;\"> job.\u00a0<\/span>This complaint is like saying that Microsoft Word sucks because it doesn&#8217;t provide finished documents for you.<\/div>\n<p><\/p>\n<div>So I wouldn&#8217;t say ActiveRecord sucks. \u00a0I would say that people are expecting ActiveRecord to magically solve their OO design for them, in a false quest to avoid doing the design themselves.<\/div>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been reading a few blog postings such as Kore Nordmann&#8217;s\u00a0ActiveRecord sucks and Mike Seth&#8217;s\u00a0ActiveRecord sucks, but Kore Nordmann is wrong. ActiveRecord is fine. \u00a0It is a tool that does just what it&#8217;s designed to do. \u00a0What sucks is when developers try to make it do other things than what it&#8217;s intended to do. I [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[30,2,7,31],"tags":[],"class_list":["post-56","post","type-post","status-publish","format-standard","hentry","category-database","category-mysql","category-php","category-rails"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pawgV7-U","jetpack-related-posts":[],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/karwin.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/56","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/karwin.com\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/karwin.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/karwin.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/karwin.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=56"}],"version-history":[{"count":0,"href":"https:\/\/karwin.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/56\/revisions"}],"wp:attachment":[{"href":"https:\/\/karwin.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=56"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/karwin.com\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=56"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/karwin.com\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=56"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}