<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;A0QBSHoycCp7ImA9WhRaEUU.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917</id><updated>2012-02-13T21:15:59.498-06:00</updated><category term="linux" /><category term="ruby" /><category term="math" /><category term="theory" /><category term="OpenAM" /><category term="active directory" /><category term="emacs" /><category term="scala" /><category term="java" /><category term="authentication" /><category term="REST" /><category term="books" /><category term="vmware" /><category term="data structure" /><category term="comics" /><category term="random" /><category term="quote" /><category term="Dijkstra" /><category term="continuations" /><category term="notation" /><category term="lisp" /><category term="protocols" /><category term="conference" /><category term="http" /><category term="SAML" /><category term="tip" /><category term="electronics" /><category term="c" /><category term="software development" /><category term="yeti" /><category term="job" /><category term="osgi" /><category term="ldap" /><category term="coq" /><category term="shell" /><category term="unix" /><category term="haskell" /><category term="link" /><category term="eclipse virgo" /><category term="toy problems" /><category term="programming language" /><category term="c++" /><category term="naming" /><category term="Knuth" /><category term="system administration" /><title>Maniagnosis</title><subtitle type="html">Not devoured by plague-bearing zombies!</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://maniagnosis.crsr.net/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>162</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/crsr/nOWs" /><feedburner:info uri="crsr/nows" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CUAGQX84fCp7ImA9WhRaEUU.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-3015197055005881733</id><published>2012-02-13T19:42:00.000-06:00</published><updated>2012-02-13T19:42:00.134-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-13T19:42:00.134-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="random" /><title>The Anti-Meeting Theory of Time</title><content type="html">&lt;a href="http://2.bp.blogspot.com/-XkTgdUHZVnE/TzWO0AxGSCI/AAAAAAAAAEA/Rjtt6AvJ98U/s1600/theoryoftime.png" imageanchor="1" style="float:right;margin-right:1em; margin-bottom:1em"&gt;&lt;img style="border:thin solid black;" border="0" height="320" width="240" src="http://2.bp.blogspot.com/-XkTgdUHZVnE/TzWO0AxGSCI/AAAAAAAAAEA/Rjtt6AvJ98U/s320/theoryoftime.png" /&gt;&lt;/a&gt;

&lt;ol&gt;
&lt;li&gt;Meetings occupy time.&lt;/li&gt;
&lt;li&gt;Meeting cancellations free up time.&lt;/li&gt;
&lt;li&gt;Scheduling a meeting, then canceling it results in the original amount of free time.&lt;/li&gt;
&lt;li&gt;What happens when you schedule a meeting, then &lt;i&gt;cancel it more than once&lt;/i&gt;?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Time is created!&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3015197055005881733?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Cr-MPwVpI2gMl7R4caFYiweKLJs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Cr-MPwVpI2gMl7R4caFYiweKLJs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Cr-MPwVpI2gMl7R4caFYiweKLJs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Cr-MPwVpI2gMl7R4caFYiweKLJs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/QQEN_yM8tX0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/3015197055005881733/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3015197055005881733" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/3015197055005881733?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/3015197055005881733?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/QQEN_yM8tX0/anti-meeting-theory-of-time.html" title="The Anti-Meeting Theory of Time" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-XkTgdUHZVnE/TzWO0AxGSCI/AAAAAAAAAEA/Rjtt6AvJ98U/s72-c/theoryoftime.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2012/02/anti-meeting-theory-of-time.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEEQH88eyp7ImA9WhRbGEk.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-1405997372544577627</id><published>2012-02-09T21:30:00.000-06:00</published><updated>2012-02-09T21:30:01.173-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-09T21:30:01.173-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="conference" /><category scheme="http://www.blogger.com/atom/ns#" term="software development" /><category scheme="http://www.blogger.com/atom/ns#" term="link" /><category scheme="http://www.blogger.com/atom/ns#" term="programming language" /><category scheme="http://www.blogger.com/atom/ns#" term="data structure" /><title>Link o' the day: Java and memory</title><content type="html">&lt;p&gt;From proggit, this is a presentation from OOPSLA 2008:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://domino.research.ibm.com/comm/research_people.nsf/pages/sevitsky.pubs.html/$FILE/oopsla08%20memory-efficient%20java%20slides.pdf"&gt;Building Memory-efficient Java Applications&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1405997372544577627?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/A2gEZEF2pV41K8_ANEcXSmV21H4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/A2gEZEF2pV41K8_ANEcXSmV21H4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/A2gEZEF2pV41K8_ANEcXSmV21H4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/A2gEZEF2pV41K8_ANEcXSmV21H4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/OX4YYpTCAsU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/1405997372544577627/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1405997372544577627" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/1405997372544577627?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/1405997372544577627?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/OX4YYpTCAsU/link-o-day-java-and-memory.html" title="Link o' the day: Java and memory" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2012/02/link-o-day-java-and-memory.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEGQX4-eyp7ImA9WhRbE04.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-6952274422402641967</id><published>2012-02-03T23:17:00.000-06:00</published><updated>2012-02-03T23:17:00.053-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-03T23:17:00.053-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="software development" /><category scheme="http://www.blogger.com/atom/ns#" term="quote" /><title>Quote o' the week: Don Stewart on the big picture</title><content type="html">&lt;p&gt;This is from &lt;a href="http://code.haskell.org/~dons/talks/padl-keynote-2012-01-24.pdf"&gt;Don Stewart's keynote at PADL'12&lt;/a&gt; (formally, the &lt;a href="http://research.microsoft.com/en-us/um/people/crusso/padl12/"&gt;Fourteenth International Symposium on Practical Aspects of Declarative Languages&lt;/a&gt;) and is one of the few fundamental truths of computer programming. (Number three might be controversial.)
&lt;blockquote&gt;
&lt;b&gt;Really big picture: why software?&lt;/b&gt;
&lt;ul&gt;
&lt;li&gt;Increase economic productivity by automating everything&lt;/li&gt;
&lt;li&gt;Make the complexity of the world tractable by making it hackable&lt;/li&gt;
&lt;li&gt;Impose structure through typed data&lt;/li&gt;
&lt;li&gt;Transform work/jobs/tasks into resuable/composable functions&lt;/li&gt;
&lt;li&gt;Find new efficiencies. Repeat&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(Demonstrate you can do this and you'll never be out of work)&lt;/p&gt;
&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-6952274422402641967?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/AqeJ9OQ1SOiK_9eP2gr2iBhpNP4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AqeJ9OQ1SOiK_9eP2gr2iBhpNP4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/AqeJ9OQ1SOiK_9eP2gr2iBhpNP4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AqeJ9OQ1SOiK_9eP2gr2iBhpNP4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/TEj8rAkB8Tw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/6952274422402641967/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=6952274422402641967" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/6952274422402641967?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/6952274422402641967?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/TEj8rAkB8Tw/quote-o-week-don-stewart-on-big-picture.html" title="Quote o' the week: Don Stewart on the big picture" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2012/02/quote-o-week-don-stewart-on-big-picture.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEECQnY4fip7ImA9WhRbFUs.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-1898175628585684379</id><published>2012-02-01T19:59:00.000-06:00</published><updated>2012-02-06T15:11:03.836-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-06T15:11:03.836-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="toy problems" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="data structure" /><title>State space search: A*</title><content type="html">&lt;p&gt;&lt;a href="http://maniagnosis.crsr.net/2012/01/state-space-search-heuristics.html"&gt;Last time&lt;/a&gt;, I quoted Wikipedia, "For the 15-puzzle, lengths of optimal solutions range from 0 to 80 moves". Unfortunately, the two solutions I found require 255 and 205 moves. That seems less than satisfactory.&lt;/p&gt;

&lt;p&gt;So, here's the state of 15-puzzle solutions as it stands: we have depth-first search, which is relatively fast but which is not guaranteed to find a solution. On the other hand, we have breadth-first search, which is guaranteed to find an &lt;i&gt;optimal&lt;/i&gt; solution, in the sense of the smallest number of moves for the 15-puzzle, but which is slow and expensive. And finally, we have a couple of heuristics which, used alone, relatively quickly find a solution, having some of the benefits of depth-first search, but which find markedly sub-optimal solutions.&lt;/p&gt;

&lt;p&gt;What this situation calls for is a slightly modified algorithm. The algorithm I have in mind is called &lt;b&gt;A*&lt;/b&gt;. A* is actually a basic modification of the state evaluation function used by an informed search. Instead of the Manhattan distance or the number of tiles out of position (which I have learned should be called the &lt;b&gt;&lt;a href="http://en.wikipedia.org/wiki/Hamming_distance"&gt;Hamming distance&lt;/a&gt;&lt;/b&gt;) as the evaluation function, A* uses the sum of a forward-looking heuristic function and the cost of the path from the initial state to the state being evaluated. For the 15-puzzle, this would be, say, the Manhattan distance of the current state from the goal state plus the number of moves from the initial state to the current state.&lt;/p&gt;

&lt;p&gt;A* works by being a &lt;b&gt;best-first&lt;/b&gt; search; by expanding the state that looks like it will produce the best solution, rather than a state that is simply structurally &lt;em&gt;next&lt;/em&gt; (as in the case of uninformed searches) or a state that looks like it is &lt;em&gt;nearest&lt;/em&gt; to a solution. As a result, A* is likely to use fewer resources than breadth-first search while finding a better solution than an informed depth-first search.&lt;/p&gt;

&lt;p&gt;In fact, A* has a very nice property: if the forward-looking heuristic function is &lt;b&gt;admissible&lt;/b&gt;, then the search algorithm is guaranteed to find the optimal solution. &lt;em&gt;Admissible&lt;/em&gt; simply means that the heuristic function does not &lt;em&gt;overestimate&lt;/em&gt; the cost of the path from the current state to a goal. Possibly the simplest way of finding an admissible heuristic function is to relax some of the constraints on the problem; for example, the Hamming distance heuristic relaxes the 15-puzzle problem by allowing tiles to be directly moved to their goal position and counting the number of tiles thus moved while the Manhattan distance heuristic relaxes the constraints by allowing tiles to move directly to their goal states (rather than requiring sliding them into the empty space) and counting the number of moves needed. Both the Hamming distance and the Manhattan distance are admissible.&lt;/p&gt;

&lt;p&gt;Converting the fifteenpuzzle code to use A* is incredibly easy:&lt;/p&gt;

&lt;pre&gt;
  public static class AStarDistance implements Comparator&amp;lt;FState&gt;
  {
    @Override
    public int compare(FState o1, FState o2)
    {
      return (o1.totalDistance() + o1.pathLength) - (o2.totalDistance() + o2.pathLength);
    }
  }
&lt;/pre&gt;

&lt;p&gt;I created a new implementation of &lt;code&gt;Comparator&amp;lt;FState&gt;&lt;/code&gt; which compares the two states by computing the &lt;code&gt;totalDistance&lt;/code&gt; value (the Manhattan distance) of each object and the length of the path from the initial state to the states and then comparing the resulting sums. When creating an instance of &lt;code&gt;Search&amp;lt;FState&gt;&lt;/code&gt;, use a &lt;code&gt;PriorityQueue&lt;/code&gt; based on this &lt;code&gt;Comparator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;How well does it work? I've got no clue. Sorry. The A* search goes through hundreds of thousands of states before it exhausts the default JVM heap size, and it takes long enough to do so that I don't really feel interested in trying it with more memory. The implementation could be optimized, but this is an exponential algorithm and optimization would be unlikely to make too much of a dent. (On the other hand, there is the possibility, however remote, that I've really hoarked something up. If so, I'd appreciate knowing about it.)&lt;/p&gt;

&lt;p&gt;But I have the next best thing: by modifying the A* evaluation function, I can bias the evaluation towards the heuristic function, producing a solution in reasonable time and space. Unfortunately by doing so, I am likely to effectively make the heuristic function inadmissible, meaning that A* is no longer guaranteed to find an optimal solution. This is the implementation:&lt;/p&gt;

&lt;pre&gt;
  public static class BiasedAStarDistance implements Comparator&amp;lt;FState&gt;
  {
    private final int bias;
    
    public BiasedAStarDistance(int bias)
    {
      this.bias = bias;
    }

    @Override
    public int compare(FState o1, FState o2)
    {
      return (bias * o1.totalDistance() + o1.pathLength) - (bias * o2.totalDistance() + o2.pathLength);
    }
  }
&lt;/pre&gt;

&lt;p&gt;For me, it works significantly better than the un-biased A* search.&lt;/p&gt;

&lt;table style="border:thin solid black; padding:5px; text-align:center;"&gt;
&lt;tr&gt;&lt;th style="padding:5px;"&gt;Bias&lt;/th&gt;&lt;th style="padding:5px;"&gt;States examined&lt;/th&gt;&lt;th style="padding:5px;"&gt;Path length&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;3865&lt;/td&gt;&lt;td&gt;75&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;4266&lt;/td&gt;&lt;td&gt;83&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;15,442&lt;/td&gt;&lt;td&gt;73&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;19,879&lt;/td&gt;&lt;td&gt;57&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;You can get the code on &lt;a href="https://github.com/tmmcguire/StateSpaceSearch"&gt;github&lt;/a&gt;. The previous posts are &lt;a href="http://maniagnosis.crsr.net/2012/01/state-space-search-basics.html"&gt;State space search: the basics&lt;/a&gt; and &lt;a href="http://maniagnosis.crsr.net/2012/01/state-space-search-heuristics.html"&gt;State space search: heuristics&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1898175628585684379?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/a2U96QvZhzjVE5Y7Q_KviUM07VY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/a2U96QvZhzjVE5Y7Q_KviUM07VY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/a2U96QvZhzjVE5Y7Q_KviUM07VY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/a2U96QvZhzjVE5Y7Q_KviUM07VY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/jGuPCBPX9JQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/1898175628585684379/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1898175628585684379" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/1898175628585684379?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/1898175628585684379?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/jGuPCBPX9JQ/state-space-search.html" title="State space search: A*" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2012/02/state-space-search.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ACQXs8fyp7ImA9WhRUGEs.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-4783737498581163039</id><published>2012-01-29T13:36:00.000-06:00</published><updated>2012-01-29T13:36:00.577-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-29T13:36:00.577-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="toy problems" /><category scheme="http://www.blogger.com/atom/ns#" term="lisp" /><category scheme="http://www.blogger.com/atom/ns#" term="emacs" /><category scheme="http://www.blogger.com/atom/ns#" term="math" /><title>Nth Fibonacci number in Emacs Lisp</title><content type="html">&lt;p&gt;Following a post by &lt;a href="http://mathproofs.blogspot.com/2005/04/nth-term-of-fibonacci-sequence.html"&gt;Phil&lt;/a&gt;, a video game developer in Orange County, this is the Fibonacci function in Emacs Lisp:&lt;/p&gt;

&lt;pre&gt;
;;; Define some constants
(defconst s5 (sqrt 5) "square root of 5")
(defconst is5 (/ 1 s5) "inverse of the square root of 5")
(defconst ps52 (/ (+ 1 s5) 2) "1 plus sqrt(5) over 2")
(defconst ns52 (/ (- 1 s5) 2) "1 minus sqrt(5) over 2")

;;; The fibonacci function
(defun fibonacci (n)
  "Nth fibonacci number"
  (truncate (* is5
               (- (expt ps52 n)
                  (expt ns52 n)))))
&lt;/pre&gt;

&lt;p&gt;I'll leave the proof of it to Phil (and it is pretty damn nice), but here are some quick examples:&lt;/p&gt;

&lt;pre&gt;
(fibonacci 0)
0
(fibonacci 1)
1
(fibonacci 2)
1
(fibonacci 3)
2
(fibonacci 4)
3
(fibonacci 5)
5
(fibonacci 6)
8
(fibonacci 8)
21
(fibonacci 10)
55
&lt;/pre&gt;

&lt;p&gt;And yes, I know it is using limited precision floating point numbers and will break six ways from Sunday.&lt;/p&gt;

&lt;p&gt;Still, this is now my favorite answer to an interview question.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4783737498581163039?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/nGcPdPhyOO9cBESjnHyh9ngQgLo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/nGcPdPhyOO9cBESjnHyh9ngQgLo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/nGcPdPhyOO9cBESjnHyh9ngQgLo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/nGcPdPhyOO9cBESjnHyh9ngQgLo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/QGdReuWdUTQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/4783737498581163039/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4783737498581163039" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/4783737498581163039?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/4783737498581163039?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/QGdReuWdUTQ/nth-fibonacci-number-in-emacs-lisp.html" title="Nth Fibonacci number in Emacs Lisp" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2012/01/nth-fibonacci-number-in-emacs-lisp.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUACQXw4eSp7ImA9WhRUFUg.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-4275035349761887054</id><published>2012-01-25T22:56:00.000-06:00</published><updated>2012-01-25T22:56:00.231-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-25T22:56:00.231-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="conference" /><category scheme="http://www.blogger.com/atom/ns#" term="random" /><category scheme="http://www.blogger.com/atom/ns#" term="quote" /><title>Quote o' the week: a journal that meets in a hotel</title><content type="html">&lt;p&gt;I reading my pile of magazines and ran across Moshe Vardi's "&lt;a href="http://cacm.acm.org/magazines/2011/9/122805-are-you-talking-to-me/fulltext"&gt;Are you talking to Me?&lt;/a&gt;" in the CACM. (It's a brilliant editorial; he mentions Doug Zongker's "&lt;a href="http://www.youtube.com/watch?v=yL_-1d9OSdk"&gt;Chicken Chicken Chicken&lt;/a&gt;" &lt;a href="http://isotropic.org/papers/chicken.ppt"&gt;talk&lt;/a&gt; (and &lt;a href="http://isotropic.org/papers/chicken.pdf"&gt;paper&lt;/a&gt;!), the number of people attending a conference who think presentations are an opportunity to check their email (yeah, I know most of the good stuff is in the "hall track"), and the following:&lt;/p&gt;

&lt;blockquote&gt;I am reminded of Lance Fortnow's pithy description of a computer-science conference as "a journal that meets at a hotel."&lt;/blockquote&gt;

&lt;p&gt;Unfortunately, Fortnow, who notably &lt;a href="http://people.cs.uchicago.edu/~fortnow/papers/growup.pdf"&gt;doesn't care for the state&lt;/a&gt; of computer science conferences, disclaims responsibility for the quote.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;How about this idea: We don't bother meeting and just collect the accepted papers into a single volume. We can give this idea an innovative name like a "journal".&lt;/p&gt;

&lt;p&gt;In this month's CACM article, Moshe Vardi complains about the quality of conference talks. (I like the "journal  that meets in a hotel" quote but it didn't originate with me). You see this at STOC and FOCS too, people giving a talk only to other specialists in their field instead of aiming for a general audience.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Personally, I believe that the word "weasel" is inherently funny and deserves to be used much more often than it is.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4275035349761887054?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/MGWcgFsnxxEHutP3x1nnGhP3uxM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MGWcgFsnxxEHutP3x1nnGhP3uxM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/MGWcgFsnxxEHutP3x1nnGhP3uxM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MGWcgFsnxxEHutP3x1nnGhP3uxM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/_AtXY3ehvKY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/4275035349761887054/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4275035349761887054" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/4275035349761887054?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/4275035349761887054?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/_AtXY3ehvKY/quote-o-week-journal-that-meets-in.html" title="Quote o' the week: a journal that meets in a hotel" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2012/01/quote-o-week-journal-that-meets-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8HQXszcCp7ImA9WhRbFUs.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-5884978790300772175</id><published>2012-01-22T14:25:00.000-06:00</published><updated>2012-02-06T15:13:50.588-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-06T15:13:50.588-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="toy problems" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="data structure" /><title>State space search: heuristics</title><content type="html">&lt;p&gt;&lt;a href="http://maniagnosis.crsr.net/2012/01/state-space-search-basics.html"&gt;Last time&lt;/a&gt;, I wrote, without any explanation&lt;/p&gt;

&lt;blockquote&gt;Using a FIFO queue searches the state space &lt;b&gt;breadth-first&lt;/b&gt;, visiting all of the states at a given distance from the initial state before any states at a greater distance. Using a LIFO queue searches the state space &lt;b&gt;depth-first&lt;/b&gt;, visiting all of the states following a given state before visiting any other states.&lt;/blockquote&gt;

&lt;p&gt;The way that works is important to the power of search. Consider using a first-in, first-out queue and expanding an initial state \(n\). Expanding \(n\) enqueues the states \((o_1, o_2, o_3)\). The next step is to remove the first state from the queue, expand it, and enqueue the results, leaving the queue as \((o_2, o_3, p_1, p_2)\) (assuming expanding \(o_1\) produced \(p_1\) and \(p_2\)). As a result, following this queuing strategy, all of the states at depth \(o\) from the initial state are expanded before any of the states at depth \(p\). Hence, "breadth-first".&lt;/p&gt;

&lt;p&gt;On the other hand, if the algorithm uses a last-in, first-out structure, expanding the same initial state \(n\) still produces a queue of \((o_1, o_2, o_3)\). However, the next step is to remove the &lt;em&gt;last&lt;/em&gt; state from the queue, expand it, and enqueue the results, producing \((o_1, o_2, p_1, p_2)\), assuming  expanding \(o_3\) produced \(p_1\) and \(p_2\) this time. This time, the &lt;em&gt;next&lt;/em&gt; step will be to expand \(p_2\), with the result that all of the states below \(o_3\) will be examined before any of the other states \(o_1\) or \(o_2\). Thus, "depth-first".&lt;/p&gt;

&lt;p&gt;So far, I have been discussing &lt;b&gt;uninformed search&lt;/b&gt;; these approaches order their exploration of the problem's state space based on the pattern of state-space expansion. There is a better way: &lt;b&gt;informed search&lt;/b&gt; applies information about the problem to focus the exploration of the state space on &lt;em&gt;important&lt;/em&gt; regions. Here's an example:&lt;/p&gt;

&lt;h2&gt;Sliding number puzzles: fifteenpuzzle&lt;/h2&gt;

&lt;p&gt;Returning to &lt;a href="http://www.aiai.ed.ac.uk/~gwickler/eightpuzzle-inf.html"&gt;Gerhard Wickler&lt;/a&gt;, he describes the basics of the 8-puzzle (a smaller version of the 15-puzzle) as,&lt;/p&gt;

&lt;img src="http://www.crsr.net/images/8puzzle.png" style="float:right; border:thin solid black; margin:10px" alt="Hideous illustration of an 8-puzzle"&gt;&lt;/img&gt;

&lt;blockquote&gt;
&lt;p&gt;The 8-puzzle is a smaller version of the slightly better known 15-puzzle. The puzzle consists of an area divided into a grid, 3 by 3 for the 8-puzzle, 4 by 4 for the 15-puzzle. On each grid square is a tile, expect for one square which remains empty. Thus, there are eight tiles in the 8-puzzle and 15 tiles in the 15-puzzle. A tile that is next to the empty grid square can be moved into the empty space, leaving its previous position empty in turn. Tiles are numbered, 1 thru 8 for the 8-puzzle, so that each tile can be uniquely identified.&lt;/p&gt;

&lt;p&gt;The aim of the puzzle is to achieve a given configuration of tiles from a given (different) configuration by sliding the individual tiles around the grid as described above.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This puzzle is not hard to put into a form suitable for state space search, which should provide a solution as long as the algorithm does not expand a state more than once. If the shortest solution is needed, the breadth-first approach is a straightforward choice.&lt;/p&gt;

&lt;p&gt;The state space for sliding puzzles is significantly larger than that of the missionaries and cannibals puzzle; there are \(n!\) ways to permute \(n\) tiles, although only half of those are reachable from a given goal state, although the proof is &lt;a href="http://en.wikipedia.org/wiki/Fifteen_puzzle"&gt;enlightening&lt;/a&gt; itself. (The 8-puzzle therefore illustrates one of the hazards of state space manipulation: some states may be unsolvable.) So, the 8-puzzle version has 181,440 possible states, including the empty tile; the 15-puzzle has 10,461,394,944,000.&lt;/p&gt;

&lt;p&gt;As a result, a complete search of the state space is likely to be infeasible and any uninformed search will also likely take more resources than strictly desirable. But there are ways to exploit knowledge about the problem to shorten the search.&lt;/p&gt;

&lt;p&gt;Suppose, for example, you can find out, given a state, approximately how many moves are needed to get from the state to a goal? Then, you could select the next state to explore based on your estimate of how close it is to the solution. Fortunately, both of these are possible: there are a number of &lt;b&gt;heuristics&lt;/b&gt; that can provide the necessary estimate, and our friend, the priority queue, can handle the selection of the next state to expand.&lt;/p&gt;

&lt;p&gt;One possible heuristic is the number of out of place tiles, because that is obviously going to be related to the number of moves necessary to get the tiles into their places. Importantly, for reasons that I don't intend to go into here, it always &lt;em&gt;underestimates&lt;/em&gt; the number of moves. If the search explores the state space, focusing on the states with fewer and fewer tiles out of place, the search is likely to find the goal while significantly reducing the resources required.&lt;/p&gt;

&lt;p&gt;To implement the states for the 15-puzzle, I chose to represent the positions of the tiles as locations in an &lt;code&gt;ArrayList&lt;/code&gt; of integers, with the tile values being 1 through 15 with 0 as the empty tile. (For expediency, I also record the location of the empty tile in the array.) As a result, determining whether a state is the goal is simple. For locations 0 to 14, whenever the value of the location is one greater than the location number, the puzzle is solved.&lt;/p&gt;
&lt;pre&gt;
  @Override
  public boolean isGoal()
  {
    // The final square should be 0 but I don't care.
    for (int i = 0; i &amp;lt; BOARD - 1; ++i)
    {
      if (board.get(i) != i + 1) { return false; }
    }
    return true;
  }
&lt;/pre&gt;

&lt;p&gt;Expanding a state a bit more complicated since it requires attempting to move the empty space left, right, up, and down. (Or, alternately, move the tile to the left into the empty space. Depends on how you look at these things.) One of the directional methods is shown below; the other three are similar.&lt;/p&gt;
&lt;pre&gt;
  @Override
  public List&amp;lt;FState&gt; expand()
  {
    List&amp;lt;FState&gt; result = new ArrayList&amp;lt;FState&gt;();
    for (FState newState : Arrays.asList(this.left(), this.right(), this.up(), this.down()))
    {
      if (newState != null) { result.add(newState); }
    }
    return result;
  }

[...]

  private FState left()
  {
    if (empty % ROW != 0)
    {
      // Empty location is not at left edge
      return new FState(this, empty - 1);
    }
    else
    {
      return null;
    }
  }
&lt;/pre&gt;

&lt;p&gt;(I'll leave it to you to figure out how modular arithmatic lets me fiddle with a rectangular grid in a one-dimensional array.)&lt;/p&gt;

&lt;p&gt;Implementing the out-of-position heuristic is similar to checking &lt;code&gt;isGoal&lt;/code&gt;, with the complication of counting the number of tiles out of place.&lt;/p&gt;
&lt;pre&gt;
  public int outOfPosition()
  {
    int out = 0;
    for (int i = 0; i &amp;lt; BOARD - 1; ++i)
    {
      if (board.get(i) != i + 1)
      {
        ++out;
      }
    }
    return out;
  }
&lt;/pre&gt;

&lt;p&gt;And finally, to allow the heuristic function to interface with a priority queue, I need a &lt;code&gt;Comparator&lt;/code&gt; subclass.&lt;/p&gt;
&lt;pre&gt;
  public static class OutOfPosition implements Comparator&amp;lt;FState&gt;
  {
    @Override
    public int compare(FState o1, FState o2)
    {
      return o1.outOfPosition() - o2.outOfPosition();
    }
  }
&lt;/pre&gt;

&lt;p&gt;The following code runs the search on a "harder" problem (harder than the one in the illustration above, anyway).&lt;/p&gt;
&lt;pre&gt;
    System.out.println("Heuristic search: out of position");
    Queue&lt;FState&gt; priority = new PriorityQueue&lt;FState&gt;(100, new FState.OutOfPosition());
    Search&lt;FState&gt; search = new Search&lt;FState&gt;(queue, new HashSet&lt;FState&gt;(), FState.harder());
    FState end = search.findGoal();
&lt;/pre&gt;
&lt;p&gt;This search exampines 4387 states to find a goal with a path length of 255.&lt;/p&gt;

&lt;p&gt;There are certainly many possible heuristics. An alternative heuristic for the 15-puzzle is the total distance for each tile in a state between its position and its goal position. Specifically, the &lt;b&gt;Manhattan distance&lt;/b&gt;, which is sum of the number of rows and columns each tile is out of position. The total of the Manhattan distance is computed by the &lt;code&gt;totalDistance&lt;/code&gt; method. The advantage of this heuristic is that it more closely estimates the number of moves necessary to solve a puzzle from a given state.&lt;/p&gt;
&lt;pre&gt;
  public int totalDistance()
  {
    int out = 0;
    for (int i = 0; i &amp;lt; BOARD; ++i)
    {
      if (i == empty) continue;
      int position = board.get(i) - 1;
      out += Math.abs((i % ROW) - (position % ROW));
      out += Math.abs((i / ROW) - (position / ROW));
    }
    return out;
  }
&lt;/pre&gt;
&lt;p&gt;In this case, rather than implementing &lt;code&gt;Comparator&lt;/code&gt;, I made the &lt;code&gt;FState&lt;/code&gt; class &lt;code&gt;Comparable&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;
  @Override
  public int compareTo(FState o)
  {
    return this.totalDistance() - o.totalDistance();
  }
&lt;/pre&gt;
&lt;p&gt;The driver program creates a &lt;code&gt;PriorityQueue&lt;/code&gt; with no arguments to use the &lt;code&gt;Comparable&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;
    System.out.println("Heuristic search: manhattan distance");
    Queue&lt;FState&gt; priority = new PriorityQueue&lt;FState&gt;();
    Search&lt;FState&gt; search = new Search&lt;FState&gt;(queue, new HashSet&lt;FState&gt;(), FState.harder());
    FState end = search.findGoal();
&lt;/pre&gt;
&lt;p&gt;This version only examines 1469 states to find a solution of 205 moves.&lt;/p&gt;

&lt;p&gt;For comparison, according to &lt;a href="http://en.wikipedia.org/wiki/Fifteen_puzzle"&gt;Wikipedia&lt;/a&gt;, "For the 15-puzzle, lengths of optimal solutions range from 0 to 80 moves". The difference is that the raw heuristic search that I am writing about here behaves similarly to depth-first search in that it makes no claim to find an optimal path. On the other hand, the raw heuristic search does find a solution quickly, much faster than a breadth-first search.&lt;/p&gt;

&lt;p&gt;You can get the code on &lt;a href="https://github.com/tmmcguire/StateSpaceSearch"&gt;github &lt;/a&gt;. Other posts on the topic are &lt;a href="http://maniagnosis.crsr.net/2012/01/state-space-search-basics.html"&gt;State space search: the basics&lt;/a&gt;, and &lt;a href="http://maniagnosis.crsr.net/2012/02/state-space-search.html"&gt;State space search: A*&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5884978790300772175?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/8bxB5kZF3vJMddnQFakbkTOwbEU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8bxB5kZF3vJMddnQFakbkTOwbEU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/8bxB5kZF3vJMddnQFakbkTOwbEU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8bxB5kZF3vJMddnQFakbkTOwbEU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/xKxzR5LG6ho" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/5884978790300772175/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5884978790300772175" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/5884978790300772175?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/5884978790300772175?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/xKxzR5LG6ho/state-space-search-heuristics.html" title="State space search: heuristics" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2012/01/state-space-search-heuristics.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEAHQ30_fyp7ImA9WhRbFUs.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-7219038370411770883</id><published>2012-01-15T22:37:00.000-06:00</published><updated>2012-02-06T15:12:12.347-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-06T15:12:12.347-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="toy problems" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="data structure" /><title>State space search: the basics</title><content type="html">&lt;p&gt;A while back, briefly &lt;a href="http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for.html"&gt;discussing Steve McConnell's Code Complete&lt;/a&gt;, I wrote, "On the other hand, McConnell previously presented as a good use of recursion a maze-solving function; maze solving is an application of state-space search, which has a simple, clear, and wildly flexible iterative implementation based on a priority queue." Between that, and the Stanford AI course (which only briefly mentioned most of what I spent a semester learning back in the late '80's), I have been pondering state space search lately. It really is an elegant algorithm. So, I thought I'd spend some spare time writing an elaborate and likely unnecessary post or three about it.&lt;/p&gt;

&lt;p&gt;I'll begin with a &lt;b&gt;state&lt;/b&gt;. A state is a particular configuration of the system in question. For example, a board position in chess is a state. When you place the pieces on the board, you create an &lt;b&gt;initial state&lt;/b&gt;; after some number of moves, the board is in some other state. When the game is over, the board is in a &lt;b&gt;terminal&lt;/b&gt; state; if you won, it's in a &lt;b&gt;goal&lt;/b&gt; state, but the difference is the topic of some other post. For the moment, I will only be talking about systems where the only terminal states are goals.&lt;/p&gt;

&lt;p&gt;A &lt;b&gt;state space&lt;/b&gt; is the set of &lt;em&gt;all&lt;/em&gt; possible states for a system. For chess, the state space is &lt;em&gt;all&lt;/em&gt; possible board positions, and there are a lot of them. Chess has a fairly large state space. The states in a state space are related by the valid actions of the system; given a state those actions produce a collection of the next states reachable by one operation of the system. For chess, the actions are the valid moves of individual chess pieces and, because the initial state is defined by the rules of chess, the state space includes all board positions reachable from that initial state by legal chess moves.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;State space search&lt;/b&gt; is the technique of searching for a goal state, beginning with an initial state and using the operations available in each state to generate new states. Or, alternatively, beginning with a goal state and searching for a suitable initial state. Or possibly even starting with an initial state &lt;em&gt;and&lt;/em&gt; a goal state and searching for a way to connect the two in the state space. Each of those approaches is suitable for some problems, depending on the nature of the problem. The key point is to explore the state space of the problem, searching for a solution.&lt;/p&gt;

&lt;p&gt;State space search is one of the most powerful techniques in computer science. If a problem can be framed in a way suitable to state space search (and most can), then the algorithm is guaranteed to find a solution. Theoretically, anyway. If you have a problem and do not have any more direct algorithm, it is the go-to way to solve it. Or, at least it was; there are other techniques that have become popular, usually for very good reasons.&lt;/p&gt;

&lt;p&gt;On the other hand, state space search has some serious weaknesses. For one thing, not all problems can be usefully framed in terms of a state space. It requires that the problem be both discrete and deterministic; discrete in such a way that all states are distinct from one another and deterministic so that an action produces exactly one subsequent state from an input state. But that is not the worst part. State space search is the poster child for exponential algorithms. I said it was guaranteed to find a solution, but I carefully didn't say you would be alive to see it. Or, &lt;em&gt;anything&lt;/em&gt; would be alive to see it. But there are plenty of problems to which state space search is applicable.&lt;/p&gt;

&lt;h2&gt;The algorithm&lt;/h2&gt;

&lt;p&gt;So, with all that buildup, the algorithm is a typical let-down:&lt;/p&gt;

&lt;pre&gt;
def search(queue):
    while not empty?(queue):
        current_state := remove_element(queue)
        if is_goal?(current_state):
            return current_state
        for next_state in expand(current_state):
            if not seen?(next_state):
                mark_seen(next_state)
                add(queue, next_state)
    return nil
&lt;/pre&gt;

&lt;p&gt;The intelligence of the algorithm is actually in the:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Queue that is used to store states before they are examined and expanded and which determines the nature of the search,&lt;/li&gt;
&lt;li&gt;The rules that determine whether a state is a goal and how the state is expanded into subsequent states, and&lt;/li&gt;
&lt;li&gt;The set used to determine whether a state has been seen before; this and the queue will determine how much memory the algorithm uses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How does this look in Java?&lt;/p&gt;

&lt;pre&gt;
  public T findGoal()
  {
    while (!queue.isEmpty())
    {
      statesExamined++;

      T current = queue.remove();
      if (current.isGoal())
      {
        return current;
      }
      for (T newState : current.expand())
      {
        if (!seen.contains(newState))
        {
          seen.add(newState);
          queue.add(newState);
        }
      }
    }
    return null;
  }
&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;statesExamined&lt;/code&gt; is an accounting addition, just used for entertainment purposes. The rest of the class similarly simple, initializing &lt;code&gt;seen&lt;/code&gt; and &lt;code&gt;queue&lt;/code&gt; based on constructor arguments. Like I said, nothing up my sleeve....&lt;/p&gt;

&lt;pre&gt;
public class Search&amp;lt;T extends State&amp;lt;T&gt;&gt;
{
  private int statesExamined;
  private final Queue&amp;lt;T&gt; queue;
  private final Set&amp;lt;T&gt; seen;

  public Search(Queue&amp;lt;T&gt; queue, Set&amp;lt;T&gt; seen, T initialState)
  {
    this.queue = queue;
    queue.add(initialState);
    this.seen = seen;
    this.statesExamined = 0;
  }

  [...findGoal...]

  public int statesExamined()
  {
    return statesExamined;
  }
}
&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;Set&lt;/code&gt; &lt;code&gt;seen&lt;/code&gt; is used to prevent states from being expanded repeatedly. It records when a state is first seen and subsequently prevents it from being re-added to the queue. Without this, the algorithm could enter an infinite loop if the state space is not acyclic.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;State&lt;/code&gt; interface is not much more interesting. The only required methods are to expand the state, producing a list of subsequent states produced by valid actions, and a predicate that is true if the state is a goal.&lt;/p&gt;

&lt;pre&gt;
public interface State&lt;T&gt;
{
  public List&lt;T&gt; expand();

  public boolean isGoal();
}
&lt;/pre&gt;

If the state space search code is so simple, how is the algorithm capable of such power? How about an example?

&lt;h2&gt;Missionaries and cannibals: rivercrossing&lt;/h2&gt;

&lt;p&gt;The problem is, according to &lt;a href="http://www.aiai.ed.ac.uk/~gwickler/missionaries.html"&gt;Gerhard Wickler&lt;/a&gt;,&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;On one bank of a river are three missionaries and three cannibals. There is one boat available that can hold up to two people and that they would like to use to cross the river. If the cannibals ever outnumber the missionaries on either of the river’s banks, the missionaries will get eaten.&lt;/p&gt;
&lt;p&gt;How can the boat be used to safely carry all the missionaries and cannibals across the river?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;(I have seen versions where the threat is the missionaries converting the cannibals, rather than the cannibals cannibalizing (ahem) the missionaries. I am a traditionalist, however.)&lt;/p&gt;

&lt;a href="http://www.aiai.ed.ac.uk/~gwickler/missionaries.html"&gt;&lt;img style="background-color: white; padding:5px; margin:10px; border:medium solid black; float:right;" src="http://www.aiai.ed.ac.uk/~gwickler/images/mc-search-space.png"&gt;&lt;/img&gt;&lt;/a&gt;

&lt;p&gt;Gerhard Wickler also has an excellent illustration of the complete state space for this problem. The initial state is on the left; the goal state is on the right. With 16 states, the state space is &lt;em&gt;tiny&lt;/em&gt; in comparison with the space of other problems, but it gets my point across.&lt;/p&gt;

&lt;p&gt;Each state is a configuration of the missionaries and cannibals on each side of the river as well as which shore the boat is on. The process of crossing the river is abstracted away; each state transition involves the boat, with at least one passenger, crossing the river.&lt;/p&gt;

&lt;p&gt;Specifically, a state in the puzzle is made up of the participants on this side of the river, the participants on that side of the river, and the location of the boat, this side or that side.&lt;/p&gt;

&lt;pre&gt;
  private static enum BoatSide { THIS, THAT };
&lt;/pre&gt;

&lt;p&gt;On either side of the river are some number of missionaries and cannibals. I abstracted out the state of each side of the river as a class. There are a couple of special features of &lt;code&gt;RiverSide&lt;/code&gt;, though.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First, the class includes methods &lt;code&gt;missionaries&lt;/code&gt;, &lt;code&gt;cannibals&lt;/code&gt;, and &lt;code&gt;both&lt;/code&gt; which returns a new &lt;code&gt;RiverSide&lt;/code&gt; instance with the number of missionaries or cannibals modified. These are used when generating new states while expanding a given state.&lt;/li&gt;
&lt;li&gt;Second, the class implements &lt;code&gt;equals&lt;/code&gt; and &lt;code&gt;hashCode&lt;/code&gt;, making instances eligible to be stored in a &lt;code&gt;HashMap&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
  private static class RiverSide
  {
    public final int missionaries;
    public final int cannibals;
    
    public RiverSide(int missionaries, int cannibals)
    {
      this.missionaries = missionaries;
      this.cannibals = cannibals;
    }
    
    public RiverSide missionaries(int n)
    {
      return new RiverSide(missionaries + n, cannibals);
    }

    public RiverSide cannibals(int n)
    {
      return new RiverSide(missionaries, cannibals + n);
    }

    public RiverSide both(int n)
    {
      return new RiverSide(missionaries + n, cannibals + n);
    }
    
    @Override
    public boolean equals(Object o)
    {
      if (! (o instanceof RiverSide)) return false;
      final RiverSide other = (RiverSide) o;
      return this.missionaries == other.missionaries
          &amp;&amp; this.cannibals == other.cannibals;
    }
    
    @Override
    public int hashCode()
    {
      return missionaries ^ cannibals;
    }
    
    @Override
    public String toString()
    {
      return String.format("[%d missionaries, %d cannibals]", missionaries, cannibals);
    }
  }
&lt;/pre&gt;

&lt;p&gt;There are two constructors for the state class: the first, public, one creates the initial state for the problem, with three missionaries, three cannibals, and the boat on this side of the river. The second, private, one creates a new &lt;code&gt;MCState&lt;/code&gt; based on a previous one and updated inhabitants of this and that side. The previous state is recorded so that the program can reconstruct the sequences of moves in a solution.&lt;/p&gt;

&lt;p&gt;The methods required for &lt;code&gt;State&lt;/code&gt; are next. &lt;code&gt;isGoal&lt;/code&gt; is implemented by checking how many missionaries and cannibals are on that side of the river. &lt;code&gt;expand&lt;/code&gt; is more complex, but breaks down into a number of branches; if the boat is on this side of the river, then &lt;code&gt;expand&lt;/code&gt; generates all possible ways for it to get to the other side of the river, carrying one or two missionaries or cannibals; if the boat is on the other side, it does the reverse. Specifically, it collects a list of subsequent states; if at least one missionary is on this side, then a possible next state has the boat and one more missionary on that side. Likewise, if there are two missionaries on this side with the boat, another next state would be two less missionaries on this side and two more and the boat on that. The same logic applies to the cannibals and to a missionary and a cannibal moving to the other side. All of these branches go through &lt;code&gt;queueNewState&lt;/code&gt;, which first checks whether the new state is invalid if it presents the opportunity for some cannibals to devour some missionaries. As a result of the branches, each state has five possible next states, although some (or most) of those states are invalid.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MCState&lt;/code&gt; also implements &lt;code&gt;hashCode&lt;/code&gt; and &lt;code&gt;equals&lt;/code&gt;, making instances eligible for &lt;code&gt;HashSet&lt;/code&gt; storage.&lt;/p&gt;

&lt;pre&gt;
public class MCState implements State&amp;lt;MCState&gt;
{
  [...]
  
  public final BoatSide boatSide;
  public final RiverSide thisSide;
  public final RiverSide thatSide;
  public final MCState previous;
  
  public MCState()
  {
    boatSide = BoatSide.THIS;
    thisSide = new RiverSide(3, 3);
    thatSide = new RiverSide(0, 0);
    previous = null;
  }
  
  private MCState(MCState previous, RiverSide thisSide, RiverSide thatSide)
  {
    this.boatSide = previous.boatSide == BoatSide.THIS ? BoatSide.THAT : BoatSide.THIS;
    this.thisSide = thisSide;
    this.thatSide = thatSide;
    this.previous = previous;
  }
  
  @Override
  public boolean isGoal()
  {
    return thatSide.missionaries == 3 &amp;&amp; thatSide.cannibals == 3;
  }

  @Override
  public List&amp;lt;MCState&gt; expand()
  {
    List&amp;lt;MCState&gt; newStates = new ArrayList&amp;lt;MCState&gt;();
    if (boatSide == BoatSide.THIS)
    {
      if (thisSide.missionaries &gt; 0)
      {
        final MCState newState =
            new MCState(this, thisSide.missionaries(-1), thatSide.missionaries(1));
        queueNewState(newStates, newState);
      }
      if (thisSide.missionaries &gt; 1)
      {
        final MCState newState =
            new MCState(this, thisSide.missionaries(-2), thatSide.missionaries(2));
        queueNewState(newStates, newState);
      }
      if (thisSide.cannibals &gt; 0)
      {
        final MCState newState =
            new MCState(this, thisSide.cannibals(-1), thatSide.cannibals(1));
        queueNewState(newStates, newState);
      }
      if (thisSide.cannibals &gt; 1)
      {
        final MCState newState =
            new MCState(this, thisSide.cannibals(-2), thatSide.cannibals(2));
        queueNewState(newStates, newState);
      }
      if (thisSide.missionaries &gt; 0 &amp;&amp; thisSide.cannibals &gt; 0)
      {
        final MCState newState =
            new MCState(this, thisSide.both(-1), thatSide.both(1));
        queueNewState(newStates, newState);
      }
    }
    else
    {
      if (thatSide.missionaries &gt; 0)
      {
        final MCState newState =
            new MCState(this,thisSide.missionaries(1), thatSide.missionaries(-1));
        queueNewState(newStates, newState);
      }
      if (thatSide.missionaries &gt; 1)
      {
        final MCState newState =
            new MCState(this,thisSide.missionaries(2), thatSide.missionaries(-2));
        queueNewState(newStates, newState);
      }
      if (thatSide.cannibals &gt; 0)
      {
        final MCState newState =
            new MCState(this,thisSide.cannibals(1), thatSide.cannibals(-1));
        queueNewState(newStates, newState);
      }
      if (thatSide.cannibals &gt; 1)
      {
        final MCState newState =
            new MCState(this,thisSide.cannibals(2), thatSide.cannibals(-2));
        queueNewState(newStates, newState);
      }
      if (thatSide.missionaries &gt; 0 &amp;&amp; thatSide.cannibals &gt; 0)
      {
        final MCState newState =
            new MCState(this,thisSide.both(1), thatSide.both(-1));
        queueNewState(newStates, newState);
      }
    }
    return newStates;
  }
  
  private void queueNewState(final List&lt;MCState&gt; newStates, final MCState newState)
  {
    if (newState.isValid())
    {
      newStates.add(newState);
    }
  }
  
  private boolean isValid()
  {
    return (thisSide.missionaries == 0 || thisSide.missionaries &gt;= thisSide.cannibals)
        &amp;&amp; (thatSide.missionaries == 0 || thatSide.missionaries &gt;= thatSide.cannibals);
  }

  @Override
  public String toString()
  {
    final String format = (boatSide == BoatSide.THIS) ? "%s * -&gt; %s" : "%s -&gt; * %s";
    return String.format(format, thisSide, thatSide);
  }
  
  @Override
  public boolean equals(final Object o)
  {
    if (! (o instanceof MCState)) return false;
    final MCState other = (MCState) o;
    return this.thisSide.equals(other.thisSide)
        &amp;&amp; this.thatSide.equals(other.thatSide)
        &amp;&amp; this.boatSide == other.boatSide;
  }
  
  @Override
  public int hashCode()
  {
    return thisSide.hashCode() ^ thatSide.hashCode() ^ boatSide.hashCode();
  }
}
&lt;/pre&gt;

&lt;p&gt;That is a fair amount of code, and nicely tedious. The key points, though, are the implementation of the &lt;code&gt;State&lt;/code&gt; interface; the State knows whether or not it is a goal, and it knows how to generate the &lt;em&gt;next&lt;/em&gt; states, following immediate, single step actions.&lt;/p&gt;

&lt;p&gt;After that big wall o' code, you are probably waiting for a punch line. Unfortunately, there isn't one. Just a driver class invoking the search twice with a couple of different queue parameters. The first option uses &lt;code&gt;ArrayDeque&lt;/code&gt;, which implements a First-In, First-Out queue.&lt;/p&gt;

&lt;pre&gt;
    Queue&lt;MCState&gt; fifo = new ArrayDeque&lt;MCState&gt;();
    Search&lt;MCState&gt; search = new Search&lt;MCState&gt;(fifo, new HashSet&lt;MCState&gt;(), new MCState());
    MCState end = search.findGoal();
&lt;/pre&gt;

&lt;p&gt;The second option uses an anonymous subclass of &lt;code&gt;ArrayDequeue&lt;/code&gt; where &lt;code&gt;remove&lt;/code&gt; calls &lt;code&gt;removeLast&lt;/code&gt; rather than &lt;code&gt;removeFirst&lt;/code&gt;. As a result, it implements a Last-In, First-Out queue, or a stack.&lt;/p&gt;

&lt;pre&gt;
    Queue&lt;MCState&gt; lifo = new ArrayDeque&lt;MCState&gt;() {

      @Override
      public MCState remove()
      {
        return super.removeLast();
      }
      
    };
    Search&lt;MCState&gt; search = new Search&lt;MCState&gt;(lifo, new HashSet&lt;MCState&gt;(), new MCState());
    MCState end = search.findGoal();
&lt;/pre&gt;

&lt;p&gt;These two options are my first demonstration of the flexibility of the state space search algorithm. Using a FIFO queue searches the state space breadth-first, visiting all of the states at a given distance from the initial state before any states at a greater distance. Using a LIFO queue searches the state space depth-first, visiting all of the states following a given state before visiting any other states. The difference in this case is modest; a FIFO queue visits 16 states while a LIFO queue visits 13 to find a solution. But that is just the tip of the iceberg.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update: completely forgot about this.&lt;/em&gt; If you want to try it yourself, there is a related problem involving a farmer crossing a river. The farmer is carrying a bushel of corn, a duck, and a fox. (Yeah, I don't really get it either.) If the duck is left unattended with the corn, the corn gets eaten. If the fox is left unattended with the duck, the duck gets eaten. The boat will only carry the farmer and one of the other items. How can the farmer get to the other side of the river with the corn, duck, and fox intact? You can get the state space search code, such as it is, and you will need to write a &lt;code&gt;State&lt;/code&gt; for the problem similar to &lt;code&gt;MCState&lt;/code&gt; and a driver program.&lt;/p&gt;

&lt;p&gt;For the continuing story of state space search, check out the next post, &lt;a href="http://maniagnosis.crsr.net/2012/01/state-space-search-heuristics.html"&gt;State space search: heuristics&lt;/a&gt; and &lt;a href="http://maniagnosis.crsr.net/2012/02/state-space-search.html"&gt;State space search: A*&lt;/a&gt;.

&lt;p&gt;You can get the code on &lt;a href="https://github.com/tmmcguire/StateSpaceSearch"&gt;github&lt;/a&gt;. I owe a considerable debt to Gerhard Wickler for his problem definition and illustration. He has a &lt;a href="http://www.aiai.ed.ac.uk/~gwickler/java/classes/ai.search.jar"&gt;Java library&lt;/a&gt; of &lt;a href="http://www.aiai.ed.ac.uk/~gwickler/java/doc/ai.search/"&gt;documented search code&lt;/a&gt; that you might want to check out as well.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7219038370411770883?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/f_hD1jxasr1rNF1zCUrEwHycjP4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/f_hD1jxasr1rNF1zCUrEwHycjP4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/f_hD1jxasr1rNF1zCUrEwHycjP4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/f_hD1jxasr1rNF1zCUrEwHycjP4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/e5I12cF0oOg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/7219038370411770883/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7219038370411770883" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/7219038370411770883?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/7219038370411770883?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/e5I12cF0oOg/state-space-search-basics.html" title="State space search: the basics" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2012/01/state-space-search-basics.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMCRnY5cCp7ImA9WhRVE0w.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-7447222538529331152</id><published>2012-01-11T15:30:00.001-06:00</published><updated>2012-01-11T15:31:07.828-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-11T15:31:07.828-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="system administration" /><category scheme="http://www.blogger.com/atom/ns#" term="quote" /><title>Quote o' the week: I've got my skillet right here, buddy</title><content type="html">&lt;p&gt;Perusing some &lt;a href="http://imgur.com/CCCcw"&gt;cable-porn&lt;/a&gt; on &lt;a href="http://www.reddit.com/r/sysadmin"&gt;/r/sysadmin&lt;/a&gt;, I found this piece of wisdom:&lt;/p&gt;

&lt;blockquote&gt;It's a two-pronged issue: Developers don't usually have the skillets or interests required for system administration.&lt;/blockquote&gt;

&lt;p&gt;That was part of a couple of insightful posts by sylver_dragon and tuba_man about the costs of using developers instead of sysadmins for system administration.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.reddit.com/r/sysadmin/comments/obazt/so_i_went_in_to_a_new_client_to_patch_in_a_few/c3g5dm0"&gt;sylver_dragon&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&gt; Developers are not sysadmins&lt;/p&gt;

&lt;p&gt;This is one of my biggest complaints about the blanket term "IT". I have dealt with too many managers who don't understand that there really is (or should be) a separation between Systems Administration and Software Development. Usually, you get a developer acting as admin when either role is (at least) a full time job. The end result is usually that the little things on the sysadmin side suffer. Cable routing is treated as, "fuck it, good enough." Documentation is usually not maintained, regular log checking doesn't happen, etc. It's not that the developer can't do it, it's just that he doesn't have time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="http://www.reddit.com/r/sysadmin/comments/obazt/so_i_went_in_to_a_new_client_to_patch_in_a_few/c3g5ked"&gt;tuba_man&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Exactly. Not only does he not have the time, but in a lot of ways, it prevents the developer (and the project or company as a whole) from operating most effectively. It's a two-pronged issue: Developers don't usually have the skillets or interests required for system administration. Application developers can work a lot better when they have solid systems to code on and deploy to. So a developer doing sysadmin work solely because he has to is in many cases shooting himself in the foot.&lt;/p&gt;

&lt;p&gt;In my instance at least, our company's two developers work a hell of a lot better when they don't have to worry about systems or infrastructure. Since hiring me on, we've had more code output, higher quality code output, more uptime, better response times, and less customer complaints.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I, personally, keep my skillet with me at all times.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7447222538529331152?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/zb9CtC51aMCMxxKbAnMDGxEX4C8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zb9CtC51aMCMxxKbAnMDGxEX4C8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/zb9CtC51aMCMxxKbAnMDGxEX4C8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zb9CtC51aMCMxxKbAnMDGxEX4C8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/872HVuVRL48" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/7447222538529331152/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7447222538529331152" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/7447222538529331152?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/7447222538529331152?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/872HVuVRL48/quote-o-week-ive-got-my-skillet-right.html" title="Quote o' the week: I've got my skillet right here, buddy" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2012/01/quote-o-week-ive-got-my-skillet-right.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UGQXg-eyp7ImA9WhRWF08.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-4180702227215630485</id><published>2012-01-04T20:07:00.000-06:00</published><updated>2012-01-04T20:07:00.653-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-04T20:07:00.653-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="link" /><title>Update to "System programming"</title><content type="html">&lt;p&gt;In case anyone is interested, I added a brief discussion of Jonathan Shapiro's "Programming Language Challenges in Systems Codes: Why Systems Programmers Still Use C, and What to Do About It" to &lt;a href="http://maniagnosis.crsr.net/2011/11/systems-programming.html"&gt;Systems programming&lt;/a&gt;. He has an interesting definition of systems programs, and significant insights into the requirements for a systems programming language.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4180702227215630485?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/vZ10813KfQ6YUcVL9Wjzys5j028/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vZ10813KfQ6YUcVL9Wjzys5j028/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/vZ10813KfQ6YUcVL9Wjzys5j028/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vZ10813KfQ6YUcVL9Wjzys5j028/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/17Q5IvYn8rQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/4180702227215630485/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4180702227215630485" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/4180702227215630485?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/4180702227215630485?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/17Q5IvYn8rQ/update-to-system-programming.html" title="Update to &quot;System programming&quot;" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2012/01/update-to-system-programming.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YFRnc7fyp7ImA9WhRWEkQ.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-3091123675978638769</id><published>2011-12-30T18:25:00.001-06:00</published><updated>2011-12-30T18:25:17.907-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-30T18:25:17.907-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="system administration" /><category scheme="http://www.blogger.com/atom/ns#" term="software development" /><category scheme="http://www.blogger.com/atom/ns#" term="tip" /><title>Tip: Converting a CVS repository to git</title><content type="html">&lt;p&gt;I have a great load of source code (and other detritus) in a CVS repository that I've been copying around for years. I have not used CVS for anything new in a very long time, but because I was the only one modifying things, I did not bother to move the contents to anything more modern.&lt;/p&gt;

&lt;p&gt;Occasionally, I need to reactivate a project, and usually want to move the history into a newer tool, git usually. And every time, I have to look up how to do it. So, here's the latest working scheme, in hopes that I don't have to search around anymore.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Copy the CVSROOT directory and the module from the repository to someplace local. My CVS root (and the master git repositories) live remotely. The destination doesn't matter much.&lt;/p&gt;
&lt;pre&gt;scp -r remote:CVS/{CVSROOT,module} CVS&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Get a copy of the latest &lt;a href="http://cvs2svn.tigris.org/servlets/ProjectDocumentList"&gt;cvs2svn&lt;/a&gt;, which includes &lt;a href="http://cvs2svn.tigris.org/cvs2git.html"&gt;cvs2git&lt;/a&gt;, which seems to be working better than I remember. Use cvs2git to create the two git fast-import format files from the repository.&lt;/p&gt;
&lt;pre&gt;cvs2svn-2.3.0/cvs2git --blobfile=module-blob.dat --dumpfile=module-dump.dat --username me CVS/&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Create a new git repository to act as the master repository for the project.&lt;/p&gt;
&lt;pre&gt;mkdir module.git
cd module.git/
git init --bare --shared
&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Import the project.&lt;/p&gt;
&lt;pre&gt;cat ../module-blob.dat ../module-dump.dat | git fast-import&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Put the new master repository back on my remote server.&lt;/p&gt;
&lt;pre&gt;cd ..; scp -r module.git remote:GIT/&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Clone the remote repository to create a local, working repository.&lt;/p&gt;
&lt;pre&gt;git clone ssh://remote/home/me/GIT/module.git&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The import above leaves the CVSROOT and module directories in the git repository, so the useful content of the module is one level down into the repository. The first git operation on the working repository fixes that.&lt;/p&gt;
&lt;pre&gt;git rm -r CVSROOT/
git mv module/* .
git rm -r module
git commit -m 'Removing cvs residue'
git push&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And with luck, that's that.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3091123675978638769?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/fRTSIUenKpGymaCsGTYrElQ7Jik/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fRTSIUenKpGymaCsGTYrElQ7Jik/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/fRTSIUenKpGymaCsGTYrElQ7Jik/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fRTSIUenKpGymaCsGTYrElQ7Jik/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/Th0Q2_cwgCo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/3091123675978638769/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3091123675978638769" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/3091123675978638769?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/3091123675978638769?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/Th0Q2_cwgCo/tip-converting-cvs-repository-to-git.html" title="Tip: Converting a CVS repository to git" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/12/tip-converting-cvs-repository-to-git.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04NQ3k4fSp7ImA9WhRXF0k.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-1085552593846090461</id><published>2011-12-24T09:52:00.001-06:00</published><updated>2011-12-24T09:53:12.735-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-24T09:53:12.735-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="quote" /><category scheme="http://www.blogger.com/atom/ns#" term="programming language" /><title>Quote o' the day: Criticism</title><content type="html">&lt;p&gt;From &lt;a href="http://www.reddit.com/r/programming/comments/no8o8/five_things_roger_ebert_taught_me_about/c3ancbb"&gt;reddit:&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;Criticizing another's favorite language is like criticizing their genitalia, religion or politics.&lt;/blockquote&gt;

&lt;p&gt;Words to live by.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1085552593846090461?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/AH989Kx3KzuLbAvTPkszHK4xA7o/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AH989Kx3KzuLbAvTPkszHK4xA7o/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/AH989Kx3KzuLbAvTPkszHK4xA7o/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AH989Kx3KzuLbAvTPkszHK4xA7o/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/D0uuxaRFv7M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/1085552593846090461/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1085552593846090461" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/1085552593846090461?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/1085552593846090461?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/D0uuxaRFv7M/quote-o-day-criticism.html" title="Quote o' the day: Criticism" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/12/quote-o-day-criticism.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUNRno5fip7ImA9WhRXEEg.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-6774262489128725670</id><published>2011-12-15T20:30:00.000-06:00</published><updated>2011-12-16T11:41:37.426-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-16T11:41:37.426-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="comics" /><category scheme="http://www.blogger.com/atom/ns#" term="theory" /><category scheme="http://www.blogger.com/atom/ns#" term="link" /><title>Link o' the day: Set Theory</title><content type="html">&lt;p&gt;I never really understood the whole deal about the &lt;a href="http://www.math.vanderbilt.edu/~schectex/ccc/choice.html"&gt;Axiom of Choice&lt;/a&gt;. ("the last great controversy of mathematics"?) But now, I get it. Thanks, Randall Munroe!&lt;/p&gt;

&lt;a href="http://xkcd.com/982/"&gt;&lt;img width="255px" height=354px" src="http://imgs.xkcd.com/comics/set_theory.png" title="Proof of Zermelo&amp;#39;s well-ordering theorem given the Axiom of Choice: 1: Take S to be any set. 2: When I reach step three, if S hasn&amp;#39;t managed to find a well-ordering relation for itself, I&amp;#39;ll feed it into this wood chipper. 3: Hey, look, S is well-ordered."&gt;&lt;/img&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-6774262489128725670?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/lxi0W9EZ-csT48GYJN8ACzDVi8M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lxi0W9EZ-csT48GYJN8ACzDVi8M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/lxi0W9EZ-csT48GYJN8ACzDVi8M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lxi0W9EZ-csT48GYJN8ACzDVi8M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/YF0MIrmEIow" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/6774262489128725670/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=6774262489128725670" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/6774262489128725670?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/6774262489128725670?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/YF0MIrmEIow/link-o-day-set-theory.html" title="Link o' the day: Set Theory" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/12/link-o-day-set-theory.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMCRXs4fSp7ImA9WhRbGU0.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-5510162608062931828</id><published>2011-12-12T06:00:00.000-06:00</published><updated>2012-02-10T15:14:24.535-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-10T15:14:24.535-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="toy problems" /><category scheme="http://www.blogger.com/atom/ns#" term="lisp" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="theory" /><category scheme="http://www.blogger.com/atom/ns#" term="notation" /><category scheme="http://www.blogger.com/atom/ns#" term="haskell" /><category scheme="http://www.blogger.com/atom/ns#" term="programming language" /><title>Mad science, abstract data types, and objects</title><content type="html">&lt;p&gt;Mad science, and mad scientists, are always good to find. They represent guaranteed entertainment. But they do show up in the &lt;i&gt;oddest&lt;/i&gt; places. How about this one: OOPSLA 2009, William Cook presents a talk entitled "No one listened! But I'll show them, I'll show them all!". And the weird part was, nobody noticed. Well, sure, it's actually a popular paper that gets referenced frequently and the title is in fact "&lt;a href="http://dl.acm.org/authorize?148131"&gt;On Understanding Data Abstraction, Revisited&lt;/a&gt;", but there's no sign that the peasants went scurrying for their pitchforks and torches.&lt;/p&gt;

&lt;div class="twocol"&gt;
&lt;div style="float:right; margin:20px;"&gt;&lt;img style="border:thick solid black;" src="http://www.crsr.net/images/will_cook2003.jpg"&gt;&lt;/img&gt;&lt;p style="text-align:center;"&gt;&lt;b&gt;William Cook&lt;/b&gt;&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;So, what's the deal with Cook and his paper?&lt;/p&gt;

&lt;h2&gt;A little backstory&lt;/h2&gt;

&lt;p&gt;In 1990, Cook published "&lt;a href="http://www.cs.utexas.edu/~wcook/papers/OOPvsADT/CookOOPvsADT90.pdf"&gt;Object-Oriented Programming Versus Abstract Data Types&lt;/a&gt;" which is almost identical in content to, but somewhat longer than, "On Understanding Data Abstraction, Revisited". In both papers Cook describes the long-established, but little known, difference between &lt;i&gt;objects&lt;/i&gt; and &lt;i&gt;abstract data types&lt;/i&gt;. (For simplicity, the object-oriented side is limited to a subset of what I learned to call "object-based programming"; objects, as you might normally think of them, minus inheritance and also without modifications.)&lt;/p&gt;

&lt;p&gt;Given those limitations, objects are data abstractions that "have a collection of methods, or procedures, that share access to private local state." Consider the type specimen of object-oriented programming: Smalltalk. In Smalltalk, objects have internal fields that contain the object's state, but this state is entirely unavailable to the outside world. Instead the object has a collection of messages that it responds to, exposing information potentially based on its internal state as necessary. Once an object is created, it is entirely encapsulated, isolated from any other code than that implementing its behavior. Because the interface of the data abstraction is the methods exposed by the object, Cook identifies objects as &lt;i&gt;procedural data abstractions&lt;/i&gt;. The key feature of an object is that its interface is defined by its constructor: the collection of methods the object responds to and the semantics of those methods are defined by the construction of the object. In a sense, those methods are associated with the specific &lt;i&gt;value&lt;/i&gt; or instance.&lt;/p&gt;

&lt;p&gt;Abstract data types, on the other hand, have "a public name, a hidden representation, and operations to create, combine, and observe values of the abstraction." The classic examples of them are the primitive types in Java, C++, or most other common languages. A value has a defined type name, say "double", &lt;i&gt;some&lt;/i&gt; representation (Do you really know, or care, what a double actually looks like? (&lt;i&gt;Note:&lt;/i&gt; You &lt;i&gt;should&lt;/i&gt;. Floating point numbers are a notoriously leaky abstraction.)), and operations like reading one or converting one from some other representation, adding or subtracting two of them, and converting one to another representation, such as a string of characters. The key feature of an ADT is that its interface is defined by a collection of operations that apply to a specific &lt;i&gt;type.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;table style="text-align:center; float:left;margin:10px;"&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;th colspan="2"&gt;Constructors&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;Observations&lt;/th&gt;&lt;th&gt;[]&lt;/th&gt;&lt;th&gt;::&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;empty?&lt;/th&gt;&lt;td&gt;true&lt;/td&gt;&lt;td&gt;false&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;head&lt;/th&gt;&lt;td&gt;error&lt;/td&gt;&lt;td&gt;value&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
Let's say we create a matrix of operations on a data abstraction. My data abstraction is a list; it has two constructors, the Haskell-like "[]", or nil, building an empty list, and "::" or "cons", representing a constructor that takes a new element and an existing list and produces a new, combined list with the new element at the head. The list also has two "observation" operations, &lt;b&gt;empty?&lt;/b&gt; which returns true for an empty list and false otherwise, and &lt;b&gt;head&lt;/b&gt;, which produces some kind of error on an empty list, but returns the first value in the list otherwise. (This example is taken directly from "OOP Versus ADT".)&lt;/p&gt;

&lt;div style="float:right; margin:10px;"&gt;&lt;table style="text-align:center;"&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;th colspan="2"&gt;Constructors&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;Observations&lt;/th&gt;&lt;th style="border-top:thin solid black;border-left:thin solid black;border-right:thin solid black"&gt;[]&lt;/th&gt;&lt;th style="border-top:thin solid black;border-left:thin solid black;border-right:thin solid black"&gt;::&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;empty?&lt;/th&gt;&lt;td style="border-left:thin solid black;border-right:thin solid black"&gt;true&lt;/td&gt;&lt;td style="border-left:thin solid black;border-right:thin solid black"&gt;false&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;head&lt;/th&gt;&lt;td style="border-bottom:thin solid black;border-left:thin solid black;border-right:thin solid black"&gt;error&lt;/td&gt;&lt;td style="border-bottom:thin solid black;border-left:thin solid black;border-right:thin solid black"&gt;value&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;p style="text-align:center;"&gt;Object-oriented&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Suppose I want to create an object-oriented version of this data abstraction. I would divide up the operations by constructor, so that I had an implementation of &lt;b&gt;empty?&lt;/b&gt; and &lt;b&gt;head&lt;/b&gt; for an empty list and &lt;b&gt;empty?&lt;/b&gt; and &lt;b&gt;head&lt;/b&gt; for a cons cell. The details of each operation is divided among the objects created by each specific constructor. Adding a new constructor is easy, since it simply requires providing implementations of the observations on the new object. On the other hand, adding a new observation is difficult, since it requires modifying all of the existing constructors. This should sound familiar to anyone who has written code in almost any object oriented language.&lt;/p&gt;

&lt;div style="float:left;margin:10px;"&gt;&lt;table style="text-align:center;"&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;th colspan="2"&gt;Constructors&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;Observations&lt;/th&gt;&lt;th&gt;[]&lt;/th&gt;&lt;th&gt;::&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th style="border-top:thin solid black;border-left:thin solid black; border-bottom:thin solid black;"&gt;empty?&lt;/th&gt;&lt;td style="border-top:thin solid black;border-bottom:thin solid black;"&gt;true&lt;/td&gt;&lt;td style="border-top:thin solid black;border-right:thin solid black; border-bottom:thin solid black;"&gt;false&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th style="border-top:thin solid black;border-left:thin solid black; border-bottom:thin solid black;"&gt;head&lt;/th&gt;&lt;td style="border-top:thin solid black;border-bottom:thin solid black;"&gt;error&lt;/td&gt;&lt;td style="border-top:thin solid black;border-right:thin solid black; border-bottom:thin solid black;"&gt;value&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;p style="text-align:center;"&gt;ADT&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;On the other hand, suppose I want an ADT version of this data abstraction. In this case, I would divide the operations by observation, so that I had an implementation of &lt;b&gt;empty?&lt;/b&gt; and &lt;b&gt;head&lt;/b&gt; that each covered all of the constructors. The details of each constructor is spread among the observation implementations. Adding new observation is easy; it just has to handle the individual cases of the constructors. Adding a new constructor is hard, though, because every observation needs to be modified. This option should be familiar to anyone who has used ML or Haskell, since it is how their algebraic data types work.&lt;/p&gt;

&lt;p&gt;There are some less obvious consequences to these two styles of data abstraction. For one thing, the two approaches are almost duals; the advantages of one are the weaknesses of the other, and vice-versa. Both approaches do, in fact, provide data abstraction; objects by encapsulating the state of the data instance behind procedural abstractions, ADTs by encapsulating that state behind a type boundary. Both also describe (if you squint a bit) common data abstraction patterns. On the other hand, each approach has some peculiarities: because an object only has access to &lt;i&gt;its own&lt;/i&gt; state, &lt;i&gt;complex&lt;/i&gt; operations require weakening the encapsulation of objects. Cook calls "an operation 'complex' if it inspects multiple representations," like for example equality testing; I may not want to expose all of the implementation information necessary to compare two instances in the methods that an object responds to, yet I have no other option in order to implement some observations. Cook claims that object oriented, procedural abstractions are possible in dynamically typed languages but ADTs are not; "abstract data types depend upon a static type system to enforce type abstraction. It is not an accident that dynamic languages use objects instead of user-defined abstract data types. Dynamic languages typically support built-in abstract data types for primitive types; the type abstraction here is enforced by the runtime system."&lt;/p&gt;

&lt;p&gt;I do not doubt the validity of this deconstruction of objects and abstract data types, if for no other reason than that it exactly covers Philip Wadler's "expression problem". Also, both ideas seem pretty productive, which is always the primary test of science on the hoof. If that was all there was to it, there would be no mad science involved.&lt;/p&gt;

&lt;h2&gt;The mad science part&lt;/h2&gt;

&lt;p&gt;&lt;b&gt;Mad Science Tip #1:&lt;/b&gt; If you have to repeat the same message over 20 years, and no one seems to be listening to you, &lt;i&gt;they're&lt;/i&gt; the crazy ones. They're the ones who don't &lt;i&gt;see.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Mad Science Tip #2:&lt;/b&gt; A beautiful theory, one that explains &lt;i&gt;everything&lt;/i&gt;, is obviously true. Even if reality doesn't seem to particularly agree. The ADT half of Cook's papers seems to be relatively uncontroversial, perhaps because no one actually uses the languages (like ML and Haskell) that have user-defined ADTs as the primary data abstraction scheme. On the other hand, Cook's minor point about the inability to use ADTs in dynamically typed languages doesn't seem particularly, well, true; most Lisps, for example, allow you to define structures (or write macros to build such structures) that have representations hidden from any functions other than a limited group. Such pseudo-ADTs may not be as encapsulated as Cook would like, but coupled with a common coding style rule, say "Don't do stupid things," they work well enough. Objects, likewise, do not actually seem to exist. It's been too long since I last used Smalltalk, but every other "object-oriented" language allows a method in a class to access the internals of more than one object of the same class, neatly avoiding (some cases of) the "complex" operation issue. (To avoid all of the difficulties presented by complex operations requires something like multimethods or other techniques that are even more rare.) Maybe some of the object systems for Scheme satisfy the requirements for objects, but &lt;i&gt;Scheme doesn't have a standard &lt;b&gt;anything&lt;/b&gt;, much less an object system; it is a toolkit for implementing other languages.&lt;/i&gt; Further, Cook's ideas on actually doing object-oriented programming in Java would likely horrify most Java-istas, even those that love interfaces as much as I do.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Mad Science Tip #3:&lt;/b&gt; You get extra points for hosting dinner parties where you torment your rivals.
&lt;blockquote&gt;What is the relationship between objects and abstract data types (ADTs)? I have asked this question to many groups of computer scientists over the last 20 years. I usually ask it at
dinner, or over drinks. The typical response is a variant of “objects are a kind of abstract data type”.&lt;/blockquote&gt; Whereupon he goes all maniacal on them.&lt;/p&gt;

&lt;p&gt;Last and possibly least, &lt;b&gt;Mad Science Tip #4:&lt;/b&gt; Being a mad scientist is fun; you get to meet interesting people, there's nothing like the je ne sais quoi of carving your name in the moon with a giant laser. (For that matter, giant lasers are just plain cool no matter what you do with them.) But it may have detrimental effects on your social life.
&lt;blockquote&gt;Most groups eventually work through the differences between objects and ADTs, but I can tell they walk away feeling uneasy, as if some familiar signposts now point in different directions.&lt;/blockquote&gt; ...or perhaps as if they're just glad to get away with all the right number of appendages.&lt;/p&gt;

&lt;p&gt;Now, I'm not saying William Cook is going to destroy the world if Java 8 doesn't get objects &lt;i&gt;right&lt;/i&gt;. But if you see him being followed by a giant tongue monster or psychopathic, hyper-intelligent gerbils, don't say I didn't warn you.&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5510162608062931828?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/K-aqrCy21T1WW7k7MNeOzd694n0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/K-aqrCy21T1WW7k7MNeOzd694n0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/K-aqrCy21T1WW7k7MNeOzd694n0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/K-aqrCy21T1WW7k7MNeOzd694n0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/9Ztaz30mnlo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/5510162608062931828/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5510162608062931828" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/5510162608062931828?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/5510162608062931828?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/9Ztaz30mnlo/mad-science-abstract-data-types-and.html" title="Mad science, abstract data types, and objects" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/12/mad-science-abstract-data-types-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ABRX4zfyp7ImA9WhRQFkk.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-821177125983421055</id><published>2011-12-08T16:22:00.001-06:00</published><updated>2011-12-11T16:15:54.087-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-11T16:15:54.087-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="random" /><title>8,827,520 pixels!</title><content type="html">&lt;ul&gt;
&lt;li&gt;1440 x 900 on the (old) laptop,&lt;/li&gt;
&lt;li&gt;3840 x 1080 in two monitors on the (new) laptop,&lt;/li&gt;
&lt;li&gt;1920 x 1080 and 1280 x 1024 on the Mac.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We had a short-lived competition. I won only briefly.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-821177125983421055?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/q1GpTzM7S_kK9eQNPy1warR7Z-w/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/q1GpTzM7S_kK9eQNPy1warR7Z-w/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/q1GpTzM7S_kK9eQNPy1warR7Z-w/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/q1GpTzM7S_kK9eQNPy1warR7Z-w/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/FnG31KqQIMU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/821177125983421055/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=821177125983421055" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/821177125983421055?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/821177125983421055?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/FnG31KqQIMU/8827520-pixels.html" title="8,827,520 pixels!" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/12/8827520-pixels.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYCRng_eip7ImA9WhRQFUo.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-3676791671874032721</id><published>2011-12-08T12:17:00.000-06:00</published><updated>2011-12-10T21:29:27.642-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-10T21:29:27.642-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="quote" /><title>Quote o' the day: flagrant reticulation</title><content type="html">&lt;p&gt;In a reply to Ben Collins-Sussman's post, &lt;a href="http://blog.red-bean.com/sussman/?p=597"&gt;Your Community is NOT Your Tools&lt;/a&gt;, MarkusQ writes:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;I think some of the git-resistance comes from different cultural assumptions around the cost of merging. I know from an svn mindset, the “mash the branches together and call it merged” mindset of the git-world can seem a little fast and loose. Likewise, I suspect the older “merging is to be approached with fear and reverence” culture may seem hidebound when you’re used to the &lt;b&gt;flagrant reticulation&lt;/b&gt;, devil take the hindmost style that the git world embraces.&lt;/p&gt;
&lt;p&gt;– MarkusQ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For those of you too lazy to look it up yourself,&lt;/p&gt;
&lt;pre&gt;

$ dict reticulation
2 definitions found

From The Collaborative International Dictionary of English v.0.48 [gcide]:

  Reticulation \Re*tic`u*la"tion\, n.
     The quality or state of being reticulated, or netlike; that
     which is reticulated; network; an organization resembling a
     net.
     [1913 Webster]
  
           The particular net you occupy in the great
           reticulation.                            --Carlyle.
     [1913 Webster]

From WordNet (r) 3.0 (2006) [wn]:

  reticulation
      n 1: (photography) the formation of a network of cracks or
           wrinkles in a photographic emulsion
      2: an arrangement resembling a net or network; "the reticulation
         of a leaf"; "the reticulation of a photographic emulsion"
&lt;/pre&gt;

&lt;p&gt;The only way to get more points would have been to work in "squamous".&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3676791671874032721?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/0JXYQdgX5Gc_HFxP9JutNOQRPR0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0JXYQdgX5Gc_HFxP9JutNOQRPR0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/0JXYQdgX5Gc_HFxP9JutNOQRPR0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0JXYQdgX5Gc_HFxP9JutNOQRPR0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/jIZzPl1GYEk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/3676791671874032721/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3676791671874032721" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/3676791671874032721?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/3676791671874032721?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/jIZzPl1GYEk/quote-o-day-flagrant-reticulation.html" title="Quote o' the day: flagrant reticulation" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/12/quote-o-day-flagrant-reticulation.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEMQ305cSp7ImA9WhRRGEQ.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-5113225659446032298</id><published>2011-12-02T23:38:00.000-06:00</published><updated>2011-12-02T23:38:02.329-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-02T23:38:02.329-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="link" /><category scheme="http://www.blogger.com/atom/ns#" term="math" /><title>Link o' the week: Bayes' Theorem</title><content type="html">&lt;p&gt;I seem to be up to my armpits in Bayesian statistics. Between &lt;a href="https://www.ai-class.com/home/"&gt;Thrun and Norvig's AI class&lt;/a&gt; (the AI classes I took back in the late '80's and early '90's primarily dealt with state-space search, neural networks, and predicate logic; there was nary a statistic to be found) and the very good textbook I ran across, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0123814855/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0123814855"&gt;Doing Bayesian Data Analysis: A Tutorial with R and BUGS&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0123814855" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt; by &lt;a href="http://www.indiana.edu/~kruschke/DoingBayesianDataAnalysis/"&gt;John K. Kruschke&lt;/a&gt;, this stuff seems to be appearing everywhere.&lt;/p&gt;

&lt;p&gt;Then I ran across Eliezer Yudkowsky's post, &lt;a href="http://yudkowsky.net/rational/bayes"&gt;An Intuitive Explanation of Bayes' Theorem&lt;/a&gt;. Now, intuition is a funny thing. It is not innate as most people seem to think, you have to train it. Yudkowsky does that, going over the same ground with many examples and good explanations. Better, his writing, like Kruschke's, is light and entertaining:
&lt;blockquote&gt;
&lt;table style="border:medium solid black;background-color: #CFF;"&gt;
&lt;tr&gt;&lt;td rowspan="11" style="vertical-align:text-top; border:thin solid black;background-color: #FF9;padding:3px;"&gt;&lt;b&gt;Fun Fact!&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;
&lt;tr style="border-left:thin solid black"&gt;&lt;td&gt;&lt;b&gt;Q.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;How can I find the priors for a problem?&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;A.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;Many commonly used priors are listed in the Handbook of Chemistry and Physics.&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;&lt;b&gt;Q.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;Where do priors originally come from?&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;A.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;Never ask that question.&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;&lt;b&gt;Q.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;Uh huh.  Then where do scientists get their priors?&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;A.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;Priors for scientific problems are established by annual vote of the AAAS.  In recent years the vote has become fractious and controversial, with widespread acrimony, factional polarization, and several outright assassinations.  This may be a front for infighting within the Bayes Council, or it may be that the disputants have too much spare time.  No one is really sure.&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;&lt;b&gt;Q.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;I see.  And where does everyone else get their priors?&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;A.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;They download their priors from Kazaa.&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;&lt;td&gt;&lt;b&gt;Q.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;What if the priors I want aren't available on Kazaa?&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;A.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;There's a small, cluttered antique shop in a back alley of San Francisco's Chinatown.  Don't ask about the bronze rat.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bronze rat aside, I also like the Javascript calculators embedded in the article, allowing a reader to try to figure out the answers to Yudkowsky's examples without dredging up another app.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5113225659446032298?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/rqtz0exeujycguiPkRFVqrIMMFA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/rqtz0exeujycguiPkRFVqrIMMFA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/rqtz0exeujycguiPkRFVqrIMMFA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/rqtz0exeujycguiPkRFVqrIMMFA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/vXftRIOn6a4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/5113225659446032298/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5113225659446032298" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/5113225659446032298?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/5113225659446032298?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/vXftRIOn6a4/link-o-week-bayes-theorem.html" title="Link o' the week: Bayes' Theorem" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/12/link-o-week-bayes-theorem.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcFSHs5eSp7ImA9WhRRFko.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-4287010422610417773</id><published>2011-11-30T10:58:00.001-06:00</published><updated>2011-11-30T11:10:19.521-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-30T11:10:19.521-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="quote" /><category scheme="http://www.blogger.com/atom/ns#" term="programming language" /><category scheme="http://www.blogger.com/atom/ns#" term="scala" /><title>Quote o' the day: Coda Hale on the value of communities</title><content type="html">&lt;p&gt;&lt;a href="http://codahale.com/"&gt;Coda Hale&lt;/a&gt; wrote a widely publicized &lt;a href="http://codahale.com/the-rest-of-the-story/"&gt;private&lt;/a&gt; &lt;a href="https://gist.github.com/1406238?1"&gt;email&lt;/a&gt; to the-powers-that-be-in-Scala with the following line:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;...but at some point a best practice emerged: ignore the community entirely.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Actually, there are some lessons there: Language communities are nice and fun and wonderful, but they may not be good ways of learning "best practices", whatever those are. It sucks to be an early adopter. (On the other hand, not having &lt;i&gt;any&lt;/i&gt; early adopters isn't good either.) Oh, and if anyone asks you if they look fat, don't answer them.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4287010422610417773?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/dfnhQ-7CcUiGAOLXTQQlhf9ygl0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dfnhQ-7CcUiGAOLXTQQlhf9ygl0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/dfnhQ-7CcUiGAOLXTQQlhf9ygl0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dfnhQ-7CcUiGAOLXTQQlhf9ygl0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/k-tzDXFLUAo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/4287010422610417773/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4287010422610417773" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/4287010422610417773?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/4287010422610417773?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/k-tzDXFLUAo/quote-o-day-coda-hale-on-value-of.html" title="Quote o' the day: Coda Hale on the value of communities" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/11/quote-o-day-coda-hale-on-value-of.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcNR3s6fyp7ImA9WhRbFkk.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-2381928848000927430</id><published>2011-11-24T11:27:00.000-06:00</published><updated>2012-02-07T14:38:16.517-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-07T14:38:16.517-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="software development" /><category scheme="http://www.blogger.com/atom/ns#" term="link" /><category scheme="http://www.blogger.com/atom/ns#" term="books" /><title>Consolidated Reference List for the Software Engineering Body of Knowledge, Pt. 2</title><content type="html">&lt;div class="twocol"&gt;
&lt;p&gt;This post contains the second half of a somewhat annotated version of the Consolidated Reference List for the IEEE Software Engineering Body of Knowledge (SWEBOK). You may want to start with the &lt;a href="http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for-ieee.html"&gt;previous half&lt;/a&gt;.&lt;/p&gt;

&lt;ol start="19"&gt;

&lt;li&gt;&lt;p&gt;A. Lopez-Ortiz. (1998, July 22, 2010). &lt;i&gt;&lt;a href="http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/node6.html"&gt;Algebraic Structures&lt;/a&gt;&lt;/i&gt;. Available: &lt;a href="http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/node6.html"&gt;http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/node6.html&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This one is more than a tiny bit ridiculous. The link is to the &lt;a href="http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/math-faq.html"&gt;Frequently Asked Questions in Mathematics&lt;/a&gt; list from the Sci.Math FAQ Team. The specific link is to the section on algebraic structures: monoids, groups, rings, fields, and ordering. I'm sure that even the Sci.Math FAQ Team would find the reference to their FAQ in this list silly, if not insulting. Is that &lt;em&gt;really&lt;/em&gt; all you need to know about abstract mathematics? Why not link to the FAQ's &lt;a href="http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/node43.html#SECTION0012000000000000000000"&gt;bibliography&lt;/a&gt;, one of the texts in it, or even my favorite, &lt;a href="http://www.amazon.com/gp/product/0486474178/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0486474178"&gt;A Book of Abstract Algebra&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0486474178&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;?&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;S. McConnell, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0735619670/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0735619670"&gt;Code Complete: A Practical Handbook of Software Construction&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0735619670&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;
&lt;/i&gt;, 2nd ed. Redmond, WA: Microsoft Press, 2004.&lt;/p&gt;
&lt;p&gt;Unlike the previous, this text is completely unsurprising. McConnell's is one of the most popular books on programming and is likely filled with information that a professional software developer cannot live without. I personally don't know; I don't have a copy. You see, when I was first looking at it in a bookstore many years ago, I flipped to the section on recursion to see what he had to say:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;One problem with computer-science textbooks is that they present silly examples of recursion. The typical examples are computing a factorial or computing a Fibonacci sequence. Recursion is a powerful tool, and it's really dumb to use it in either of those cases. &lt;b&gt;If a programmer who worked for me used recursion to compute a factorial, I'd hire someone else.&lt;/b&gt; Here's the recursive version of the factorial routine:&lt;/p&gt;
&lt;pre&gt;
 int Factorial( int number ) {
    if ( number == 1 ) {
      return 1;
    } else {
      return number * Factorial( number - 1 );
    }
  }
&lt;/pre&gt;
&lt;p&gt;In addition to being slow and making the use of run-time memory unpredictable, &lt;b&gt;the recursive version of this routine is harder to understand than the iterative version&lt;/b&gt;, which follows:&lt;/p&gt;
&lt;pre&gt;
  int Factorial( int number ) {
    int intermediateResult = 1;
    for ( int factor = 2; factor &lt;= number; factor++ ) {
      intermediateResult = intermediateResult * factor;
    }
    return intermediateResult;
  }
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;(Emphasis mine.) Now, where to start with this passage? Recursion &lt;i&gt;is&lt;/i&gt; a powerful tool, and in some programming languages that McConnell may not be familiar with, it's &lt;em&gt;fundamental&lt;/em&gt;; there may not even be any other iteration structures. So, whether it's dumb to use it in any specific case is a more difficult question than he seems to think. Heck, even most decent modern C compilers include tail call optimization, so the speed and memory use of recursion is an open question. On the other hand, McConnell previously presented as a &lt;em&gt;good&lt;/em&gt; use of recursion a maze-solving function; maze solving is an application of state-space search, which has a simple, clear, and wildly flexible implementation based on a priority queue. Further, I find it simply bizarre that McConnell believes a recursive version of factorial is "harder to understand" than the iterative version. Quick! Prove to me that his two versions actually compute a factorial:&lt;/p&gt;
\[
n! = \begin{array}{lr}
1 &amp;amp; \textrm{if \(n\) = 1} \\
n * (n-1)! &amp;amp; \textrm{if \(n\) &gt; 1}
\end{array}
\]
&lt;p&gt;Finally, there's the whole "If a programmer who worked for me...I'd hire someone else" thing. The sections before and after recursion are on multiple returns in a routine and goto's; I'm afraid to look at either.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;S. J. Mellor and M. J. Balcer, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0201748045/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0201748045"&gt;Executable UML: A Foundation for Model-Driven Architecture&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0201748045&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 1st ed. Boston: Addison-Wesley, 2002.&lt;/p&gt;
&lt;p&gt;This is another topic that leaves me cold. UML is good enough for what it is, a way of communicating ideas about a project, and I'm certainly a programming language collector. However, I have never felt that UML would make a good programming language, which is exactly what xUML and other executable model languages are.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;D. C. Montgomery and G. C. Runger, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0470053046/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0470053046"&gt;Applied Statistics and Probability for Engineers&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0470053046&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;
&lt;/i&gt;, 4th ed. Hoboken, NJ: Wiley, 2007.&lt;/p&gt;
&lt;p&gt;(The link is to the fifth edition.) Statistics and I have an uneasy relationship. I know there is a great deal of value in statistical data analysis, as an end itself as well as about the software development process. On the other hand, I don't really know much about the topic, and I reference my previous comments about lacking numerical methods experience and thus my inability to use floating point numbers. Anyway, it's an important topic; this may or may not be a good reference (several of the Amazon reviewers mention errors in the text), and I don't have a better one at hand. Your mileage may vary.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;J. W. Moore, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0471683620/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0471683620"&gt;The Road Map to Software Engineering: A Standards-Based Guide&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0471683620&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 1st ed. Hoboken, NJ: Wiley-IEEE Computer Society Press, 2006.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The Road Map to Software Engineering organizes relevant IEEE software and systems standards, along with standards from other sources, using two frameworks: the SWEBOK Guide's topical knowledge areas and the widely used &lt;a href="http://standards.ieee.org/findstds/standard/12207.0-1996.html"&gt;IEEE/EIA 12207 standard&lt;/a&gt; [IEEE Standard for Information Technology - Software Life Cycle Processes].&lt;/p&gt;&lt;p&gt;&lt;i&gt;The Road Map to Software Engineering&lt;/i&gt; allows practitioners to quickly locate the standards pertinent to questions arising in real projects. Providing students with a comprehensive body of knowledge, the text also assists experienced professionals in finding and filling gaps in their understanding.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Probably a vital reference for those using official standards; probably not something I need.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;J. Nielsen, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0125184069/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0125184069"&gt;Usability Engineering&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0125184069&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 1st ed. Boston: Morgan Kaufmann, 1993.&lt;/p&gt;
&lt;p&gt;Jakob Nielsen is a very good writer on usability topics. I own and appreciate a copy of his &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/156205810X/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=156205810X"&gt;Designing Web Usability&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=156205810X&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt; even though my idea of usability seems to differ strongly from others'. I will be getting a copy, since I was not previously aware if this. On the other hand, this is nearly 20 years old; is there no more recent reference?&lt;/p&gt;
&lt;p&gt;Update: I just got a copy of this book, and I am very impressed so far. The emphasis, at least from the parts I have read so far, is on providing basic usability information and usability testing techniques that &lt;em&gt;do not&lt;/em&gt; require massive investments of resources. I do not have the book handy while I'm writing this, but if I interpret Nielsen correctly he writes that a (quantifiable) big win can be had by simply observing actual users for a few hours, and by asking them what they think.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;L. Null and J. Lobur, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/1449600069/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=1449600069"&gt;Essentials of Computer Organization and Architecture&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=1449600069&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 2nd ed. Sudbury, MA: Jones and Bartlett Publishers, 2006.&lt;/p&gt;
&lt;p&gt;(Link is to the third edition.) I love Linda Null's name, let me get that out of the way. Computer architecture is a topic I know a bit about, and, although I'm not familiar with this book, it does seem to cover most of the bases appropriately. Certainly, if a programmer who worked for me &lt;i&gt;didn't&lt;/i&gt; know a good bit of this stuff, I'd hire someone else. But this text seems to relegate parallel and concurrent architectures to a section of a chapter on alternative organizations, which is somewhat surprising given the not-so-recent trend towards those architectures. There doesn't even seem to be anything on pipelines, which is vital for high-performance software. Another book, &lt;a href="http://www.amazon.com/gp/product/0136073735/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0136073735"&gt;&lt;i&gt;Computer Organization and Architecture: Designing for Performance&lt;/i&gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0136073735&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt; by William Stallings, does have extensive coverage of parallel architectures although it looks to be less clear and well organized. Given the choice, I would probably favor clarity over coverage.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;M. Page-Jones, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/020169946X/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=020169946X"&gt;Fundamentals of Object-Oriented Design in UML&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=020169946X&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 1st ed. Reading, MA: Addison-Wesley, 1999.&lt;/p&gt;
&lt;p&gt;Object-oriented design and programming are not the end-all of software development strategies. It is not appropriate for everything, and an uncritical use of it is not appropriate for &lt;i&gt;anything&lt;/i&gt;. I view it as a technique for &lt;i&gt;managing&lt;/i&gt; complexity since is pretty successful at that while bringing along its own complications. I, on the other hand, would prefer to &lt;i&gt;remove&lt;/i&gt; complexity. That being said, you will need to know &lt;i&gt;a lot&lt;/i&gt; about object-oriented design, and Page-Jones is probably a good-enough teacher. (I have his &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0136907695/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0136907695"&gt;Practical Guide to Structured Systems Design&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0136907695&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt; and don't know of anything wrong with it.) On the other hand, if you need a guide to UML, I prefer &lt;em&gt;&lt;a href="http://www.amazon.com/gp/product/0321193687/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0321193687"&gt;UML Distilled: A Brief Guide to the Standard Object Modeling Language&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0321193687&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/em&gt; by Martin Fowler.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;G. K. Palshikar, "&lt;a href="http://csdl.computer.org/comp/mags/so/2001/06/s6089.pdf"&gt;Applying Formal Specifications to Real-World Software Development&lt;/a&gt;," IEEE Software, vol. 18, pp. 89-97, 2001.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;While formal methods are gaining acceptance in the software industry, there is a need for practical guidelines for making the best use of formal specifications. The author provides a few such pragmatic tips for people involved in the industrial use of formal specifications. The 15 guidelines are split into two areas, dealing with process and content. The author also includes a full-page reference for literature available over the Web.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;A very good introduction to the use of formal specification methods. I hope the computer.org link above is available to non-IEEE and non-Computer Society members; if it isn't, please let me know. I am tempted to throw propriety (and copyright) out the window and host a link to this paper myself.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;S. Redwine, "&lt;a href="http://www2.computer.org/cms/Computer.org/SWEBOK/Information-for-Item-Writers-v14.pdf"&gt;Security-Oriented Pointwise Changes to SWEBOK Guide&lt;/a&gt;," 2009. Available: &lt;a href="http://www2.computer.org/cms/Computer.org/SWEBOK/Information-for-Item-Writers-v14.pdf"&gt;http://www2.computer.org/cms/Computer.org/SWEBOK/Information-for-Item-Writers-v14.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The original set of suggested changes to the 2004 SWEBOK to incorporate topics from the new security knowledge area. This paper is probably only useful in conjunction with that version of the SWEBOK guide. As an addition, two of the three referenced texts are &lt;i&gt;Software Security Engineering&lt;/i&gt; and &lt;i&gt;Computer Security&lt;/i&gt;, already found on this consolidated reference list; the third is Summerville's &lt;i&gt;Software Engineering&lt;/i&gt; below. A fourth reference is to "&lt;a href="https://buildsecurityin.us-cert.gov/bsi/940-BSI/version/default/part/AttachmentData/data/CurriculumGuideToTheCBK.pdf"&gt;Software Assurance: A Curriculum Guide to the Common Body of Knowledge to Produce, Acquire, and Sustain Secure Software Version 1.2&lt;/a&gt;", edited by Redwine and from the US Department of Homeland Security. (My tax dollars at work!)&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;K. Rosen, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0073383090/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0073383090"&gt;Discrete Mathematics and Its Applications&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0073383090&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 6th ed. Boston: McGraw-Hill, 2006.&lt;/p&gt;
&lt;p&gt;(Link is to the seventh edition.) Discrete mathematics is probably more important to software developers than, say, differential and integral calculus, and I'm not just saying that because calculus and I didn't really agree back in my undergraduate years. More information is available from the &lt;a href="http://highered.mcgraw-hill.com/sites/0073383090/information_center_view0/"&gt;McGraw-Hill site for the book&lt;/a&gt;, including a sample chapter.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;A. Silberschatz, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0470128720/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0470128720"&gt;Operating System Concepts&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0470128720&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 8th ed. Hoboken, NJ: Wiley, 2008.&lt;/p&gt;
&lt;p&gt;True story: I was at a conference looking at the forthcoming books table and a full professor near me pointed to a copy of a new edition of one of Avi's (Abraham Silberschatz) books and asked "Avi has another kid going to college?" I seem to recall learning operating systems from a previous edition of this text, and databases from another of Avi's books, and I haven't been adversely affected. (The tics have mostly gone away.) They are pretty common, for a good reason, but there are alternatives from &lt;a href="http://www.amazon.com/gp/product/0136006639/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0136006639"&gt;Tanebaum&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0136006639&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;, &lt;a href="http://www.amazon.com/gp/product/0136006329/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0136006329"&gt;Stallings&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0136006329&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;, &lt;a href="http://www.amazon.com/gp/product/0131828274/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0131828274"&gt;Deitel&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0131828274&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;, and probably others that are just as good.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;I. Sommerville, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0137035152/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0137035152"&gt;Software Engineering&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0137035152&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 8th ed. New York: Addison-Wesley, 2006.&lt;/p&gt;
&lt;p&gt;(Link is to the ninth edition.) A general text on software engineering, this got good reviews from Dr. Tom Hilburn, who taught the software engineering course at the IEEE Smart Tech mini-conference. It's about 800 pages and should be good to bludgeon many, many infidel software developers, managers, and what-not.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The Data and Analysis Center for Software. (2008, July 22, 2010). &lt;a href="https://goldpractice.thedacs.com/practices/gqm/"&gt;Goal-Question-Metric (GQM) Approach&lt;/a&gt;. Available: &lt;a href="https://goldpractice.thedacs.com/practices/gqm/"&gt;https://www.goldpractices.com/practices/gqm/&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GQM is a top-down approach to establish a goal-driven measurement system for software development, in that the team starts with organizational goals, defines measurement goals, poses questions to address the goals, and identifies metrics that provide answers to the questions.... [It] is particularly useful for the following purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understanding and baselining an organization’s software practices&lt;/li&gt;
&lt;li&gt;Guiding and monitoring software processes&lt;/li&gt;
&lt;li&gt;Assessing new software engineering technologies&lt;/li&gt;
&lt;li&gt;Evaluating and certifying improvement activities&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;GQM seems to be a general, relatively process-agnostic method for generating metrics for software development processes; it looks interesting. I need to look at it further.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;S. Tockey, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0321228758/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0321228758"&gt;Return on Software: Maximizing the Return on Your Software Investment&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0321228758&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 1st ed. Boston: Addison-Wesley, 2004.&lt;/p&gt;
&lt;p&gt;Assuming this book does what it claims, it would be a very good text to have around. Particularly given the recent appearances of "&lt;a href="http://www.kalzumeus.com/2011/10/28/dont-call-yourself-a-programmer/"&gt;Don't call yourself a programmer&lt;/a&gt;" postings, giving career advice on the advantages of appealing to the business side of technical decisions.
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Estimate how much each proposed software technical decision will cost, and how much it will return.&lt;/li&gt;
&lt;li&gt;Weigh the time frames for a software decision's costs and benefits against each other to reveal when there might be a more important factor than schedule.&lt;/li&gt;
&lt;li&gt;Attach a value to quality and produce a rational answer to the question, "How much testing is enough?"&lt;/li&gt;
&lt;li&gt;Account for risk and uncertainty in software technical decisions, such as when considering a new technology.&lt;/li&gt;
&lt;li&gt;Communicate your decisions in a way that speaks to the all-important bottom line.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Also from the back cover:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;"This just what the doctor ordered to help software programs solve the problem of how to introduce engineering economics and business decision-making into their curricula. The economics of software development should not only be part of any computing curriculum they are an essential element of recent accreditation and certification recommendations.&lt;/p&gt;&lt;p&gt;This book is an accessible and relevant text for any student of software engineering. The style is clear and straightforward and the software examples will be appealing to students and faculty alike. I can't wait to use it in class!"&lt;/p&gt;&lt;p&gt;Thomas B. Hilburn, Professor&lt;br /&gt;Department of Computer and Software Engineering&lt;br /&gt;Embry-Riddle Aeronautical University&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;a href="http://www.informit.com/articles/article.aspx?p=332848"&gt;introduction&lt;/a&gt; of the book is available online; I especially like this paragraph:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;In another case I was developing software to monitor radiation at nuclear power plants. Part of that software needed a sorting routine. I wrote a simple insertion sort routine and had that part of the system running in a matter of hours. A coworker insisted on developing a QuickSort routine because "everybody knows that QuickSort is better than insertion sort." At that time (early 1980s) reusable QuickSort routines weren't available; if you wanted one, you had to write it yourself. Unfortunately, QuickSort is a recursive algorithm, and the programming language we were using, Fortran-IV, didn't support recursion. My coworker spent more than a week developing QuickSort in Fortran-IV. Only later did he realize that the list that needed sorting averaged only about 30 entries and was predominantly sorted to begin with. Small lists that are already mostly sorted cause QuickSort to have extremely poor performance, typically worse than simpler algorithms such as insertion sort. Moreover, sorting happened in this system fewer than 50 times a day. Even if QuickSort did perform better than insertion sort, it would take decades for the company to recover its investment. My coworker's effort turned out to be a pretty big waste of the company's money and time.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;This is going onto my shopping cart.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;G. Voland, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0131409190/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0131409190"&gt;Engineering by Design&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0131409190&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 2nd ed. Upper Saddle River, NJ: Prentice Hall, 2003.&lt;/p&gt;
&lt;p&gt;This looks to be a very interesting book, and I'm saying that as a Henry Pretrovski addict. Judging by what I can find, it appears to come from the physical object design world.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The book introduces readers to a broad range of important design topics. It provides numerous cases that illustrate both successes and failures in engineering design; qualitative presentation of engineering practices are easily understood by readers with little technical knowledge, and analytical techniques are given that allow the development and evaluation of proposed engineering solutions. Coverage includes: an overview of engineering design, needs assessment, structuring the search for the problem, structuring the search for a solution (design goals and specifications), acquiring and applying technical knowledge, abstraction and modeling, synthesis, ethics and product liability issues, and hazards analysis and failure analysis. An excellent handbook for design engineers.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Gerard Voland is Provost and Vice Chancellor at the University of Michigan-Flint. I've got no idea if that is a good thing or a bad thing.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;K. E. Wiegers, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0735618798/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0735618798"&gt;Software Requirements&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0735618798&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 2nd ed. Redmond, WA: Microsoft Press, 2003.&lt;/p&gt;
&lt;p&gt;A book about requirements engineering. Keep in mind that, whatever I say about this book, the only reliable way I have found to identify, analyze, and satisfy requirements is by some variant of the "agile", open-source, throw-it-at-the-wall-and-see-what-sticks approach (which cannot with any justice be called prototyping). I do have a copy of the follow-on, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0735622671/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0735622671"&gt;More About Software Requirements: Thorny Issues and Practical Advice&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0735622671&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, and have not seen anything particularly wrong in it. Just not very applicable.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;J. M. Wing, "&lt;a href="http://www.cs.cmu.edu/~wing/publications/Wing90a.pdf"&gt;A Specifier's Introduction to Formal Methods&lt;/a&gt;," Computer, vol. 23, pp. 8, 10-23, 1990.&lt;/p&gt;
&lt;p&gt;I found two links to PDF versions of this paper, one a copy of &lt;a href="http://www.cs.cmu.edu/~wing/publications/Wing90a.pdf"&gt;the article as it appeared&lt;/a&gt; in &lt;em&gt;Computer&lt;/em&gt; and the other a CMU technical report, &lt;a href="http://www.cs.cmu.edu/~wing/publications/CMU-CS-90-136.pdf"&gt;CMU-CS-90-136&lt;/a&gt;. Pick the way you want to read it, I guess.&lt;/p&gt;
&lt;p&gt;This paper is a decent introduction to formal methods, including examples of a fair number of specific techniques in the last half, as they stood in 1990. There is nothing really wrong with that; there have only been a few major changes in formal methods since then. Z (pronounced "Zed") and communicating sequential processes both appear, and both are as relevant or irrelevant as they ever were. (As an aside, I have a small stack of very good Z books.) I did not see anything covering model checking, and there certainly was nothing on dependently typed programming languages, two of what I believe to be the biggest changes in formal methods. That aside, it is a pretty good read.&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-2381928848000927430?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/5PjH90H-rEgCVNuOs1rC2Jz8aDw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5PjH90H-rEgCVNuOs1rC2Jz8aDw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/5PjH90H-rEgCVNuOs1rC2Jz8aDw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5PjH90H-rEgCVNuOs1rC2Jz8aDw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/iTB3zX7R30s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/2381928848000927430/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=2381928848000927430" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/2381928848000927430?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/2381928848000927430?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/iTB3zX7R30s/consolidated-reference-list-for.html" title="Consolidated Reference List for the Software Engineering Body of Knowledge, Pt. 2" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcHSH87fSp7ImA9WhRbFkk.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-2951372889504955161</id><published>2011-11-21T23:02:00.000-06:00</published><updated>2012-02-07T14:37:19.105-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-07T14:37:19.105-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="software development" /><category scheme="http://www.blogger.com/atom/ns#" term="link" /><category scheme="http://www.blogger.com/atom/ns#" term="books" /><title>Consolidated Reference List for the IEEE Software Engineering Body of Knowledge</title><content type="html">&lt;div class="twocol"&gt;
This is the first half of a none-too-serious annotated bibliography of the &lt;a href="http://www.computer.org/portal/web/swebok/consolidated_reference_list"&gt;references&lt;/a&gt; that the IEEE Computer Society has identified as the most important sources for its Software Engineering Body of Knowledge (SWEBOK). (When you get done with this, you can read the &lt;a href="http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for.html"&gt;second part&lt;/a&gt;.) Note: I have not actually read &lt;i&gt;all&lt;/i&gt; (or most, for that matter) of these books, nor do I intend to. I will identify those I have, and those I have not are evaluated on what I, as a professional, think of their publicly available information. You have been warned.&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;A. Abran, et al., Eds., &lt;i&gt;&lt;a href="http://www.computer.org/portal/web/swebok/html/contents"&gt;Guide to the Software Engineering Body of Knowledge&lt;/a&gt;&lt;/i&gt;. Los Alamitos, CA: IEEE Computer Society, 2004.&lt;br /&gt;

This consolidated reference list (if I were a true software engineer, I would have written that as "CRL") is associated with the version 3 of the SWEBOK (which is really too long to type out). However, because that version is still in development, it refers to the previous, 2004 version. The new version is supposed to add knowledge areas on professionalism, software engineering economics, mathematical and computing foundations, and possibly measurement and security, and revise the existing structure. Duck and cover!&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;J. H. Allen, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/032150917X/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=032150917X"&gt;Software Security Engineering: A Guide for Project Managers&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=032150917X&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;. Upper Saddle River, NJ: Addison-Wesley, 2008.&lt;br /&gt;

Yes. Well. So, any book with "managers" in the title leaves me with a sort of squishy feeling, particularly as a reference for practitioners. The advertising text doesn't really help:
&lt;br /&gt;
&lt;blockquote&gt;
One view of secure software is software that is engineered “so that it continues to function correctly under malicious attack” [McGraw 2006] and is able to recognize, resist, tolerate, and recover from events that intentionally threaten its dependability. Broader views that can overlap with software security (for example, software safety, reliability, and fault tolerance) include the notion of proper functioning in the face of unintentional failures or accidents and inadvertent misuse and abuse, as well as reducing software defects and weaknesses to the greatest extent possible regardless of their cause. This book addresses the &lt;b&gt;narrower view&lt;/b&gt;.&lt;/blockquote&gt;
(Emphasis mine.) Personally, I do not really feel I need to "increase [my] awareness and understanding of the security issues in the design and development of software"; rather I need good information on producing secure systems or, better yet, a general approach that leads to secure systems by construction. But then, I suspect I take the broader view described above.
&lt;/li&gt;
&lt;li&gt;M. Bishop, &lt;a href="http://www.amazon.com/gp/product/0201440997/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0201440997"&gt;&lt;i&gt;Computer Security: Art and Science&lt;/i&gt;&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201440997&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;. Boston: Addison-Wesley, 2002.&lt;br /&gt;

This sounds like a much more useful book. It seems to have gotten good reviews in both &lt;i&gt;SysAdmin&lt;/i&gt; and by Peter Salus in &lt;i&gt;;login&lt;/i&gt;, and appears to be an attempt at a complete reference tome. There are a couple of &lt;a href="http://nob.cs.ucdavis.edu/book/book-aands/index.html"&gt;chapters available online&lt;/a&gt; at Bishop's UC Davis page; &lt;a href="http://nob.cs.ucdavis.edu/book/book-aands/aands13.pdf"&gt;Chapter 13: Design Principles&lt;/a&gt; leaves me interested.
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Principle of Least Privilege&lt;/li&gt;
&lt;li&gt;Principle of Fail-Safe Defaults&lt;/li&gt;
&lt;li&gt;...Economy of Mechanism&lt;/li&gt;
&lt;li&gt;...Complete Mediation&lt;/li&gt;
&lt;li&gt;...Open Design&lt;/li&gt;
&lt;li&gt;...Separation of Privilege&lt;/li&gt;
&lt;li&gt;...Least Common Mechanism&lt;/li&gt;
&lt;li&gt;...Psychological Acceptability&lt;/li&gt;
&lt;/ul&gt;
Bishop also has an alternate version, &lt;a href="http://www.amazon.com/gp/product/0321247442/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0321247442"&gt;&lt;i&gt;Introduction to Computer Security&lt;/i&gt;&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321247442&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
, that "omits much of the mathematical formalism, making it more accessible for professionals and students who have a less formal mathematical background, or for readers with a more practical than theoretical interest". I think I may have to get a copy of &lt;i&gt;Computer Security: Art and Science&lt;/i&gt;.
&lt;/li&gt;
&lt;li&gt;B. Boehm and R. Turner, &lt;a href="http://www.amazon.com/gp/product/0321186125/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0321186125"&gt;&lt;i&gt;Balancing Agility and Discipline: A Guide for the Perplexed&lt;/i&gt;&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321186125&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
. Boston: Addison-Wesley, 2003.&lt;br /&gt;

This book about agile software development processes also looks pretty interesting. One common complaint about agile methods from traditional or more engineering-oriented developers is that they are undisciplined; a common complaint from agile developers is that more disciplined processes are unusable. Both are ironic, since most methods are followed in name only, in my experience.&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;F. Bott, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0748409513/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0748409513"&gt;Professional Issues in Software Engineering&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0748409513&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;, 3rd ed. New York: Taylor &amp;amp; Francis, 2000.&lt;br /&gt;

&lt;i&gt;Professional Issues in Software Engineering&lt;/i&gt; looks like a good reference to, well, professional issues: the profession and professional organizations, economics, contracts, intellectual property, employee relations, health and safety, liability, criminal law, and regulation of personal information are all represented in the table of contents. Now, professional issues may not interest most developers (or anybody else), but they are something that I am beginning to appreciate more, and something that I detect a serious lack of, now that I have moved into less technically-oriented employment. (Ahem.)&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;J. G. Brookshear, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0132569035/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399373&amp;amp;creativeASIN=0132569035"&gt;Computer Science: An Overview&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0132569035&amp;amp;camp=217145&amp;amp;creative=399373" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;, 10th ed. Boston: Addison-Wesley, 2008.&lt;br /&gt;

Again, this is an introductory text that doesn't seem to be terribly useful to someone engaged in the profession of creating software systems.&lt;br /&gt;
&lt;blockquote&gt;
Computer Science: An Overview uses broad coverage and clear exposition to present a complete picture of the dynamic computer science field. Accessible to students from all backgrounds, Glenn Brookshear uses a language-independent context to encourage the development of a practical, realistic understanding of the field. An overview of each of the important areas of Computer Science (e.g. Networking, OS, Computer Architecture, Algorithms) provides students with a general level of proficiency for future courses.&lt;/blockquote&gt;
On the other hand, it looks like a very good book to give to someone who wants to know what computer science is &lt;i&gt;about&lt;/i&gt;. On the &lt;i&gt;other&lt;/i&gt;, other hand, however, it seems a little pricey.(The link is to the more-recent 11th edition.)
&lt;/li&gt;
&lt;li&gt;D. Budgen, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0201722194/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0201722194"&gt;Software Design&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201722194&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;, 2nd ed. New York: Addison-Wesley, 2003.&lt;br /&gt;

I have my own ideas about the concept of software design, which I will keep to myself for the moment. In the mean time, this book appears to be more of a meditation on what "design" is than a useful guide to software designs-man-ship. The three parts of the book are the nature of the design process, transferring design knowledge (which includes a chapter on "some design representations" and a chapter on design patterns), and design practices; the last breaks down into chapters on stepwise refinement, incremental design, structured analysis and design, Jackson Structured Programming, Jackson System Development, object-oriented design, component-based design, and the formal approach to design. Certainly, it seems a limited and idiosyncratic choice of topics.&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;E. W. Cheney and D. R. Kincaid, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0495114758/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0495114758"&gt;Numerical Mathematics and Computing&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0495114758&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;, 6th ed. Belmont, CA: Brooks/Cole, 2007.&lt;br /&gt;

Strangely, I do not know either Ward Cheney or David Kincaid, although I've heard of the latter often enough. Also, I have never taken a course on numerical methods, which by my own rules means that I should never use floating-point numbers. I am afraid all I can say is that this looks like a textbook on numerical methods. Enjoy!&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;P. Clements, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0321552687/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0321552687"&gt;Documenting Software Architectures: Views and Beyond&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321552687&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;. Boston: Addison-Wesley, 2002.&lt;br /&gt;

This is a text on documenting software architectures. That is probably not as goofy an idea as it sounds, since the architecture of a system is, in the first place, somewhat fundamental to the software, but, in the second, usually hidden behind the mass of trees. The actual architecture of a system may not appear outside of its documentation, and the notation for that documentation may well guide the architecture you get. Note: I'm still reserving my ideas about design and indeed, architecture.&lt;br /&gt;

One reviewer on Amazon writes that this book is an extension of the Carnegie Mellon Software Engineering Institute technical report 
&lt;a href="http://www.sei.cmu.edu/library/abstracts/reports/01tn010.cfmCMU/SEI-2001-TN-010%20-%20Documenting%20Software%20Architectures:%20Organization%20of%20Documentation%20Package"&gt;CMU/SEI-2001-TN-01, &lt;i&gt;Documenting Software Architectures: Organization of Documentation Package&lt;/i&gt;&lt;/a&gt; by a subset of the authors.  That document may be a good place to start. (Book link is to the second edition.)&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;L. Copeland, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/158053791X/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=158053791X"&gt;A Practitioner's Guide to Software Test Design&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=158053791X&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;, 1st ed. Boston: Artech House, 2004.&lt;br /&gt;

This book seems to be a decent reference to some various forms of test design, black box and white box. On the other hand, the only references to unit testing are in chapter 1, the testing process, under "testing levels", and the introduction to white box testing. Test-driven development is not mentioned at all. In other words, it is a reference to &lt;i&gt;old-school&lt;/i&gt; test methods. Not that those are unnecessary or detrimental, just that they are the kinds of things you run less than frequently, just prior to a release. Knowing how they work will certainly expand your options, even if you are into TDD, and &lt;em&gt;somebody&lt;/em&gt; in your project will probably need to know this stuff.&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;R. E. Fairley, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0470294558/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0470294558"&gt;Managing and Leading Software Projects&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0470294558&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;. Hoboken, NJ: Wiley-IEEE Computer Society Press, 2009.&lt;br /&gt;

Some management topics are necessary to development projects: estimating, measuring, and risks. I might just buy it for this sentence on the back cover:&lt;br /&gt;
&lt;blockquote&gt;
It introduces software development methods, from traditional (&lt;b&gt;hacking&lt;/b&gt;, requirements to code, and waterfall) to iterative (incremental build, evolutionary, agile, and spiral), and illustrates and emphasizes how to tailor the development process to specific projects.&lt;/blockquote&gt;
(Emphasis mine.) On page 54, "hacking" is characterized by a reference to the cartoon with the caption, "You start coding and I'll go find out what they want," which is actually a pretty fair description of one of the few ways I know to reliably come up with a project's requirements.
&lt;/li&gt;
&lt;li&gt;[12] E. Gamma, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0201633612/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0201633612"&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201633612&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;, 1st ed. Reading, MA: Addison-Wesley Professional, 1994.&lt;br /&gt;

And finally, a book that I own and have read. Now, this is an important book, and contains many good ideas, both for software designs and for communicating those designs. Yet, I am not a pattern-ista. In fact, I am of the set that regards design patterns as work-arounds for poor programming languages. Still, the contents of this book are probably necessary, if you are going to hang around software development for very long.&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;T. Gilb and D. Graham, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0201631814/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0201631814"&gt;Software Inspection&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201631814&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;, 1st ed. Reading, MA: Addison-Wesley, 1993.&lt;br /&gt;

An inspection is a formal examination of some artifact specifically to detect problems. &lt;br /&gt;
&lt;blockquote&gt;
Zero-defect software is the Holy Grail of all software developers. It has proved to be an elusive goal - until now. The Inspection techniques illustrated in this book have brought clear benefits in terms of lower (or even zero) defects, higher productivity, better project tracking and improved documentation.&lt;/blockquote&gt;
Maybe there is a silver bullet, after all.
&lt;/li&gt;
&lt;li&gt;P. Grubb and A. A. Takang, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/981238426X/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=981238426X"&gt;Software Maintenance: Concepts and Practice&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=981238426X&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;, 2nd ed. River Edge, NJ: World Scientific Publishing, 2003.&lt;br /&gt;

Judging by the table of contents, this looks like an interesting book; it includes how new development differs from maintenance, what takes place during maintenance (program understanding, reverse engineering, reuse, testing), and tools. On the other hand, the authors write in the preface, "...challenges that software engineers face when modifying complex software systems...can be seen in the cost of modifying software...[which] can reach 70% of the total life-cycle cost." That number always leaves a strange taste in my mouth, since for any successful project I have encountered, the cost actually asymptotically approaches 100%.&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;A. M. J. Hass, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0321117662/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0321117662"&gt;Configuration Management Principles and Practice&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321117662&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;, 1st ed. Boston: Addison-Wesley, 2003.&lt;br /&gt;

I am the first to claim that configuration management is one key to any reasonably successful project. However, I suspect that this is not the best book on the subject. The table of contents runs for 18 pages out of 350 or so with several interesting looking sections, but I do not see anything compelling overall. For example, Chapter 22 is "Getting started on configuration management---up to capability level 1" with subsections on "How to get started from nothing" and "First steps toward configuration management", but the next chapter, "Planning configuration management---up to capability level 2" seems to be all about a configuration management plan document, not what to do with the foundation from the previous chapter.&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;E. Horowitz, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0929306414/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399373&amp;amp;creativeASIN=0929306414"&gt;Computer Algorithms&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0929306414&amp;amp;camp=217145&amp;amp;creative=399373" style="border: none !important; margin: 0px !important;" width="1" /&gt;
&lt;/i&gt;, 2nd ed. Summit, NJ: Silicon Press, 2007.&lt;br /&gt;

I have never seen this book before. If they had referenced &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0262033844/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0262033844"&gt;Introduction to Algorithms&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0262033844&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt; by Comen, Leiserson, Rivest, and Stein, I would not have said anything at all; that is the book most people would think of, I believe. (Strange but true: that was the one computer science class I ever dropped. After a single class session.) Still, &lt;i&gt;Computer Algorithms&lt;/i&gt; looks to be a good book, although at 773 pages of algorithmy goodness, I suspect it's not light reading.&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;IEEE-CS/ACM Joint Task Force on Software Engineering Ethics and Professional Practices. (1999, July 22, 2010). &lt;i&gt;&lt;a href="http://www.acm.org/about/se-code/"&gt;Software Engineering Code of Ethics and Professional Practice&lt;/a&gt;&lt;/i&gt; (Version 5.2).&lt;br /&gt;

This one is free, reasonably short, and quick reading. The short version is:&lt;br /&gt;

&lt;blockquote&gt;
Software engineers shall commit themselves to making the analysis, specification, design, development, testing and maintenance of software a beneficial and respected profession. In accordance with their commitment to the health, safety and welfare of the public, software engineers shall adhere to the following Eight Principles:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;PUBLIC&lt;/b&gt; - Software engineers shall act consistently with the public interest.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CLIENT AND EMPLOYER&lt;/b&gt; - Software engineers shall act in a manner that is in the best interests of their client and employer consistent with the public interest.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PRODUCT&lt;/b&gt; - Software engineers shall ensure that their products and related modifications meet the highest professional standards possible.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JUDGMENT&lt;/b&gt; - Software engineers shall maintain integrity and independence in their professional judgment.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MANAGEMENT&lt;/b&gt; - Software engineering managers and leaders shall subscribe to and promote an ethical approach to the management of software development and maintenance.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PROFESSION&lt;/b&gt; - Software engineers shall advance the integrity and reputation of the profession consistent with the public interest.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;COLLEAGUES&lt;/b&gt; - Software engineers shall be fair to and supportive of their colleagues.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SELF&lt;/b&gt; - Software engineers shall participate in lifelong learning regarding the practice of their profession and shall promote an ethical approach to the practice of the profession.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
Learn it; love it; live it.&lt;br /&gt;

&lt;/li&gt;
&lt;li&gt;S. H. Kan, &lt;a href="http://www.amazon.com/gp/product/0201729156/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0201729156"&gt;&lt;i&gt;Metrics and Models in Software Quality Engineering&lt;/i&gt;&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201729156&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;
, 2nd ed. Boston: Addison-Wesley, 2002.&lt;br /&gt;

This is another topic that I have never spent much time with. Looking at the table of contents, this text seems to offer a lot of interesting options, although I do not know if it goes into enough detail to actually implement them. Certainly, it cannot be worse than the "time to fix" numbers from various build and bug tracking tools. Chapters 15, 16, 17, and 18, on quality assessments and process improvement, do leave me somewhat concerned about the amount of snake oil involved.&lt;br /&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are not completely bored yet, you can go to the &lt;a href="http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for.html"&gt;second half&lt;/a&gt; of the list.&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-2951372889504955161?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/uSj5hC9rOj5XoyJ0TOw9MBUWAIA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uSj5hC9rOj5XoyJ0TOw9MBUWAIA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/uSj5hC9rOj5XoyJ0TOw9MBUWAIA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uSj5hC9rOj5XoyJ0TOw9MBUWAIA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/zF01aYbzih4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/2951372889504955161/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=2951372889504955161" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/2951372889504955161?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/2951372889504955161?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/zF01aYbzih4/consolidated-reference-list-for-ieee.html" title="Consolidated Reference List for the IEEE Software Engineering Body of Knowledge" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for-ieee.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUAMR38zeSp7ImA9WhRSFUk.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-1202764363415481032</id><published>2011-11-17T10:29:00.000-06:00</published><updated>2011-11-17T10:36:26.181-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-17T10:36:26.181-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="link" /><category scheme="http://www.blogger.com/atom/ns#" term="programming language" /><title>Link o' the day: Roslyn and eval for C#</title><content type="html">&lt;p&gt;Engaging in a journey of adventure and discovery, InfoWorld's &lt;a href="http://www.infoworld.com/d/application-development/microsofts-roslyn-reinventing-the-compiler-we-know-it-176671"&gt;Microsoft's Roslyn: Reinventing the compiler as we know it&lt;/a&gt; shows that C# developers are on the way to learning that eval in production code is not such a great idea.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;So what is Roslyn good for?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The most obvious advantage of this kind of "deconstructed" compiler is that it allows the entire compile-execute process to be invoked from within .Net applications. Hejlsberg demonstrated a C# program that passed a few code snippets to the C# compiler as strings; the compiler returned the resulting IL assembly code as an object, which was then passed to the Common Language Runtime (CLR) for execution. Voilà! With Roslyn, C# gains a dynamic language's ability to generate and invoke code at runtime.&lt;/p&gt;
&lt;p&gt;Put that same code into a loop that accepts input from the user, and you've created a fully interactive read-eval-print loop (REPL) console for C#, allowing you to manipulate and experiment with .Net APIs and objects in real time. With the Roslyn technology, C# may still be a compiled language, but it effectively gains all the flexibility and expressiveness that dynamic languages such as Python and Ruby have to offer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(One of the benefits of the difficulty of doing this sort of thing in C, for example, is that it's so painful that no one who would likely misuse it ever actually &lt;i&gt;does&lt;/i&gt;.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1202764363415481032?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ZaxjeMQnfAMFEbH9p63rI0qTYnY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZaxjeMQnfAMFEbH9p63rI0qTYnY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ZaxjeMQnfAMFEbH9p63rI0qTYnY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZaxjeMQnfAMFEbH9p63rI0qTYnY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/sgef-NVCeys" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/1202764363415481032/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1202764363415481032" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/1202764363415481032?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/1202764363415481032?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/sgef-NVCeys/link-o-day-roslyn-and-eval-for-c.html" title="Link o' the day: Roslyn and eval for C#" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/11/link-o-day-roslyn-and-eval-for-c.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YEQHk-eyp7ImA9WhRSEkk.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-7388332769623486001</id><published>2011-11-12T12:15:00.001-06:00</published><updated>2011-11-13T22:31:41.753-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-13T22:31:41.753-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="conference" /><title>IEEE Smart Tech Workshop, Huntsville</title><content type="html">&lt;p&gt;Last weekend, I spent a couple of days going to the &lt;a href="http://www.ieee.org/membership_services/mga_maw.html"&gt;IEEE Smart Tech&lt;/a&gt; metro-area workshop in Huntsville, AL. The Metropolitan Area Workshop is a traveling conference sponsored by the IEEE Power and Energy Society, IEEE Computer Society, IEEE Communications Society, and IEEE-USA, with tracks on software engineering, wireless communications, smart power grid and, in our case, career assistance. In Huntsville, it was November 4-5 at the Von Braun Center.&lt;/p&gt;

&lt;p&gt;Overall, the workshop was pretty decent. About 120 people attended; breakfast (pastries), lunch (boxed sandwiches), and a reception with enough food for dinner were provided; the price for IEEE members was $119; and there were no major catastrophes. (And I'm not just saying that because I set up the wireless access point that seems to have survived pretty well. Go &lt;a href="http://www.dd-wrt.com/site/index"&gt;DD-WRT&lt;/a&gt;!)&lt;/p&gt;

&lt;h2&gt;Software engineering essentials&lt;/h2&gt;

&lt;span style="float:right; margin:10px;border:thin solid black;"&gt;&lt;a href="http://www.crsr.net/images/ford-gibbs-1.2.png"&gt;&lt;img src="http://www.crsr.net/images/ford-gibbs-1.2-sm.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/span&gt;

&lt;p&gt;Friday, I went to the "Software engineering essentials" track session, which was billed as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Designed for software development professionals interested in confirming knowledge of industry-standard software practices.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn the principles, standards, and practices of software engineering to create more robust applications.&lt;/li&gt;
&lt;li&gt;Review all 15 Knowledge Areas presented in the Guide to the Software Engineering Body of Knowledge (SWEBOK) with a special focus on principles and practices of Software Requirements, Design, Construction, and Testing.&lt;/li&gt;
&lt;li&gt;Quizzes to test knowledge.&lt;/li&gt;
&lt;li&gt;Course based on curriculum for the IEEE &lt;a href="http://www.computer.org/portal/web/certification/csdp"&gt;CSDP&lt;/a&gt; [Certified Software Development Professional] designation.&lt;/li&gt;
&lt;li&gt;Increase your overall knowledge of the software development lifecycle and value to your company.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The reality was not quite as expected. The class was taught by Dr. Tom Hilburn, Professor Emeritus of Software Engineering and Distinguished Engineering Professor at Embry-Riddle Aeronautical University. It briefly reviewed the following Knowledge Areas:&lt;ul&gt;
&lt;li&gt;Software architecture and design&lt;/li&gt;
&lt;li&gt;Software engineering process models&lt;/li&gt;
&lt;li&gt;Software engineering economics&lt;/li&gt;
&lt;li&gt;Professionalism and professional practice&lt;/li&gt;
&lt;li&gt;Configuration management&lt;/li&gt;
&lt;li&gt;Computing foundations, mathematical foundations, engineering foundations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There were more details on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requirements&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;/ul&gt;

&lt;span style="float:left; margin:10px;border:thin solid black;"&gt;&lt;a href="http://www.crsr.net/images/ford-gibbs-1.3.png"&gt;&lt;img src="http://www.crsr.net/images/ford-gibbs-1.3-sm.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/span&gt;

&lt;p&gt;The workshop was focused on the &lt;a href="http://www.computer.org/portal/web/certification/csdp/prepare"&gt;CSDP Assessment Course&lt;/a&gt;. The detailed information about requirements and testing was presented by going through the assessment course sections on those KAs. As a result, the course was described by one participant as an "advertisement" for the assessment course.&lt;/p&gt;
&lt;p&gt;As a result, it failed as both an introduction to the essentials of software engineering and as a preparation for the CSDP. Like the &lt;em&gt;Head First...&lt;/em&gt; books I have read, it was too focused on the assessment (in this case) to work as a tutorial on the given topic. And, because it spent so much time on the detailed topics, there was no time or effort put into trying to cover the scope of the CSDP.&lt;/p&gt;

&lt;p&gt;The two images are taken from CMU/SEI technical report CMU/SEI-96-TR-004 / ESC-TR-96-004, &lt;a href="http://www.sei.cmu.edu/reports/96tr004.pdf"&gt;&lt;i&gt;A Mature Profession of Software Engineering&lt;/i&gt;&lt;/a&gt;, Gary Ford and Norman E. Gibbs, January 1996. The first, Figure 1-2, was was used by Dr. Hilburn as an illustration of a profession for software engineering; the second, Figure 1-3, is a little clearer about what is going on.&lt;/p&gt;

&lt;h2&gt;Introduction to the smart grid&lt;/h2&gt;

&lt;p&gt;The course I attended on Saturday was another kettle of fish. It's billing was:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Recommended for all technology professionals&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NIST Conceptual Model and its domains and interfaces.
&lt;/li&gt;
&lt;li&gt;Smart metering.&lt;/li&gt;
&lt;li&gt;The current state of smart grid applications and how these drive infrastructure requirements.&lt;/li&gt;
&lt;li&gt;The integration of smart grid elements into utility operations.&lt;/li&gt;
&lt;li&gt;Distribution automation as an enabling technology for smart grid.&lt;/li&gt;
&lt;li&gt;Smart grid cyber security technology.&lt;/li&gt;
&lt;li&gt;Smart grid standards framework and its challenges.&lt;/li&gt;
&lt;li&gt;Overview of smart grid network communications and the data needed in/out of the network.&lt;/li&gt;
&lt;li&gt;Monitoring equipment used by smart grid applications in the network to generate data for analysis and improving customer service.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;The class not only covered all that, it was entertaining to boot. The class was presented by &lt;a href="http://www.quanta-technology.com/staff/jerry-melcher"&gt;Jerry Melcher&lt;/a&gt; of Quanta Technology and included a stack of random factoids:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Storage per volume:&lt;/b&gt; Diesel 3300 joules/cc, lead acid battery 50 joules/cc, lithium ion batteries 150 joules/cc.&lt;/li&gt;
&lt;li&gt;Storage on the customer side, rather than the utility side, is most efficient.&lt;/li&gt;
&lt;li&gt;Economics today call for natural gas generators, or demand response technology.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Demand response&lt;/b&gt; systems look like generators to the utility. They act by reducing load from the consumer, providing the equivalent of low-cost generation for the provider. Demand response techniques are in widespread use for industrial consumers, but modern advanced metering technology and home area networking are needed to allow the utility to communicate with a non-industrial consumer's loads.&lt;/li&gt;
&lt;li&gt;The expected &lt;b&gt;longevity&lt;/b&gt; of utility equipment is 40 years, something that is a surprise to most technology firms attempting to enter the business.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Quote&lt;/b&gt;: "The worst thing that we could allow to happen to our client was to let them talk us into a custom deployment."&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unfortunately, since I know almost nothing about electrical power technology, most of the details of the class were not terribly useful for me.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7388332769623486001?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/IrpypZqdB1pMuEYrr0MtF5uVZhE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/IrpypZqdB1pMuEYrr0MtF5uVZhE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/IrpypZqdB1pMuEYrr0MtF5uVZhE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/IrpypZqdB1pMuEYrr0MtF5uVZhE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/q9wc5aUk6zI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/7388332769623486001/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7388332769623486001" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/7388332769623486001?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/7388332769623486001?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/q9wc5aUk6zI/ieee-smart-tech-workshop-huntsville.html" title="IEEE Smart Tech Workshop, Huntsville" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/11/ieee-smart-tech-workshop-huntsville.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EGSXg8eCp7ImA9WhRSEU8.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-3599897356843115490</id><published>2011-11-10T19:16:00.000-06:00</published><updated>2011-11-12T12:13:48.670-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-12T12:13:48.670-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="system administration" /><category scheme="http://www.blogger.com/atom/ns#" term="tip" /><category scheme="http://www.blogger.com/atom/ns#" term="shell" /><title>ed is the standard text editor</title><content type="html">&lt;p&gt;Yes, I know there are other ways of doing this kind of thing, particularly if you have &lt;a href="http://www.opscode.com/chef/"&gt;chef&lt;/a&gt; or &lt;a href="http://www.gnu.org/software/cfengine/"&gt;cfengine&lt;/a&gt; or whatever configured. Right here, right now, I don't. Yay.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.gnu.org/fun/jokes/ed.msg.html"&gt;ed&lt;/a&gt; has one very strong advantage over other editors: it is scriptable. No, not scriptable as in you can write code to modify how it works, scriptable as in it can be driven by a file full of commands, and thus can be run remotely, in a loop. So, if you need to edit a file on a mess of machines, to make the same change everywhere, remember, "ed is the standard text editor."&lt;/p&gt;

&lt;p&gt;Create a script file containing the ed commands and the appropriate text:&lt;/p&gt;
&lt;pre&gt;$ cat /tmp/edit 
g/^SSLRandomSeed connect/
a

# http://www.g-loaded.eu/2011/09/27/mod_gnutls-rc4-cipher-beast/
SSLHonorCipherOrder on
SSLCipherSuite !aNULL:!eNULL:!EXPORT:!DSS:!DES:RC4-SHA:RC4-MD5:ALL
.
w
q
$ 
&lt;/pre&gt;

&lt;p&gt;Then, use ssh to connect to the remote host and run the ed command on the file to be edited, reading standard input from the file. Trust me, using the separate file is easier than writing the commands in a here-document or something.&lt;/p&gt;

&lt;pre&gt;$ for j in 01 02; do for k in b c; do ssh host$k$j ed /usr/local/httpd/conf/httpd.conf &lt; /tmp/edit; done; done&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3599897356843115490?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/5ippdUMQDCjOjIC7udD5tWnrR00/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5ippdUMQDCjOjIC7udD5tWnrR00/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/5ippdUMQDCjOjIC7udD5tWnrR00/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5ippdUMQDCjOjIC7udD5tWnrR00/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/zZLpidZajIA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/3599897356843115490/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3599897356843115490" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/3599897356843115490?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/3599897356843115490?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/zZLpidZajIA/yes-i-know-there-are-other-ways-of.html" title="ed is the standard text editor" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/11/yes-i-know-there-are-other-ways-of.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQCQX44eSp7ImA9WhRTE0Q.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-5535757501989614357</id><published>2011-11-04T02:56:00.000-05:00</published><updated>2011-11-04T02:56:00.031-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-04T02:56:00.031-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="theory" /><category scheme="http://www.blogger.com/atom/ns#" term="notation" /><category scheme="http://www.blogger.com/atom/ns#" term="Knuth" /><category scheme="http://www.blogger.com/atom/ns#" term="link" /><category scheme="http://www.blogger.com/atom/ns#" term="Dijkstra" /><category scheme="http://www.blogger.com/atom/ns#" term="programming language" /><title>Link o' the day: Donald Knuth, Tony Hoare, and goto</title><content type="html">&lt;p&gt;Hah! I found it!&lt;/p&gt;

&lt;p&gt;Ok, I suspect I've found (and possibly blogged about) this before, but I like it, I think it is important and in any case, I just found it (again).&lt;/p&gt;

&lt;p&gt;Following Edsger Dijkstra's &lt;a href="http://www.cs.utexas.edu/~EWD/ewd02xx/EWD215.PDF"&gt;Goto statement considered harmful&lt;/a&gt; [PDF], Donald Knuth wrote &lt;a href="http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.103.6084"&gt;Structured programming with go to statements&lt;/a&gt;, in which is written (p. 289):
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;Axiomatics of Jumps&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;Just recently, however, Hoare has shown that there is, in fact, a rather simple way to give an axiomatic definition of &lt;b&gt;go to&lt;/b&gt; statements; indeed, he wishes quite frankly that it hadn't been quite so simple. For each label \(L\) in a program, the programmer should state a logical assertion \(\alpha(L)\) which is to be true whenever we reach \(L\). Then the axioms
\[ \{\alpha(L)\}\ \textbf{go to}\ L\ \{false\} \]
plus the rules of inference
\[ \{\alpha(L)\}\ S\ \{P\}\ \vdash\ \{\alpha(L)\}\ L:S\ \{P\} \]
are allowed in program proofs, and all properties of labels and &lt;b&gt;go to&lt;/b&gt;'s will follow if the \(\alpha(L)\) are selected intelligently. One must, of course, carry out the entire proof using the same assertion \(\alpha(L)\) for each appearance of the label \(L\), and some choices of assertions will lead to more powerful results than others.&lt;/p&gt;
&lt;p&gt;Informally, \(\alpha(L)\) represents the desired state of affairs at label \(L\); this definition says essentially that a program is correct if \(\alpha(L)\) holds at \(L\) and before all "&lt;b&gt;go to&lt;/b&gt; \(L\)" statements, and that control never "falls through" a &lt;b&gt;go to&lt;/b&gt; statement to the following text. Stating the assertions \(\alpha(L)\) is analogous to formulating loop invariants. Thus, it is not difficult to deal formally with tortuous program structure if it turns out to be necessary; all we need to know is the "meaning" of each label.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unfortunately, Knuth does not cite &lt;em&gt;where&lt;/em&gt; Hoare had just recently shown that.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5535757501989614357?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/slsR3P66raBG1lkwGzetEHGUM5M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/slsR3P66raBG1lkwGzetEHGUM5M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/slsR3P66raBG1lkwGzetEHGUM5M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/slsR3P66raBG1lkwGzetEHGUM5M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/nuVoFczR9CQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/5535757501989614357/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5535757501989614357" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/5535757501989614357?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/5535757501989614357?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/nuVoFczR9CQ/link-o-day-donald-knuth-tony-hoare-and.html" title="Link o' the day: Donald Knuth, Tony Hoare, and goto" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/11/link-o-day-donald-knuth-tony-hoare-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEENQ3gzfSp7ImA9WhRbFkk.&quot;"><id>tag:blogger.com,1999:blog-5087326709910512917.post-436915903590940999</id><published>2011-11-01T22:07:00.000-05:00</published><updated>2012-02-07T14:31:32.685-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-07T14:31:32.685-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="software development" /><category scheme="http://www.blogger.com/atom/ns#" term="c" /><category scheme="http://www.blogger.com/atom/ns#" term="programming language" /><title>Systems programming</title><content type="html">&lt;div style="-webkit-column-count:2;-webkit-column-gap:2em;-webkit-column-rule:1px solid black; -moz-column-count:2;-moz-column-gap:2em;-moz-column-rule:1px solid black;"&gt;
&lt;p&gt;People frequently come up to me and ask, "Bob, what is systems programming?" or, "Hey, Bob, what is a systems programming language?"&lt;/p&gt;

&lt;p&gt;Those are more difficult questions than they appear. For part of the confusion, I blame John Ousterhout, the creator of the TCL programming language. TCL does not seem to get much use these days, but was one of the early, popular dynamic languages along with Perl, Python, and PHP. In "&lt;a href="http://www.tcl.tk/doc/scripting.html"&gt;Scripting: Higher Level Programming for the 21st Century&lt;/a&gt;", Ousterhout wrote, &lt;blockquote&gt;System programming languages were designed for building data structures and algorithms from scratch, starting from the most primitive computer elements such as words of memory. In contrast, scripting languages are designed for gluing: they assume the existence of a set of powerful components and are intended primarily for connecting components together.&lt;/blockquote&gt; I believe he was wrong on both counts. On the one hand, &lt;em&gt;all&lt;/em&gt; programming languages are, or should be, designed for building data structures and algorithms; to do otherwise severely limits what can be done with the language, even more so than not being Turing complete&lt;a href="#one"&gt;[1]&lt;/a&gt;. On the other hand, designing a language for connecting components primarily written in some other language is a losing game since most users will not create separate components.&lt;a href="#two"&gt;[2]&lt;/a&gt;&lt;a href="#three"&gt;[3]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What have Ousterhout's comments got to do with systems programming? His definition has, I believe, either led to (or been a result of the same cause of) many other languages such as Java being called "systems programming languages" when they rightly are not. The right question is not "What is the difference between systems programming languages and scripting languages", but "What is the difference between systems programming and applications programming?" To my mind, there is less real difference between TCL, Python, Perl, Ruby, and so on, and Java, Go, C#, etc., than between C and anything on that list.&lt;/p&gt;

&lt;p&gt;So, what exactly is systems programming? It's hard to say. What are some of the characteristics of systems programming? That's an easier question. Systems programming usually involves the creation of software &lt;em&gt;for use by other software&lt;/em&gt;, not by humans. Systems programming is almost always about &lt;em&gt;managing resources&lt;/em&gt; for use by that other software. Systems programs may, and likely will, be built around complex data structures and algorithm and will also likely be built from the "most primitive computer elements" such as words of memory, if only because either
&lt;ol&gt;
&lt;li&gt;there is &lt;i&gt;nothing below them&lt;/i&gt; to create "less primitive" abstractions, or&lt;/li&gt;
&lt;li&gt;it is absolutely vital that their performance, or memory, or some other footprint not directly related to whatever the ultimate task is, be optimized.
&lt;/ol&gt;
Operating system kernels are definitely systems programming. As are device drivers. Compilers? Not systems programs. Interpreters and virtual machines? Maybe. Embedded programming is a bit of a special case: many of the tasks involved in embedded software may be similar to the tasks involved in applications, but because the resources available to embedded software are so relatively expensive, their management becomes essential to every part of the device. On the other hand, technological advances have moved some of what was embedded development solidly into the applications arena; witness smart phones in the past few years.&lt;/p&gt;
 
&lt;p&gt;Here's a rule of thumb I came up with back when it seemed necessary to choose between C and one of those other, applications languages for some task: Does the problem statement explicitly mention having to manage your own memory? If not, then you shouldn't be using C, and you probably aren't doing systems programming.&lt;/p&gt;

&lt;p&gt;James Iry made a very insightful &lt;a href="http://james-iry.blogspot.com/2010/09/moron-why-c-is-not-assembly.html?rip_ritchie=true"&gt;observation&lt;/a&gt; about the nature of the C programming language:&lt;blockquote&gt;Alan Perlis famously said "a programming language is low level when its programs require attention to the irrelevant." What's relevant depends on the problem and the domain, so a corollary would be that a language that's at too high a level prevents paying attention to some of what is relevant for your needs.&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;I believe that statement is insightful (and it is the casus belli for this post) because it touches on exactly the key of systems programming. What would it mean to write a memory manager or garbage collector in a language that has garbage collection? How could you use a language for systems programming if you cannot manipulate a device whose control system is mapped into memory at a &lt;i&gt;specific&lt;/i&gt; location? Alternatively, why the stinking hell would you write an application in C if you didn't have to do some of those things?&lt;/p&gt;

&lt;p&gt;I recently discovered a 2006 paper by Jonathan Shapiro, "&lt;a href="http://www.bitc-lang.org/docs/papers/PLOS2006-shap.pdf"&gt;Programming Language Challenges in Systems Codes: Why Systems Programmers Still Use C, and What to Do About It&lt;/a&gt;", describing the motives for &lt;a href="http://www.bitc-lang.org/"&gt;BitC&lt;/a&gt;, a systems programming language that integrates advances of the last thirty years of programming language technology. Shapiro provides a very idiosyncratic, but also very accurate description of systems programs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Systems programs operate in constrained memory.&lt;/li&gt;
&lt;li&gt;Systems programs are strongly driven by bulk I/O performance.&lt;/li&gt;
&lt;li&gt;Performance matters. (And as a corollary, data representation matters.)&lt;/li&gt;
&lt;li&gt;Systems programs retain state. (And as a corollary, user-managed storage is a requirement.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Shapiro's description of the first ("On a 32-bit [...] machine with [...] 64 gigabyte physical memory, it is extremely difficult to get the per-page book-keeping data structures to fit within a 0.5 gigabyte kernel virtual region."), second ("...the goal is to [perform] zero copies of that data [..., requiring] the creation of pointers that do not point to the beginning of an object [...or objects] multiply aliased in both the virtual and physical maps (e.g. by DMA) [...and sub-objects that] reference the storage of the original."), and third points ("...in the critical paths [...], the addition of only a few cache references — or worse, cache misses — in an inner loop can mean the difference between winning and losing customers") are largely what I mean by "resource management", specifically memory. Shapiro's fourth point is a little less obvious: &lt;blockquote&gt;The most common pattern in systems programs is event loops. While there is short-lived data within these processing loops, the pattern overall is that there are (relatively) large amounts of state that live for the duration of the event processing cycle. This tends to penalize the performance of automatic storage reclamation strategies. To make matters more interesting, there are caches. These update frequently enough that “old space” techniques may not perform well, but are large enough that scanning them can be quite expensive.&lt;/blockquote&gt; Consider that the event loops he is speaking about may continue for the up-time of the device. My original thought was that &lt;em&gt;implementing&lt;/em&gt; memory managers would be problematic in a language that provided automatic memory management; Shapiro is making the point that the &lt;em&gt;presence&lt;/em&gt; of automatic memory management may be detrimental.&lt;/p&gt;

&lt;p&gt;Oh, and when someone comes up to me and asks one of those "Bob,...?" questions, I always answer the same way: "My name's not Bob."&lt;/p&gt;

&lt;p&gt;[Edit: Added the link to and paragraphs about Jonathan Shapiro's paper. Thanks to Eli Gottlieb and "&lt;a href="http://decac.googlecode.com/files/Deca%20Thesis.pdf"&gt;The design and implementation of a modern systems programming language&lt;/a&gt;" for pointing it out (and &lt;a href="http://code.google.com/p/decac/"&gt;Deca&lt;/a&gt;). And my name's still not Bob.]&lt;/p&gt;

&lt;p&gt;&lt;a name="one"&gt;&lt;b&gt;[1]&lt;/b&gt;&lt;/a&gt; For example, TCL itself  was designed with sole concern for glue capability, which leads to most of the reasons it has lost favor.&lt;/p&gt;

&lt;p&gt;&lt;a name="two"&gt;&lt;b&gt;[2]&lt;/b&gt;&lt;/a&gt; TCL's glue capability created Tk, &lt;a href="http://www.nist.gov/el/msid/expect.cfm"&gt;Expect&lt;/a&gt;, and &lt;a href="http://www.aolserver.com/"&gt;AOLserver&lt;/a&gt;, but many more, complex, programs were simply written in TCL (likely using Tk) than were built by gluing other components together.&lt;/p&gt;

&lt;p&gt;&lt;a name="three"&gt;&lt;b&gt;[3]&lt;/b&gt;&lt;/a&gt; Modulo command line shells such as sh, bash, etc., which are examples of programming languages as user interfaces. Also, the term "scripting" is much more appropriate for these languages. Complex applications in these languages are some of the most disturbing things I have ever seen.&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-436915903590940999?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/8VihjOyHn-xFJeNg_cKSsOqd-pI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8VihjOyHn-xFJeNg_cKSsOqd-pI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/8VihjOyHn-xFJeNg_cKSsOqd-pI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8VihjOyHn-xFJeNg_cKSsOqd-pI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/crsr/nOWs/~4/9ODMKDuqT30" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maniagnosis.crsr.net/feeds/436915903590940999/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=436915903590940999" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/436915903590940999?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5087326709910512917/posts/default/436915903590940999?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/crsr/nOWs/~3/9ODMKDuqT30/systems-programming.html" title="Systems programming" /><author><name>Tommy McGuire</name><uri>https://profiles.google.com/102334632004599133425</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-FJ-DhlqLhm8/AAAAAAAAAAI/AAAAAAAAAC0/O2O4DibDeRw/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://maniagnosis.crsr.net/2011/11/systems-programming.html</feedburner:origLink></entry></feed>

