<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Michael Schuerig</title>
	<atom:link href="http://www.schuerig.de/michael/blog/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.schuerig.de/michael/blog</link>
	<description>Sentenced to making sense</description>
	<lastBuildDate>Thu, 04 Jun 2009 01:58:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Humble HATEOAS</title>
		<link>http://www.schuerig.de/michael/blog/index.php/2009/06/04/humble-hateoas/</link>
		<comments>http://www.schuerig.de/michael/blog/index.php/2009/06/04/humble-hateoas/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 01:52:57 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[REST]]></category>
		<category><![CDATA[SOA]]></category>

		<guid isPermaLink="false">http://www.schuerig.de/michael/blog/?p=64</guid>
		<description><![CDATA[HATEOAS is an acronym coined in the context of RESTful web services. It stands for Hypermedia as the engine of application state. Imagine the client, human or machine, in a conversation with the server.
They take it in turns, the client asks (requests) something of the server, who promptly responds. Of course, a polite client doesn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p><em>HATEOAS</em> is an acronym coined in the context of <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">RESTful web services</a>. It stands for <em>Hypermedia as the engine of application state</em>. Imagine the client, human or machine, in a conversation with the server.</p>
<p>They take it in turns, the client asks (<em>requests</em>) something of the server, who promptly responds. Of course, a polite client <a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">doesn&#8217;t ask just anything of the humble server</a>. Rather, in keeping with protocol, the client only follows the leads (<em>links</em>) suggested by the server. Thus, the conversation is advanced by following link after link.</p>
<p>That&#8217;s as good as it is, no diplomatic incidents caused by a client stepping out of line. But does it make for a good conversation? Hardly, with a client who only knows how to be polite, but has no idea what he is talking about. Talking <em>about</em> something presupposes semantics, in this case, an agreement about the <em>meaning</em> of following a particular lead (link).</p>
<p>Talking about something becomes a lot easier when you have an idea what the topic is supposed to be. Enter <a href="http://en.wikipedia.org/wiki/Internet_media_type"><em>Media Types</em></a>. Not any old <code>text/plain</code>, <code>application/xml</code> &#8212; that&#8217;s like talking about the weather, only for machines. You want something with substance, something fitting your own conversational niche:</p>
<p><code>
<pre>
  application/x.mytopic+xml
</pre>
<p></code></p>
<p>There, <code>application</code> indicates a &#8220;multipurpose&#8221; file, not specifically geared towards human consumption. <code>x.</code> indicates that it is an experimental media type, not registered with IANA. If you&#8217;ve got more clout, maybe you&#8217;ll be able to officially register a <code>vnd.</code> (vendor) or <code>.prs</code> (personal) type. Finally, the <code>+xml</code> suffix says that the media type is based on <tt>XML</tt>.</p>
<p>Now for the dénouement: That&#8217;s it.</p>
<p>No magic RESTful pixie dust. No script for successfully chatting up every server. Nothing. You could use <tt>XML Schema</tt> or a relative to specify the data contents of the media types you are using. You could even write some nice prose explaining in so many words what lies ahead when someone follows a link with, say, <code>rel="payment"</code>. If you fancy arcane arts, you might write pre- and postconditions in <a href="http://en.wikipedia.org/wiki/Object_Constraint_Language"><tt>OCL</tt></a>.</p>
<p>In summary, HATEOAS doesn&#8217;t imbue client software with more intelligence. It inserts a (useful) level of indirection by offering the client a choice of transitions. Thereby achieving two things: The client is ignorant of the concrete <tt>URI</tt>s associated with transitions; for all it knows they can be different each time. The client doesn&#8217;t have to figure out which transitions are applicable, because the server only offers those to begin with.</p>
<p>What it <em>means</em> to effect a particular transition must still be explicitly coded. So, if the client-side workflow stipulates that a payment transaction is to be started at some point, someone, somewhere has to know of the agreement that such a transition is indicated by a link with <code>rel="payment"</code> and write code to look for and follow such a link.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.schuerig.de/michael/blog/index.php/2009/06/04/humble-hateoas/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Creative Associations</title>
		<link>http://www.schuerig.de/michael/blog/index.php/2009/05/29/creative-associations/</link>
		<comments>http://www.schuerig.de/michael/blog/index.php/2009/05/29/creative-associations/#comments</comments>
		<pubDate>Fri, 29 May 2009 14:01:58 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.schuerig.de/michael/blog/?p=62</guid>
		<description><![CDATA[A presentation I held on May 28 at Düsseldorf on Rails about interesting and useful things you can do with ActiveRecord, SQL, and a smart database.

german
english

.
]]></description>
			<content:encoded><![CDATA[<p>A presentation I held on May 28 at <a href="http://groups.google.de/group/duesseldorf-on-rails">Düsseldorf on Rails</a> about interesting and useful things you can do with <tt>ActiveRecord</tt>, <tt>SQL</tt>, and a smart database.</p>
<ul>
<li><a href="http://www.schuerig.de/michael/pres/kreative-assoziationen/index.html">german</a></li>
<li><a href="http://www.schuerig.de/michael/pres/kreative-assoziationen/index.html.en">english</a></li>
</ul>
<p>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.schuerig.de/michael/blog/index.php/2009/05/29/creative-associations/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>No database to rule them all. Branch databases for Rails and git</title>
		<link>http://www.schuerig.de/michael/blog/index.php/2009/04/09/branch-db/</link>
		<comments>http://www.schuerig.de/michael/blog/index.php/2009/04/09/branch-db/#comments</comments>
		<pubDate>Wed, 08 Apr 2009 23:04:37 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[git]]></category>

		<guid isPermaLink="false">http://www.schuerig.de/michael/blog/?p=59</guid>
		<description><![CDATA[You&#8217;re using git to manage your Ruby on Rails projects? Then you&#8217;ve probably come to appreciate topic branches as a kind of transaction facility for programmers. If you need to implement a non-trivial or just try something, the way to go is onto a new &#8220;topic&#8221; branch. There you can mangle the code all you [...]]]></description>
			<content:encoded><![CDATA[<p>You&#8217;re using <em><code>git</code></em> to manage your <em>Ruby on Rails</em> projects? Then you&#8217;ve probably come to appreciate topic branches as a kind of transaction facility for programmers. If you need to implement a non-trivial or just try something, the way to go is onto a new &#8220;topic&#8221; branch. There you can mangle the code all you like, without fearing to cause any lasting harm. In case everything works out fine, you merge the branch into the master branch and discard it. If you come to a dead end &#8212; well, you <em>just</em> discard the misbegotten branch.</p>
<p>But what about the database? If moving along your branch involves changes to the database, structural changes in particular, you can&#8217;t easily switch to another branch without these changes. In other words, your development database is really only suitable for a single branch.</p>
<p>Up to now, that is. Install the <code>branch_db</code> gem and what you get is a private database for your branch that you can mutilate without interfering with work on the other branches.</p>
<p>For details and installation instructions see the <a href="http://github.com/mschuerig/branch_db/blob/master/README.rdoc">README</a>. Here&#8217;s just an appetizer. Say you&#8217;re on branch &#8220;feature&#8221; and want a private copy of the &#8220;master&#8221; database. Here&#8217;s how you do it:</p>
<p><code>
<pre>
$ rake db:branches:copy ORIG_BRANCH=master
</pre>
<p></code></p>
<h2>Getting it</h2>
<ul>
<li><a href="http://github.com/mschuerig/branch_db">github</a></li>
<li>$ sudo gem install mschuerig-branch_db</li>
</ul>
<h2>Let your Rails app know about it</h2>
<p>In the appropriate place in <code>config/environment.rb</code> add</p>
<p><code>
<pre>
config.gem "mschuerig-branch_db", :lib =&gt; 'branch_db'
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.schuerig.de/michael/blog/index.php/2009/04/09/branch-db/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby as a language for Rails views</title>
		<link>http://www.schuerig.de/michael/blog/index.php/2009/04/02/ruby-views/</link>
		<comments>http://www.schuerig.de/michael/blog/index.php/2009/04/02/ruby-views/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 22:55:31 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.schuerig.de/michael/blog/?p=57</guid>
		<description><![CDATA[Didn&#8217;t you always want to write your Rails views as plain Ruby objects? &#8212; &#8220;What?&#8221;, I hear you say. No, I haven&#8217;t lost my mind and the idea is quite sensible (or so I hope), once you add the restriction that it is JSON-formatted data that you want to return.
Say you need to set up [...]]]></description>
			<content:encoded><![CDATA[<p>Didn&#8217;t you always want to write your Rails views as plain Ruby objects? &#8212; <em>&#8220;What?&#8221;</em>, I hear you say. No, I haven&#8217;t lost my mind and the idea is quite sensible (or so I hope), once you add the restriction that it is JSON-formatted data that you want to return.</p>
<p>Say you need to set up some hashes or arrays for rendering to JSON. This is best done in Ruby and it is clearly a view concern. So let&#8217;s do it in the views. Like this:</p>
<p><code>
<pre>
  # app/controllers/movies_controller.rb
  def index
    respond_to do |format|
      format.json do
        @movies = Movie.all
        @count = Movie.count
        render :template =&gt; 'movies/index.json.rb'
      end
    end
  end
</pre>
<p></code></p>
<p><code>
<pre>
  # app/views/movies/index.json.rb
  {
    :identifier =&gt; Movie.primary_key,
    :totalCount =&gt; @count,
    # render @movies does not work as it insists on returning a string
    :items =&gt; @movies.map { |m| render(m) }
  }
</pre>
<p></code></p>
<p><code>
<pre>
  # app/views/movies/_movie.json.rb
  {
    :id =&gt; movie.to_param,
    :title =&gt; movie.title,
    :releaseDate =&gt; movie.release_date
  }
</pre>
<p></code></p>
<h2>Getting it</h2>
<ul>
<li><a href="http://github.com/mschuerig/ruby_template_handler">github</a></li>
<li>$ sudo gem install mschuerig-ruby_template_handler</li>
</ul>
<h2>Let your Rails app know about it</h2>
<p>In the appropriate place in <code>config/environment.rb</code> add</p>
<p><code>
<pre>
config.gem "mschuerig-ruby_template_handler", :lib =&gt; 'ruby_template_handler'
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.schuerig.de/michael/blog/index.php/2009/04/02/ruby-views/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simplistic Enumerations for ActiveRecord</title>
		<link>http://www.schuerig.de/michael/blog/index.php/2009/04/02/simplistic-enums/</link>
		<comments>http://www.schuerig.de/michael/blog/index.php/2009/04/02/simplistic-enums/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 19:49:03 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://www.schuerig.de/michael/blog/?p=55</guid>
		<description><![CDATA[Invariably, in almost every application there happen to be lists of data items that are immutable, just for reference. It could be colors, the four seasons, continents, the states of your country, kinds or types of this and that. These items are almost like constants. As accessible as they are through the ordinary ActiveRecord API, [...]]]></description>
			<content:encoded><![CDATA[<p>Invariably, in almost every application there happen to be lists of data items that are immutable, just for reference. It could be colors, the four seasons, continents, the states of your country, kinds or types of this and that. These items are <em>almost</em> like constants. As accessible as they are through the ordinary ActiveRecord API, it seems an utter waste to hit the database again and again, for data that won&#8217;t change however often you request it.</p>
<p>Of course, the Rails community recognized early on that some data are more constant than others and over the years several plugins have been published that add cached and easily accessible enumerations to ActiveRecord. Some of these additions are quite complicated or befuddle ActiveRecord by not backing the enumeration values with real database objects. My experience has been that these attempted optimizations result in bizarre behavior when I did interesting things with ActiveRecord such as multiply nested named scopes plus custom SQL.</p>
<p>So, I thought a basic, no, simplistic, version of enumerations is called for. Here&#8217;s how it looks:</p>
<p><code>
<pre>
class Color &lt; ActiveRecord::Base
  enumerates do |e|
    e.value :name =&gt; 'red'
    e.value :name =&gt; 'green'
    e.value :name =&gt; 'blue'
  end
end

Color[:green]
Color.find_by_name('red')
Color.find_by_name!(:red)
Color.all
Color.count
Color.reload
</pre>
<p></code></p>
<p><code>
<pre>
e.value :name =&gt; 'red'
</pre>
<p></code></p>
<p>ensures that a Color object with name &#8216;red&#8217; exists, if it does not, one is created.</p>
<h2>Caveats</h2>
<p>Although there is a <code>#reload</code> method defined on enumeration models, i.e. <code>Color.reload</code>, it is very unwise to use it. The point is that this method only affects a single server process and you most likely have many of them.</p>
<p>So, if you need to change enumeration values, the only way to do it is to treat it like an update to your application code.</p>
<h2>Getting it</h2>
<ul>
<li><a href="http://github.com/mschuerig/easy_enums">github</a></li>
<li>$ sudo gem install mschuerig-easy_enums</li>
</ul>
<h2>Let your Rails app know about it</h2>
<p>In the appropriate place in <code>config/environment.rb</code> add</p>
<p><code>
<pre>
config.gem "mschuerig-easy_enums", :lib => 'easy_enums'
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.schuerig.de/michael/blog/index.php/2009/04/02/simplistic-enums/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Lifting indexes with ActiveRecord</title>
		<link>http://www.schuerig.de/michael/blog/index.php/2009/04/02/lifting-indexes/</link>
		<comments>http://www.schuerig.de/michael/blog/index.php/2009/04/02/lifting-indexes/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 16:40:22 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://www.schuerig.de/michael/blog/?p=49</guid>
		<description><![CDATA[On a Rails project I&#8217;m currently working on I need to fill the database with test data to have something to play with. Apart from large imports, that&#8217;s the time when indexes may slow down operation severely instead of speeding things up. Consider: The indexes are not used, but have to be updated again and [...]]]></description>
			<content:encoded><![CDATA[<p>On a Rails project I&#8217;m currently working on I need to fill the database with test data to have something to play with. Apart from large imports, that&#8217;s the time when indexes may slow down operation severely instead of speeding things up. Consider: The indexes are not used, but have to be updated again and again for each new record that is inserted into the database. It is <em>much</em> cheaper, to <em>lift</em> &#8212; well, really <em>drop</em> &#8212; the indexes during mass operation and recreate them afterwards.</p>
<p>Here&#8217;s an example:</p>
<p><code>
<pre>
namespace :db do
  desc "Populate the database with sample data"
  task :populate =&gt; :environment do

    retained_indexes = [
      'index_people_on_lastname_and_firstname',
      { :table =&gt; :movies, :columns =&gt; :title }
      { :table =&gt; 'people', :columns =&gt; ['lastname', :firstname] }
    ]

    ActiveRecord::Base.transaction do
      IndexLifter.without_indexes(
        # Only consider indexes on these tables;
        # all tables by default.
        :movies,
        :people,
        # Don't lift these indexes
        :except =&gt; retained_indexes,
        # Don't lift unique indexes; default: false.
        :except_unique =&gt; true
      ) do
        ActiveRecord::Base.silence do

          # import or generate large amounts of data here

        end
      end
    end
  end
end
</pre>
<p></code></p>
<p>Please bear in mind that dropping and creating of indexes is a rather intrusive operation on the structure of your database. You should only perform it while no other users (or processes) are accessing it.</p>
<p>Also, consider that some indexes may be important for the proper function of your database. If you have <em>unique indexes</em>, i.e. indexes that enforce that particular columns or combinations of columns are unique, and if you are handling violations of this constraint in your application code, then you might need to retain these indexes even during data generation.</p>
<h2>Getting it</h2>
<ul>
<li><a href="http://github.com/mschuerig/index_lifter">github</a></li>
<li>$ sudo gem install mschuerig-index_lifter</li>
</ul>
<h2>Let your Rails app know about it</h2>
<p>In the appropriate place in <code>config/environment.rb</code> add</p>
<p><code>
<pre>
config.gem "mschuerig-index_lifter", :lib => 'index_lifter'
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.schuerig.de/michael/blog/index.php/2009/04/02/lifting-indexes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Emacs Tidbit: Console or GUI?</title>
		<link>http://www.schuerig.de/michael/blog/index.php/2009/01/23/emacs-console-or-gui/</link>
		<comments>http://www.schuerig.de/michael/blog/index.php/2009/01/23/emacs-console-or-gui/#comments</comments>
		<pubDate>Fri, 23 Jan 2009 20:10:32 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Emacs]]></category>

		<guid isPermaLink="false">http://www.schuerig.de/michael/blog/?p=46</guid>
		<description><![CDATA[Emacs has two different UIs: one using only a text console, the other using the window system. Even when a window system is present, Emacs can be started in a terminal emulator with the -nw option to show its text UI.
There are some customizations you might want to make conditional on the kind of UI. [...]]]></description>
			<content:encoded><![CDATA[<p>Emacs has two different UIs: one using only a text console, the other using the window system. Even when a window system is present, Emacs can be started in a terminal emulator with the <code>-nw</code> option to show its text UI.</p>
<p>There are some customizations you might want to make conditional on the kind of UI. In my case, I use <a href="http://ecb.sourceforge.net/">ECB</a>, and in general I&#8217;d like it to start up automatically when I launch Emacs, but only when running in GUI mode.</p>
<p>It&#8217;s pretty simple to achieve this, a small addition to <code>~/.emacs</code> does the trick.</p>
<p><code>
<pre>
(if (memq window-system '(x w32 mac))
  (ecb-activate))
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.schuerig.de/michael/blog/index.php/2009/01/23/emacs-console-or-gui/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Line movement for Emacs</title>
		<link>http://www.schuerig.de/michael/blog/index.php/2009/01/16/line-movement-for-emacs/</link>
		<comments>http://www.schuerig.de/michael/blog/index.php/2009/01/16/line-movement-for-emacs/#comments</comments>
		<pubDate>Fri, 16 Jan 2009 09:55:59 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Emacs]]></category>
		<category><![CDATA[Emacs Lisp]]></category>

		<guid isPermaLink="false">http://www.schuerig.de/michael/blog/?p=44</guid>
		<description><![CDATA[Recently, I&#8217;ve been mingling with two old acquaintances (if not downright friends): C and Emacs. Through my interaction with other text editors I&#8217;ve come to know functions to move the current line, i.e. the one containing the cursor, up or down. That&#8217;s something I wanted to have in Emacs too. And so I wrote my [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I&#8217;ve been mingling with two old acquaintances (if not downright friends): <tt>C</tt> and <tt>Emacs</tt>. Through my interaction with other text editors I&#8217;ve come to know functions to move the current line, i.e. the one containing the cursor, up or down. That&#8217;s something I wanted to have in <tt>Emacs</tt> too. And so I wrote my first ever <tt>Emacs Lisp</tt> functions with some help from <a href="http://groups.google.com/group/comp.emacs/browse_thread/thread/9a0b9b2ab342762d#"><tt>comp.emacs</tt></a>.</p>
<p>Stick these definitions in <tt>~/.emacs</tt> and evaluate them or restart <tt>Emacs</tt>.</p>
<p><code>
<pre>
(defun move-line-down ()
  (interactive)
  (let ((col (current-column)))
    (save-excursion
      (next-line)
      (transpose-lines 1))
    (next-line)
    (move-to-column col)))

(defun move-line-up ()
  (interactive)
  (let ((col (current-column)))
    (save-excursion
      (next-line)
      (transpose-lines -1))
    (move-to-column col)))

(global-set-key [\M-down] 'move-line-down)
(global-set-key [\M-up] 'move-line-up)
</pre>
<p></code></p>
<p>Now you have Meta-Down and Meta-Up (i.e., probably Alt-Down and Alt-Up) bound to moving the current line around.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.schuerig.de/michael/blog/index.php/2009/01/16/line-movement-for-emacs/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Emperor Ming strikes back</title>
		<link>http://www.schuerig.de/michael/blog/index.php/2008/05/04/celko-thinking-in-sets/</link>
		<comments>http://www.schuerig.de/michael/blog/index.php/2008/05/04/celko-thinking-in-sets/#comments</comments>
		<pubDate>Sun, 04 May 2008 00:17:35 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://schuerig.de/michael/blog/index.php/2008/05/04/celko-thinking-in-sets/</guid>
		<description><![CDATA[Emperor Ming strikes back
May 5, 2008by Michael Schürigproduct
Joe Celko&#8217;s Thinking in Sets
&#9733;&#9733;&#9733;&#9734;&#9734;
I have (read) copies of five earlier of Celko&#8217;s books on my shelf, still I am again amazed by the cultural distance. Most of my programming life I have spent with object-oriented programming languages and associated technologies. Thus, when Celko starts the present book [...]]]></description>
			<content:encoded><![CDATA[<p>Emperor Ming strikes back</p>
<div class="hreview" id=""><abbr class="dtreviewed" title="2008-05-05T00:00">May 5, 2008</abbr>by <span class="reviewer vcard"><span class="fn">Michael Schürig</span></span><span class="type">product</span>
<div class="item"><span class="fn">Joe Celko&#8217;s Thinking in Sets</span></div>
<p><abbr title="3" class="rating">&#9733;&#9733;&#9733;&#9734;&#9734;</abbr></div>
<p>I have (read) copies of five earlier of Celko&#8217;s books on my shelf, still I am again amazed by the cultural distance. Most of my programming life I have spent with object-oriented programming languages and associated technologies. Thus, when Celko starts the present book with a discussion of the differences between flat files and relational databases, it could hardly be more distant than if he had extolled the virtues of the gasoline engine over its steam predecessor.</p>
<p>Celko likes to refer to his informers as &#8220;Mr. So-and-so, working for company X&#8221; this again moves the cultural differences to the front, and I can&#8217;t avoid a slight chuckle when he reverently cites &#8220;Dr. E.F. Codd&#8221; for the umpteenth time. It all decidedly feels like a tale from an imaginary 1950s. I certainly envision people in lab coats.</p>
<p>The tone moves from enjoyably quaint to annoying, when Celko (again and again) ridicules the many failings of database novices and sophomores. He might not realize that those who share in the joke have no need to read his book &#8212; and that those who bought the book to learn something from it may feel a wee bit offended. After all, we are already aware that there&#8217;s something we don&#8217;t know yet and want to learn, there&#8217;s really no need to rub it in.</p>
<p>So much for the atmospheric stuff. But, of course, I didn&#8217;t buy this book to make me feel good, but to learn something, come rain or shine. And, yes, there is a lot useful stuff in this book. More in the bits and pieces than in some generalized approach. And by far more in line with the subtitle, &#8220;Auxiliary, Temporal and Virtual Tables in SQL&#8221; than with &#8220;Thinking in Sets&#8221;, the main title. Regarding the latter, I found the most worthwhile part of the book to be the discussion of why boolean flags are bad (ch. 11, Thinking in SQL).</p>
<p>Celko&#8217;s effort to distance the relational, set-based approach from earlier practices crops up all over the book. I had expected &#8212; and hoped! &#8212; that Celko would put considerably energy into comparing, contrasting, and hopefully complementing set-based thinking with current object-oriented approaches. Alas, he&#8217;s completely preoccupied with his own tradition and doesn&#8217;t wander into OO-land at all.</p>
<p>I would have been very interested in reading a knowledgable discussion of where to draw the line between procedural and set-based approaches. And, as most practical programs will employ both of these approaches, how to interface the respective parts. On the latter issue, there&#8217;s not a single word in this book. The treatment of the former issue is interesting, in a twisted sense. Celko demonstrates some string processing in SQL and concedes that this would be much easier in languages such as ICON or SNOBOL, those stalwarts of 1970s era dataprocessing (does he even know Perl?). Well, why then try to abuse SQL to do something for which it is ill-suited and results in bloated code? Why anyone would want to solve Sudoku puzzles in SQL I cannot fathom, either. Celko doesn&#8217;t tell, and neither does he present the whole (repetitive) code, nor explain how the set-based approach works in any sufficient detail.</p>
<p>The overarching mindset exemplified in this book is to push as much into the database as possible, even if it hurts at times. I don&#8217;t mean to denigrade the intention, namely application-independent, consistent data storage. However, the reality in current software engineering is that a shared database is but one solution among others. For instance, SOA (Service Oriented Architecture) is specifically about connecting applications through services they provide, not by tying them to a shared database.</p>
<p>Celko likes to style himself in the image of Ming the Merciless. The semblance is indeed uncanny and as I hinted already, he tries to live up to the role as his author persona. Unfortunately, he doesn&#8217;t seem to realize that there&#8217;s one thing that can&#8217;t be tolerated in an arch-villain (as well as in his henchmen and henchwomen): sloppiness. The book has more than its fair share of typos and grammatical accidents. A particularly amusing case in point &#8212; due to his belligerent character, a deeper insight, or simply search-and-replace gone awry &#8212; is an example that consistently refers to &#8220;martial status&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.schuerig.de/michael/blog/index.php/2008/05/04/celko-thinking-in-sets/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Collecting DOM events</title>
		<link>http://www.schuerig.de/michael/blog/index.php/2008/01/08/event-collector/</link>
		<comments>http://www.schuerig.de/michael/blog/index.php/2008/01/08/event-collector/#comments</comments>
		<pubDate>Tue, 08 Jan 2008 20:24:12 +0000</pubDate>
		<dc:creator>michael</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Prototype.js]]></category>

		<guid isPermaLink="false">http://schuerig.de/michael/blog/index.php/2008/01/08/event-collector/</guid>
		<description><![CDATA[The DOM change notification I presented yesterday is one piece in the puzzle to rejuvenate my languishing JavaScript form validator. I&#8217;ve not yet made up my mind on a lot of issues, but there&#8217;s one thing that&#8217;s certain: the next version will have to be able to work with changing forms, that is, forms that [...]]]></description>
			<content:encoded><![CDATA[<p>The DOM change notification I presented <a href="http://schuerig.de/michael/blog/index.php/2008/01/07/dom-change-notification/">yesterday</a> is one piece in the puzzle to rejuvenate my languishing JavaScript <a href="http://schuerig.de/michael/blog/index.php/2006/12/15/rails-almost-automatic-client-side-validation/">form validator</a>. I&#8217;ve not yet made up my mind on a lot of issues, but there&#8217;s one thing that&#8217;s certain: the next version will have to be able to work with changing forms, that is, forms that show different input elements depending on already chosen values.</p>
<p>Since yesterday, I have a way to be notified when the DOM has changed. As it is, the <tt>dom:changed</tt> custom event is completely general and not quite what I need. Of course, I do need some kind of notification, but what I get when a function changes the DOM in several places, is a barrage of <tt>dom:changed</tt> events. I don&#8217;t want to do lots of stuff for each of these events, but I&#8217;ve got to do something about the events collectively. There is no natural bracketing for events, there&#8217;s nothing that says which events belong to the same high-level change. But that&#8217;s not really necessary, rather, it is good enough to collect all relevant events that occur in period of time.</p>
<p>Here&#8217;s a class that collects all events that it receives over a given <tt>interval</tt> (of seconds) and passes them on to a <tt>handler</tt> function.</p>
<p><code>
<pre>
Element.EventCollector = Class.create({
  initialize: function(handler, interval) {
    this.handler = handler;
    this.interval = (interval || 1) * 1000;
    this.reset();
    this.dischargeEvents = this.discharge.bind(this);
  },
  reset: function() {
    this.events = [];
    this.timer = null;
  },
  observer: function() {
    return this.onEvent.bindAsEventListener(this);
  },
  onEvent: function(event) {
    this.events.push(event);
    this.wait();
  },
  wait: function() {
    if (!this.timer) {
      this.timer = setTimeout(this.dischargeEvents, this.interval);
    }
  },
  discharge: function() {
    this.timer = null;
    var events = this.events;
    this.reset();
    this.handler(events);
  }
});
</pre>
<p></code></p>
<p>Add some syntactic sugar, so that we can do things like</p>
<p><code>
<pre>
document.body.collectEvents('dom:changed', function(events) { ... });
</pre>
<p></code></p>
<p><code>
<pre>
Element.addMethods({
  collectEvents: function(element, eventName, handler, interval) {
    var collector = new Element.EventCollector(handler, interval);
    $(element).observe(eventName, collector.observer());
  }
});
</pre>
<p></code></p>
<p>For my motivating case of the validator that&#8217;s still not exactly what I need. I can arrange to get a notification that a whole bunch of elements was changed, but I don&#8217;t want to deal with these elements individually. The validator I have (and the next version I envision) works it&#8217;s way down from a starting element and attaches its magic pixie dust to everything below. Thus, what I need is a common ancestor element for all the changed elements. The idea is easy: Go down from the root of the &#8220;family&#8221; (document) tree and follow it until the path to the elements branches.</p>
<p><code>
<pre>
Element.addMethods({
  commonAncestor: function() {
    var ancestorsLists = $A(arguments).map(function(el) {
      el = $(el);
      var ancestors = el.ancestors().reverse()
      ancestors.push(el);
      return ancestors;
    });
    var common = document;
    Enumerable.zip.apply(ancestorsLists.shift(), ancestorsLists).each(
      function(ancestorTuple) {
        var cand = ancestorTuple.shift();
        if (!ancestorTuple.all(function(el) { return el == cand; })) {
          throw $break;
        }
        common = cand;
      });
    return common;
  }
});
</pre>
<p></code></p>
<p>[See <a href="http://prototypejs.org/api/element/methods/ancestors"><tt>Element#ancestors</tt></a>, <a href="http://prototypejs.org/api/enumerable/zip"><tt>Enumerable#zip</tt></a>, <a href="http://prototypejs.org/api/enumerable/each"><tt>$break</tt></a>.]</p>
<p>Finally, here&#8217;s an example that puts the existing pieces together.</p>
<p><code>
<pre>
document.observe('dom:loaded', function() {
  document.body.collectEvents('dom:changed', function(events) {
    var affectedElements = events.invoke('element');
    var ancestor = Element.commonAncestor.apply(null, affectedElements);
    console.log('dom:changed below: ', ancestor);
  }, 10);
});
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.schuerig.de/michael/blog/index.php/2008/01/08/event-collector/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
