<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-19725519</id><updated>2012-01-02T14:23:57.806-05:00</updated><category term='Sun Ray'/><category term='Python'/><category term='Unix'/><category term='math'/><category term='Software Engineering'/><category term='cloud computing'/><category term='politics'/><category term='actors'/><category term='programming'/><category term='IT'/><category term='OCaml'/><category term='sbt'/><category term='privacy'/><category term='Engineering'/><category term='benchmarks'/><category term='algorithms'/><category term='Apple'/><category term='Java'/><category term='Lisp'/><category term='concurrency'/><category term='Metaprogramming'/><category term='Google'/><category term='Finance'/><category term='widefinder'/><category term='Scala'/><category term='economics'/><category term='Sun'/><category term='enterprise software'/><category term='Functional Programming'/><category term='Ruby'/><category term='AI'/><category term='Linux'/><category term='user interface'/><category term='twitter'/><category term='abstraction'/><category term='innovation'/><category term='Mac'/><category term='Solaris'/><category term='parallelism'/><category term='microsoft'/><category term='windows'/><category term='fail'/><category term='architecture'/><category term='management'/><title type='text'>Erik Engbrecht's Blog</title><subtitle type='html'>Thoughts and Essays on Systems Engineering and Software Engineering,  and IT</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>64</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-19725519.post-1062267845009995389</id><published>2011-01-16T22:42:00.003-05:00</published><updated>2011-01-16T22:42:00.512-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Metaprogramming'/><category scheme='http://www.blogger.com/atom/ns#' term='Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='abstraction'/><title type='text'>Martin Odersky's Scala Levels</title><content type='html'>&lt;p&gt;I just saw Martin's post on &lt;a href="http://www.scala-lang.org/node/8610"&gt;levels of expertise in Scala&lt;/a&gt;, and &lt;a href="http://blog.tmorris.net/critique-of-oderskys-scala-levels/"&gt;Tony Morris's response&lt;/a&gt;. The concept of levels is something that many in the community have called for repeatedly, in order to help ease people - especially team members who may be a little put off by some of Scala's more advanced features - into the language more gently. I understand the motivation, but it has always struck me as somewhat odd. The reason is that I think one needs to have very compelling reason for such a significant change to be justified, especially a change from a mature, mainstream technology such as Java into one as new an immature as Scala. To being, I'll recount my experience with adding &lt;a href="http://www.python.org//"&gt;Python&lt;/a&gt; as a stable in my programming toolbox.&lt;/p&gt;
&lt;h3&gt;Learning Python&lt;/h3&gt;
&lt;p&gt;I dabbled it Python a lot before really using it extensively. Much of my initial usage basically amounted to using &lt;a href="http://www.jython.org/"&gt;Jython&lt;/a&gt; as a repl for interactively poking at Java libraries, especially ones that weren't particularly well documented. I thought Python was neat, but at the time most of my programming experience was in C++ and Java. I valued static typing. I valued having a compiler. When I was in college, I had a professor who said something along the line so of "The compiler is your friend. Write your code so that the compiler is more likely to catch your mistakes. Don't try to trick it or bypass it." This was in the context of C++ programming, and given all the ways that one can shoot himself in the foot using C++, it always seemed like sage advice. So giving up have a compiler to catch my mistakes, and an explicit structure clearly present in my code, seemed like an awful lot to ask. Sure, Python is more concise, but in my opinion conciseness is often more a matter of how closely the libraries you're using match the problem that you are trying to solve. About a year ago I had some experimental Python code that I had thrown together that did some regular expression heavy text processing then some XML processing (I was processing output of an application that produced invalid XML, so the first phase was the fix it so the XML parser wouldn't crash and the second was to actually process it). I can't remember why, but I decided to convert it to Java. I think it was because I wanted to integrate it with something that integrated well with Java, but not as well with Python. Anyway, the point is that the Python code and the Java code weren't that different in length. Sure, Java has a lot more boiler plate, but once your code starts being dominated by actual logic instead of getters and setters, it's the libraries that make the difference.&lt;/p&gt;
&lt;p&gt;Anyway, I didn't really get into Python until I discovered and thoroughly learned &lt;a href="http://www.python.org/download/releases/2.2.3/descrintro/"&gt;metaclasses and descriptors&lt;/a&gt;. In my mind, they took Python from being a toy with a clean syntax to a language that opened up an entire new dimension of abstraction. A dimension of abstraction that had been missing all me life. A dimension that I had glimpsed in C++ template metaprogramming but had never quite managed to enter. All of a sudden I had this tool that enabled me to drastically and repeatedly reduce code sizes all while making the business logic cleaner and more explicit. I had a means to encode my ideas such that they enabled my coworkers to use them without fulling understanding them (an admittedly dangerous proposition). It was beautiful! They remain an important part of my toolbox to this day.&lt;/p&gt;
&lt;p&gt;Incidentally, my first uses metaclasses and descriptors was to concisely implement immutable, lazy data structures. This was long before I knew anything about functional programming.&lt;/p&gt;
&lt;h3&gt;Learning Scala&lt;/h3&gt;
&lt;p&gt;I also dabbled in Scala a lot before really becoming enamored with it. I was caught by the conciseness over Java, especially the absence of getters and setters, the presence of operator overloading, and multiple inheritance using traits. But I had operator overloading and multiple inheritance in both C++ and Python. I could usually abstract away explicit getters and setters in Python, and by the time I started picking up Scala I had already made a significant shift towards immutability and laziness, so setters weren't as necessary. Scala was neat, and the compatibility with Java was a real benefit, but at first it didn't seem compelling. In fact, when I first started experimenting with Scala it seemed too buggy to really be worth it. Something worth watching, but not yet worth using. Also, by the time I started learning Scala I had already learned Common Lisp and functional programming with full tail-call optimization seemed awkward (and still does).&lt;/p&gt;
&lt;p&gt;What eventually sold me on Scala was higher-kinded types, companion objects, and objects-as-modules. You see, but the time I started picking up Scala I had already developed a habit of using a lot of generic programming. This is easy in Python where there's no compiler check a type system to tell you that you are wrong. But a lot of the patterns I commonly used couldn't be translated into Java generics (in fact, in my first foray into Java generics I crashed javac writing code that was compliant with the Java specification). Scala gave me concise programs and type safety! And with the introduction of collections that actually use higher-kinded types in 2.8.0, along with the leaps and bounds made in robustness, I think it finally reached threshold for serious use.&lt;/p&gt;
&lt;p&gt;That's not to say these are the only key features. Understanding folds was a real eureka moment for me. I'm not sure how one can do effective functional programming without them, but perhaps there is a way. Implicit definitions are also key, and they are used so extensively in Scala libraries that I think writing Scala without a decent understanding of them is nothing short of voodoo programming. In short, there's a lot, and the features tend combine together in powerful ways.&lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;I understand the motivation for establishing levels, but I personally think if one avoids many of the features that Martin has flagged as advanced, then the benefits of Scala don't justify the risk of using such a new technology and the need to retrain people. I think without them one is better off finding a better library or framework for their current stack. Also, between the fact that advanced features are omnipresent in the libraries, and teams will always have someone who wants to use the more powerful features, avoiding them works a lot better in theory than it does in practice. You can't not use them, unless you don't use Scala's standard library and avoid almost any library written explicitly for Scala. You can only pretend that you are not using them.&lt;/p&gt;
&lt;p&gt;This is probably going to get me flamed, but reward must justify risk. In many circumstances Scala has the features to justify the risk associated with it, but the justification quickly vanishes as the more powerful features are stripped away. So while I think a programmer may be productive at Martin's lower levels, they don't justify Scala over Java.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-1062267845009995389?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/1062267845009995389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=1062267845009995389' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/1062267845009995389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/1062267845009995389'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2011/01/martin-odersky-scala-levels.html' title='Martin Odersky&amp;#39;s Scala Levels'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7953611282637715349</id><published>2011-01-12T00:00:00.001-05:00</published><updated>2011-01-12T00:21:54.816-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><title type='text'>Types of Project Failure</title><content type='html'>&lt;p&gt;I saw this &lt;a href="http://programmers.stackexchange.com/questions/35293/failed-project-when-to-call-it"&gt;question&lt;/a&gt; on &lt;a href="http://programmers.stackexchange.com/"&gt;StackExchange&lt;/a&gt; and it made me think about all the projects I've been on that have failed in various ways, and at times been both declared a success and in my opinion been a failure at the same time (this happens to me a lot). &lt;a href="http://www.zdnet.com/blog/projectfailures?tag=mantle_skin;content"&gt;Michael Krigsman&lt;/a&gt; posted a list of &lt;a href="http://www.zdnet.com/blog/projectfailures/six-types-of-it-project-failure/5981"&gt;six different types&lt;/a&gt; a while back, but they are somewhat IT centric and are more root causes than types (not that identifying root causes isn't a worthwhile exercise - it is). In fact, when if you Google for &lt;a href="http://www.google.com/search?rls=en&amp;amp;q=types+of+project+failure&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8"&gt;"types of project failures,"&lt;/a&gt; the hits in general are IT centric. This may not seem surprising, but I think the topic deserves more general treatment. I'm going to focus on product development and/or deployment type projects, although I suspect much can be generalized to other areas.&lt;/p&gt;
&lt;p&gt;Here's my list:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Failure to meet one or more readily measurable objectives (cost, schedule, testable requirements, etc)&lt;/li&gt;

  &lt;li&gt;Failure to deliver value consummate with the cost of the project&lt;/li&gt;

  &lt;li&gt;Unnecessary &lt;a href="http://en.wikipedia.org/wiki/Collateral_damage"&gt;collateral damage&lt;/a&gt; done to individuals or business relationships&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I think these are important because in my experience they are the types of failure that are traded "under the table." Most good project managers will watch their measurable objectives very closely, and wield them as a weapon as failure approaches. They can do this because objective measures rarely sufficiently reflect "true value" to the sponsor. They simply can't, because value is very hard to quantify, and may take months, years, or even decades to measure. By focusing on the objective measures, the PM can give the sponsor the opportunity to choose how he wants to fail (or "redefine success," depending on how you see it) without excessive blame falling of the project team.&lt;/p&gt;
&lt;h3&gt;Subjective Objective Failure&lt;/h3&gt;
&lt;p&gt;The objective measures of failure are what receive the most attention, because, well, they're tangible and people can actually act upon them. My definition of failure here is probably a bit looser than normal. I believe that every project involves an element of risk. If you allocate the budget and schedule for a project such that is has a 50% chance of being met - which may be a perfectly reasonable thing to do - and the project comes in over budget but within a reasonably expected margin relative to the uncertainty, then I think the project is still a success. The same goes for requirements. There's going to be some churn, because no set of requirements is ever complete. There's going to be some unmet requirements. There are always some requirements that don't make sense, are completely extraneous, or are aggressive beyond what is genuinely expected. The customer may harp on some unmet requirement, and the PM may counter with some scope increase that was delivered, but ultimately one can tell if stakeholders feel a product meets its requirements or not. It's a subjective measure, but it's a relatively direct derivation from objective measures.&lt;/p&gt;
&lt;h3&gt;Value Failure&lt;/h3&gt;
&lt;p&gt;Failure to deliver sufficient value is usually what the customer really cares about. One common situation I've seen is where requirements critical to the system's &lt;a href="http://en.wikipedia.org/wiki/Concept_of_Operations"&gt;ConOps&lt;/a&gt;, especially untestable ones or ones that are identified late in the game, are abandoned in the name of meeting more tangible measures. In a more rational world such projects would either be canceled or have success redefined to include sufficient resources to meet the ConOps. But the world is not rational. Sometimes the resources can't be increased because they are not available, but the sponsor or other team members chooses to be optimistic that they will become available soon enough to preserve the system's value proposition, and thus the team should soldier on. This isn't just budget and schedule - I think one of the more common problems I've seen is allocation of critical personnel. Other times it would be politically inconvenient to terminate a project due to loss of face, necessity of pointing out an inconvenient truth about some en vogue technology or process (e.g. one advocated by a politically influential group or person), or idle workers who cost just as much when they're idle as when they're doing something that might have value, or just a general obsession with &lt;a href="http://en.wikipedia.org/wiki/Sunk_costs"&gt;sunk costs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is where the "value consummate with the cost" comes in. Every project has an &lt;a href="http://en.wikipedia.org/wiki/Opportunity_cost"&gt;opportunity cost&lt;/a&gt; in addition to a direct cost. Why won't critical personnel be reallocated even though there's sufficient budget? Because they're working on something more important. A naive definition of value failure would be a negative &lt;a href="http://en.wikipedia.org/wiki/Return_on_Investment"&gt;ROI&lt;/a&gt;, or an ROI below the &lt;a href="http://en.wikipedia.org/wiki/Cost_of_capital"&gt;cost of capital&lt;/a&gt;, but it's often much more complicated.&lt;/p&gt;
&lt;p&gt;It's also important to note here that I'm not talking about promised ROI or other promised operational benefits. Often times projects are sold on the premise that they will yield outlandish gains. Sometimes people believe them. Often times they don't. But regardless, and usually perfectly possible to deliver significant value without meeting these promises. This would be a case of accepting objective failure because the value proposition is still there, it's just not as sweet as it was once believed to be.&lt;/p&gt;
&lt;h3&gt;Collateral Damage&lt;/h3&gt;
&lt;p&gt;Collateral damage receives a fair amount of press. We've all heard of, and most of us have one time or another worked, a &lt;a href="http://en.wikipedia.org/wiki/Death_march_(software_development)"&gt;Death March&lt;/a&gt; project. In fact, when I first thought about failure due to collateral damage, I thought any project causing significant collateral damage would also fall under at least one of the other two categories. It would be more a consequence of the others than a type unto itself. But then I thought about it, and realized experienced a couple projects where I feel the damage done to people was unacceptable, despite the fact that in terms of traditional measures and value delivered they were successful. There's a couple ways this can happen. One is that there are some intermediate setbacks from which the project ultimately recovers, but one or more people are made into &lt;a href="http://en.wikipedia.org/wiki/Scapegoating"&gt;scapegoats&lt;/a&gt;. Another way arises from interactions among team members that are allowed to grow toxic but never reach the point where they boil over. In my experience a common cause is an "extreme" performer, either someone who is really good or &lt;a href="http://www.pyxisinc.com/NNPP_Article.pdf"&gt;really bad&lt;/a&gt;, with a very &lt;a href="http://c2.com/cgi/wiki?PrimaDonna"&gt;difficult personality&lt;/a&gt;, particularly when the two are combined on a project with weak management.&lt;/p&gt;
&lt;p&gt;Now, you might be wondering what the necessary causes of collateral damage are. It's actually fairly simple. Consider a large project that involves a large subcontract. The project may honestly discover that the value contributed by the subcontract does not justify its cost, or that the deliverables of the subcontract are entirely unnecessary. In this case the subcontract should be terminated, which in turn is likely to lead to a souring of the business relationship between the contractor and the subcontractor, along with potentially significant layoffs at the subcontractor. Often times a business must take action, and there will be people or other businesses who lose out through no fault of their own.&lt;/p&gt;
&lt;h3&gt;Back to Trading Among Failure Types&lt;/h3&gt;
&lt;p&gt;A Project Manager, along with projects sponsors and other key stakeholders, may actively choose which type of failure, or balance among them, is most desirable. Sometimes this "failure" can even really be success, so long as significant value is delivered. Some of the possible trades include:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Failing to meet budget and schedule in order to ensure value.&lt;/li&gt;

  &lt;li&gt;Sacrificing value in order to meet budget and schedule...&lt;/li&gt;

  &lt;li&gt;...potentially to avoid the collateral damage that would be inflicted in the case of an overt failure&lt;/li&gt;

  &lt;li&gt;Inflicting collateral damage through practices such as continuous overtime in order to ensure value or completing on target&lt;/li&gt;

  &lt;li&gt;Accepting reduced value or increased budget/schedule in order to avoid the collateral damage of the political fallout for not using a favored technology or process&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ultimately some of these trades are inevitable. Personally, I strongly prefer focusing on value. Do what it takes while the value proposition remains solid and the project doesn't resemble a money pit. Kill it when the value proposition disappears or it clearly becomes an infinite resource sink. But of course I know this is rather naive, and sometimes preventing political fallout, which I tend to willfully ignore in my question for truth, justice, and working technology; has an unacceptable if intangible impact. One of my most distinct memories is having a long conversation with a middle manager about a runaway project, and at the end being told something like "Erik, I agree with you. I know you're right. We're wasting time and money. But the money isn't worth the political mess it would create if I cut it off or forcefully reorganized the project." I appreciated the honesty, but it completely floored me, because it meant not only that politics could trump money, but politics could trump my time, which was being wasted. Now I see the wisdom in it, and simply try to avoid such traps when I see them and escape them as quickly as possible when I trip over them.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7953611282637715349?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7953611282637715349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7953611282637715349' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7953611282637715349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7953611282637715349'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2011/01/types-of-project-failure.html' title='Types of Project Failure'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-2124077355529853700</id><published>2011-01-03T12:49:00.001-05:00</published><updated>2011-01-03T12:53:06.291-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorithms'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>StackOverflow and Scraper Sites</title><content type='html'>&lt;p&gt;I recently noticed that Google searches were turning up a lot of sites that mirror &lt;a href="http://stackoverflow.com"&gt;StackOverflow&lt;/a&gt; content as opposed to the originals. It appears that I'm not alone. This morning &lt;a href="http://www.codinghorror.com/blog/2004/02/about-me.html"&gt;Jeff Atwood&lt;/a&gt; blogged about how they're having increasing problems with these sites receiving &lt;a href="http://www.codinghorror.com/blog/2011/01/trouble-in-the-house-of-google.html" title="Trouble in the House of Google"&gt;higher Google rankings&lt;/a&gt;. His post, and especially the comments, are filled with righteous indignation about how it's the end of the Internet as we know it. Of course, I can't remember a time when search results weren't polluted faked-out results, so I don't understand why he's so surprised.&lt;/p&gt;
&lt;p&gt;But I do think this situation is different. The difference is that in many cases the presentation is far different from my previous exposure to &lt;a href="http://en.wikipedia.org/wiki/Link_farm" title="Link Farm - Wikipedia"&gt;link farms&lt;/a&gt;. Historically, my impression is that pages on such sites generally have the following attributes:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;The recycled content is poorly formated and often truncated&lt;/li&gt;
  &lt;li&gt;Unrelated content from multiple sources is lumped together in a single page (usually there is some common keyword)&lt;/li&gt;
  &lt;li&gt;Advertisements are extremely dominant and often unrelated to the content&lt;/li&gt;
  &lt;li&gt;The link-to-content ratio is often very high, and the links are to unrelated content&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In fact, I think if one were to develop a set of quantitative metrics that could be automatically measured for pages based on the above criteria, I think StackOverflow would perform worse than some of the sites that mirror its content. It's rather ironic, but if you think about it, if you wanted to defeat an algorithm that was developed to find the "best" source for some common content, you'd do everything you could to make your scraper site look more legitimate than the original. Let's compare a question on &lt;a href="http://stackoverflow.com/questions/1833762/scala-reflection-getdeclaringtrait"&gt;StackOverflow&lt;/a&gt; with it's cousin on &lt;a href="http://efreedom.com/Question/1-1833762/Scala-Reflection-GetDeclaringTrait"&gt;eFreedom.com&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Analysis&lt;/h3&gt;
&lt;p&gt;The primary content is essentially the same with similar formatting. The two major differences are that eFreedom only directly displays the selected answer, as opposed to all of the answers with the selected answer on the top, and none of the comments are displayed. This may help avoid triggering the "unrelated content" rule, because the selected answer is probably the most cohesive with the question, and comments frequently veer off-topic. But I suspect the affect is minimal.&lt;/p&gt;
&lt;p&gt;Now consider the advertisements. eFreedom has a few more, but they are more closely tied to the content (using Google AdWords, which probably helps). The advertisements on StackOverflow are for jobs identified via geolocation (I live in Maryland), and the words in them don't correlate particularly well to the primary content, even though they are arguably more relevant to StackOverflow users that run-of-the-mill AdWords ones.&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_-ZOtVRo0ba8/TSIMBpUGgKI/AAAAAAAAAFk/Eu-xALjVoDg/s1600/so_ads.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 151px; height: 320px;" src="http://1.bp.blogspot.com/_-ZOtVRo0ba8/TSIMBpUGgKI/AAAAAAAAAFk/Eu-xALjVoDg/s320/so_ads.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5558018112538181794" /&gt;&lt;/a&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-ZOtVRo0ba8/TSIMR0GjjEI/AAAAAAAAAFs/8rI7wmHrv40/s1600/efreedom_ads.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 42px;" src="http://3.bp.blogspot.com/_-ZOtVRo0ba8/TSIMR0GjjEI/AAAAAAAAAFs/8rI7wmHrv40/s320/efreedom_ads.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5558018390312062018" /&gt;&lt;/a&gt;
&lt;p&gt;Now let's consider the related links. StackOverflow has links to ~25 related questions in a column along the side. The only content from the questions in the title, and the majority seem to be related based on matching a single tag from the question. eFreedom, on the other hand has links to 10 related questions (they appear to be matching on both tags), puts them inline with the main content, and includes a brief summary. As a human being I think the StackOverflow links are much more noisy and less useful. If I try to think like an algorithm, what I notice is StackOverflow has a higher link-to-content ratio, and the links are to more weakly related content.&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_-ZOtVRo0ba8/TSIMooIij6I/AAAAAAAAAF8/uWHIGqaK8gI/s1600/so_related.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 213px; height: 174px;" src="http://1.bp.blogspot.com/_-ZOtVRo0ba8/TSIMooIij6I/AAAAAAAAAF8/uWHIGqaK8gI/s320/so_related.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5558018782236151714" /&gt;&lt;/a&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-ZOtVRo0ba8/TSIMcEcyQnI/AAAAAAAAAF0/y31W-Y3QbRM/s1600/efreedom_related.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 63px;" src="http://3.bp.blogspot.com/_-ZOtVRo0ba8/TSIMcEcyQnI/AAAAAAAAAF0/y31W-Y3QbRM/s320/efreedom_related.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5558018566498959986" /&gt;&lt;/a&gt;
&lt;p&gt;
The only other major difference is that eFreedom has a "social network bar" on the page. I'm not sure how this would affect ranking. It probably helps with obtaining links.
&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_-ZOtVRo0ba8/TSIM2TNocNI/AAAAAAAAAGE/uRB4HkF4XWc/s1600/efreedom_social.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 26px;" src="http://2.bp.blogspot.com/_-ZOtVRo0ba8/TSIM2TNocNI/AAAAAAAAAGE/uRB4HkF4XWc/s320/efreedom_social.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5558019017138532562" /&gt;&lt;/a&gt;
&lt;p&gt;
If you look at the HTML for each page, both use Google Analytics, both use what I'm assuming is a CDN for images, and StackOverflow appears to have a second analysis service. On casual inspection, neither appear to be laden with external content for tracking purposes, although without deeper inspection there's no way to be sure. But I presume a having a large number of tracking links would make a site look more like spam, and having few of them make it look more legit.
&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;I don't think either site looks like spam, but between the two, StackOverflow has more spam-like characteristics. eFreedom's content and links are considerably less noisy than StackOverflow's. Is eFreedom being a leach? Yes, certainly, but it, and I believe some of the other sites replicating StackOverflow's content, don't look like traditional link-spam sites. In fact, for a person who is just looking for content, as opposed to looking to participate in a community, then eFreedom is at least as good, if not slightly better. There may be a moral argument that the original source should be given priority over replications, but from a pure content quality perspective StackOverflow and its copiers are essentially identical, and computer algorithms aren't generally in the business of making moral judgements. Also, there are many forums and mailing list archives out there that have atrocious user interfaces where the casual searcher is likely better off being directed to a content aggregator than to the original source, so I don't think a general rule giving preference to original sources would be productive. Ultimately, I think open community sites like StackOverflow are going to have to compete with better SEO and perhaps better search and browsing UI's for non-contributors, rather than relying up search engines to perform some miracle, because the truth is that from a content consumption perspective the replicated sites are just as good.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-2124077355529853700?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/2124077355529853700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=2124077355529853700' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2124077355529853700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2124077355529853700'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2011/01/stackoverflow-and-scraper-sites.html' title='StackOverflow and Scraper Sites'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_-ZOtVRo0ba8/TSIMBpUGgKI/AAAAAAAAAFk/Eu-xALjVoDg/s72-c/so_ads.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-8530813039474343285</id><published>2010-12-28T18:54:00.003-05:00</published><updated>2010-12-28T19:09:23.762-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Easier object inspection in the Scala REPL</title><content type='html'>&lt;p&gt;
If you're like me, you spend a fair amount of time poking at objects of poorly documented classes in a REPL (Scala or otherwise...).  This is great compared to writing whole test programs solely for the purpose of seeing what something does or what data it really contains, but it can be quite time consuming.  So I've written a utility for use on the Scala REPL that will print out all of the "attributes" of an object.  Here's some sample usage:
&lt;/p&gt;
&lt;pre&gt;
scala&gt; import replutils._
import replutils._

scala&gt; case class Test(a: CharSequence, b: Int)
defined class Test

scala&gt; val t = Test("hello", 1)
t: Test = Test(hello,1)

scala&gt; printAttrValues(t)
hashCode: int = -229308731
b: int = 1
a: CharSequence (String) = hello
productArity: int = 2
getClass: Class = class line0$object$$iw$$iw$Test
&lt;/pre&gt;
&lt;p&gt;
That looks fairly anti-climatic, but after spending hours typing objName.&lt;tab&gt; to see what's there, and poking at methods, it seems like a miracle.  Also, one neat feature of it is that if the class of the object returned is different from the class declared on the method, it prints both the declared class and the actual returned class.
&lt;/p&gt;
&lt;p&gt;
Code and further usage instructions is available on BitBucket &lt;a href="https://bitbucket.org/eengbrec/scala-repl-utils/wiki/Home"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;h3&gt;So what exactly is an attribute?&lt;/h3&gt;
&lt;p&gt;
I haven't quite figured that out yet.  Right now it is any method that meets the following criteria:
&lt;ol&gt;
&lt;li&gt;the method has zero arguments&lt;/li&gt;
&lt;li&gt;the method is public&lt;/li&gt;
&lt;li&gt;the method is not static&lt;/li&gt;
&lt;li&gt;the method's name is not on the exclude list (e.g. wait)&lt;/li&gt;
&lt;li&gt;the method's return type is not on the exclude list (e.g. Unit/void)&lt;/li&gt;
 &lt;li&gt;the method is not a "default argument" method&lt;/li&gt;
&lt;/ol&gt;
Please post any feedback in the comments here, or better yet in the &lt;a href="https://bitbucket.org/eengbrec/scala-repl-utils/issues?status=new&amp;status=open"&gt;issue tracker&lt;/a&gt; on Bitbucket.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-8530813039474343285?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/8530813039474343285/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=8530813039474343285' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8530813039474343285'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8530813039474343285'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/12/easier-object-inspection-in-scala-repl.html' title='Easier object inspection in the Scala REPL'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-3112160071011846346</id><published>2010-12-27T21:25:00.003-05:00</published><updated>2010-12-27T22:12:18.369-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Playing with Scala Products</title><content type='html'>&lt;p&gt;
Have you ever wanted something like a case class, that magically provides decent (for some definition of decent) implementations of methods like equals and hashCode, but without all of the restrictions?  I know that I have.  Frequently.  And recently I ran into an answer on &lt;a href="http://stackoverflow.com/questions/4526706/what-code-is-generated-for-an-equals-hashcode-method-of-a-case-class"&gt;StackOverflow&lt;/a&gt; that gave me an idea for how to do it.  The trick is to play with Products.  I'm not sure how good of an idea it is, but I figure the Internet will tell me.  Here's the basic idea:
&lt;/p&gt;
&lt;pre&gt;
import scala.runtime.ScalaRunTime

trait ProductMixin extends Product {
  def canEqual(other: Any) = toProduct(other) ne null
  protected def equalityClass = getClass
  protected def equalityClassCheck(cls: Class[_]) = equalityClass.isAssignableFrom(cls)
  protected def toProduct(a: Any): Product = a match {
    case a: Product if productArity == a.productArity &amp;&amp; equalityClassCheck(a.getClass) =&gt; a
    case _ =&gt; null
  }
  override def equals(other: Any) = toProduct(other) match {
    case null =&gt; false
    case p if p eq this =&gt; true
    case p =&gt; {
      var i = 0
      var r = true
      while(i &lt; productArity &amp;&amp; r) {
 if (productElement(i) != p.productElement(i)) r = false
 i += 1
      }
      r
    }
  }
  override def productPrefix = try {
    getClass.getSimpleName()
  } catch {
    //workaround for #4118, so classes can be defined in the REPL that extend ProductMixin
    case e: InternalError if e.getMessage == "Malformed class name" =&gt; getClass.getName()
  }
  override def hashCode = ScalaRunTime._hashCode(this)
  override def toString = ScalaRunTime._toString(this)
}
&lt;/pre&gt;
&lt;h3&gt;Basic Usage&lt;/h3&gt;
&lt;p&gt;
There's a couple ways to use ProductMixin.  The first, and probably the simplest, is to extends one of the ProductN classes and provide the appropriate defs:
&lt;/p&gt;
&lt;pre&gt;
class Cat(val name: String, val age: Int) extends Product2[String, Int] with ProductMixin {
  def _1 = name
  def _2 = age
}
&lt;/pre&gt;
&lt;p&gt;
The second way is to provide them yourself:
&lt;/p&gt;
&lt;pre&gt;
 class Dog(val name: String, age: Int) extends ProductMixin {
  def productArity = 2
  def productElement(i: Int) = i match {
    case 0 =&gt; name
    case 1 =&gt; age
  }
}
&lt;/pre&gt;
&lt;p&gt;Either way, the result is something that has many of the benefits of case classes but allows for more flexibility.  Here's some sample usage:
&lt;/p&gt;
&lt;pre&gt;
scala&gt; val c1 = new Cat("Felix", 2)
val c1 = new Cat("Felix", 2)
c1: Cat = Cat(Felix,2)

scala&gt; val c2 = new Cat("Alley Cat", 1)
val c2 = new Cat("Alley Cat", 1)
c2: Cat = Cat(Alley Cat,1)

scala&gt; val c3 = new Cat("Alley Cat", 1)
val c3 = new Cat("Alley Cat", 1)
c3: Cat = Cat(Alley Cat,1)

scala&gt; c2 == c3
c2 == c3
res0: Boolean = true

scala&gt; c1 == c2
c1 == c2
res1: Boolean = false
&lt;/pre&gt;
&lt;h3&gt;Dealing with Inheritance&lt;/h3&gt;
&lt;p&gt;
Equality in the presence of inheritance is very tricky.  But, possibly foolishly, ProductMixin makes it easy!  Let's say you have a hierarchy, and you want all the classes under some root class to be able to equal each other.  Here's how it would be done by overriding the equalityClass so that it is the root of the hierarchy (using a not-so-good example):
&lt;/p&gt;
&lt;pre&gt;
scala&gt; abstract class Animal(val name: String, val age: Int) extends Product2[String, Int] with ProductMixin {
     | override protected def equalityClass = classOf[Animal]
     | def _1 = name
     | def _2 = age
     | }
defined class Animal

scala&gt; class Dog(name: String, age: Int) extends Animal(name, age)
class Dog(name: String, age: Int) extends Animal(name, age)
defined class Dog

scala&gt; class Cat(name: String, age: Int) extends Animal(name, age)
class Cat(name: String, age: Int) extends Animal(name, age)
defined class Cat

scala&gt; val c = new Cat("Felix", 1)
val c = new Cat("Felix", 1)
c: Cat = Cat(Felix,1)

scala&gt; val d = new Dog("Felix", 1)
val d = new Dog("Felix", 1)
d: Dog = Dog(Felix,1)

scala&gt; c == d
c == d
res0: Boolean = true
&lt;/pre&gt;
&lt;p&gt;
The reverse can also be accomplished by overriding equalityClassCheck such that it checks that the classes are equal instead of using isAssignableFrom.  That would mean two objects could be equal if and only if they are the same class.
&lt;/p&gt;
&lt;h3&gt;Wrapup&lt;/h3&gt;
&lt;p&gt;
I don't know to what extent this is a good idea.  I've only tested it a bit in the REPL.  It's neat, but there is one problem that comes to mind: performance.  Any primitive members that are elements of the product will end up being boxed prior to usage in the hashCode and equality methods, the extra layers of indirection aren't free, and neither is the loop.  That being said, case classes use the exact same method for hashing, so in what way they pay the same penalty, and unless code is really hashing and equality heavy it probably wouldn't be noticeable.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-3112160071011846346?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/3112160071011846346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=3112160071011846346' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3112160071011846346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3112160071011846346'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/12/playing-with-scala-products.html' title='Playing with Scala Products'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-1452176707084833322</id><published>2010-08-26T07:44:00.003-04:00</published><updated>2010-08-26T08:29:16.706-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='microsoft'/><title type='text'>Scala is for VB programmers</title><content type='html'>&lt;p&gt;
Normally I don't go for flame bait titles.  But I haven't finished my morning coffee yet so I can't help myself.  There's once again a debate raging across the internet about whether Scala is more or less complex than Java, along with the more nuanced argument that yes, it is more complex but only framework and library developers have to contend with this complexity.  This argument usually happens when someone &lt;a href="http://java.dzone.com/articles/scala-complex-yes-and"&gt;posts a little bit of code like this&lt;/a&gt;:
&lt;/p&gt;
&lt;pre&gt;
def map[B, That](f: A =&gt; B)(implicit bf: CanBuildFrom[Repr, B, That]): That
&lt;/pre&gt;
&lt;p&gt;
And then someone responds &lt;a href="http://warpedjavaguy.wordpress.com/2010/08/02/the-scala-is-too-complex-conspiracy-1/#comment-400"&gt;like this:&lt;/a&gt;
&lt;/p&gt;
&lt;blockquote&gt;
Why do not people realize that Java is too difficult for the average programmer? That is the true purpose of Scala, to escape the complexity of Java code!

Framework code in Scala, with heavy use of implicit keywords and all kinds of type abstractions, is very difficult. This is correct, but this code is not meant for innocent eyes. You do not use that sort of code when you write an application.
&lt;/blockquote&gt;
&lt;p&gt;
I've seen this type of thinking before.  A few years ago I had a bout of insanity and lead an ASP.NET project using ASP.NET 2.0.  I had no .NET experience prior to this project.  The project failed, although the reasons for that failure are legion and unimportant here.  But I noticed something about ASP.NET developers: they have no clue how the technology works.  It's a black box.  Do you why?  Because it &lt;b&gt;is&lt;/b&gt; a black box.  I searched and searched and couldn't even find a good illustration of the lifecycle for an ASP.NET page that's using events.  This type of information is put front and center in the Java world.  It's absolutely buried in the Microsoft world.  Or at least the parts of it that target the hoards of VB programmers that are undyingly loyal to MS.  The framework is magic dust created by the great wizards in Redmond so that you can build solutions for your customers.  Do not question the dust.  Think about VB.  Or, no don't, it might damage your brain.  My coffee hasn't quite kicked in, so I should have some immunity, so I'll do it for you.  VB is a black box (well, at old school VB6).  It was designed to allow people who do not know how to really program, and who will probably never know how to program, to create applications.  It's completely flat, opaque abstraction.  The dichotomy between the application developer and the framework developer is as high and as thick as the gates of Mordor.
&lt;/p&gt;
&lt;p&gt;
There are many people in the Scala community that claim Scala's complexity can be hidden from the application program.  I don't believe them, but there's a chance that they are right.   It's technically feasible, and I can see how it could happen if Scala started attracting lots of VB programmers.  I can't see how it's going to attract lots of VB programmers, but apparently many people in the Scala community think Scala is for VB programmers.  So we'll just have to wait and see...
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-1452176707084833322?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/1452176707084833322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=1452176707084833322' title='46 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/1452176707084833322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/1452176707084833322'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/08/scala-is-for-vb-programmers.html' title='Scala is for VB programmers'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>46</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-3926620988428095194</id><published>2010-08-22T21:41:00.003-04:00</published><updated>2010-08-22T22:28:45.220-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='benchmarks'/><title type='text'>Scala Actors: loop, react, and schedulers</title><content type='html'>&lt;p&gt;
One of the unfortunate aspects of many of the "published" (meaning blogged) &lt;a href="http://www.scala-lang.org/node/242"&gt;Scala Actor&lt;/a&gt; benchmarks out there is that they rarely pay much attention, if any, to the affects of seemingly idiomatic patterns on performance.  Some of the main culprits are:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;react versus receive (event-based versus threaded)&lt;/li&gt;
&lt;li&gt;loop/react versus recursive react&lt;/li&gt;
&lt;li&gt;loop/receive versus receive/while&lt;/li&gt;
&lt;li&gt;tweaking (or failing to tweak) the scheduler&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
I've been working on setting up a "benchmarking framework" in conjunction with experimenting with modifications to the underlying thread pool so that all the possible permutations are automatically tested.  What I have right now is a classic "ring" benchmark setup to permute the schedulers and loop/react versus recursive react.  The loop/react pattern is more idiomatic (or at least more common), but higher overhead, and it looks something like this:
&lt;/p&gt;
&lt;pre&gt;
loop {
  react {
    case Msg(m) =&gt; // do stuff
    case Stop =&gt; exit()
  }
}
&lt;/pre&gt;
&lt;p&gt;
The reason it is high-overhead is that both loop and react raise control flow exceptions that result in the creation of new tasks for the thread pool when they are hit, so for each loop, two exceptions are raised and two tasks are executed.  There's overhead in both of the operations, especially raising the exceptions.  The recursive react pattern looks like this, so it can avoid the extra exception/task:
&lt;/p&gt;
&lt;pre&gt;
def rloop(): Unit = react {  //this would be called by the act() method
  case Msg(m) =&gt; {
    // do stuff
    rloop()
  }
  case Stop =&gt; // just drop out or call exit()
}
&lt;/pre&gt;
&lt;p&gt;
Using loop instead of recursive react effectively doubles the number of tasks that the thread pool has to execute in order to accomplish the same amount of work, which in turn makes it so any overhead in the scheduler is far more pronounced when using loop.  Now, I should point out that the overhead really isn't that large, so if the actor is performing significant computations it will be lost in the noise.  But it's fairly common to have actors do fairly little with each message.  Here's some results from the ring benchmark using 10 rings of 10,000 actors passing a token around them 100 times before exiting.  I'm using multiple rings because otherwise there is no parallelism in the benchmark.  These are being run on my dual core Macbook.
&lt;/p&gt;
&lt;table border="1"&gt;
&lt;tr&gt;
  &lt;th&gt;Scheduler&lt;/th&gt;&lt;th&gt;ReactMethod&lt;/th&gt;&lt;th&gt;Time (sec)&lt;/th&gt;
&lt;tr&gt;
&lt;tr&gt;
  &lt;td&gt;ManagedForkJoinScheduler&lt;/td&gt;&lt;td&gt;LoopReact&lt;/td&gt;&lt;td&gt;45.416058&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;ManagedForkJoinScheduler&lt;/td&gt;&lt;td&gt;RecursiveReact&lt;/td&gt;&lt;td&gt;25.509482&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;ForkJoinScheduler&lt;/td&gt;&lt;td&gt;LoopReact&lt;/td&gt;&lt;td&gt;65.268584&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;ForkJoinScheduler&lt;/td&gt;&lt;td&gt;RecursiveReact&lt;/td&gt;&lt;td&gt;45.85605&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;ResizableThreadPoolScheduler&lt;/td&gt;&lt;td&gt;LoopReact&lt;/td&gt;&lt;td&gt;98.084794&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;ResizableThreadPoolScheduler&lt;/td&gt;&lt;td&gt;RecursiveReact&lt;/td&gt;&lt;td&gt;53.379757&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;
The fork/join schedulers are faster than the ResizableThreadPoolScheduler because rather than have all of the worker threads pull tasks off of a single, shared queue; each thread maintains its own local dequeue where it can place tasks directly onto if they are generated while it is running a task.  This creates a kind of "fast path" for the tasks that involves much less overhead.
&lt;/p&gt;
&lt;p&gt;
I believe the primary reason ManagedForkJoinScheduler is faster because ForkJoinScheduler does not always leverage the "fast path," even when in theory it could be used.  I'm unsure about some of the rationale behind it, but I know some of the time the fast path is bypassed probabilistically in order to reduce the chances of starvation causing deadlock in the presence of long running or blocking tasks.  ManagedForkJoinScheduler escapes this particular issue by more actively monitoring the underlying thread pool, and growing it when tasks are being starved.   The second reason, and I'm somewhat unsure of the actual degree of the affects, if that ForkJoinScheduler configures the underlying thread pool so that the threads work through the local dequeues in FIFO order, while ManagedForkJoinScheduler configures the pool such that the local dequeues are processed in LIFO order.  Processing in LIFO order allows the pool to take advantage of locality with regard to the tasks, basically assuming that the last task generated is the most likely to use data that's currently in cache, and thus reduce cache misses.
&lt;/p&gt;
&lt;p&gt;
The benchmark outputs a lot more information than I captured in the above table.  If you'd like to run it, you can obtain the code &lt;a href="https://bitbucket.org/eengbrec/managedforkjoinpool"&gt;here&lt;/a&gt;.  The project uses &lt;a href="http://code.google.com/p/simple-build-tool/"&gt;sbt&lt;/a&gt;, so you'll need to have it working on your computer.  After you run update in sbt to download all of the dependencies, you can run the ring benchmark as follows:
&lt;/p&gt;
&lt;pre&gt;
$ sbt
[info] Building project ManagedForkJoinPool 1.0 against Scala 2.8.0
[info]    using ManagedForkJoinPoolProject with sbt 0.7.4 and Scala 2.7.7
&gt; ringbenchmark
[info] 
[info] == compile ==
[info]   Source analysis: 1 new/modified, 0 indirectly invalidated, 0 removed.
[info] Compiling main sources...
[info] Compilation successful.
[info]   Post-analysis: 79 classes.
[info] == compile ==
[info] 
[info] == copy-resources ==
[info] == copy-resources ==
[info] 
[info] == ringbenchmark ==
[info] RingBenchmark ManagedForkJoinScheduler LoopReact 2 ....output truncated...
&lt;/pre&gt;
&lt;p&gt;
You can tweak the benchmarks by modifying the sbt project file.  If you do run them, I'm very interested in the results.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-3926620988428095194?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/3926620988428095194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=3926620988428095194' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3926620988428095194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3926620988428095194'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/08/scala-actors-loop-react-and-schedulers.html' title='Scala Actors: loop, react, and schedulers'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4428924252454371333</id><published>2010-08-21T15:09:00.006-04:00</published><updated>2010-08-21T17:10:19.100-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='sbt'/><category scheme='http://www.blogger.com/atom/ns#' term='benchmarks'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Concurrency Benchmarking, Actors, and sbt tricks</title><content type='html'>&lt;p&gt;
Have you ever noticed that other people's &lt;a href="http://en.wikipedia.org/wiki/Benchmark_(computing)"&gt;microbenchmarks&lt;/a&gt; tend to be hard to run and often impossible to duplicate?  And are frequently caveated to the hilt?  When it gets down to it, a benchmark is really an experiment, and ideally a scientific experiment.  That means all factors that are relevant to the results should be clearly recorded, and the tests should be easy for others to duplicate.
&lt;/p&gt;
&lt;h3&gt;Custom sbt actions for benchmarks&lt;/h3&gt;
&lt;p&gt;
In order to test and run benchmarks on the work I'm doing around creating a managed variant of the &lt;a href="http://artisans-serverintellect-com.si-eioswww6.com/default.asp?W9"&gt;JSR-166y&lt;/a&gt; &lt;a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166ydocs/jsr166y/ForkJoinPool.html"&gt;ForkJoinPool&lt;/a&gt; along with supporting infrastructure for use with &lt;a href="http://www.scala-lang.org/node/242"&gt;Scala Actors&lt;/a&gt;, I'm creating a &lt;a href="https://bitbucket.org/eengbrec/managedforkjoinpool/src/tip/src/main/scala/actorbench/TestHarness.scala"&gt;test harness&lt;/a&gt; that captures &lt;a href="https://bitbucket.org/eengbrec/managedforkjoinpool/src/1cf3a55d2aa0/src/main/scala/actorbench/TestHarness.scala#cl-107"&gt;a host of environmental factors&lt;/a&gt; about how it was run, and writing &lt;a href="http://code.google.com/p/simple-build-tool/wiki/CustomActions"&gt;sbt actions&lt;/a&gt; to make it easy to run the benchmarks and automatically permute the variables.
&lt;/p&gt;
&lt;p&gt;
It still needs a lot of work, but I had some trouble figuring out a really basic task so I thought I'd share it.  Basically I wanted to build a &lt;a href="http://simple-build-tool.googlecode.com/svn/artifacts/latest/api/sbt/TaskManager.Task.html"&gt;Task object&lt;/a&gt; that consists of several tasks based on information in the project definition and permuted parameters.  It actually pretty easy, as you can see in the snippet below from my project definition:
&lt;/p&gt;
&lt;pre&gt;
  /** this task executes the PingPong benchmark using each available scheduler */
  lazy val pingpongbench = pingpongTaskList
  /** produces a sequence of run tasks using all the available schedulers  */
  def pingpongTaskList = {
    val pairs = 100
    val messagesPerPair = 10000
    val tasks = for(sched &lt;- schedulers) yield pingpongTask(sched, pairs, messagesPerPair)
    tasks.reduceLeft((a, b) =&gt; a &amp;&amp; b)
  }
&lt;/pre&gt;
&lt;p&gt;You can see the whole file &lt;a href="https://bitbucket.org/eengbrec/managedforkjoinpool/src/1cf3a55d2aa0/project/build/ManagedForkJoinPool.scala"&gt;here&lt;/a&gt;.  Basically &lt;code&gt;Task&lt;/code&gt; has an &lt;code&gt;&amp;&amp;&lt;/code&gt; operator that essentially allows you to concatenate one task with another task.  This allows you to build a whole chain of tasks.  In the example above, I'm having it run the benchmark once for each scheduler configuration.  Soon, I'm going to make it permute other parameters.  But right now my test harness isn't playing nicely with the schedulers included in the Scala distribution, so first things first.&lt;/p&gt;
&lt;p&gt;
There's also one other little customization, which is documented, but I think it's important for benchmarking.  By default, sbt runs your code in its own process.  This can cause &lt;a href="http://code.google.com/p/simple-build-tool/wiki/RunningProjectCode"&gt;problems&lt;/a&gt; with multithreaded code, especially if it doesn't terminate properly.  It also means the next benchmark to run has to content with any junk that the previous benchmark left around.  So I configured sbt to &lt;a href="http://code.google.com/p/simple-build-tool/wiki/Forking"&gt;fork&lt;/a&gt; new processes.  It just required one line:
&lt;/p&gt;
&lt;pre&gt;
override def fork = forkRun
&lt;/pre&gt;
&lt;h3&gt;Important variables&lt;/h3&gt;
&lt;p&gt;
Here's what I'm capturing for each run right now so that the results can all be dumped into a big spreadsheet for analysis.  I'd like to capture more information about the host machine, such as more information about the CPUs and the loading when the benchmark is being run, but haven't got that far yet.  Currently these are all captured from within the benchmark process, mostly using &lt;a href="http://download.oracle.com/javase/6/docs/api/java/lang/System.html#getProperties()"&gt;system properties&lt;/a&gt; and the &lt;a href="http://download.oracle.com/javase/6/docs/api/java/lang/Runtime.html"&gt;Runtime&lt;/a&gt; object.
&lt;/p&gt;
&lt;ol&gt;
 &lt;li&gt;Test Name - obviously needed so that results from multiple benchmarks can be stored in the same file&lt;/li&gt;
  &lt;li&gt; Scheduler - this is my primary variable right now, I want to run each benchmark with each scheduler while holding everything else constant&lt;/li&gt;
  &lt;li&gt;# of Cores/Processors - essential so that anyone looking at the results has an idea about the hardware used&lt;/li&gt;
  &lt;li&gt;Java VM Name - different VMs can perform quite differently&lt;/li&gt;
  &lt;li&gt;Java VM Version - performance characteristics change from version to version (usually getting better)&lt;/li&gt;
  &lt;li&gt;Java Version - same reason as above, but this is probably the more publicly known version number&lt;/li&gt;
  &lt;li&gt;Scala Version - this could be important in the future, as it becomes more common for different projects to be on different version of Scala&lt;/li&gt;
  &lt;li&gt;OS Name and version - again, it can affect performance&lt;/li&gt;
  &lt;li&gt;Processor Architecture&lt;/li&gt;
  &lt;li&gt;Approximate Concurrency (number of simultaneously alive actors) - this allows us to examine concurrency levels versus resource consumption, more concurrency does not necessarily mean that more cores or threads would be helpful&lt;/li&gt;
  &lt;li&gt;Approximate Parallelism (number of simultaneously runnable actors) - this measures how many cores/threads the benchmark can really keep busy&lt;/il&gt;
  &lt;li&gt;Approximate Total Messages - this estimates the amount of activity that takes place during the benchmark, generally the benchmarks I'm looking at contain very little logic because they are intended to measure overhead introduced by the framework&lt;/li&gt;
  &lt;li&gt;Total Wall Clock Time (seconds) - as measured using nanoTime within the benchmark process&lt;/li&gt;
  &lt;li&gt;Initial Thread and Maximum Observed Thread Count - used to examine automatic expansion of the thread pool&lt;/li&gt;
  &lt;li&gt;Initial Free Memory and Minimum Observed Free Memory - threads use a fair amount of memory, so performance impacts may show up as pressure on the GC as well has contention for the CPU&lt;/li&gt;
  &lt;li&gt;Initial and Maximum Observed Total Memory - threads use a lot of memory, so it's important to track usage&lt;/li&gt;
  &lt;li&gt;Verbose - debugging output pretty much invalidates any of these tests&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/19725519-4428924252454371333?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4428924252454371333/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4428924252454371333' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4428924252454371333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4428924252454371333'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/08/concurrency-benchmarking-actors-and-sbt.html' title='Concurrency Benchmarking, Actors, and sbt tricks'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4795895098451857372</id><published>2010-08-08T18:33:00.007-04:00</published><updated>2010-08-10T21:24:28.721-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Improving Schedulers for High-level, Fine-grained Concurrency Frameworks</title><content type='html'>&lt;p&gt;
Quite a while ago, &lt;a href="http://biosimilarity.blogspot.com/"&gt;Greg Meredith&lt;/a&gt; made a &lt;a href="http://scala-programming-language.1934581.n4.nabble.com/Re-scala-user-Profiling-Actor-based-server-Lots-of-time-in-FJTaskRunner-td2008446.html#a2008446"&gt;comment&lt;/a&gt; that really made me stop and think, and that has been lingering in the back of my mind ever since:
&lt;blockquote&gt;
Erik, Alex, John, et al,

i'm loathe to hijack this thread -- which is a good one -- but the experience with the lock up described below is really just the tip of the iceberg. Unless specific scheduling contracts and semantics can be worked out, a pluggable scheduling architecture is just asking for disaster. Worse, it means that a whole host of compiler support that could be provided to apps that use actor-based concurrency is null and void because those solutions (be they model-checking or types-based) will critically depend on specific ranges of scheduling semantics.

Actors and other higher level concurrency constructs are a major appeal of languages like scala. If they prove themselves to be "not ready for prime time" the impact on perception might not be contained to just that usage of the language.

Best wishes,

--greg
&lt;/blockquote&gt;
That wasn't the &lt;a href="http://scala-programming-language.1934581.n4.nabble.com/scala-Actors-and-scheduling-td1997822.html#a1997825"&gt;first time&lt;/a&gt; that Greg made a comment along those lines, and it certainly wasn't the last.  At one point he &lt;a href="http://www.scala-lang.org/node/2825"&gt;offered to allow a few individuals look at some older code&lt;/a&gt; that he believed could help.  Greg's a really smart guy.  If he's worried, we should all be worried.
&lt;/p&gt;
&lt;h3&gt;Empirical Evidence of the Problem&lt;/h3&gt;
&lt;p&gt;
Contrary to what many may think this is hardly an academic problem.  A significant portion of the issues people new to Scala Actors have trace to the fact that they expect the scheduler to be making guarantees that it simply does not make.  Here's a sampling:
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://scala-programming-language.1934581.n4.nabble.com/Actor-not-creating-enough-threads-td1935577.html"&gt;Actors not creating enough threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/2288723/scala-actors-different-behavior-on-jre-1-5-and-1-6/"&gt;Scala Actors different behavior on JRE 1.5 and 1.6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://comments.gmane.org/gmane.comp.lang.scala.internals/2971"&gt;Actor starvation problem&lt;/a&gt; (related to previous)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://thread.gmane.org/gmane.comp.lang.scala.user/27602/"&gt;Actor as new thread&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
There are others, including cases where people have both rightly and wrongly blamed the default scheduler for serious problems with their programs.  Most of the above can be traced back to the fact that the default scheduler for Scala Actors uses a slightly modified version of the JSR166y ForkJoinPool, which has issues described below (&lt;a href="http://artisans-serverintellect-com.si-eioswww6.com/default.asp?W9"&gt;source&lt;/a&gt;):
&lt;blockquote&gt;
Like all lightweight-task frameworks, ForkJoin (FJ) does not explicitly cope with blocked IO: If a worker thread blocks on IO, then (1) it is not available to help process other tasks (2) Other worker threads waiting for the task to complete (i.e., to join it) may run out of work and waste CPU cycles. Neither of these issues completely eliminates potential use, but they do require a lot of explicit care. For example, you could place tasks that may experience sustained blockages in their own small ForkJoinPools. (The Fortress folks do something along these lines mapping fortress "fair" threads onto forkjoin.) You can also dynamically increase worker pool sizes (we have methods to do this) when blockages may occur. All in all though, the reason for the restrictions and advice are that we do not have good automated support for these kinds of cases, and don't yet know of the best practices, or whether it is a good idea at all.
&lt;/blockquote&gt;
&lt;/p&gt;
&lt;h3&gt;The Scope of the Issue&lt;/h3&gt;
&lt;p&gt;
The issue here is neither limited to Scala nor to actor based concurrency.  The general consensus in the concurrency community is that locks and threads are not the right abstractions for concurrency in application code (or hardly any code, for that matter), but there isn't any consensus on what the right abstractions are, or if there is consensus it is that the right abstractions are problem specific.  There's no one-size-fits-all concurrency abstraction.
&lt;/p&gt;
&lt;p&gt;
The one trait that all high-level or higher-order concurrency abstractions have in common is that under the hood they rely on some sort of managed thread pool and/or scheduler.  For purposes here, when I say "scheduler," I mean the layer with which a concurrency framework interacts directly and likely contains framework-specific logic.  When I say "thread pool," I mean the layer that directly manages the threads and is concurrency framework agnostic and may even be shared by several schedulers (sharing will be problematic, but I think ultimately necessary).  This isn't a hard line, and often times they may be lumped into one.  However I think it's a useful dichotomy.  I'm also assuming the scheduler and thread pool rely on cooperative thread sharing, and that preemptive multitasking is left to the virtual machine and/or operating system.
&lt;/p&gt;
&lt;p&gt;
The point is, any concurrency abstraction where the user can submit arbitrary code to be executing can ultimately run into serious issues if that user code does something it does not expect.  For example, the fork-join scheduler from JSR-166y that the Scala Actors library uses (I think Clojure uses it as well, but it may not) doesn't automatically enlarge its pool in the presence of unmanaged blocks (including normal blocking IO) or simple long-running computations.  This results in the majority of the problems I previously cited, because blocking operations are extremely common tasks, and thus a very leaky abstraction.
&lt;/p&gt;
&lt;h3&gt;Key Characteristics of a Good Scheduler&lt;/h3&gt;
&lt;p&gt;
Unfortunately my command of type theory is rudimentary at best, so while Greg could probably describe a well-behaved scheduler using types, I'm going to have to resort to plain English:
&lt;ol&gt;
&lt;li&gt;The user should not have to think about choosing a scheduler.&lt;/li&gt;
&lt;li&gt;The user should not have to think about the size of the thread pool managed by the scheduler.&lt;/li&gt;
&lt;li&gt;The user should be able to write code naturally without worrying about any assumptions the scheduler may make&lt;/li&gt;
&lt;li&gt;The user should not have to worry about starting or stopping the scheduler&lt;/li&gt;
&lt;li&gt;Multiple flavors of concurrency abstraction should be able to share the same thread pool.&lt;/li&gt;
&lt;li&gt;The scheduler should impose minimal overhead.&lt;/li&gt;
&lt;/ol&gt;
There's probably others, but I think this is a good start.
&lt;/p&gt;
&lt;h3&gt;The Performance Problem&lt;/h3&gt;
&lt;p&gt;
So why hasn't this problem already been solved?  Perhaps it has been already and I just don't know about it.  If someone has, please let me know.  But as far as I can tell it's because there's a perceived nasty performance trade.  Here's a quote from &lt;a href="http://scala-programming-language.1934581.n4.nabble.com/Scala-Actors-Starvation-td2281657.html"&gt;Philipp Haller&lt;/a&gt;:
&lt;blockquote&gt;
The starvation detection mechanism in Scala 2.7 was too expensive to support in the new default scheduler. However, there is a starvation  detection mechanism for thread-blocking methods of the `Actor` object (`receive` etc.). 
&lt;/blockquote&gt;
Similar answers have been provided when people have questioned the wisdom of using the FJ framework over the classes included with the JDK.  I've tested it a bit and it's true, the FJ framework does yield a significant improvement for certain classes of tasks over JDK classes (although I believe using exceptions for control flow imposes a far larger &lt;a href="http://erikengbrecht.blogspot.com/2009/02/profiling-exceptionblob.html"&gt;penalty&lt;/a&gt;).   Basically it appears that the overhead associated with known solutions to the problem overcomes the introduced benefits of fine-grained concurrency,
&lt;/p&gt;
&lt;h3&gt;ForkJoinPool in a nutshell&lt;/h3&gt;
&lt;p&gt;
What makes &lt;a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166ydocs/jsr166y/ForkJoinPool.html"&gt;ForkJoinPool&lt;/a&gt; so fast (other than highly optimized code) is that uses a two-level architecture for its task queues.  There's one queue for the pool, and the one dequeue per thread.  Most of the data associated with the dequeues is only updated from the owning thread so that tasks can be added and removed without synchronization and minimal volatile and CAS operations.  The worker threads also steal work from one another in order to spread out the load.  When a worker is deciding the next task to execute, it performs the following checks, using the first one to return a task:
&lt;ol&gt;
&lt;li&gt;The thread's own local dequeue&lt;/li&gt;
&lt;li&gt;The dequeues of other threads in the pool, scanned in a psuedo-random pattern with guiding hints&lt;/li&gt;
&lt;li&gt;The common task queue&lt;/li&gt;
&lt;/ol&gt;
Threads are only added to the pool if a &lt;a href="http://download-llnw.oracle.com/javase/7/docs/api/java/util/concurrent/ForkJoinPool.ManagedBlocker.html"&gt;ManagedBlocker&lt;/a&gt; that the pool can see if used to block causing the target concurrency to not the be met.  The default target concurrency for the ForkJoinPool is set to the number of available processors.  In Scala Actors this is overridden to be twice the number of available processors.  The idea behind this is simple:  If you're keeping all your processors busy, then adding more threads will just slow you down.  As we've seen, problems arise when a higher level of concurrency is needed due to unmanaged blocks, long running computations, or simply the required concurrency being inherently higher than the default concurrency.  This happens because as long as a worker is busy or has something in its local dequeue, it won't look elsewhere for tasks.  If all the workers are in this state, tasks can simply accumulate, resulting in starvation.
&lt;/p&gt;
&lt;h3&gt;A Crack at Solving the Problem&lt;/h3&gt;
&lt;p&gt;
As you might have guessed by now, I'm trying to solve &lt;a href="http://bitbucket.org/eengbrec/managedforkjoinpool/wiki/Home"&gt;this problem&lt;/a&gt;.  Right now I wouldn't use the code for anything beyond testing the code, but despite the fact I'm still wrestling with the internals of ForkJoinPool I've experienced good results so far.  My approach is simple: I added in a &lt;a href="http://bitbucket.org/eengbrec/managedforkjoinpool/src/tip/src/main/java/jsr166y/ManagedForkJoinPool.java"&gt;manager thread&lt;/a&gt; that monitors the changes in size of the various queues in the pool, and if they've been flushed since the last check, and grows the pool it tasks appear to be being starved.  The overhead imposed on each worker is minimal, as it only has to update a single additional volatile field when it clears out its queue.  The overhead of the manager thread is something, but in the benchmarking I've done so far it doesn't seem to add noticeable overhead.  Ironically, Scala Actors already maintain a &lt;a href="https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors/scheduler/ForkJoinScheduler.scala"&gt;dedicated thread for the scheduler&lt;/a&gt;, its just that the heuristic check on the size of the pool were removed in 2.8 (although honestly they never worked that well).
&lt;/p&gt;
&lt;p&gt;
I have two simple tests/micro-benchmarks using Scala Actors with a &lt;a href="http://bitbucket.org/eengbrec/managedforkjoinpool/src/081cf027383e/src/main/scala/scalax/concurrent/ManagedForkJoinScheduler.scala"&gt;custom scheduler&lt;/a&gt; built on my ManagedForkJoinPool.  The &lt;a href="http://bitbucket.org/eengbrec/managedforkjoinpool/src/081cf027383e/src/main/scala/scalax/concurrent/SleepyActor.scala"&gt;SleepyActor&lt;/a&gt; benchmark performs extremely poorly if the scheduler doesn't significantly grow the pool, because each actor sleeps on the thread.  The &lt;a href="http://bitbucket.org/eengbrec/managedforkjoinpool/src/081cf027383e/src/main/scala/scalax/concurrent/PingPong.scala"&gt;PingPong&lt;/a&gt; benchmark spawns a bunch of pairs of actors that simply message each other back-and-forth.  It is the type of use case where the ForkJoinScheduler shines, at least in terms of throughput.  The results on my MacBook are as follows (these are NOT scientific):
&lt;table border="1"&gt;
&lt;tr&gt;&lt;th&gt;Benchmark&lt;/th&gt;&lt;th&gt;Default Scheduler&lt;/th&gt;&lt;th&gt;ManagedForkJoinScheduler&lt;/th&gt;&lt;th&gt;&lt;a href="https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors/scheduler/ResizableThreadPoolScheduler.scala"&gt;ResizeableThreadPoolScheduler&lt;/a&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;SleepyActor&lt;/th&gt;&lt;td&gt;92 sec&lt;/td&gt;&lt;td&gt;30 sec&lt;/td&gt;&lt;td&gt;not tested&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;PingPong&lt;/th&gt;&lt;td&gt;59.49 sec&lt;/td&gt;&lt;td&gt;47.17 sec&lt;/td&gt;&lt;td&gt;66.02 sec&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
As you can see, performance actually improved with my scheduler.  This is because the default scheduler for Scala Actors does not always use the "fast path" and put new tasks on the dequeue of the thread creating them.  It only does it about half the time.  So for the PingPong test you can see how the thread local queues impact performance.
&lt;/p&gt;
&lt;h3&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;
It's too early to draw solid conclusions, but based on what I've done so far I think I can develop a solid heuristic for managing the thread pool size, and that the overhead will be negligible.  The key is to not impose any more overhead on the worker threads, and to keep the computational overhead of the manager thread a low as possible.  This means that the heuristic needs to be simple, and that the wait times between checks should be a long as possible, probably dynamically sized based on how smoothly the pool seems to be running.
&lt;/p&gt;
&lt;p&gt;
What I need right now are more tests and benchmarks to cover "real world" scenarios.  I also need to test on machines with more cores.  My MacBook doesn't exactly present a powerful system.  If anyone has suggestions, please post them!
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-4795895098451857372?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4795895098451857372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4795895098451857372' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4795895098451857372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4795895098451857372'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/08/improving-schedulers-for-high-level.html' title='Improving Schedulers for High-level, Fine-grained Concurrency Frameworks'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-6014372711056218181</id><published>2010-08-01T08:55:00.004-04:00</published><updated>2010-08-01T13:11:54.978-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='economics'/><category scheme='http://www.blogger.com/atom/ns#' term='Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><title type='text'>Is the Market for Technical Workers a Market for Lemons?</title><content type='html'>&lt;p&gt;
I saw this &lt;a href="http://behind-the-enemy-lines.blogspot.com/2010/07/mechanical-turk-low-wages-and-market.html"&gt;article&lt;/a&gt; about &lt;a href="https://www.mturk.com/mturk/welcome"&gt;Amazon Mechanical Turk&lt;/a&gt; this morning, and it struck me that the market for technical talent, and especially in software engineering and IT talent, is a &lt;a href="http://en.wikipedia.org/wiki/The_Market_for_Lemons"&gt;market for lemons&lt;/a&gt;.  For a little more critical (and hopeful!) look at the idea, take a look at this &lt;a href="http://mises.org/daily/801"&gt;post&lt;/a&gt; at the &lt;a href="http://mises.org/"&gt;Mises Institute&lt;/a&gt;. 
&lt;/p&gt;
&lt;h3&gt;What's a Lemon Market?&lt;/h3&gt;
&lt;p&gt;
The basic idea behind a market for lemons is that the seller has significantly more information about the quality of a product than the buyer (e.g. an &lt;a href="http://en.wikipedia.org/wiki/Asymmetric_information"&gt;information asymmetry&lt;/a&gt;).  The consequence of this is that buyers are unwilling to pay for more than the perceived average value of the goods on the market, because the buyer does not know whether he is going to get a cherry (a high quality good) or a lemon (a low quality good).  This then creates disincentives to sell cherries, because buyers will not pay their market value, and incentives to sell lemons, because they can be sold for more than they are worth.  This creates a sort of vicious cycle where high quality goods are withdrawn for the market, thus lowering the average quality of the available goods and consequently the prices buyers are willing to pay.  The ultimate result is a race to the bottom in terms of prices, with high quality goods vanishing as collateral damage.
&lt;/p&gt;
&lt;p&gt;
There are five criterion for a lemon market (paraphrased and reordered from Wikipedia):
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Asymmetry of information such that buyers cannot accurately assess the quality of goods and sellers can.&lt;/li&gt;
&lt;li&gt;There is an incentive for sellers to pass off low quality goods has high quality goods.&lt;/li&gt;
&lt;li&gt;There is either a wide continuum in the quality of goods being sold, or the average quality is sufficiently low such that buyers are pessimistic about the quality of goods available.&lt;/li&gt;
&lt;li&gt;Sellers have no credible means of disclosing the quality of the goods they offer.&lt;/li&gt;
&lt;li&gt;There is a deficiency of available public quality assurance.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;The Lemon Market for Technical Talent&lt;/h3&gt;
&lt;p&gt;
The market for technical talent is similar.  The information available about most job candidates for technical positions is superficial at best, and completely inaccurate at worst.  Furthermore, even when information is available, the buyers often do not have the knowledge required to evaluate it.  This even extends existing, long term employees and contractors.  Finally, the quality of an employee is often highly contextual - environmental and cultural factors can significantly boost or dampen a person, and those same factors may have the opposite effect on another.  So let's rundown the different factors:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Information Asymmetry: Resumes are short, shallow, and often deceptive.  Technical skills are very difficult to assess during an interview, and cultural fit can be almost impossible to assess.&lt;/li&gt;
&lt;li&gt;Incentives for sellers to deceive buyers:  Resumes are deceptive for a reason.  It's often stated that you need to pad your resume, because the person looking at it is automatically going to assume it is padded.  Furthermore, for almost two decades now technology has been a source of high paying jobs that can be obtained with marginal effort (just turn on the radio and listen for advertisements for schools offering technology training).&lt;/li&gt;
&lt;li&gt;Continuum in the quality of goods: This exists in all professions.&lt;/li&gt;
&lt;li&gt;Sellers have no credible means of disclosing quality: This is largely but not entirely true.  Most paid work that technology professionals do cannot be disclosed in detail, and even when it is there is reason for sellers to doubt the credibility.  Employment agreements may also place restrictions of the disclosure of closely related work, even if it is done on one's on time with one's own resources.&lt;/li&gt;
&lt;li&gt;Deficiency of public quality assurance: Employment laws and potentials for litigation (at least here in the U.S.) make the disclosure of employee or even outsourcer performance very risky.  Individual workers cannot effectively provide guarantees, and those provided by outsourcers are generally meaningless.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All this really amounts to is:  Sellers have no good way of providing information regarding their high quality products, and buyers have no good way of obtaining reliable information about a seller's products.  The problem centers entirely around making information available and ensuring its accuracy.
&lt;/p&gt;
&lt;h3&gt;What Technology Professionals can do&lt;/h3&gt;
&lt;p&gt;
Technology Professionals need to build up public reputations.  We need to make samples of our work, or at least proxies of samples, publicly available.  We need to build more professional communities with broader participation and more local, face-to-face engagement.
&lt;/p&gt;
&lt;p&gt;
I think broader participation is the key.  If you look at other professions (yes, I know, I'm lumping all "technology professionals" together and I frequently rant against such a lumping), members are much more active in various groups and associations.  In many it's expected and even explicitly required by employers.  Sure, there are tons of groups on the internet.  There are numerous, and often times enormous technology conferences.  There are countless technology blogs and community websites.  But I think the conferences are generally too big to be meaningful because most attendees essentially end up being passive receptacles for sales pitches (that's the purpose of these conferences) and maybe they do a little networking and learning on the side.  I think even the most active community sites really represent very small slices of the professionals they are intended to serve.  Most professionals are passive participants in them at best, just like with conferences.
&lt;/p&gt;
&lt;p&gt;
But there are millions of engineers, software developers, and IT professionals out there.  Millions!  How many of them do you find actively participating in professional communities of any kind?  Not many when you really think about it.  This is a problem because as long as the vast majority technology professionals have no public, professional identity, the vast majority of employers aren't going to see professional reputation as a useful search criterion or even measure when considering candidates.  
&lt;/p&gt;
&lt;h3&gt;What Employers can do&lt;/h3&gt;
&lt;p&gt;
Employers can do one of two things:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Expect applicants for new positions to provide meaningful evidence of their skills and take the time to evaluate such evidence&lt;/li&gt;
&lt;li&gt;Just outsource everything to the cheapest company possible.  Information on quality is largely unavailable and unreliable, but information on price is readily available and relatively accurate.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can see which one of those strategies is dominating the marketplace.  One requires effort and involves going against the tide.  The other is easy (at least to start, it's not easy to make work), and involves running along with the herd.
&lt;/p&gt;
&lt;p&gt;Except in the limited number of cases were employers, and the hiring managers who work for them, genuinely believe they can achieve a competitive advantage by actively seeking out candidates with demonstrated qualifications (as opposed to a padded resume and fast talk during an interview), I don't think employers are going to seriously consider reputation and objective evidence of skills until such information is easily obtainable and fairly reliable.&lt;/p&gt;
&lt;h3&gt;Is there any hope?&lt;/h3&gt;
&lt;p&gt;Yes!&lt;/p&gt;
&lt;p&gt;
We live and work in an information economy where new forms of information become available everyday.  There is no reason to believe just because today employers mostly hire on faith and expect luck to carry them through, the in the future there won't be much more information available.  I'm sure there are several companies working on aggregating such information right now.  The market is huge.  While companies will rarely put much effort into obtaining information and aggregating it into a useful form, they will often pay large quantities of money for it.  The key is to make sure the information is there for them to use.
&lt;/p&gt;
&lt;p&gt;
Also, if your resume makes it through all the wickets to a real hiring manager, if you provide an easy way for him to find more good information about you, he'll probably use it.  Interviewing people is a lot of work.  Deciding among candidates can be very hard.  Extra information will almost certainly be used.  It just has to be easy to obtain.  People are lazy.
&lt;/p&gt;
&lt;h3&gt;But what about old fashioned networking?&lt;/h3&gt;
&lt;p&gt;
I think the numbers involved are too large and relying on old-fashioned networks tends to yield too poor of results.  Recommendations and referrals are certainly useful and lead to many, many hires.  But they tend to be made more based on personal relationships than based on real qualifications and therefore need to be checked.  Schmoozing isn't a real technical skill.  That being said, it could quite likely get you a job.  It's just that in general I don't want to work with such people in a technical capacity, so I'm not going to recommend people go do it in order to obtain technical jobs.  I'm selfish that way.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-6014372711056218181?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/6014372711056218181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=6014372711056218181' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6014372711056218181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6014372711056218181'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/08/is-market-for-technical-workers-market.html' title='Is the Market for Technical Workers a Market for Lemons?'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-6937506591624231062</id><published>2010-07-27T21:35:00.009-04:00</published><updated>2010-07-29T08:40:55.819-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Metaprogramming'/><category scheme='http://www.blogger.com/atom/ns#' term='Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Higher-Level versus Higher-Order Abstraction</title><content type='html'>&lt;p&gt;
Engineering in general, and software engineering in particular, is all about abstraction.  The creation and utilization of abstractions is a core part of the daily activities of every good engineer, and many engineers are on a never ending quest to increase their level of abstraction.  Abstraction both increases productivity and increases the complexity of problems that can be tackled.  Few would argue that increased abstraction is a bad thing.
&lt;/p&gt;
&lt;p&gt;
But people do argue about abstraction, and often condemn abstractions that they view as unfit or too complex.  It is common to hear a software developer praise the merits of one means of abstraction and then demean another in the same breath.  Some abstractions are too general.  Some aren't general enough.  Some are simply too complex or, ironically, too abstract.  So while engineers almost universally agree that abstraction is good, and more abstraction is better; they often disagree fiercely about what genuinely constitutes "better."
&lt;/p&gt;
&lt;h3&gt;What is an abstraction?&lt;/h3&gt;
&lt;p&gt;
Simply put, an abstraction is something that hides the details involved in realizing a concept, and thus frees the engineer to focus on the problem at hand rather than the details of some other concern.  This can take many, many forms.  The simplest and most common, so common that the term is often used to describe almost all "good" abstractions, is higher-level abstractions.
&lt;/p&gt;
&lt;h3&gt;Higher-level Abstractions&lt;/h3&gt;
&lt;p&gt;
Higher-level abstractions are fairly simple: they encapsulate details so that they can be used without knowledge or concern about the details.  Let's consider a simple example in &lt;a href="http://www.scala-lang.org/node/7009"&gt;Scala 2.8&lt;/a&gt; (you can copy and paste these examples directly into the Scala 2.8 REPL):
&lt;/p&gt;
&lt;pre&gt;
scala&gt; def sum(data: Array[Double]): Double = {
     |   var i = 0
     |   var total = 0.0 
     |   while(i &lt; data.length) {
     |     total = total + data(i)
     |     i = i + 1
     |   }
     |   total
     | }
scala&gt; def mean(data: Array[Double]): Double = sum(data) / data.length
&lt;/pre&gt;
&lt;p&gt;
So we have two functions: one that computes the sum of an array of doubles, and one that computes the mean.  Pretty much any programmer (professional or otherwise) would feel confident both writing and using such functions.  They are written in a modern multi-paradigm programming language yet I bet if you went back in time and showed them to programmers in some of the very first high-level languages they would recognize exactly what they do.  They clearly encapsulate the details of performing certain computations.  But what's more interesting about them is what's missing from them:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming"&gt;Polymorphism&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Closure_(computer_science)"&gt;Closures&lt;/a&gt; or &lt;a href="http://en.wikipedia.org/wiki/First-class_function"&gt;first-class functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Usage or creation of &lt;a href="http://en.wikipedia.org/wiki/Higher-order_function"&gt;higher-order functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Other Scala magic such as &lt;a href="http://dibblego.wordpress.com/2007/05/23/the-power-of-type-classes-with-scala-implicit-defs/"&gt;type classes&lt;/a&gt; and &lt;a href="http://www.scala-lang.org/node/114"&gt;implicit parameters&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
In other words, they provide a simple, layered, hierarchical abstraction in a very bounded way.  If we step away from software for a minute, you can imagine a digital designer placing a symbol for an adder or a register on a schematic without worrying about the arrangement of transistors that will be required to realize them in an actual circuit, or a mechanical engineer selecting a standard screw or clamp.  These are parts that can be simply built, tested, and composed into larger devices.
&lt;/p&gt;
&lt;h3&gt;Higher-Order Abstraction Take 1: The Mathematics of Fruit&lt;/h3&gt;
&lt;p&gt;
Imagine I have some apples.  But unfortunately I'm here, off in the internet, show I can't show them to you.  I need an abstraction to tell you about them.  For example, I could say I have two apples.  Two is a number, and numbers are abstractions.  I can use the same number two to describe the number of &lt;a href="http://en.wikipedia.org/wiki/McIntosh_(apple)"&gt;McIntoshes&lt;/a&gt; in my refrigerator or the number of Apple Macintoshes I own.  Now let's say I also want to talk about my strawberries and blueberries.  I have 16 strawberries and 100 blueberries.  How many pieces of fruit do I have?  118!  How did I figure that out?  I used arithmetic, which is an abstraction of higher order than numbers.  How let's say I want to know how many days it will be before I will have eaten all my strawberries.  I can write an equation such as: current_fruit - pieces_per_day * number_of_days = fruit_after_number_of_days.  I can do even more with this by solving for different variables.  This is algebra, and it is a higher-order abstraction than arithmetic.  Now let's say I want to build upon that so that I can study the dynamics of the amount of fruit in my refrigerator.  I purchase fruit and put it in my refrigerator.  I take fruit out and eat it.  I forget about fruit and it gets moldy, the I remove it and throw it away.  I can capture all of these as a system of &lt;a href="http://en.wikipedia.org/wiki/Differential_equation"&gt;differential equations,&lt;/a&gt; and using &lt;a href="http://en.wikipedia.org/wiki/Calculus"&gt;calculus&lt;/a&gt; describe all sorts of things about my fruit at any given point in time.  Calculus is a higher-order abstraction that algebra.  In fact, abstractions similar to the ones built with calculus are what I mean when I say "higher-order abstraction."
&lt;/p&gt;
&lt;p&gt;
At each step up the chain of mathematics both the generality and number of concepts that can be conveyed by a single abstraction increased.  In the case of calculus it becomes essentially infinite, and that's the essence of higher-order abstractions: they deal with the infinite or near-infinite.  Also, observe that almost everyone from relatively small children on up understand numbers and arithmetic, most adolescents and adults can stumble through applying algebra, and only a very small portion of the population knows anything about calculus, much less can effectively apply it.  Also observe that the functions I defined earlier are just below algebra in terms of their order of abstraction.
&lt;/p&gt;
&lt;h3&gt;Higher-Order Abstraction Take 2: Programming in Scala&lt;/h3&gt;
&lt;p&gt;
Let's see if we can sprinkle some higher-order abstraction into our previously defined functions:
&lt;/p&gt;
&lt;pre&gt;
scala&gt; def sum(data: Traversable[Double]) = data.foldLeft(0.0)(_ + _)
&lt;/pre&gt;
&lt;p&gt;
This definition of sum exposes one higher-order abstraction (polymorphism - it now can use any Traversable[Double] instead of just an Array[Double]), and it uses higher-order functions in its implementation to perform the summation.  This new definition is both much shorter and much more general, but it's still relatively approachable, especially for use.  Calling it with an Array[Double] works as before, and now it can be used with any number of collections, so long as the collections contain doubles.  But forcing the collections to contain doubles is very limiting, so let's see if we can do better:
&lt;/p&gt;
&lt;pre&gt;
scala&gt; def sum[T](data: Traversable[T])(implicit n: Numeric[T]): T = {                                  
     |   import n._
     |   data.foldLeft(zero)(_ + _)
     | }
&lt;/pre&gt;
&lt;p&gt;
Ahhh, that's better!  Much more general.  Not only will this work for any numeric type defined in the Scala standard library, but for any numeric type for which the Numeric type class has been defined!  It doesn't even need to be in the same class hierarchy!  In order to introduce this new level of generality, we've also introduced the following higher-order abstractions:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Classic polymorphism (Traversable instead of Array)&lt;/li&gt;
&lt;li&gt;Parametric polymorphism (the type parameter T for various classes)&lt;/li&gt;
&lt;li&gt;Higher-order functions and closures (foldLeft and it's argument that does addition)&lt;/li&gt;
&lt;li&gt;Type classes (well, Scala's flavor of type classes, e.g. Numeric)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Now, this is the point where people start screaming that abstraction has gone too far.  Many professional programmers would look at it and think "WTF?"  They could still guess what it does, but the mechanics are quite elusive for anyone that doesn't know Scala reasonably well.  That being said, the code is still far more compact than the original imperative version and is extremely general (to which someone replies "Yes, but it's slow a heck compared to the original!").  At this point I would say the order of abstraction has went from being just below algebra to being on par with integral calculus.  Just like with mathematics, we see a significant drop off in the number of people who readily understand it.
&lt;/p&gt;
&lt;h3&gt;Higher-Order Abstraction Take 3: Conclusions&lt;/h3&gt;
&lt;p&gt;
Let's consider a short, incomplete list of higher-order abstractions, means of abstraction, and fields that rely upon higher-order abstractions:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Higher-order functions&lt;/li&gt;
&lt;li&gt;Polymorphism and parametric polymorphism&lt;/li&gt;
&lt;li&gt;Metaclasses such as in &lt;a href="http://www.ibm.com/developerworks/linux/library/l-pymeta.html"&gt;Python&lt;/a&gt; and &lt;a href="http://www.ifi.uzh.ch/richter/Classes/oose2/05_Metaclasses/02_smalltalk/02_metaclasses_smalltalk.html"&gt;Smalltalk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rich macros such as in &lt;a href="http://www.apl.jhu.edu/~hall/Lisp-Notes/Macros.html"&gt;Lisp&lt;/a&gt; or &lt;a href="http://www.cplusplus.com/doc/tutorial/templates/"&gt;C++ Templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Calculus and all the mathematics built upon it (and various other forms of advanced math)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/First-order_logic"&gt;First-order Logic&lt;/a&gt; and its &lt;a href="http://en.wikipedia.org/wiki/Common_logic"&gt;kin&lt;/a&gt;, and all the &lt;a href="http://en.wikipedia.org/wiki/Higher-order_logic"&gt;higher-order logics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Any physics or other sciences that are built upon calculus&lt;/li&gt;
&lt;li&gt;Any engineering or other applications that are built upon physics&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Higher-order abstractions tend to exhibit one or more of the following traits:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;They deal in infinities (e.g. integration and differentiation in calculus, universal and existential quantification in first-order logic, polymorphism and type classes in programming)&lt;/li&gt;
&lt;li&gt;They deal in transformations (e.g. integration and differentiation in calculus, metaclasses and macros in programming)&lt;/li&gt;
&lt;li&gt;They rely upon composition rules (e.g. &lt;a href="http://mathworld.wolfram.com/ChainRule.html"&gt;chain rule&lt;/a&gt; and &lt;a href="http://mathworld.wolfram.com/IntegrationbyParts.html"&gt;integration by parts&lt;/a&gt; in calculus, higher-order functions in programming)&lt;/li&gt;
&lt;li&gt;Learning to use any given form of higher-order abstraction requires significant effort and discipline, therefore they tend to be the tools of specialists&lt;/li&gt;
&lt;li&gt;They form the foundation of our modern, technological society.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
The last two can be converted into conclusions:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Higher-order abstractions are critical for most interesting forms of science and technology&lt;/li&gt;
&lt;li&gt;You can't expect a colleague or customer from another field to understand the higher-order abstractions in your field, even if his own field is totally immersed in higher-order abstraction&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/19725519-6937506591624231062?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/6937506591624231062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=6937506591624231062' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6937506591624231062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6937506591624231062'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/07/higher-level-versus-higher-order.html' title='Higher-Level versus Higher-Order Abstraction'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-5447849996398155887</id><published>2010-07-24T20:32:00.002-04:00</published><updated>2010-07-24T21:30:54.995-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fail'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='microsoft'/><title type='text'>Windows 7 Upgrade (so far)</title><content type='html'>A few weeks ago my wife's Lenovo laptop caught a really nasty virus.  Symantec antivirus couldn't clean it up.  But I had recovery media (although it was Vista instead of XP), so I used Knoppix to low-level the HD and flashed an updated BIOS (I've had previous experience with viruses that could be stopped via nothing less).  Unfortunately the restore media didn't work...it would boot up, think a while, and the reboot.  I also tried a XP install using an old XP disk I had laying around, but the XP installer doesn't get along with the new SATA controller in the laptop, so it BSODs.  Working around this problem seems to require creating a special driver disk, which seems to require Windows, which creates a problem because all I have are Leopard (about 2 crashes in almost 3 years, a no viruses, versus what seems like a plague on my wife's laptop every 6 months), and Knoppix.

So, being a person who value's his time more than his money, I went out and bought a Windows 7 Professional upgrade.  All the Microsoft related blogs assured me this would work, and indeed I have a working install the went almost a smooth as butter.  The "almost" is the activation process.  I have yet to successfully activate.  Going into this my assumption was I would have to call Microsoft in order to activate.  What I didn't realize is that their human systems don't seem any smarter than their automated systems.

So first I called the phone number that Microsoft's support website told me to call.  Several layers deep this told me to call a special activation line.  I want to commend Microsoft at this point for avoiding such advanced technology as call transfers.  You really can't trust technology that's decades old.  It's better to let people transfer themselves.

So I call the line, and speak to a very friendly automated system.  It's asking me for my "installation id," but there isn't one.  There isn't one because the computer is connected to the internet, and some genius decided that if one has the internet one would never use the phone system, which would normally be true if some brilliant licensing policy maker hadn't decided that the only way to activate a "clean install" is via the phone system.  Anyway, the nice automated system transfers me to a human being.

Guess what the human asks me for?  An installation id.  I tell him I don't have one.  I read the various things on my screen to him.  He then asks if I am connected to the internet.  I say yes.  He tells me to disconnect.  I disconnect and start over, ultimately ending up in the same place with no installation ID.  The support person gives up and tells me I have a deep technical problem, which will require technical support, not activation support (I'm now imaging myself setting up a conference call with tech support, activation support, and the nice automated system lady).  Tech support is of course only a US working hours affair, not a Saturday evening affair.

It turns out the automated support guy just wasn't persistent enough.  After hanging up, I reboot the computer and try again without internet.  It appears to get me to the same place, except when I hit the magic "next" button, instead of receiving a message telling me that my product key is not valid, I receive an installation ID and am told to call the activation line (which is a 3rd phone number, but gets me to the same place as the first).

I want to take a moment to point out some huge flaws here:
&lt;ol&gt;
&lt;li&gt;The automated system just assumed I would have an installation ID, and had no explanation of how I was supposed to obtain one or why I might not see one, while the activation software is explicitly designed to not provide one to someone connected to the internet&lt;/li&gt;
&lt;li&gt;The human being had a vague idea that being connected to the internet was a problem, although he didn't realize it until repeating his requests half a dozen times, and even though he had a vague idea how to induce Windows 7 into providing one, he didn't actually know and gave up quickly&lt;/li&gt;
&lt;li&gt;About 2 minutes would of poking after 30 minutes of bouncing around on the phone rewarded me with an installation id&lt;/li&gt;
&lt;/ol&gt;

Ok, so let's try again.  This time I provide the installation id to the automated system, and the automated system informs me that it is invalid, and sends me to another human being.  After 5 or 10 minutes the human being informs me that I need to have a Microsoft OS already installed in order to use an upgrade, and that I cannot use a clean install.  He says it is impossible that Windows XP would refuse to install, and thinks it's completely reasonable that I would install one OS just to install another.  I rant at him for a few minutes about how my product packaging says nothing about not being able to do a clean install (in fact, it's the only way to upgrade from XP according to the included instructions, although maybe it does some magic if the installer reformats the HD instead of the user already doing it).

Anyway, I explain this all to him while trying to remain calm.  He puts me on hold.  Then when he comes back he tells me that he gave me wrong information because a server is down, and that I need to call back in 30 minutes when the server is up.

So I did that.  This time after I read my installation ID to the support person, which he told me was invalid.  He told me to exit activation and enter my product key again.  I dutifully did this, then he put me on hold while he waited for my product key to come up.  This of course would never happen, because I wasn't connected to the internet, and it fact cannot obtain an installation id when connected to the internet.  After a few minutes on hold, I was transfered to Microsoft technical support, which of course was closed.

So let's recap so far:
&lt;ol&gt;
&lt;li&gt;None of the Microsoft activation people or systems know what you need to do in order to obtain an installation id, all of them expect you to just have one&lt;/li&gt;
&lt;li&gt;In order to obtain an installation id, as far as I can tell you can't be connected to the internet (certain options only appear if you are not connected)&lt;/li&gt;
&lt;li&gt;Some support people seem to assume that you are connected to the internet, even though the information they request will never come up if you are not connected to the internet&lt;/li&gt;
&lt;li&gt;Support people will transfer you to a line that will not answer without even telling you that you are being transfered&lt;/li&gt;
&lt;li&gt;That line seems to only be open during US business hours, which would mean they seem to assume that either you professionally support Microsoft products or are unemployed.&lt;/li&gt;
&lt;/ol&gt;

If I can't make this work tomorrow, I think I'm going to obtain an updated version of MS Office for my Mac and give it to my wife, then just install Ubuntu on her laptop.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-5447849996398155887?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/5447849996398155887/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=5447849996398155887' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/5447849996398155887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/5447849996398155887'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/07/windows-7-upgrade-so-far.html' title='Windows 7 Upgrade (so far)'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-3554240647358890387</id><published>2010-01-16T10:31:00.000-05:00</published><updated>2010-01-16T10:32:19.487-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='innovation'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><title type='text'>Changing Tastes</title><content type='html'>&lt;p&gt;When I was a kid, I hated onions, green peppers, and mushrooms. I used to tell people I was allergic to mushrooms so they wouldn't try to make me eat them. I hated any sort of chunky sauce or really textured meat. I think I wanted everything to have either the consistency of a chicken nugget or ketchup. My parents used to tell me that when I was older my tastes would change. That I liked crappy food, disliked good food, and eventually I would realize it. They were right.&lt;/p&gt;&lt;p&gt;So kids like chicken nuggets and ketchup. Wow, huge revelation. What does this have to do with technology? I'm on the steering committee for an internal conference on software engineering that my employer is holding. I'm the most junior person on the committee, and most of the members are managers who have more managers reporting to them. Our technical program committee (separate, more technical people on it, but all very senior) just finished abstract selection and we've been discussing topics and candidates for a panel discussion. During this process I have been absolutely shocked by how my tastes differ from those of my colleagues.&lt;/p&gt;&lt;p&gt;I've noticed that within the presentations selected topics on process, architecture, and management are over-represented. On the other side, many of the abstracts that I thought were very good and deeply technical fell below the line. I can't quite say there was a bias towards "high level" topics, because I think they were over-represented in the submissions. Given the diversity of technology that's almost inevitable. A guy doing embedded signal processing and a guy doing enterprise systems would most likely submit very different technical abstracts, but ones on management or process could be identical. It's almost inevitable that topics that are common across specialties will have more submissions.&lt;/p&gt;&lt;p&gt;There's a similar story with the panel discussion. I wanted a narrower technical topic, preferably one that is a little controversial so panelists and maybe even the audience can engage in debate. My colleagues were more concerned with who is going to be on the panel than what they would talk about, and keeping the topic broad enough to give the panelists freedom.&lt;/p&gt;&lt;p&gt;What's clear is that my colleagues clearly have different tastes in presentation content than me. I think they are genuinely trying to compose the best conference they can, and using their own experiences and preferences as a guide. I think their choices have been reasonable and well intentioned. I just disagree with many of them. If I had been the TPC chair, I would have explicitly biased the selection criteria towards deeper, technical topics. Those are the topics I would attend, even if they are outside my area of expertise. I would use my preferences as a guide. But that leaves me wondering, in another five years or ten years are my tastes going change? My tastes have certainly changed over the past decade, so I have no reason to believe they won't change over the next. Will I prefer process over technology and architecture over implementation? Will I stop thinking "show me the code!" and "show me the scalability benchmarks!" when see a bunch of boxes with lines between them? I don't think so, but only time will tell. When I was a kid, I would have never believed that I would ever willingly eat raw fish, much less enjoy it, but today I do.&lt;/p&gt;&lt;br class='final-break'  /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-3554240647358890387?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/3554240647358890387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=3554240647358890387' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3554240647358890387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3554240647358890387'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/01/changing-tastes.html' title='Changing Tastes'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7015383362032325749</id><published>2010-01-05T22:59:00.001-05:00</published><updated>2010-01-05T23:00:41.006-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='cloud computing'/><category scheme='http://www.blogger.com/atom/ns#' term='enterprise software'/><title type='text'>Your Company's App</title><content type='html'>&lt;p&gt;&lt;a href="http://www.tbray.org/ongoing/"&gt;Tim Bray&lt;/a&gt; just posted a blog about how Enterprise IT is &lt;a href="http://www.tbray.org/ongoing/When/201x/2010/01/02/Doing-It-Wrong"&gt;doing it wrong&lt;/a&gt;.&lt;span class="Apple-converted-space"&gt;  &lt;/span&gt;I can't really argue with that.  He goes on to explain that Enterprise IT needs to learn from those companies building &lt;a href="http://oreilly.com/web2/archive/what-is-web-20.html"&gt;Web 2.0&lt;/a&gt;, because they deliver more functionality in less time and for a whole lot less money.  This is where his argument breaks down.  The problem is the type of &lt;a href="http://en.wikipedia.org/wiki/Enterprise_system"&gt;Enterprise Systems&lt;/a&gt; he's talking about aren't &lt;a href="http://twitter.com"&gt;Twitter&lt;/a&gt;, they're &lt;a href="http://stuffthathappens.com/blog/2008/03/05/simplicity/"&gt;your company's app&lt;/a&gt;.&lt;/p&gt;
&lt;p class="p2"&gt;I work at a pretty big, stodgy, conservative company.  I'm pretty sure, as far as things like ERP and &lt;a href="http://en.wikipedia.org/wiki/Product_lifecycle_management"&gt;PLM&lt;/a&gt; are concerned, my employer is exactly the type of company Tim is talking about, and like I said - he's probably right about the problem.  But based on my own experiences and observations at my one lonely company, I think he's wrong in his suggestions.  Comparing &lt;a href="http://en.wikipedia.org/wiki/Enterprise_resource_planning"&gt;ERP&lt;/a&gt; and &lt;a href="http://www.facebook.com/"&gt;Facebook&lt;/a&gt; is like comparing &lt;a href="http://www.bestapples.com/"&gt;apples&lt;/a&gt; and &lt;a href="http://www.applejacks.com/healthymessage/index.html"&gt;Apple Jacks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The reason I think this is that in terms of deploying &lt;a href="http://en.wikipedia.org/wiki/Enterprise_social_software"&gt;Enterprise 2.0&lt;/a&gt; applications I think my employer has done fairly well.  We have...&lt;/p&gt;
&lt;ul class="ul1"&gt;
  &lt;li&gt;A &lt;a href="http://en.wikipedia.org/wiki/Wiki"&gt;wiki&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;A "business networking" site, kind of like &lt;a href="http://www.linkedin.com/"&gt;Linkedin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;A &lt;a href="http://en.wikipedia.org/wiki/Microblogging"&gt;microblogging&lt;/a&gt; site&lt;/li&gt;
  &lt;li&gt;A question &amp;amp; answer board similar to &lt;a href="http://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;An on-demand cloud computing environment, kind of like &lt;a href="http://aws.amazon.com/ec2/"&gt;Amazon E2C&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;...and probably more stuff that I'm not aware of yet.  Some of the above were bought, some were built, some were cobbled together with stuff from a variety of sources.  I think most of them were built and deployed, at least initially, for costs about as competitive as possible with Web 2.0 startups and in reasonable timeframes.  Of course, this means intranet scale at a &lt;a href="http://money.cnn.com/magazines/fortune/fortune500/2009/full_list/"&gt;Fortune 100&lt;/a&gt; company (or in some cases a subset of it), not successful internet scale.&lt;/p&gt;
&lt;p&gt;The problems the above face is much like the problem your typical startup faces: attracting users, keeping investors (sponsors) happy, dealing with the occasional onslaught of visitors after some publicity.  But these problems are very different from the problems a traditional Enterprise Application faces.  There is &lt;a href="http://en.wikipedia.org/wiki/Sarbanes%E2%80%93Oxley_Act"&gt;SOX&lt;/a&gt; compliance.  There are no entrenched stakeholders.  There are no legacy systems, or if there are they aren't that important.  If only 10% of the potential user community actually uses the application, it's a glowing success.  Negligible adoption can be accepted for extended periods while the culture adjusts, because the carrying cost of such applications is low.&lt;/p&gt;
&lt;p&gt;But enterprise systems needs to deal with SOX.  They have more entrenched stakeholders than you can count.  These days there's always at least one legacy system, and often several due to disparate business units and acquisitions.  If these systems fail, business stops, people don't get paid, or the financials are wrong.  If only 90% of your buyers use your ERP systems to process purchase orders, it's an abject failure and possibly endangering the company.&lt;/p&gt;
&lt;p&gt;A year or two ago someone "discovered" that a very common, important record in one of our internal systems had 44 (or something like that) required fields, and decided that this was ridiculous.  A team was formed to streamline the processes associated with this record by reducing the number of fields.  A detailed process audit was conducted.  It turned out that every single one of them played a critical role in a downstream process.  All the fields remained, and some old timers smiled knowingly.&lt;/p&gt;
&lt;p&gt;As many humorless commenters pointed out on Eric Burke's blog, your company's app is your company's app for a reason, and often it's a good reason.  These applications aren't complicated because of the technology.  Internet applications are complex due to extrinsic forces - the sheer number of users and quantity of data that can deluge the application at any given moment.  Enterprise systems tend to be the opposite.  Their complexity is intrinsic due to the complexity of the diverse processes the support.  The technology complexity (most of which is accidental) is secondary.  Tim's suggestions provide a means of addressing technological complexity, and of building green field non-business critical applications in the face of uncertain requirements.  They don't provide a means for dealing with critical systems laden with stakeholders, politics, and legacy.&lt;/p&gt;
&lt;p&gt;I think the solution, or at least part of the solution, to the problem with enterprise systems lies in removing much of the functionality from them.  There are things that must be right all of them time, but most of business (and engineering, etc) exists on a much fuzzier plane.  The problem comes from coupling the precise (e.g. general ledger) with the imprecise (e.g. CM on an early stage design), and thus subjecting the imprecise to overly burdensome controls and restrictions.  Only after this separation has been carefully implemented can functionality evolve in an agile fashion.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7015383362032325749?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7015383362032325749/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7015383362032325749' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7015383362032325749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7015383362032325749'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2010/01/your-companys-app.html' title='Your Company&apos;s App'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7660120549919445761</id><published>2009-06-21T21:20:00.002-04:00</published><updated>2009-06-21T21:22:07.543-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='parallelism'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Pondering Actor Design Trades</title><content type='html'>&lt;p&gt;There's been a lot of discussion of the Scala actors library lately, much of it critical, and a recent flurry of alternate implementations.  The alternate implementations (except my languishing state-based one ;-) all have one thing in common:  They are several orders of magnitude simpler.  Writing a basic actor implementation is actually pretty trivial, especially given &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/package-summary.html"&gt;java.util.concurrent&lt;/a&gt; classes that provide a decent chunk of the functionality in Scala actors, all for free on JDK5+.  So this begs the question few questions:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Why is the standard Scala actor implementation so complex when others have done it in a such simpler fashion?&lt;/li&gt;
    &lt;li&gt;Is it better to have one, big actor library that supports a wide variety of use cases, or a bunch of smaller ones targeted at specific niches and programming styles?&lt;/li&gt;
    &lt;li&gt;If there are to be a bunch, should they just be conceptually similar (e.g. all based on the actor model), or should there be interoperability among them?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I'm not going to answer these questions now.  Instead, I'm going to try to start laying out some of what I believe to be the key characteristics of an actor implementation, and how they detract or enforce one another.  So here it goes:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Guarantees&lt;/li&gt;
    &lt;li&gt;Expressivity&lt;/li&gt;
    &lt;li&gt;Extensibility&lt;/li&gt;
    &lt;li&gt;Performance&lt;/li&gt;
    &lt;li&gt;Scalability&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Guarantees&lt;/h3&gt;
&lt;p&gt;The purpose of a concurrency framework is to make concurrency easier.  Concurrency is hard largely because it is extremely difficult to reason about, and thus concurrent code tends to be hard to write, laden with bugs, and subject to various odd pitfalls.  By providing various guarantees, a concurrency framework makes it easier to reason about concurrent code.  Actors are intended to free the programmer from worrying about things like locks, semaphores, thread management, etc. by encapsulating all that complexity behind a simple interface, assuming the programmer follows some basic rules like &amp;quot;no shared mutable state among actors.&amp;quot;&lt;/p&gt;
&lt;p&gt;The problem with guarantees is that in they tend to break down in the presence of limited CPU and memory resources.&lt;/p&gt;
&lt;h3&gt;Expressivity&lt;/h3&gt;
&lt;p&gt;Expressivity is difficult to define.  For purposes here, I'm going to define it as the degree to which a concise, natural expression of the programmer's intent is supported, and illustrate it by comparing &lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors/Actor.scala"&gt;Scala Actor&lt;/a&gt; to &lt;a href="http://github.com/dpp/liftweb/blob/e1568d144d95443b96bf5d6f49a5b4a984caa032/lift-actor/src/main/scala/net/liftweb/actor/LiftActor.scala"&gt;Lift Actor&lt;/a&gt;.  Scala Actors allow you to execute logic independent of message processing (note: this a violation of the &lt;a href="http://yangtze.cs.uiuc.edu/~thati/festschrift.pdf"&gt;theoretical model for actors&lt;/a&gt;) by simply placing it in the act method.  Lift Actors, on the other hand, are only triggered when they receive of message (this is consistent with the theoretical model).  For example, this makes it so that Scala Actors can do things such as perform possibly costly setup operations in their own thread before they start listening for messages.  In order to accomplish this in the Lift model, the programmer must create the actor and then send it some sort of &amp;quot;init&amp;quot; message.  The same effect can be achieved with both implementations, but it is more naturally supported by Scala Actors.  Of course there is a tradeoff here, as deviating from the theoretical model potentially weakens any guarantees that the model may provide.  The Scala Actor way also implies that an Actor has an explicit lifecycle, which as we'll see later has other significant implications.&lt;/p&gt;
&lt;p&gt;Another example is what I'll call the &amp;quot;nested react pattern.&amp;quot;  It is relatively common to want an actor to take on a different behavior after processing a message, thus altering which messages are ignored and how the received messages are processed.&lt;/p&gt;
&lt;pre&gt;
loop {
 react {
    case 'foo =&amp;gt; { 
      // do some stuff...
      react {
        case 'bar =&amp;gt; // do some other stuff... 
      } 
    } 
  } 
}
&lt;/pre&gt;
&lt;p&gt;The code above alternates between processing &lt;code&gt;'foo&lt;/code&gt; messages and &lt;code&gt;'bar&lt;/code&gt; messages.  This can be done with Lift Actor as well, but the expression is a little less natural:&lt;/p&gt;
&lt;pre&gt;
class MyActor extends LiftActor {
  private val fooMode: PartialFunction[Any, Unit] = {
    case 'foo =&amp;gt; {
      // do some stuff
      mode = barMode
    }
  }
  private val barMode: PartialFunction[Any, Unit] = {
    case 'bar =&amp;gt; {
      // do some other stuff...
      mode = fooMode
    }
  }
  private var mode = fooMode
  protected def messageHandler = mode
}
&lt;/pre&gt;
&lt;p&gt;Finally, Lift Actors exclusively use an event-based model and have no support for blocking on a thread while waiting for a message, and thus looses the ability to express patterns such as the following:&lt;/p&gt;
&lt;pre&gt;
loop {
  react {
    case 'converToNumber =&amp;gt; {
      val i: Int = receive {
        case 'one =&amp;gt; 1
        case 'two =&amp;gt; 2
        case 'three =&amp;gt; 3
      }
      reply(i)
    }
  }
}
&lt;/pre&gt;
&lt;h3&gt;Extensibility&lt;/h3&gt;
&lt;p&gt;For purposes here, I'm going to use &amp;quot;extensible&amp;quot; to mean that a piece of software is extensible if capabilities can be added without modifying the core or breaking its semantics in a amount of effort proportional to the size of the extension.  This is narrower than the traditional definition of extensibility, which also covers the ability of a system to evolve internally.  A good example of extensibility is the ability of both Scala Actors and Lift Actors to allow the user to specify a custom &lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors/IScheduler.scala"&gt;scheduler&lt;/a&gt;.  Other examples could include adding control structures, using a different data structure for a mailbox.&lt;/p&gt;
&lt;p&gt;The challenge with extensibility is that in order to enable it, what could otherwise be treated as the internal bits of the library must instead have well defined interfaces for components along with appropriate hooks for inserting them.  For example, a while ago I did some &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/14e33a6ea1f8/src/actors/scala/actors/MessageQueue.scala"&gt;work&lt;/a&gt; to make the &lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors/MessageQueue.scala"&gt;MessageQueue&lt;/a&gt; used for the mailbox overrideable (it has temporarily been overcome-by-events due to other changes).  This is a small example, but it shows how extensibility requires a greater degree of forethought.&lt;/p&gt;
&lt;p&gt;Extensibility also benefits substantially from simplicity.  Scala Actors are almost impossible to extend from outside the &lt;code&gt;scala.actors&lt;/code&gt; package because of their heavy reliance on package-private methods and state (mostly fixed &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/9da337a0db7f/"&gt;here&lt;/a&gt;, but I broke remote actors in the process so no patch yet).  Lift Actors, on the other hand, are very extensible, at least within the bounds of their design (purely event-based actors with no explicit lifecyle).  Many of the flow control mechanisms could be implemented on top of the baseline approach.&lt;/p&gt;
&lt;p&gt;At this point we see that extensibility has an interesting relationship with expressivity.  I previously claimed that Scala Actors were more expressive because the wide variety of control structures they provide (and I didn't even touch on some of the &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/9da337a0db7f/src/actors/scala/actors/ActorDSL.scala"&gt;DSL-like functionality&lt;/a&gt; that enables all sorts of interesting things).  However, given Lift Actors far simpler and more extensible foundation, there is much more opportunity to create custom control structures as extensions to Lift Actors without modifying the core.  Thus, if you are willing to do some lower-level programming, it could be argued that Lift Actors are in reality more expressive due to their extensibility.&lt;/p&gt;
&lt;h3&gt;Performance and Scalability&lt;/h3&gt;
&lt;p&gt;For purposes here, I'm going to treat performance as the rate a which an actor can receive and process messages at a relatively small, fixed number of simultaneous actors.   This means that improving performance in largely a matter of reducing the time it takes from when a message is initially sent to when user-code within the actor begins processing the message, including minimizing any pause between when an actor finishes processing one message and is available to start processing the next.  For moderate numbers of actors, performance is often maximized by having one thread per actor, and having the actor block while waiting for a message.  Given enough actors, the memory requirements of using a thread for each actor will eventually cause more slowdown than cost of scheduling a new reaction for each message.  This is illustrated in Philipp Haller's paper, &amp;quot;&lt;a href="http://lamp.epfl.ch/~phaller/doc/haller07actorsunify.pdf"&gt;Actors that Unify Threads and Events&lt;/a&gt;&amp;quot; in the following graph:&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-ZOtVRo0ba8/Sj7cg55bpxI/AAAAAAAAADw/sDRTvCi9Wes/s1600-h/actor_scale_graph.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 290px;" src="http://3.bp.blogspot.com/_-ZOtVRo0ba8/Sj7cg55bpxI/AAAAAAAAADw/sDRTvCi9Wes/s400/actor_scale_graph.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5349955865218361106" /&gt;&lt;/a&gt;
&lt;p&gt;Note that the above graph covers a microbenchmark running a simple, non-memory intensive task, and that the thread line is not a measurement of thread-bound actors, but rather of a simple threaded implementation.  However, my own benchmarking has shown that receive-based (ones that block on a thread) compare to event-based actors in almost the same way as threads to event-based actors in the above graph.  Also, remember that given a real application where heap space is needed for things besides the stacks of thousands of threads the point where the JVM throws an &lt;a href="http://java.sun.com/javase/6/docs/api/java/lang/OutOfMemoryError.html"&gt;OutOfMemoryError&lt;/a&gt; will be much farther to the left.  There are also more subtle issues.  One of my first experiences with the Scala Actors library was creating a deadlock.  I created more thread-bound actors than the scheduler wanted to create threads, and thus actors were stuck blocking on threads waiting for messages from an actor that hadn't started yet because there were no available threads.  In other words, blocking can lead to situations such as deadlock, starvation, and simply extreme forms of unfairness with respect to how much CPU time is allocated each actor.  These all go against highly desirable guarantees that a actor library should provide outside of extreme circumstances.&lt;/p&gt;
&lt;p&gt;Ultimately event-based actors make the better model.  For one, part of the reason why event-based Scala Actors are so expensive is that they suspend by throwing an exception to return control from user code to the library.  While exceptions have been heavily optimized in the JVM, especially in recent versions, they are still substantially slower than normal return paths.  Scala Actors need to use exceptions to suspend is a consequence of their expressivity.  Basically, because the library as little or no knowledge of what an actor is doing within a reaction, it cannot rely on traditional returns without introducing special control structures (see reactWhile numbers in one of my &lt;a href="http://erikengbrecht.blogspot.com/2009/02/scala-actors-versus-exceptionblob.html"&gt;previous blogs&lt;/a&gt;).  Lift Actors, on the other hand, have do not need to use exceptions for control flow because the message processing cycle is essentially fixed - user code cannot intersperse weird (or even not-so-weird) patterns within it, or mix in blocking receives with event-based ones.  Another potential optimization of event-based actors is to have them block if there are plenty of threads available, and then release it if the thread they are on is needed by the scheduler.  To my knowledge this optimization is not implemented anywhere, but I think it would be relatively straight forward.  The only problem is that the actor becomes more tightly bound to its scheduler.&lt;/p&gt;
&lt;h3&gt;Parting Thoughts&lt;/h3&gt;
&lt;p&gt;Ultimately, time and community willing, I'd like to evolve what is here, plus solid treatment of a lot of lower-level details, into a &lt;a href="http://www.scala-lang.org/node/233"&gt;Scala Improvement Document (SID&lt;/a&gt;).  There are a lot of subtle trades involved, and I think producing a general-purpose actors library is at least an order-of-magnitude more difficult than producing a special-purpose one.  I also believe that if an actor implementation is part of the standard library, then it should provide the necessary extension points for when users need something special-purpose they can create it and still leverage components of the standard library and interoperate with other actors.  In order words, I think it should define both the interface portion of an API along with providing a solid implementation.  I don't think we'll even get their without a clear and common understanding of the various considerations involved.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7660120549919445761?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7660120549919445761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7660120549919445761' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7660120549919445761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7660120549919445761'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2009/06/pondering-actor-design-trades.html' title='Pondering Actor Design Trades'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_-ZOtVRo0ba8/Sj7cg55bpxI/AAAAAAAAADw/sDRTvCi9Wes/s72-c/actor_scale_graph.png' height='72' width='72'/><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7940624815281444410</id><published>2009-05-25T22:42:00.001-04:00</published><updated>2009-05-25T22:44:09.254-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='twitter'/><title type='text'>I'm on Twitter!</title><content type='html'>For those of you with ADD or it's internet induced equivalents, I've started posting on &lt;a href="http://twitter.com/ErikEngbrecht"&gt;Twitter&lt;/a&gt;.  I long avoided it because I feel like the last thing people need is yet another half-baked information stream, but then people seem to like it so I'm giving it a shot.  I'll post links to bugs, patches, and other comments regarding my efforts (and those of others) with Scala actors...along with other less important matters.

http://twitter.com/ErikEngbrecht&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7940624815281444410?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7940624815281444410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7940624815281444410' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7940624815281444410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7940624815281444410'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2009/05/im-on-twitter.html' title='I&apos;m on Twitter!'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-543132670654961435</id><published>2009-05-25T22:32:00.002-04:00</published><updated>2009-05-25T22:33:53.735-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='parallelism'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Refactoring Scala Actors: Progress Update</title><content type='html'>&lt;p&gt;It's been a while since I've posted, so I thought I'd give everyone a status update.  This post covers several different semi-disjoint topics at a fairly high level.  I plan on diving into some of the issues later this week and beyond, but for now...&lt;/p&gt;
&lt;h2&gt;State-machine Based Actors&lt;/h2&gt;
&lt;p&gt;A while back Philipp Haller, the original author and current maintainer of the Scala actors library, contacted and basically said he found the changes I was making really interesting, but he really needed a smaller, more gradual set of patches.  It's a perfectly reasonable request, as I had pretty much completely ripped apart his library.  I had rethought my approach, anyway, so I went about moving my state-machine based actor implementation into its own package and rewiring some of the pieces so that they could share common base traits, common infrastructure, and interoperate with one another as if they were the same library.  So I shoved my code into scalax.actors, and started hacking insertion points for my code into the main library.&lt;/p&gt;
&lt;p&gt;The first thing I thought I needed was a base trait that defines the basic structure and operations of an actor, so created a &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/24c0eb1f167b/src/actors/scala/actors/BaseActor.scala"&gt;BaseActor&lt;/a&gt; in between &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/24c0eb1f167b/src/actors/scala/actors/AbstractActor.scala"&gt;AbstractActor&lt;/a&gt; and &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/24c0eb1f167b/src/actors/scala/actors/Actor.scala"&gt;Actor&lt;/a&gt; (as well as my own &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/24c0eb1f167b/src/actors/scalax/actors/StateActor.scala"&gt;StateActor&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;
trait BaseActor extends AbstractActor {
  def react(f: PartialFunction[Any, Unit]): Nothing
  def reactWithin(msec: Long)(f: PartialFunction[Any, Unit]): Nothing
  def receive[A](f: PartialFunction[Any, A]): A
  def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R
  /*def loop(body: =&amp;gt; Unit): Nothing */
  /*def loopWhile(cond: =&amp;gt; Boolean)(body: =&amp;gt; Unit): Nothing */
  protected[actors] def mailbox: MessageQueue[Message[Any]]
  private[actors] final def mailboxForChannel: MessageQueue[Message[Any]] = mailbox
  def mailboxSize: Int
  def send(msg: Any, replyTo: OutputChannel[Any]): Unit
  def forward(msg: Any): Unit
  def reply(msg: Any): Unit
  /*protected[actors]*/ def sender: OutputChannel[Any]
  def ? : Any
  def start(): AbstractActor
  def freshReplyChannel: Channel[Any] = new Channel[Any](this)
  def scheduler: IScheduler //TODO: restrict access to scheduler??
}
&lt;/pre&gt;
&lt;p&gt;I don't think BaseActor is going to be a permanent fixture because its contents probably belong in AbstractActor instead, but for now it serves its purpose.  One of the first things you should notice is that way to much stuff in there is public.  Most of it should be protected, or perhaps somewhere else entirely (like an &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/24c0eb1f167b/src/actors/scala/actors/InputChannel.scala"&gt;InputChannel&lt;/a&gt; encapsulated by the actor).&lt;/p&gt;
&lt;h2&gt;Reworking MessageQueue&lt;/h2&gt;
&lt;p&gt;There's also the issue of the mailbox, which is a rather important and a den of mutable data that is passed all around with private[actors] qualifiers.  Basically it separates the &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/14e33a6ea1f8/src/actors/scala/actors/Message.scala"&gt;Message&lt;/a&gt; from the elements within the &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/14e33a6ea1f8/src/actors/scala/actors/MessageQueue.scala"&gt;MessageQueue&lt;/a&gt;, so that the MessageQueue can keep its internal structure private, and thus facilitating making it a trait so that an actor can provide its own specialized implementation.  I was about to submit a patch for the change, but a fix for a &lt;a href="http://lampsvn.epfl.ch/trac/scala/ticket/1801"&gt;memory leak&lt;/a&gt; in &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/14e33a6ea1f8/src/actors/scala/actors/FJTaskRunner.java"&gt;FJTaskRunner&lt;/a&gt; came about that relied on clearing mutable fields in the message when a task is done processing.  I have an alternative fix by changing pieces of &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/14e33a6ea1f8/src/actors/scala/actors/FJTaskScheduler2.scala"&gt;FJTaskScheduler2&lt;/a&gt;, but schedulers in general and FJTaskScheduler2 in specific are in flux right now due to bugs (&lt;a href="http://lampsvn.epfl.ch/trac/scala/ticket/1999"&gt;here&lt;/a&gt; and &lt;a href="http://lampsvn.epfl.ch/trac/scala/ticket/1965"&gt;here&lt;/a&gt; and probably elsewhere), and I want to tweak the design a bit, so I'm holding off.&lt;/p&gt;
&lt;h2&gt;Fixing Schedulers&lt;/h2&gt;
&lt;p&gt;Which brings me to schedulers...  Problems with plugging in &lt;a href="http://lampsvn.epfl.ch/trac/scala/ticket/1405"&gt;custom schedulers&lt;/a&gt; (mostly &lt;a href="http://lampsvn.epfl.ch/trac/scala/changeset/16970/scala/trunk/src/actors/scala/actors/Actor.scala"&gt;fixed&lt;/a&gt;) are what originally caused me to dive into the guts of the actor library.  Closely related to schedulers is &lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_7_4_final/src/actors/scala/actors/ActorGC.scala?rev=17815"&gt;ActorGC,&lt;/a&gt; which is absolutely essential to actors (almost) transparently abstracting threads, but can also be problematic due to it's fundamentally non-deterministic nature (it relies on the garbage collector for some of its more advanced capabilities).  That being said, now in trunk &lt;a href="http://lampsvn.epfl.ch/trac/scala/ticket/2012"&gt;ActorGC is optional&lt;/a&gt;, so environments that don't require an implicit shutdown of the actor worker threads can avoid the added complexity.  I intend to cover the details of ActorGC very soon.  There should also be a default scheduler with daemon semantics coming, which has a number of use cases.&lt;/p&gt;
&lt;h2&gt;Closing Matter&lt;/h2&gt;
&lt;p&gt;There's a lot more going on.  Some recent flare-ups on &lt;a href="http://thread.gmane.org/gmane.comp.lang.scala.internals/453"&gt;Scala&lt;/a&gt; &lt;a href="http://thread.gmane.org/gmane.comp.lang.scala.internals/505"&gt;Internals&lt;/a&gt; &lt;a href="http://thread.gmane.org/gmane.comp.lang.scala.internals/517"&gt;mailing&lt;/a&gt;, despite being a tad melodramatic, brought a welcome focus on actors for the next release of Scala.  The issue has also given rise to two minimalistic actor implementations, one in &lt;a href="http://github.com/dpp/liftweb/blob/b59fd205fa812ba527172be7250d12cf5921b776/lift-actor/src/main/scala/net/liftweb/actor/LiftActor.scala"&gt;Lift&lt;/a&gt; and the other in &lt;a href="http://code.google.com/p/scalaz/source/browse/trunk/src/main/scala/scalaz/concurrent/Actor.scala"&gt;Scalaz&lt;/a&gt;.  They both make interesting data points for design and potential interoperability (remember: one of my primary goals is an actor implementation that lets you plug in what you need).  There's &lt;a href="http://lampsvn.epfl.ch/trac/scala/ticket/1794"&gt;issues&lt;/a&gt; around &lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_7_4_final/src/actors/scala/actors/ActorProxy.scala?rev=17815"&gt;ActorProxy&lt;/a&gt; that I think will be a little hairy to sort out, but I'm confident they will be.  And finally, there's the omnipresent &lt;a href="http://lampsvn.epfl.ch/trac/scala/ticket/2009"&gt;issue&lt;/a&gt; of ensuring actor's really make the guarantees that they claim (right now I think they do, but I wouldn't place money on it until I have tests to prove it).&lt;/p&gt;
&lt;p&gt;That's it for now.  I'm going to try to take the time to blog about many of the above issues and more in depth in the coming weeks, and hopefully gain some insights from out in the cloud.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-543132670654961435?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/543132670654961435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=543132670654961435' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/543132670654961435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/543132670654961435'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2009/05/refactoring-scala-actors-progress.html' title='Refactoring Scala Actors: Progress Update'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4852443213427788983</id><published>2009-04-21T22:39:00.002-04:00</published><updated>2009-04-21T22:40:46.243-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><category scheme='http://www.blogger.com/atom/ns#' term='cloud computing'/><title type='text'>McKinsey and Cloud Computing</title><content type='html'>&lt;p&gt;McKinsey has created a tempest-in-a-teapot by &lt;a href="http://uptimeinstitute.org/images/stories/McKinsey_Report_Cloud_Computing/clearing_the_air_on_cloud_computing.pdf"&gt;denouncing the economics&lt;/a&gt; behind both in-the-cloud-cloud such as &lt;a href="http://aws.amazon.com/ec2/"&gt;Amazon E2C&lt;/a&gt; and behind-the-firewall clouds for large enterprises.  At a high level I think their analysis is actually pretty good, but the conclusions misleading due to a semantic twist.  They use Amazon E2C as a model, and their conclusions go something like this:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Amazon E2C virtual CPU cycles are more expensive than real, in-house CPU cycles&lt;/li&gt;
    &lt;li&gt;You waste 90% of those in-house CPU cycles&lt;/li&gt;
    &lt;li&gt;You'll waste almost as many of those virtual cloud CPU cycles, only they cost more, so they are a bad deal&lt;/li&gt;
    &lt;li&gt;You stand a decent shot at saving some of those real CPU cycles through virtualization, so you should aggressively virtualize your datacenter&lt;/li&gt;
    &lt;li&gt;You're too inept to deliver a flexible cloud behind-the-firewall, so don't even try&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I'll let you ponder which of the above statements is misleading while I address some related topics.&lt;/p&gt;
&lt;p&gt;The goals of cloud computing are as old as computing itself.  They are:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Reduce the time it takes to deploy a new application&lt;/li&gt;
    &lt;li&gt;Reduce the marginal cost of deploying a new application over &amp;quot;standard&amp;quot; methods&lt;/li&gt;
    &lt;li&gt;Reduce the marginal increase to recurring costs caused by deploying a new application over &amp;quot;standard&amp;quot; methods&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Back in the days of yore, when programmers were real men, the solution to this was &lt;a href="http://en.wikipedia.org/wiki/Time-sharing"&gt;time sharing&lt;/a&gt;.  Computers were expensive and therefore should be run at as a high of utilization as possible.  While making people stand in line a wait to run their batch jobs was a pleasing ego trip for the data center operators, the machines still wasted CPU time while performing slow I/O operations and waiting in line generally made users unhappy.  Thus time sharing was born, and in a quite real sense the first cloud computing environments, because in many cases a large institution would purchase and host the infrastructure and then lease it out of smaller institutions or individuals.&lt;/p&gt;
&lt;p&gt;The problem here is that the marginal cost equations end up looking like a stair-step function.  If you had a new application, and your enterprise / institution had excess mainframe capacity, then the marginal cost of letting you run your application was near zero.  But if there was no spare capacity - meaning the mainframe was being efficiently utilized - then the marginal cost was high because either someone else had to be booted off or you needed an additional mainframe.&lt;/p&gt;
&lt;p&gt;Now fast-forward a couple decades to the PC revolution.  Somewhere along the way the cost curves for computers and people crossed, so it became appropriate to let the computer sit idle waiting for input from a user rather than having a user sit idle while waiting for a computer.  Now you could have lots of computers with lots of applications running on each one (although initially it was one application at at time, but still, the computer could run any number of them).  This smoothed out the non-recurring marginal cost curve, but as PCs proliferated it drove up recurring costs through sheer volume.&lt;/p&gt;
&lt;p&gt;Unfortunately this had problems.  Many applications didn't work well without centralized backends, and some users still needed more compute power than could be reasonably mustered on the desktop.  So the new PCs were connected to mainframes, minicomputers, and eventually servers.  Thus client-server computing was born, along with increasingly confusing IT economics.  PCs were cheap, and constantly becoming cheaper, but backend hardware remained expensive.  The marginal non-recurring cost becomes completely dependent on the nature of the application, and recurring costs simply begin to climb with no end in sight.&lt;/p&gt;
&lt;p&gt;Now fast forward a little more.  Microsoft releases a &amp;quot;server&amp;quot; operating system that runs on suped up PCs an convinces a whole bunch of bean counters that they can solve their remaining marginal non-recurring cost problems with Wintel servers that don't cost much more than PCs.  Now more expensive servers.  No more having to divide the cost of a single piece of hardware across several project.  Now if you want to add an application you can just add an inexpensive new Wintel server.  By this time the recurring cost equation had already become a jumbled mess, and the number of servers was still dwarfed by the PC on every desk, so there no tying back the ever increasing recurring costs.  This problem was then further exacerbated by Linux giving the Unix holdouts access to the same cheap hardware.&lt;/p&gt;
&lt;p&gt;Thus began the era of one or more physical servers per application, which is where we are today, with McKinsey's suggestion for addressing: virtualization behind the firewall.  The problem with this suggestion is that, for a large enterprise, it isn't really that different from the cloud-in-the-cloud solution that they denounce as uneconomical.  One way is outsourcing a virtualized infrastructure to Amazon or similar, and the other is outsourcing it to their existing IT provider (ok, not all large enterprises outsource their IT, but a whole lot do).&lt;/p&gt;
&lt;p&gt;Virtualization, in the cloud or otherwise, isn't the solution because it doesn't address the root cause of the problem - proliferation of (virtual) servers and the various pieces of infrastructure software that run on them, such as web servers and databases.  Hardware is cheap.  Software is often expensive.  System administrators are always expensive.  Virtualization attacks the most minor portion of the equation.&lt;/p&gt;
&lt;p&gt;Virtualization is the right concept applied to the wrong level of the application stack.  Applications need to be protected from one another, but if they are built in anything resembling a reasonable way (that's a big caveat, because many aren't) then they don't need the full protections of running in a separate OS instance.  There's even a long standing commercially viable market for such a thing: &lt;a href="http://en.wikipedia.org/wiki/Shared_hosting"&gt;shared web hosting.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It may not be very enterprisey, but shared web site/application hosting can easily be had for about $5 per month.  The cost quickly goes up as you add capabilities, but still - companies are making money by charging arbitrary people $5 per month to let them run arbitrary code on servers shared by countless other customers running arbitrary code.  How many enterprise IT organizations can offer a similar service at even an order-of-magnitude greater cost?&lt;/p&gt;
&lt;p&gt;Not many, if any.  Yet do we see suggestions pointing out that Apache, IIS, Oracle, SQL Server, and countless other pieces of infrastructure can relatively easily be configured to let several applications share compute resources and expensive software licenses?  Nope.  They suggest you take your current mess, and virtualize it behind the firewall instead of virtualizing it outside the firewall.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-4852443213427788983?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4852443213427788983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4852443213427788983' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4852443213427788983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4852443213427788983'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2009/04/mckinsey-and-cloud-computing.html' title='McKinsey and Cloud Computing'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4462328390052896724</id><published>2009-02-10T20:17:00.002-05:00</published><updated>2009-02-10T20:17:56.448-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='parallelism'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Refactoring Scala Actors:  Rethinking the Approach</title><content type='html'>&lt;p&gt;When I started refactoring Scala's actor library, I really had several goals:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Reduce the coupling within the library so that the implementation can be more easily extended and customized&lt;/li&gt;
    &lt;li&gt;Create a more transparent and &amp;quot;programmer friendly&amp;quot; actor implementation&lt;/li&gt;
    &lt;li&gt;Improve performance of various use cases&lt;/li&gt;
    &lt;li&gt;Make actors that interact better with their environment, particularly non-actor code&lt;/li&gt;
    &lt;li&gt;Maintain API compatibility with the existing library to the maximum extent practical&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thus far I've done my work by completely overhauling the &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/tip/src/actors/scala/actors/Actor.scala"&gt;Actor&lt;/a&gt; &lt;a href="http://www.scala-lang.org/node/126"&gt;trait&lt;/a&gt; directly in the library.  While I have plans for how this will reduce coupling, the haven't come to fruition yet.  I think my state machine model is considerably more transparent and programmer friendly than the current implementation.  The state an actor in is always clear, transition are reasonably well defined, and performing correct locking and unlocking is now pretty straight forward.  I've substantially improved the performance of event-based actors for the common case where an actor loops while it receives messages until some termination criterion is reached.  I haven't done anything with making them interact better with their environment yet, as I believe &lt;a href="http://lamp.epfl.ch/~phaller/"&gt;Philipp Haller&lt;/a&gt; is in the process of incorporating some changes for which I submitted patches several months back that will help considerably (he doesn't appear to be using the patches directly, but the changes I've seen are close enough).&lt;/p&gt;
&lt;p&gt;A few days ago &lt;a href="http://www.drmaciver.com/"&gt;David MacIver&lt;/a&gt; asked me a couple interesting questions on IRC:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Have you considered using &lt;a href="http://kilim.malhar.net/"&gt;Kilim&lt;/a&gt;?&lt;/li&gt;
    &lt;li&gt;Have you looked at the &lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/compiler-plugins/continuations/trunk"&gt;continuations support&lt;/a&gt; that appears to be emerging as a compiler plugin?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using Kilim would almost certainly disqualify the changes I'm making from incorporation into the standard library because of the external dependency on a prerelease framework that uses bytecode manipulation, and I don't think the fledgling continuation support is mature enough to experiment with yet (or maybe just not well documented enough yet, who knows...).  That being said, both of these would be interesting avenues of development.  Event based actors rely heavily on continuations, and the performance of those continuations has a substantial effect on the performance of the actors.  Ultimately a properly decoupled implementation would allow someone to build an API compatible actor implementation on either of these technologies, or something else entirely.&lt;/p&gt;
&lt;p&gt;I also received a recent nudge on the mailing list, when someone pointed out that it would be easier to experiment with my library if it was in it's own package.  I somewhat disagree with that.  It would be easier to experiment with it if you didn't have to do an entire build of the Scala distribution that has my code in it, and unfortunately for the foreseeable future I'm going to be depending on both code that is being committed into the trunk and on the ability to modify said code.  Also, the way I have it setup today, if someone wanted to test their Scala application/library/framework against my state-based actors, they would just have to pull my &lt;a href="http://www.selenic.com/mercurial/"&gt;Mercurial&lt;/a&gt; &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/"&gt;repository&lt;/a&gt;, build it, and rebuild against the resulting distribution.  On the downside, it's a pain to do side-by-side comparisons between the two implementations, because you have to switch distributions and rebuild every time.&lt;/p&gt;
&lt;p&gt;That being said, decoupling is one of my primary goals, and Martin &amp;amp; Company have already set the precedence of doing major work in a separate package with their efforts on&lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scalax/collection"&gt; redesigning the Scala collections&lt;/a&gt; library.  So as soon as I finish up some of my immediate tasks and have a good build again (I'm in the middle of redesigning the control flow pattern to minimize the stack size when exceptions are thrown), I'm going to push most of the public and protected interface on &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/tip/src/actors/scala/actors/Actor.scala"&gt;Actor&lt;/a&gt; into a new trait that will be between Actor and &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/tip/src/actors/scala/actors/AbstractActor.scala"&gt;AbstractActor&lt;/a&gt; as abstract methods, move my code out of &lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors"&gt;scala.actors&lt;/a&gt; and into scalax.actors in my own directory.  I definitely keep it within the same repository as the Scala distribution code, and will probably just make another directory for it.  This means I'll have to mess with &lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/build.xml"&gt;Sabbus&lt;/a&gt; to add my portion to the build, which won't be fun, but shouldn't be too hard.  I'm sure there's going to be a lot more to do to extract it out, so I'll be adding items to my issues list as I think of them.&lt;/p&gt;
&lt;p&gt;The end result should be my state based actors and the existing actors being able to live side-by-side and interact with one another in the same program.  Assuming I can at least get some patches into the main library, it will also mean that the future of my work will not be dependent on being incorporated into the standard distribution.  If it is, great, if not, I can distribute it separately.  I would have done this from the start, but initially I was highly dependent on the existing code and infrastructure into order to get something working reasonably quickly, and to be able to smoke it out to see if it indeed worked.  Back in December I was basically breaking &lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/test"&gt;partest&lt;/a&gt; with every change.  But now things are reasonably stable, I rarely break partest, and I don't think it will take much for my code to be able to stand on its own.&lt;/p&gt;
&lt;p&gt;So what does everyone think?  Is this a good direction to head in?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-4462328390052896724?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4462328390052896724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4462328390052896724' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4462328390052896724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4462328390052896724'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2009/02/refactoring-scala-actors-rethinking.html' title='Refactoring Scala Actors:  Rethinking the Approach'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-2459488312011080440</id><published>2009-02-06T22:37:00.002-05:00</published><updated>2009-02-06T22:38:04.091-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Profiling the ExceptionBlob</title><content type='html'>&lt;p&gt;Last week on the Scala IRC channel (#scala) I chatted with several people about the need to substantially reduce the use of exceptions for flow control within the Scala Actors library.  My remarks were met with a certain amount of healthy skepticism, as significant progress has been made on improving the performance of Java exceptions, as stated by &lt;a href="http://blogs.sun.com/jrose/"&gt;John Rose&lt;/a&gt; in his blog &lt;a href="http://blogs.sun.com/jrose/entry/longjumps_considered_inexpensive"&gt;Longjumps Considered Inexpensive&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I highly suggest you go read the post.  I don't doubt anything stated in it, and in fact noticed a substantial performance improvement when I stopped benchmarking against Java 5 and started doing it against &lt;a href="https://jdk6.dev.java.net/"&gt;Java 6&lt;/a&gt; (I usually work on a Mac, and Java 5 is the default VM), and expect even more improvements with &lt;a href="https://jdk7.dev.java.net/"&gt;Java 7&lt;/a&gt;.  Once you're done, I'd like to call your attention to a couple fragments of it (additional emphasis mine):&lt;/p&gt;
&lt;blockquote&gt;
    &lt;p&gt;The Hotspot JIT can optimize a throw of a preallocated exception into a simple goto, if the &lt;strong&gt;thrower and catcher are together in the same compilation unit&lt;/strong&gt; (which happens because of inlining).&lt;/p&gt;
    &lt;p&gt;Here is a concrete example of non-local return, implemented efficiently via a cloned exception. I have observed the Hotspot server compiler emitting a machine-level goto for the throws. With current server VM optimizations of this code, the cost of a non-local return is &lt;strong&gt;less than three times the cost of a plain (local) return&lt;/strong&gt;; with the client VM the ratio is ten. See the code example and benchmark for details: NonLocalExit.java (javadoc).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These statements have a couple implications:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Reducing a throw to a long jump requires a certain amount of HotSpot magic take place to ensure that the throw and catch are in the same compilation unit.  The more complex the code is, the less likely this is to happen.&lt;/li&gt;
    &lt;li&gt;Long jumps are still substantially slower than normal returns&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I think John's post received a lot of attention, and people (including myself) saw it, didn't read it carefully, and assumed that HotSpot now performed miracles with cached exceptions.   What we missed was a &lt;a href="http://mail.openjdk.java.net/pipermail/mlvm-dev/2008-May/000114.html"&gt;post&lt;/a&gt; to the &lt;a href="http://openjdk.java.net/projects/mlvm/"&gt;MLVM&lt;/a&gt; development &lt;a href="http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev"&gt;mailing list&lt;/a&gt; about a year later by &lt;a href="http://blog.headius.com/"&gt;Charles Nutter&lt;/a&gt;, who had noticed that his non-local returns in &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt; where not being compiled down into long jumps, and &lt;a href="http://mail.openjdk.java.net/pipermail/mlvm-dev/2008-May/000115.html"&gt;subsequent response&lt;/a&gt; from John Rose.  There's a lot of very good technical discussion in there, but I think the gist is that HotSpot's ability to optimize throws into long jumps is still limited, it often needs help to do so, and very smart people are working at improving it.&lt;/p&gt;
&lt;p&gt;Of course that all still leaves the question:  Just how much slower are cached exceptions than a normal return?  I can't really answer that in the general case, but I did put together a couple mircobenchmarks in Java that somewhat simulate the type of stack creation that happens within my state-based actors.  The benchmark is pretty simple.  It recursively descends down, incrementing a member variable, and then on the way back up it decrements another member variable.  In the case of the exception-based return, it does the decrements within a finally block.  This admittedly is rather pathological code, but it is also simple and easy to understand.&lt;/p&gt;
&lt;p&gt;Here's the normal return version:&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
public class NormalReturn {
    public static void main(String[] args) {
        NormalReturn m = new NormalReturn();
        m.doTest(10000000);
    }
    public void doTest(int times) {
        for(int i = 0; i &amp;lt; times; i++) {
            down = 0;
            up = 0;
            deepRecurse(1000);
        }
        System.out.println(down);
        System.out.println(up);
    }
    private int down = 0;
    private int up = 0;
    public void deepRecurse(int i) {
        down++;
        if (down &amp;lt;= i) {
            deepRecurse(i);
            up--;
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;...and here's the version that uses a cached exception:&lt;/p&gt;
&lt;pre name="code" class="java"&gt;
public class TryFinally {
    private static class Signal extends RuntimeException {
        @Override
        public Signal fillInStackTrace() { return this; }
    }
    private Signal signal = new Signal();
    public static void main(String[] args) {
        TryFinally m = new TryFinally();
        m.doTest(10000000);
    }
    public void doTest(int times) {
        for(int i = 0; i &amp;lt; times; i++) {
            try {
                down = 0;
                up = 0;
                deepRecurse(1000);
            } catch (Signal s) {
                // do nothing
            }
        }
        System.out.println(down);
        System.out.println(up);
    }
    private int down = 0;
    private int up = 0;
    public void deepRecurse(int i) {
        try {
            down++;
            if (down == i) throw signal;
            else deepRecurse(i);
        } finally {
            up--;
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;With profiling turned off on and -server on Java 6 on my Mac, the normal return version takes about 60 seconds to complete, while the TryFinally version takes over 10 minutes.  That's certainly much better than the 30x figure John Rose cited for the client VM, but it's still an order-of-magnitude worse than a normal return.  One interesting thing about the benchmark is that if you decrease the recursion depth and increase the number of times deepRecurse() is executed the total time stays relatively constant.&lt;/p&gt;
&lt;p&gt;So with this in mind, I'm going to work hard to refactor the actors library to keep exception usage to a minimum, an where it must be used to minimize the depth of the stack.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-2459488312011080440?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/2459488312011080440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=2459488312011080440' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2459488312011080440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2459488312011080440'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2009/02/profiling-exceptionblob.html' title='Profiling the ExceptionBlob'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-6595238701058213206</id><published>2009-02-06T18:03:00.003-05:00</published><updated>2009-02-06T18:07:29.631-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='parallelism'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Scala Actors versus the ExceptionBlob</title><content type='html'>&lt;p&gt;I've begun some very preliminary benchmarking of my state-based actors library against the current standard actors library and seen some rather interesting results.  The test I'm running spawns four pairs of actors and sends about 40 million messages between each pair.  The only logic in the actors is to count how many messages they have received, ensure they are received in order, and occasionally send back a &amp;quot;More&amp;quot; message.  This is so the mailbox doesn't overfill and cause out-of-memory errors.&lt;/p&gt;
&lt;p&gt;The benchmark has three different incarnations, each testing a different way of processing messages until some termination condition occurs.  The versions are:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;loop&lt;/li&gt;
    &lt;li&gt;recursive react&lt;/li&gt;
    &lt;li&gt;reactWhile (only available with the State-based actors, but relatively easy to port to &amp;quot;classic&amp;quot; actors)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The code for the loop version is below:&lt;/p&gt;
&lt;pre name="code" class="scala"&gt;
class LoopPingSender(val totalPings: Int, val pingReceiver: LoopPingReceiver) extends Actor {
  private var pingsSent = 0
  def act() {
    Actor.loop {
      pingReceiver ! Ping(pingsSent)
      pingsSent += 1
      if (pingsSent == totalPings) {
        println("Sender Done")
        exit("sender completed successfully")
      } else if ((pingsSent % 1000) == 0) react {
        case More =&amp;gt; 
      }
    }
  }
}
class LoopPingReceiver(val totalPings: Int) extends Actor {
  private var pingsReceived = 0
  def act() {
    Actor.loop {
      react {
        case Ping(n) if n == pingsReceived =&amp;gt; {
          pingsReceived += 1
          if (pingsReceived == totalPings) {
            println("Receiver Done")
            exit("receiver completed successfully")
          } else if ((pingsReceived % 1000) == 0) {
            reply(More)
          }
        }
        case Ping(n) =&amp;gt; {
          println("error")
          exit("invalid n value: " + n)
        }
      }
    }
  }
}
&lt;/pre&gt;
&lt;p&gt;The non-scientifically gathered results are as follows, all times in seconds:&lt;/p&gt;
&lt;table border="1"&gt;
    &lt;tr&gt;
        &lt;th&gt;Version&lt;/th&gt;
        &lt;th&gt;Standard Actors&lt;/th&gt;
        &lt;th&gt;State-based Actors&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;loop&lt;/td&gt;
        &lt;td&gt;298.22&lt;/td&gt;
        &lt;td&gt;96.84&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Recursive react&lt;/td&gt;
        &lt;td&gt;90.25&lt;/td&gt;
        &lt;td&gt;113.57&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;reactWhile&lt;/td&gt;
        &lt;td&gt;N/A&lt;/td&gt;
        &lt;td&gt;40.63&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;h3&gt;Standard Actor &lt;code&gt;loop&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Let's consider the loop version first.  loop in the standard actor implementation is rather convoluted.  Rather than directly supporting looping, the standard actor implementation provides a package private hook for a function that is executed when the actor is terminating.  loop uses this hook to subvert the termination process by throwing an exception and subsequently restarting execution of the actor.  This makes it so that two exceptions are thrown per message processed rather than the normal one.  Here's a small snippet from the profiling results:&lt;/p&gt;
&lt;pre&gt;
     Compiled + native   Method                        
 40.0%  5148  +     0    ExceptionBlob
 13.9%   658  +  1133    scala.actors.Scheduler$$anon$2.run
 13.1%   391  +  1299    scala.actors.Actor$.loop
  3.4%   441  +     0    scala.actors.FJTaskRunner.run
--- snip ---
 73.7%  6705  +  2771    Total compiled
&lt;/pre&gt;
&lt;pre&gt;
         Stub + native   Method                        
 20.6%     0  +  2654    java.lang.Thread.isInterrupted
&lt;/pre&gt;
&lt;p&gt;What you can see is that the &lt;a href="http://docjar.org/docs/api/sun/jvm/hotspot/code/ExceptionBlob.html"&gt;ExceptionBlob&lt;/a&gt; is dominating the runtime, followed by Thread.isInterrupted.  &lt;a href="http://docjar.org/docs/api/sun/jvm/hotspot/code/ExceptionBlob.html"&gt;ExceptionBlob&lt;/a&gt; is a class in the JVM that observes the unwinding of the stack.  As far as I could discern through so separate microbenchmarking (which I'll discuss another day, after I've spent some time in HotSpot code), the amount of time consumed by &lt;a href="http://docjar.org/docs/api/sun/jvm/hotspot/code/ExceptionBlob.html"&gt;ExceptionBlob&lt;/a&gt; is proportionate depth of the stack being unwound by exceptions.  In other words, throwing fewer exceptions doesn't do any good if you use them to unwind deeper stacks, and unwinding shallower stacks doesn't do any good if you throw more exceptions.  Caching exceptions doesn't help, either, but I digress.  The bottom line is that loop is pretty inefficient in the standard actors implementation.&lt;/p&gt;
&lt;h3&gt;State-based Actor &lt;code&gt;loop&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;In my state-based actors, there are two states to handle looping, both of which are subclasses of &lt;code&gt;Running&lt;/code&gt;.  The first is &lt;code&gt;Looping&lt;/code&gt;, which is initially entered when the actor starts looping.  The second is &lt;code&gt;ResumeLooping&lt;/code&gt;, which is used to resume looping after the actor has been suspended.  Both run the body of the react in a tail-recursive loop until their are no more messages to process, at which time they suspend the actor.  This means that many message can potentially be processed before any exception-based signaling is used.  The following is a snippet from a profile:&lt;/p&gt;
&lt;pre&gt;
     Compiled + native   Method                        
 67.5%  3233  +     0    ExceptionBlob
  6.4%   306  +     0    scala.actors.Actor$class.withLock
  4.9%    44  +   189    actorbench.LoopPingSender$$anonfun$act$1.apply
  4.8%    97  +   135    scala.actors.Actor$$anonfun$send$1.apply
  4.5%   116  +    99    scala.actors.Actor$Running.tr$1
  3.8%    36  +   145    scala.actors.Actor$ResumeLooping.enter
--- snip ---
         Stub + native   Method                        
  0.2%     0  +     9    java.lang.Thread.isInterrupted
&lt;/pre&gt;
&lt;p&gt;Again, &lt;a href="http://docjar.org/docs/api/sun/jvm/hotspot/code/ExceptionBlob.html"&gt;ExceptionBlob&lt;/a&gt; dominates the execution time, although the total time it consumes is lower.  Unfortunately, despite using significantly fewer exception signals, my state-based actors tend to build up significantly deeper stacks than the actors in the standard library.&lt;/p&gt;
&lt;h3&gt;Standard Actor recursive &lt;code&gt;react&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Recursive react seems to be the best performing looping pattern for the standard actor library.  It's a pretty simple pattern:&lt;/p&gt;
&lt;pre name="code" class="scala"&gt;
class PingSender(val totalPings: Int, val pingReceiver: PingReceiver) extends Actor {
  def act() {
    def recurse(i: Int): Unit = {
      if (i &amp;gt; 0) {
        pingReceiver ! Ping(i)
        if ((i % 1000) == 0) {
          react {
            case More =&amp;gt; recurse(i - 1)
          }
        } else {
          recurse(i - 1)
        }
      } else {
        println("Sender Done")
      }
    }
    recurse(totalPings)
  }
}
&lt;/pre&gt;
&lt;p&gt;As you can see, the function containing the &lt;code&gt;react&lt;/code&gt; block is simply recursively called as needed.  Note that despite the fact that the recursive call appears to be in a tail position, it is not a tail recursive call and will not be optimized by the compiler.  The &lt;code&gt;&lt;a href="http://www.scala-lang.org/docu/files/api/scala/PartialFunction.html"&gt;PartialFunction&lt;/a&gt;&lt;/code&gt; defined within the &lt;code&gt;react&lt;/code&gt; block is actually a separate object with an apply method, so while &lt;code&gt;recurse&lt;/code&gt; and the &lt;code&gt;PartialFunction&lt;/code&gt; are mutually recursive, they are not tail recursive.&lt;/p&gt;
&lt;pre&gt;
     Compiled + native   Method                        
 19.1%   456  +     0    ExceptionBlob
 13.0%    89  +   221    scala.actors.Reaction.run
  8.6%    53  +   152    scala.actors.Actor$class.send
  7.9%    61  +   127    scala.actors.Actor$class.react
  5.3%    59  +    67    scala.Iterator$class.toList
--- snip ---
 68.1%   862  +   765    Total compiled

         Stub + native   Method                        
 26.4%     0  +   631    java.lang.Thread.isInterrupted
--- snip ---
 26.9%     0  +   643    Total stub
&lt;/pre&gt;
&lt;p&gt;This time &lt;code&gt;Thread.isInterrupted&lt;/code&gt; dominates, with &lt;code&gt;ExceptionBlob&lt;/code&gt; not too far behind.&lt;/p&gt;
&lt;h3&gt;Actor States recursive &lt;code&gt;react&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;It turns out that the &amp;quot;hybrid trampoline&amp;quot; I implemented to facilitate recursive reacts without giving up the thread provides pretty bad performance.&lt;/p&gt;
&lt;pre&gt;
 64.9%  3714  +     0    ExceptionBlob
 11.4%   568  +    85    scala.actors.Actor$class.withoutLock
  8.4%   478  +     1    scala.actors.Actor$class.withLock
  5.1%    90  +   201    scala.actors.Actor$$anonfun$reactWithin$1.apply
  4.2%   115  +   125    scala.actors.Actor$$anonfun$send$1.apply
--- snip ---
 97.8%  5006  +   595    Total compiled
         Stub + native   Method                        
  0.1%     0  +     6    java.lang.Thread.currentThread
--- snip ---
  0.2%     0  +    12    Total stub
&lt;/pre&gt;
&lt;p&gt;The problem is that when I wrote it, I thought that the cost of throwing exceptions was primarily proportionate to the number of exceptions thrown rather than the amount of stack that is unwound. Consequently, I made the trampoline only bounce once every &lt;em&gt;n&lt;/em&gt; invocations in order to reduce the number of exceptions being thrown. As it turns out, what I should do is find a place where the stack is likely to be the shallowest, and throw an exception every time.&lt;/p&gt;
&lt;h3&gt;Actor States &lt;code&gt;reactWhile&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;reactWhile&lt;/code&gt; addresses the pitfalls presented in the previous versions and provides roughly twice the performance of next best performer, recursive &lt;code&gt;react&lt;/code&gt; on the standard actor library.&lt;/p&gt;
&lt;pre&gt;
     Compiled + native   Method                        
 30.0%   171  +   331    scala.actors.Actor$Running.tr$1
 24.4%   263  +   146    actorbench.ReactWhileReceiver.withLock
 12.4%    26  +   181    actorbench.ReactWhileSender.sendPings
  8.5%   142  +     0    scala.actors.Actor$class.withoutLock
--- snip ---
 79.0%   660  +   661    Total compiled

         Stub + native   Method                        
 15.1%     0  +   252    java.lang.Thread.isInterrupted
  0.9%     0  +    15    java.lang.Thread.currentThread
 16.0%     0  +   267    Total stub
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ExceptionBlob&lt;/code&gt; has completely disappeared from the profile. That is because &lt;code&gt;reactWhile&lt;/code&gt; makes minimal use of exceptions for signaling.  Consequently, its performance is dominated by some of the complicated for my (worthless) hybrid trampoline, my completely unoptimized lock implementation, and calls to &lt;code&gt;Thread.isInterrupted&lt;/code&gt; that are made when the bound thread is returned to the pool when the actor suspends.  I'll write a blog on how &lt;code&gt;reactWhile&lt;/code&gt; works at a later date, after I cleanup some of the other problems that I've listed.&lt;/p&gt;
&lt;h3&gt;Parting Matter&lt;/h3&gt;
&lt;p&gt;It really annoys me when people post benchmark results without providing details of their setup along with all of the code required to duplicate them, and that's just what I've done.  I've also benchmarked a very narrow set of behavior, failed for warm up the JVM, and not run multiple trials.  Developing a &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/issue/14/make-a-simple-framework-for-benchmarking"&gt;lightweight framework&lt;/a&gt; for benchmarking actor performance, along with a more comprehensive set of benchmarks is on my &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/issues/?status=new&amp;status=open"&gt;to-do list&lt;/a&gt;.  Once I have that, I'll start doing more rigorous benchmarking.  But I don't think I quite need it yet because bottlenecks are showing up quickly and consistently in my profiling, and in most cases they seem to have reasonably straight forward solutions.  All the above profiles against my library were done against &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/changeset/49658b3475e2/"&gt;revision 49658b3475e2&lt;/a&gt; in my &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/overview/"&gt;bitbucket repository&lt;/a&gt;, so you can at least access that code.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-6595238701058213206?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/6595238701058213206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=6595238701058213206' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6595238701058213206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6595238701058213206'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2009/02/scala-actors-versus-exceptionblob.html' title='Scala Actors versus the ExceptionBlob'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-6370008183620208056</id><published>2009-01-31T10:16:00.005-05:00</published><updated>2009-01-31T10:21:21.312-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><title type='text'>Google is Paranoid</title><content type='html'>&lt;p&gt;Apparently Google has recently become extremely paranoid about what may harm my computer.  Here's a screenshot of some search results:&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_-ZOtVRo0ba8/SYRrq508AOI/AAAAAAAAADg/04K-u8zDJN4/s1600-h/search_results.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 370px; height: 400px;" src="http://2.bp.blogspot.com/_-ZOtVRo0ba8/SYRrq508AOI/AAAAAAAAADg/04K-u8zDJN4/s400/search_results.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5297477446516080866" /&gt;&lt;/a&gt;
&lt;p&gt;Looks like every result is dangerous...now here's what happens when I click on one of these dangerous links:&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_-ZOtVRo0ba8/SYRr8bCk-0I/AAAAAAAAADo/rKw_xsCJopU/s1600-h/click_link.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 274px;" src="http://4.bp.blogspot.com/_-ZOtVRo0ba8/SYRr8bCk-0I/AAAAAAAAADo/rKw_xsCJopU/s400/click_link.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5297477747489438530" /&gt;&lt;/a&gt;
&lt;p&gt;Must be Apple's developer website is out to get me...&lt;/p&gt;
&lt;p&gt;Note:  The behavior seems to have stopped.  Quick failed Google experiment?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-6370008183620208056?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/6370008183620208056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=6370008183620208056' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6370008183620208056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6370008183620208056'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2009/01/google-is-paranoid.html' title='Google is Paranoid'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_-ZOtVRo0ba8/SYRrq508AOI/AAAAAAAAADg/04K-u8zDJN4/s72-c/search_results.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-8240731004528113002</id><published>2009-01-24T15:52:00.002-05:00</published><updated>2009-01-24T15:53:41.512-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='parallelism'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Refactoring Scala Actors</title><content type='html'>&lt;p&gt;I've been experimenting in my spare time with the Scala actors library for about a year now. Initially it was mostly as part of my participation in the &lt;a href="http://erikengbrecht.blogspot.com/search/label/widefinder"&gt;Widefinder&lt;/a&gt; project, but for the past several months I've been working on building more complicated abstractions using the actor library. The challenge with Widefinder, if you chose to keep your parallelism implementation generic and reusable, was to spread line-oriented input stream processing across as many threads as possible (ok, some may disagree with that, but that was my simplified take). This was relatively straight forward because the lines didn't have to be processed in any given order. Actors worked well for the task, and I was able to build a fairly generic set of classes that could be used in a very natural way for any similar problem.&lt;/p&gt;
&lt;p&gt;I was feeling pretty good about Widefinder so I decided tackle a more complicated problem: parallelizing XML parsing (I'll write more on that later). In the process of exploring various ideas to help parallelize the parsing of XML I started butting my head against limitations of the actors library. For example, I built an &amp;quot;asynchronous stream&amp;quot; class - something like a normal Scala stream but instead of being entirely lazy, it asynchronously evaluates itself ahead of what has already been consumed, effectively parallelizing computation of the stream. This worked, except that if the stream wasn't fully evaluated the application using the stream wouldn't terminate properly because it's actor was still active. That made sense, as in many actor based applications you wouldn't want them to terminate before all the actors were finished, so I tried to make a custom scheduler that used daemon threads and therefore would allow the application to terminate without all of the actor threads terminating. This seemed like a straight forward task, except that it turned out to not be possible given some current limitations (link to enhancement about schedulers). So I set myself to fixing/enhancing the actors library to meet my needs and submit some patches.&lt;/p&gt;
&lt;p&gt;Making fixes and enhancements to the actors library turned out to be a much bigger challenge than I expected. The external API for actors, particularly the documented part, is pretty clean and flexible. However internally, at least to a new set of eyes, there is a lot of spaghetti (count methods and variables that are defined as private[actors] so all the classes in the package can muck with them), oddly named variables and methods, and over a dozen mutable variables on the Actor trait that must all be correctly set in the right combination in order for the actor to work - and completely lacking any sort of structured means of manipulating them. I braved this, submitted some patches, and even wrote several enhancements that I did not submit, but I kept running into subtle problems that seemed almost impossible to track down. I would sprinkle assertions throughout the code only to realize that even when things seemed to work much of what I assuming was really holding. In other words I was getting lucky - or unlucky - as challenges like this are pretty common when doing parallel programming.&lt;/p&gt;
&lt;p&gt;By this time I had a reasonable, albeit incomplete and with some inaccuracies, idea of what all those magical instance variables within Actor do and how they correspond to meaningful states. Here is my take on it:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;code&gt;waitingFor&lt;/code&gt; - the partial function that the actor is using to wait for a matching message&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;shouldExit&lt;/code&gt; - used to signal that the actor should exit instead of doing normal processing&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;isSuspended&lt;/code&gt; - seems to indicate that the actor is waiting while blocked on a thread&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;isDetached&lt;/code&gt; - the actor is waiting and is not attached to a thread&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;isWaiting&lt;/code&gt; - the actor is waiting in some way&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;mailbox&lt;/code&gt; - queue of messages for the actor&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;sessions&lt;/code&gt; - list used as a stack to keep track of the sender of messages while they are being processed&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;received&lt;/code&gt; - the message that was received, used to pass around a received message, could be replaced with local variable within functions&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;exitReason&lt;/code&gt; - the reason why the actor exited, default to 'normal when the actor is initialized and can be modified at any time, so it is there even when the actor has not yet exited.&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;onTimeout&lt;/code&gt; - used for keeping track of a timeout action so that it can be canceled if a message is received within the timeout period&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;kill&lt;/code&gt; - a function invoked by reaction prior to invoking exit on the actor. It is used by loop and loopWhile to bypass the normal exit process of reactions&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;trapExit&lt;/code&gt; - if false (the default) then the actor will exit when an actor that it is linked to exits, if it's true then it will receive an Exit message&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;rc&lt;/code&gt; - a reply channel - unclear why it is actually needed because it is never used other than to be set in freshReplyChannel on every invokation&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;links&lt;/code&gt; - a list of linked actors. Linked actors are notified or shutdown when the actor that they are linked to shuts down&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;continuation&lt;/code&gt; - the function to be executed when the actor resumes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All those were pretty confusing, and it took me weeks to make any sense out of them - and usually the sense I made contained subtle flaws, so I decided to do something drastic. In my opinion the actors library is in desperate need of being refactored into something that encapsulates its state better and makes it much more explicit so you do not need to be an advanced adept to figure out what is happening inside the library. So I decided to do that refactoring and see where it lead me.&lt;/p&gt;
&lt;p&gt;I distilled much of the above instance variables into the following states, which I have represented as immutable objects:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;code&gt;NotStarted&lt;/code&gt; - the initial state of the actor&lt;/li&gt;
    &lt;li&gt;
Active States
        &lt;ul&gt;
            &lt;li&gt;&lt;code&gt;StartScheduled&lt;/code&gt; - the actor has been started but has not yet been attached a thread or started executing its body&lt;/li&gt;
            &lt;li&gt;
Running States - states where the actor is bound to a thread and is executing its body
                &lt;ul&gt;
                    &lt;li&gt;&lt;code&gt;Running&lt;/code&gt; - the actor is bound to a thread and is executing its body&lt;/li&gt;
                    &lt;li&gt;&lt;code&gt;Looping&lt;/code&gt; - a special case of running where the body is repeated while a specified condition holds&lt;/li&gt;
                    &lt;li&gt;&lt;code&gt;Killing&lt;/code&gt; - when an actor is Running it cannot be directly stopped by the library, so it is shifted into the Killing state. When the library receives control while the actor is running it checks to see if the state has been changed to Killing. If the state has been changed to Killing, then it takes actions to regain control from user code so that the actor can be cleanly shutdown.&lt;/li&gt;
                &lt;/ul&gt;
            &lt;/li&gt;
            &lt;li&gt;
Wait States
                &lt;ul&gt;
                    &lt;li&gt;&lt;code&gt;BlockedWait&lt;/code&gt; - the type of wait performed within a receive block where the actor is waiting for a message while attached to a thread. There may be a timeout specified after which the actor will wakeup.&lt;/li&gt;
                    &lt;li&gt;&lt;code&gt;DetachedWait&lt;/code&gt; - the type of wait performed within a react block when no matching message is available.&lt;/li&gt;
                &lt;/ul&gt;
            &lt;/li&gt;
            &lt;li&gt;&lt;code&gt;ContinuationScheduled&lt;/code&gt; - similar to &lt;code&gt;StartScheduled&lt;/code&gt;, only the processing of the message the actor was waiting for when in the &lt;code&gt;DetachedWait&lt;/code&gt; state is scheduled instead of the starting of the actor.&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;
Terminal States
        &lt;ul&gt;
            &lt;li&gt;&lt;code&gt;Finished&lt;/code&gt; - the actor teriminated normally&lt;/li&gt;
            &lt;li&gt;&lt;code&gt;Killed&lt;/code&gt; - the actor was killed before it could complete execution&lt;/li&gt;
            &lt;li&gt;&lt;code&gt;UnhandledThrowable&lt;/code&gt; - an exception was thrown, usually from &amp;quot;user code,&amp;quot; and not handled&lt;/li&gt;
            &lt;li&gt;&lt;code&gt;InternalError&lt;/code&gt; - an error occurred within the actor library&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;...and now there are the following instance variables:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;code&gt;state&lt;/code&gt; - the state of the actor&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;mailbox&lt;/code&gt; queue of messages for the actor&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;sessions&lt;/code&gt; list used as a stack to keep track of the sender of messages while they are being processed&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;trapExit&lt;/code&gt; - if false (the default) then the actor will exit when an actor that it is linked to exits, if it's true then it will receive an &lt;code&gt;Exit&lt;/code&gt; message&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;links&lt;/code&gt; - a list of linked actors. Linked actors are notified or shutdown when the actor that they are linked to shuts down .&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Reducing the statefulness of the actor, and more importantly making the primary state explicit instead of implicit, makes the code much easier to both debug and extend.  In working with actors, I found that it's relatively common to have an actor just seem to stop.  It could be because it's waiting for a message, it could be because it's stuck in a loop, it could be any number of things.  Without explicit state, it's very difficult to tell exactly what's happening with an actor.  With explicit state, it's right there in your debugger.&lt;/p&gt;
&lt;p&gt;I have the code in a &lt;a href="http://bitbucket.org/eengbrec/scala-enhancements/src/2502a5041010/"&gt;Bitbucket repository&lt;/a&gt; in the &amp;quot;actor_state_machine&amp;quot; branch.  Most of the changes are in the actor.scala file and I highly encourage you to take a look at the differences.  Right now it the Scala test suite completes with the same results as the trunk as of a couple months ago, and I've added a couple tests to catch problems that it didn't.  Next I'm going to do a little more refactoring and general code cleanup, then I'm going to focus on expanding the test suite.  The current Scala testing tool, partest, uses actors heavily so it gives them a workout, but there aren't any explicit tests for actors.  Finally, I'm going to try to decouple the states from one another and try to extract their code from the Actor trait so that they can be tested as independent units and are more extensible.  I'm not sure what I'm actually going to do with the code.  I'd be happy to contribute it back to the EPFL, but given it is such a substantial departure I'm not sure they would want it.  So I'll probably end up moving it into another namespace and distributing it as a separate library.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-8240731004528113002?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/8240731004528113002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=8240731004528113002' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8240731004528113002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8240731004528113002'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2009/01/refactoring-scala-actors.html' title='Refactoring Scala Actors'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-5739753190208899848</id><published>2008-11-05T07:08:00.003-05:00</published><updated>2008-11-05T07:17:48.546-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><title type='text'>Countdown to the U.S.S.R.</title><content type='html'>Normally I don't blog on politics.  I think they tend to draw away from technical content. But it's the day after the election, so I can't help myself.

The countdown to the birth of the U.S.S.R. has begun.  That's the United States Socialist Republic.  For years now Bush has eroded our personal freedoms in the name of physical safety from terrorists.  Now Obama will launch down the same path in pursuit of economic safety.  In the end, America stands to lose all that has made it great, not from powers from without, but wasted away due to fears from within.

Of course it's not too late.  We stand to lose our greatest strengths, but they are not lost yet, and what is lost can be regained.  We are still a democracy, by and large we are still free, and the voice of liberty will still be heard if we have the courage to raise it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-5739753190208899848?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/5739753190208899848/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=5739753190208899848' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/5739753190208899848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/5739753190208899848'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/11/countdown-to-ussr.html' title='Countdown to the U.S.S.R.'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-8414327184061408677</id><published>2008-08-04T22:29:00.004-04:00</published><updated>2008-10-06T20:33:10.778-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Languages Readability and Tool Support</title><content type='html'>&lt;p&gt;I received a few comments on my blog about type inference and its affect on readability saying that the problem isn't really a problem if you have proper tool support.  You have API docs, IDE based assistance, and even interesting tools like the OCaml Browser.  The problem is that these don't really address the problem.  Programming requires a lot of concentration and is best done in a state of flow.  This means that anything that causes distraction or disruption is the enemy.  Flipping to another window in order to see some documentation requires a non-value added thought.  So does moving the cursor so that an IDE will display a popup with the inferred type.  Thoughts simply flow better if the code is readily readable, and code that requires a special tool to read is not readable.&lt;/p&gt;
&lt;p&gt;There's also less benefits to having code that is readable without external assistance.  While code may spend most of its life being displayed in an IDE, it certainly doesn't spend all of its life there.  Books, articles, blogs, and other such media often contain code as well.  Despite the ubiquity of the internet, I think having at least one book in dead tree format is still essential for a programming languages to be successful (and in some cases even taken seriously), and the last time I checked dead trees don't have popup windows.  Most online postings don't have intelligent help, either, although I suppose it would be possible if someone really wanted to put in the effort.  Regardless, the readability of a language in these formats will have a major impact on how easy a language is to learn, and ultimately how well it is accepted.&lt;/p&gt;
&lt;p&gt;The bottom line is that despite all the great and useful tools there are out there, it is still critical for a language to stand on its own without major tool support.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-8414327184061408677?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/8414327184061408677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=8414327184061408677' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8414327184061408677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8414327184061408677'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/08/languages-readability-and-tool-support.html' title='Languages Readability and Tool Support'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-2834502991858384742</id><published>2008-08-03T20:24:00.002-04:00</published><updated>2008-08-03T20:25:54.772-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='algorithms'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>The Costs of Generality</title><content type='html'>&lt;p&gt;I've been pondering the results of the&lt;a href="http://beust.com/weblog/archives/000491.html"&gt; Cedric's Code Challenge&lt;/a&gt;, and wondering just how much benefit is derived from optimized, purpose-specific solutions as opposed to solutions that rely on a more general libraries or frameworks.  It's fairly common to see debates where one person (or group) insists that general constructs from a standard library or other such solutions represent an unacceptable overhead, and the other side claims that the overhead is meaningless compared to runtime optimizations performed by &lt;a href="http://java.sun.com/javase/technologies/hotspot/"&gt;HotSpot&lt;/a&gt; and the cost of programmer time.  These debates can be rather painful to watch, as both sides generally have good points, yet often seem to be arguing right past one another.  Consequently, I think a little exploration of various potential optimizations and what their respective impacts on performance would be beneficial.&lt;/p&gt;
&lt;p&gt;For purposes here, I'm going to say that a solution based on a general framework would be one that uses a general purpose library to generate permutations of digits, filters out the ones with a leading zero, converts the permutations to numbers, and then collects the desired statistics.  A purpose specific solution would be one such as Crazy Bob's that is tailor-made for generating numbers based on permuted digits.&lt;/p&gt;
&lt;h3&gt;The General Solution&lt;/h3&gt;
&lt;p&gt;I'm not aware of a combinatronics library for Scala, but it is simple enough to write a generic permutation generating function:&lt;/p&gt;
&lt;pre class="scala" name="code"&gt;
  def permute[E](s: Set[E], n: Int)(f: List[E] =&amp;gt; Unit): Unit = {
    def p(s: Set[E], r: List[E]): Unit =
      if (r.length == n) f(r) else for(e &amp;lt;- s) p(s - e, e :: r)
    p(s, Nil)
  }
&lt;/pre&gt;
&lt;p&gt;This recursively generates all of the possible permutations.  When it as generated a complete permutation, it passes it to the function specified by the caller.  If &lt;code&gt;s&lt;/code&gt; is an ordered set, then the permutations will be generated in a predictable order. This can then be used to generate the permutations of digits for the code challenge, as follows:&lt;/p&gt;
&lt;pre class="scala"  name="code"&gt;
  val digits = TreeSet(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L)
  def main(args: Array[String]): Unit = {
    val start = java.lang.System.nanoTime
    var last, cnt, jumpLow, jumpMagnitude = 0L
    for(d &amp;lt;- 1 to 10) permute(digits, d) { p =&amp;gt;
      val xs = p.reverse // digits are generated in the wrong order so must be reversed
      if (xs.head != 0L) {  // make sure this is a valid set of digits
        val cur = xs.foldLeft(0L)((z, a) =&amp;gt; (z * 10L) + a)
        val dif = cur - last
        if (dif &amp;gt; jumpMagnitude) {
          jumpLow = last
          jumpMagnitude = dif
        }
        last = cur
        cnt = cnt + 1L
      }

    }
    val end = java.lang.System.nanoTime
    println("Count: " + cnt)
    println("Jump: " + jumpMagnitude + " (from " + jumpLow + " to " + (jumpLow + jumpMagnitude) + ")")
    println("Time: " + ((end - start) / 1000000L) + " ms")
  }
&lt;/pre&gt;
&lt;p&gt;This solution takes about 13 seconds on my MacBook.&lt;/p&gt;
&lt;h3&gt;Generate Only Valid Permutations&lt;/h3&gt;
&lt;p&gt;The above permutation function can be tweaked as follows to generate only valid permutations (ones without the leading zero), and thereby saving about 10% execution time.&lt;/p&gt;
&lt;pre class="scala"  name="code"&gt;
  def digitPermute(n: Int)(f: List[Long] =&amp;gt; Unit): Unit = {
    def p(s: Set[Long], r: List[Long]): Unit =
      if (r.length == n) f(r) else for(e &amp;lt;- s) p(s - e, e :: r)
    for(first &amp;lt;- (digits - 0L)) p(digits - first, first :: Nil)
  }
&lt;/pre&gt;
&lt;p&gt;The above solution executes in about 12 seconds.&lt;/p&gt;
&lt;h3&gt;Accumulating Numbers Instead of Lists&lt;/h3&gt;
&lt;p&gt;Both of the methods above construct lists of numbers which are later assembled into numbers.  This wastes memory and cycles, because only the resulting numbers are required and they can be accumulated much more efficiently.  Doing so, as shown below, reduces execution time to about 7 seconds.&lt;/p&gt;
&lt;pre class="scala"  name="code"&gt;
  val digits = TreeSet(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L)
  def digitPermute(n: Int)(f: Long =&amp;gt; Unit): Unit = {
    def p(s: Set[Long], d: Int, r: Long): Unit =
      if (d == n) f(r) else for(e &amp;lt;- s) p(s - e, d + 1, r * 10L + e)
    for(first &amp;lt;- (digits - 0L)) p(digits - first, 1, first)
  }
&lt;/pre&gt;
&lt;h3&gt;Long Set without Boxing&lt;/h3&gt;
&lt;p&gt;The above implementations all use &lt;a href="http://www.scala-lang.org/docu/files/api/scala/collection/immutable/TreeSet.html"&gt;TreeSet&lt;/a&gt; from Scala's standard library, which imposes a few performance penalties. For one, it is &amp;quot;generic.&amp;quot; This means that it requires both type-erasure and boxing instead of using primitives.  Second, if you look carefully at the definition of TreeSet, you'll notice that it doesn't require its contents to be &lt;a href="http://www.scala-lang.org/docu/files/api/scala/Ordered.html"&gt;Ordered&lt;/a&gt;, but rather uses a (potentially implicit) view converting the contained type into an Ordered.  This adds an extra layers of indirection and therefore an extra cost.&lt;/p&gt;
&lt;pre class="scala"  name="code"&gt;
  final class LongSet (val contents: Array[Long]) {
    private def indexOf(v: Long, min: Int, max: Int): Int = {
      if (min &amp;gt; max) -1
      else {
        val mid = (min + max) &amp;gt;&amp;gt;&amp;gt; 1
        val midVal = contents(mid)
        if (midVal &amp;lt; v) indexOf(v, mid + 1, max)
        else if (midVal &amp;gt; v) indexOf(v, min, mid - 1)
        else mid
      }
    }
    def foreach(f: Long =&amp;gt; Unit) {
      var i = 0
      val max = contents.length
      while (i &amp;lt; max) {
        f(contents(i))
        i = i + 1
      }
    }
    def -(v: Long): LongSet = {
      val max = contents.length - 1
      if (indexOf(v, 0, max) &amp;lt; 0) this
      else {
        val a = new Array[Long](max)
        var i, j = 0
        while (i &amp;lt;= max) {
          val cur = contents(i)
          if (cur != v) {
            a(j) = contents(i)
            j = j + 1
          }
          i = i + 1
        }
        new LongSet(a)
      }
    }
  }
  val digits = new LongSet(Array(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L))
  def digitPermute(n: Int)(f: Long =&amp;gt; Unit): Unit = {
    def p(s: LongSet, d: Int, r: Long): Unit =
      if (d == n) f(r) else for(e &amp;lt;- s) p(s - e, d + 1, r * 10L + e)
    for(first &amp;lt;- (digits - 0L)) p(digits - first, 1, first)
  }
&lt;/pre&gt;
&lt;p&gt;This implementation brings the execution time down to ~1.7 seconds, representing a substantial savings over TreeSet. The comparison isn't quite fair, as TreeSet uses a Red-Black balanced tree and the code above uses a sorted array, but the difference is still substantial and shows that having a more targeted data structure can improve performance significantly.  At this point you might be thinking &amp;quot;Well no sh*t sherlock!  Of course a data structure tuned for a specific type is faster than one that is written to handle any type!&amp;quot;  That's true...to a point.  Not all languages implement generics using type erasure and require boxing of values within parameterized classes.  For example, C++ was designed to ensure that data structures implemented using templates imposed little or no overhead above more raw ones.&lt;/p&gt;
&lt;h3&gt;Special Purpose Set for Permutation Generation&lt;/h3&gt;
&lt;p&gt;Another approach is to use a more special-purpose data structure in the permutation function without reducing its generality.  The linked set used in &lt;a href="http://crazybob.org/BeustSequence.java.html"&gt;Crazy Bob&lt;/a&gt;'s solution can be generalized to generating permutations of any type.  Unfortunately, this structure is mutable, and mutates on every invocation.  This means that while it would be possible to pass it directly to client code, it would be extremely dangerous because the client code may maintain a reference to the rapidly changing data structure.  Consequently, the structure needs to be copied into a list or similar structure before being passed to client code.  The solution built around the code below completes in ~5 seconds, which is slower than using an structure explicitly coded for dealing with longs and generating longs, but over twice as fast as generating permutations using the standard TreeSet class.&lt;/p&gt;
&lt;pre class="scala"  name="code"&gt;
  private final class Element[E](val value: E, var next: Element[E], var previous: Element[E]) {
    /** remove an element from the set*/
    def use() {
      if (previous ne null) previous.next = next
      if (next ne null) next.previous = previous
    }
    /** put an element back in the set */
    def yieldValue() {
      if (previous ne null) previous.next = this
      if (next ne null) next.previous = this
    }
  }
  private def buildElements[E](s: Set[E]): Element[E] = {
    val iter = s.elements
    val first = new Element(iter.next, null, null)
    var cur = first
    while(iter.hasNext) {
      cur.next = new Element(iter.next, null, cur)
      cur = cur.next
    }
    first
  }
  def permute[E](s: Set[E], n: Int)(f: List[E] =&amp;gt; Unit): Unit = {
    def p(start: Element[E], head: Element[E], r: List[E]): Unit = {
      def take(current: Element[E]): Unit = {
        if (current ne null) {
          val newR = current.value :: r
          if (newR.length == n) {
            f(newR)
            take(current.next)
          } else {
            current.use()
            val newHead = if (current eq head) head.next else head
            p(newHead, newHead, newR)
            current.yieldValue()
            take(current.next)
          }
        }
      }
      take(start)
    }
    val first = buildElements(s)
    p(first, first, Nil)
  }
&lt;/pre&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The various implementations here represent a sampling of various ways that Cedric's Code Challenge can be implemented in Scala, and the effects they have on performance.  A relatively direct port of Crazy Bob's solution to Scala completes in ~0.4 seconds, making it by far the fastest solution and about 30 times faster than the solution using standard data structures with a generic permutation generator.  That's not really surprising, so what can we conclude?  The most obvious conclusion is that avoiding the construction of intermediate objects yields a substantial speedup.  This can be seen in two places.  The first is in the switch from constructing a List to represent the permutation to accumulating the Long directly.  The second is in using a special-purpose mutable data structure to generate the permutations, thereby avoiding repeated allocations of Set objects.  Finally, reducing overhead due to things like boxing and the casts associated with type erasure does make a noticeable difference in performance.  On the flip side, Scala's closure based constructs, such as nested functions and for loops, added negligible overhead, if any at all. Using more general constructs instead of more specific ones clearly has a substantial performance cost, but it's also worth mentioning that the cost is trivial compared to the benefit received in the transition from a brute-force solution to an optimal algorithm.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-2834502991858384742?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/2834502991858384742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=2834502991858384742' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2834502991858384742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2834502991858384742'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/08/costs-of-generality.html' title='The Costs of Generality'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-2584378239870915308</id><published>2008-07-15T22:06:00.002-04:00</published><updated>2008-07-15T22:07:35.955-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>System.identityHashCode</title><content type='html'>&lt;p&gt;A recent &lt;a href="http://james-iry.blogspot.com/2008/07/is-scala-for-academics-and-egomaniacs.html"&gt;thread on the the Scala IRC channel&lt;/a&gt; piqued my curiosity about exactly how &lt;a href="https://java.sun.com/javase/6/docs/api/java/lang/System.html#identityHashCode(java.lang.Object)"&gt;System.identityHashcode&lt;/a&gt; works.  It looks like as less heated remarks have flushed out the conversation more the definition was irrelevant, but regardless, I think it's interesting.  Thankfully Sun open-sourced the their &lt;a href="http://openjdk.java.net/"&gt;implementation of the Java platform&lt;/a&gt; so it was pretty easy to find out exactly how it works.&lt;/p&gt;
&lt;p&gt;It turns out the Sun JVM contains three different algorithms for calculating the identity hash, none of which are guaranteed to yield unique hash codes.  That's not surprising, because on a 64 bit architecture, doing that would be almost impossible.  I say almost because one could just generate them as sequential numbers, and then crash the JVM when it runs out of 32 bit hash codes (an OutOfHashCodesError ;-).&lt;/p&gt;
&lt;p&gt;From share/vm/runtime/synchronizer.cpp:&lt;/p&gt;
&lt;pre&gt;
static inline intptr_t get_next_hash(Thread * Self, oop obj) {
  intptr_t value = 0 ; 
  if (hashCode == 0) { 
     // This form uses an unguarded global Park-Miller RNG, 
     // so it's possible for two threads to race and generate the same RNG.
     // On MP system we'll have lots of RW access to a global, so the
     // mechanism induces lots of coherency traffic.  
     value = os::random() ; 
  } else
  if (hashCode == 1) { 
     // This variation has the property of being stable (idempotent)
     // between STW operations.  This can be useful in some of the 1-0
     // synchronization schemes.  
     intptr_t addrBits = intptr_t(obj) &amp;gt;&amp;gt; 3 ; 
     value = addrBits ^ (addrBits &amp;gt;&amp;gt; 5) ^ GVars.stwRandom ; 
  } else 
  if (hashCode == 2) { 
     value = 1 ;            // for sensitivity testing
  } else { 
     // Marsaglia's xor-shift scheme with thread-specific state
     // This is probably the best overall implementation -- we'll
     // likely make this the default in future releases.
     unsigned t = Self-&amp;gt;_hashStateX ; 
     t ^= (t &amp;lt;&amp;lt; 11) ; 
     Self-&amp;gt;_hashStateX = Self-&amp;gt;_hashStateY ; 
     Self-&amp;gt;_hashStateY = Self-&amp;gt;_hashStateZ ; 
     Self-&amp;gt;_hashStateZ = Self-&amp;gt;_hashStateW ; 
     unsigned v = Self-&amp;gt;_hashStateW ; 
     v = (v ^ (v &amp;gt;&amp;gt; 19)) ^ (t ^ (t &amp;gt;&amp;gt; 8)) ; 
     Self-&amp;gt;_hashStateW = v ; 
     value = v ; 
  } 

  value &amp;amp;= markOopDesc::hash_mask;
  if (value == 0) value = 0xBAD ; 
  assert (value != markOopDesc::no_hash, "invariant") ; 
  TEVENT (hashCode: GENERATE) ;
  return value;
}
&lt;/pre&gt;
&lt;p&gt;What's interesting is that there's an algorithm in there (hashCode == 2) where the identity hash code turns out to always be the same all objects.  I'm pretty sure it's there solely for testing purposes, so they can run tests against the JVM and standard library and ensure no piece of code is relying on the uniqueness of the identity hash code.&lt;/p&gt;
&lt;p&gt;This relates back to my previous point about &lt;a href="http://erikengbrecht.blogspot.com/2008/07/trust-in-authority-vs-trust-in.html"&gt;transparency.&lt;/a&gt;  Because Sun's JVM is open source, it's possible for anyone to peek inside and see how the various bits work, and what assumptions the Sun JVM engineers are and are not making about those pieces.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-2584378239870915308?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/2584378239870915308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=2584378239870915308' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2584378239870915308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2584378239870915308'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/07/systemidentityhashcode.html' title='System.identityHashCode'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-969345141895738275</id><published>2008-07-15T07:19:00.001-04:00</published><updated>2008-07-15T07:19:48.952-04:00</updated><title type='text'>Trust in Authority vs Trust in Transparency</title><content type='html'>&lt;p&gt;This morning Murph posted a &lt;a href="http://blogs.zdnet.com/Murphy/?p=1190"&gt;blog&lt;/a&gt; on the &amp;quot;censorship&amp;quot; of &lt;a href="http://www.wikipedia.org"&gt;Wikipedia&lt;/a&gt; by over-zealous article owners, citing a &lt;a href="http://article.nationalreview.com/?q=NjU1ZDBhOGExOWRlNzc5ZDcwOTUxZWM3MWU2Mjc5MGE="&gt;posting&lt;/a&gt; by Lawrence Solomon about an experience with editing an &lt;a href="http://en.wikipedia.org/wiki/Naomi_Oreskes"&gt;article&lt;/a&gt; related to global warming.  Murph uses this to support one of his common conspiracy theories that Wikipedia, and social media in general, is doomed because of this kind of censorship and deliberate distortion of the facts.&lt;/p&gt;
&lt;p&gt;What's interesting is that this censorship took place in the open.  Anyone who knows where to look can see exactly what changes were made by Solomon, and their disposition relative to the current official article or any other version of it.  &lt;a href="http://en.wikipedia.org/w/index.php?title=Naomi_Oreskes&amp;diff=cur&amp;oldid=201071198"&gt;Here's&lt;/a&gt; Solomon's version versus the current version.&lt;/p&gt;
&lt;p&gt;The core issue here isn't censorship.  Editors will always censor.  Their job is to act as filters.  Furthermore, every editor is subject to biases, whether they be his own or those imposed on him by a third party such as his employer.  With most publications the editorial process happens behind closed doors with unseen forces.  With Wikipedia the process happens right before the eyes of the world.&lt;/p&gt;
&lt;p&gt;The real issue here is that Murph trusts authority more than transparency.  Someone corrected an article, and the correction was subsequently removed due to political bias.  I'm sure that's happened time and time again in every encyclopedia that has ever been published.  The difference is in this case the change was transparent, with the politics open for all to judge, where with a traditional model we would have never known.&lt;/p&gt;
&lt;p&gt;If history has taught us anything, it's that placing too much faith in authority is a bad idea.  Our authority figures are all human, and our authoritative organizations are still organizations of people.  They are both fallible and corruptable.  We can't entirely strip authority from our society because that would lead to anarchy, but we can make authority more transparent, and with transparency we can judge for ourselves.&lt;/p&gt;
&lt;p&gt;In this particular case the editorial process of Wikipedia probably failed to yield the most accurate article possible, at least as the article stands today.  I'm not an expert on the subject matter, but I think Solomon's corrections were most likely correct.  That being said, I think the process has succeeded.  The changes Solomon made have not be entirely censored, they have merely been driven from the main page.  Discourse continues with regards to their validity.  The biases of the editors have been made public.  The last thing we want to do is reseal that process behind closed doors, simply because in this case we didn't like some of the results.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-969345141895738275?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/969345141895738275/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=969345141895738275' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/969345141895738275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/969345141895738275'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/07/trust-in-authority-vs-trust-in.html' title='Trust in Authority vs Trust in Transparency'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-6330623079002590212</id><published>2008-07-13T13:49:00.006-04:00</published><updated>2008-07-14T06:17:46.290-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='OCaml'/><title type='text'>Love, Hate, and Type Inference</title><content type='html'>&lt;p&gt;Ever since I started using Scala, I've had somewhat of a love-hate relationship with type inference.  On the local level, type inference can make code much more concise, easier to read, and easier to refactor.  It makes code easier to read because in cases where the type of variable is obvious, type annotations just add noise that distract from the meaning of the code.  It makes code easier to refactor, because often times changes to the type of something in one place in a program can ripple throughout the rest of the program through a simple recompile, assuming the new type supports the methods being used on the original type.  This leads to something akin to structural typing without the associated overhead.&lt;/p&gt;
&lt;p&gt;However, at a more macro level I think type inference can make code much more difficult to read.  For example, consider the following code from the &lt;a href="http://scalax.scalaforge.org/"&gt;Scalax&lt;/a&gt; library (full source &lt;a href="http://hg.scalaforge.org/scalax/general/file/a3da8d853336/src/scalax/io/resources.scala"&gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;pre  name="code" class="scala"&gt;
//  Scalax - The Scala Community Library
//  Copyright (c) 2005-8 The Scalax Project. All rights reserved
abstract class InputStreamResource[+I &amp;lt;: InputStream] extends CloseableResource[I] {
    def buffered : InputStreamResource[BufferedInputStream] =
        new InputStreamResource[BufferedInputStream] with Wrapper {
            type Handle = BufferedInputStream
            override def wrap(is : SelfHandle) = new BufferedInputStream(is)
            
            override def buffered = this
        }

    def slurp() = for (is &amp;lt;- this) yield StreamHelp.slurp(is)
    
    /* Obtains a Reader using the system default charset. */
    def reader =
        new ReaderResource[Reader] with Wrapper {
            type Handle = Reader
            // XXX: should be UTF-8 by default instead of OS default
            // practically, here in Russia I never used default charset
            override def wrap(is : SelfHandle) = new InputStreamReader(is)
        }
    
    def gunzip =
        new InputStreamResource[GZIPInputStream] with Wrapper {
            type Handle = GZIPInputStream
            override def wrap(is : SelfHandle) = new GZIPInputStream(is)
        }
    
    /** Obtains a Reader using the supplied charset. */
    def reader(charset : String) = {
        // Do this lookup before opening the file, since it might fail.
        val cs = Charset.forName(charset)
        new ReaderResource[Reader] with Wrapper {
            type Handle = Reader
            override def wrap(is : SelfHandle) = new InputStreamReader(is, cs)
        }
    }
    
    def lines = reader.lines
    
    def lines(charset : String) = reader(charset).lines
    
    def readLines() = reader.readLines()
    
    def readLine() = reader.readLine()
    
    def pumpTo[O &amp;lt;: OutputStream](osr : OutputStreamResource[O]) {
        // Note InputStream should be opened before OutputStream
        for (is &amp;lt;- this; os &amp;lt;- osr) StreamHelp.pump(is, os)
    }
}
&lt;/pre&gt;
&lt;p&gt;This is an example of where type inference makes code easier to refactor yet more difficult to read.  If one were to change the return type of the &lt;code&gt;reader&lt;/code&gt; methods, or the subsequent &lt;code&gt;lines&lt;/code&gt; and/or &lt;code&gt;readLines&lt;/code&gt; methods on that type, then the return types of these methods would automatically change on recompile.  However, now try to figure out the return types of the &lt;code&gt;lines&lt;/code&gt; and &lt;code&gt;readLines&lt;/code&gt; methods.  In order to do that, you need to know what the return type of the &lt;code&gt;reader&lt;/code&gt; method is, and the structure of that type. Figuring out the return type of &lt;code&gt;reader&lt;/code&gt; is reasonably straight forward, as it is defined in the same.  However, the base class for the return type is not, so in order to figure it out you need to trace through several class definitions and potentially in other source files.  I doubt this is a big deal for those people who are intimately familiar with the code, but I pity the new guy who has to sort it out when he's trying to create a new subclass of this abstract class.  Of course, there's always the &lt;a href="http://scalax.scalaforge.org/api/scalax/io/InputStreamResource.html"&gt;API docs&lt;/a&gt;, so users of the code, and the poor new guy, do have a place to turn.&lt;/p&gt;
&lt;p&gt;So that's Scala, which supports a relatively limited form of type inference.  Now, let's consider a snippet of OCaml, which has much fuller &lt;a href="http://www.cs.cmu.edu/~rwh/courses/refinements/papers/PottierRemy04/hmx.pdf"&gt;type inference&lt;/a&gt;, that I stole from &lt;a href="http://eigenclass.org/hiki/ordered_permutations"&gt;Mauricio Fernandez&lt;/a&gt;:&lt;/p&gt;
&lt;pre name="code"&gt;
   (* Copyright (C) 2008 Mauricio Fernandez  http//eigenclass.org
      Solution to the coding challenge at
      http://beust.com/weblog/archives/000491.html *)
   open Printf
   module S = Set.Make(struct type t = int let compare = (-) end)
   let (--) set elm = S.remove elm set
  
   let permutations f zero digits len =
     let base = S.cardinal digits in
     let rec aux n digits = function
         0 -&amp;gt; f n
       | len -&amp;gt; S.iter (fun s -&amp;gt; aux (n * base + s) (digits -- s) (len-1)) digits
     in S.iter (fun s -&amp;gt; aux s (digits -- s) (len - 1)) (digits -- zero)
 
   let () =
     let max = 10_000_000_000 in
     let digits = List.fold_right S.add [0; 1; 2; 3; 4; 5; 6; 7; 8; 9] S.empty in
  
     let count = ref 0 and prev = ref 0 and maxj = ref 0 and base = ref 0 in
     let report () = printf "Found %d numbers under %d.\n" !count max;
                     printf "Max jump: %d (%d -- %d).\n" !maxj !base (!base + !maxj)
   
     in try
       for i = 1 to 10 do
         permutations
           (fun num -&amp;gt;
              if num &amp;gt;= max then raise Exit;
              (* printf "%d\n" num; *)
              incr count;
              let jump = num - !prev in
                if jump &amp;gt; !maxj then (maxj := jump; base := !prev);
                prev := num)
           0 digits i
       done;
       report ()
     with Exit -&amp;gt; report ()
&lt;/pre&gt;
&lt;p&gt;It's not entirely fair that I am picking on this &lt;a href="http://caml.inria.fr/resources/index.en.html"&gt;OCaml&lt;/a&gt; code, because I don't know the language.  Also, this is a short, self-contained program that I personally would be likely to write in &lt;a href="http://www.python.org"&gt;Python&lt;/a&gt; without any type annotations at all.  So in a way, for short programs like this, I think full type inference is great.  You get all of the protection of static typing with none of the hassle.  That being said, I think it would be extremely difficult to approach a large code base that is this devoid of type annotations.&lt;/p&gt;
&lt;p&gt;All this adds up to my love-hate relationship with type inference.  I love it when I'm writing my own code, and I hate it (aside from local variables) when I am reading other people's code.  Over the past months I've decreased my use of it in Scala, preferring instead to explicitly specify types wherever they would not be entirely obvious from looking at the code, even though all my Scala code is hobby-work so no one else has to read it.  Of course, being hobby work, I often go days, weeks, or even months without looking at a chunk of code, so I often need help remembering what I wrote.  Overall I would say that excessive reliance on type inference obfuscates code, and that there are plenty ways for programmers to obfuscate their code, so it is a style issue as opposed to a language design issue.  I also think it will be interesting to see how many &lt;a href="http://en.wikipedia.org/wiki/Dynamic_programming_language"&gt;dynamic language&lt;/a&gt; people migrate over to languages with strong type inference as these languages gain more attention.  As you can see from the OCaml code above, there is no extra &amp;quot;typing burden&amp;quot; placed on the programmer.  If the program is correctly typed, it will compile and run quickly.  If not, it won't.  In theory this should satisfy the &amp;quot;type annotations are too much work/add too much noise to my program&amp;quot; camp, but not the &amp;quot;I don't want the compiler telling me what I can and can't do&amp;quot; camp.  My guess is that more people fall into the latter than the former, even the ones that claim they don't, but only time will tell.&lt;/p&gt;
&lt;p&gt;Update:  I just had a thought.  Try thinking of type inference like using pronouns in natural languages.  Imagine talking to a person who rarely uses pronouns.  It's slow, cumbersome, and occasionally makes you think the speaker thinks you are an idiot who can't remember what he said 30 seconds ago.  Likewise, when someone speaks entirely in pronouns, especially when they use a pronoun to refer to something that isn't part of the immediate conversation, it leads to utter confusion.  Context is key, and the compiler can usually keep a much more distant context in its working memory than a programmer can.  Type annotations provide context.  Type inference assumes context.&lt;/p&gt;
&lt;p&gt;Update 2:  Here's a link to some &lt;a href="http://caml.inria.fr/pub/docs/manual-ocaml/libref/Set.S.html"&gt;OCaml API doc&lt;/a&gt;s, where, just like in Scala, you can clearly see the inferred types.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-6330623079002590212?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/6330623079002590212/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=6330623079002590212' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6330623079002590212'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6330623079002590212'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/07/love-hate-and-type-inference.html' title='Love, Hate, and Type Inference'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-1055961345112811883</id><published>2008-06-28T21:17:00.003-04:00</published><updated>2008-07-01T13:11:04.754-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='algorithms'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Cedric's Code Challenge</title><content type='html'>&lt;P &gt;Cedric Buest issued a interesting
little &lt;A HREF="http://beust.com/weblog/archives/000491.html"&gt;challenge&lt;/A&gt;
this morning:&lt;/P&gt;
&lt;blockquote&gt;
&lt;P&gt;Here is an
interesting coding challenge: write a counter function that counts
from 1 to max but only returns numbers whose digits don't repeat.&lt;/P&gt;
&lt;P&gt;For example, part of the output would be:&lt;/P&gt;
&lt;UL&gt;
 &lt;LI&gt;8, 9, 10, 12 (11 is not valid)&lt;/LI&gt;
 &lt;LI&gt;98, 102, 103 (99, 100 and 101 are not valid)&lt;/LI&gt;
 &lt;LI&gt;5432, 5436, 5437 (5433, 5434 and 5435 are not valid)&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Also:&lt;/P&gt;
&lt;UL&gt;
 &lt;LI&gt;Display the biggest jump (in the sequences above, it's 4: 98 -&amp;gt; 102)&lt;/LI&gt;
 &lt;LI&gt;Display the total count of numbers&lt;/LI&gt;
 &lt;LI&gt;Give these two values for max=10000&lt;/LI&gt;
&lt;/UL&gt;
&lt;/blockquote&gt;
&lt;P &gt;He welcomed brute-force solutions, but
really the challenge here is in coming up with something more
efficient and elegant.  There are basically three general approaches:&lt;/P&gt;
&lt;OL&gt;
 &lt;LI&gt;&lt;P &gt;Run through all the numbers from 0
 to &lt;I&gt;n&lt;/I&gt;, test each for no
 repeating digits, and track the above statistics while you do it. 
 This is the brute force method.&lt;/P&gt;
 &lt;LI&gt;&lt;P &gt;Permute
 the digits in a fashion that generates numbers sequentially and
 track the statistics. Alternatively you could generate them in any
 order, sort them, and then calculate the statistics.&lt;/P&gt;
 &lt;LI&gt;&lt;P&gt;Derive
 a heuristic that proves a given sequence of numbers will all contain
 repeated digits and can therefore be skipped.&lt;/P&gt;
&lt;/OL&gt;
&lt;P &gt;I think #2 is probably the ideal fashion, but I didn't think of it
until I was mostly done coding #3.&lt;/P&gt;
&lt;H3&gt;Finding Repeated Digits&lt;/H3&gt;
&lt;P&gt;The first step in solving this problem, no matter what the approach, is
to come up with an algorithm to detect repeated digits.  Commenters
on Cedric's blog came up with a number of ways to do this, most of
which centered around converting the integer into a string and then
finding repeated characters.  This is a rather frighteningly
inefficient approach.  There is certainly no need to convert the
number into a string in order to know its digits.  A much simpler
approach is allocate a ten element array of booleans initialized to
false, and start generate the digits from lowest to highest by moding
the number by ten.  The first time you encounter a digit, you flip
it's associated array element to true.  The second time, you exit
because you have detected a repeat.  The array is essentially serving
as a thrifty man's map.  Here it is in Scala:&lt;/P&gt;
&lt;pre name="code" class="scala"&gt;
  def containsRepeatedDigit(i: Long): Boolean = {
    val digits = new Array[Boolean](10) // elements default to false
    def f(i: Long): Boolean = {
      if (i == 0L) false // all digits have been processed
      else {
        val d = (i % 10L).asInstanceOf[Int]
        if (digits(d)) true
        else {
          digits(d) = true
          f(i / 10L)
        }
      }
    }
    if (i &lt; 11L) false else f(i)
  }
&lt;/pre&gt;
&lt;H3&gt;The Heuristic&lt;/H3&gt;
&lt;P &gt;Consider
the number 2201.  It has repeating digits.  The question is:  What's
the next number without repeating digits?  It is 2301.  You could
calculate it using brute-force, but you'd end up scanning an extra 99
numbers.  Notice that the repetition is in the upper digits.  This
means that you will cannot get a number with non-repeating digits
until the second digit (counting from the left) changes.  Now
consider the number 2200.  In this case changes need to occur in both
the lower digits and the upper digits, however addressing the upper
digits allows us to skip a much larger section of the search space. 
Finally, consider 22200.  In this case, you still want the second
digit.  However, you are searching from the right, so algorithms what
detect the first repeat won't work.  Here's Scala code to find the
appropriate digit.  Notice that it looks very similar to the repeated
digit test above.&lt;/P&gt;
&lt;pre name="code" class="scala"&gt;
  def max(array: Array[Int]): Int = {
    def f(idx: Int, m: Int): Int = {
      if (idx == array.length) m
      else if (array(idx) &gt; m) f(idx + 1, array(idx))
      else f(idx + 1, m)
    }
    f(1, array(0))
  }

  def repeatedDigit(i: Long): Int = {
    val prevIdx = new Array[Int](10)
    val recentIdx = new Array[Int](10)
    def f(i: Long, idx: Int) {
      if (i &gt; 0) {
        val d = (i % 10L).asInstanceOf[Int]
        if (recentIdx(d) &gt; 0) prevIdx(d) = recentIdx(d)
        recentIdx(d) = idx
        f(i / 10L, idx + 1)
      }
    }
    f(i, 1)
    Math.max(max(prevIdx), 0)
  } 
&lt;/pre&gt;
&lt;P &gt;Now
that we have an algorithm for finding the highest digit that needs to
be changed, we need one that will take that information and turn it
into the next possible number containing no repeating digits.  This
simply requires basic arithmetic.&lt;/P&gt;
&lt;pre name="code" class="scala"&gt;
  def nextPossibleNonRepeating(i: Long): Long = 
        nextPossibleNonRepeating(i, repeatedDigit(i))

  def nextPossibleNonRepeating(i: Long, idx: Int): Long = {
    if (idx == 0) i + 1L
    else {
      val p = Math.pow(10.0, (idx - 1).asInstanceOf[Double]).asInstanceOf[Long]
      val r = i % p
      val d = p - r
      i + d
    }
  }
&lt;/pre&gt;
&lt;p&gt;Given this, it is easy to generate a sequence:&lt;/p&gt;
&lt;pre name="code" class="scala"&gt;
  def nextNonRepeating(i: Long): Long = nextNonRepeating(i, repeatedDigit(i))
  def nextNonRepeating(i: Long, idx: Int): Long = {
    val p = nextPossibleNonRepeating(i, idx)
    val d = repeatedDigit(p)
    if (d == 0) p else nextNonRepeating(p, d)
  }
&lt;/pre&gt;
&lt;H3&gt;Solution&lt;/H3&gt;
&lt;P &gt;Once
this is all done, the solution is pretty straight-forward.  It takes
the general form of the function use to generate the next number with
non-repeating digits, only it has to keep track of a bunch of extra
information.&lt;/P&gt;
&lt;pre name="code" class="scala"&gt;
  def printNonRepeatingReport(start: Long, stop: Long, last: Long, gapLow: Long,
                              gapHigh: Long, cnt: Long): Unit = {
    if (start &gt; stop) {
      println("max: " + last)
      println("max gap: " + (gapHigh - gapLow) + " between " + 
              gapLow + " and " + gapHigh)
      println("count: " + cnt)
    } else {
      val d = repeatedDigit(start)
      if (d == 0L) {
        //println(start)
        val gap = start - last
        val (gl, gh) = if (gap &gt; (gapHigh - gapLow)) (last, start) 
                       else (gapLow, gapHigh)
        printNonRepeatingReport(start + 1L, stop, start, gl, gh, cnt + 1L)
      } else {
        printNonRepeatingReport(nextPossibleNonRepeating(start, d), stop, last, 
                                gapLow, gapHigh, cnt)
      }
    }
  }
&lt;/pre&gt;

&lt;H3&gt;Results&lt;/H3&gt;
&lt;P &gt;I'm not going to list all the numbers here, just the statistics for
1-10,000:&lt;/P&gt;
&lt;UL&gt;
 &lt;LI&gt;max: 9,876&lt;/LI&gt;
 &lt;LI&gt;max gap: 105 between 1,098 and 1,203&lt;/LI&gt;
 &lt;LI&gt;count: 5,274&lt;/LI&gt;
&lt;/UL&gt;
&lt;P &gt;Of course I haven't checked it against
a brute-force solution or other posted solution, so I owe a
beer/coffee/tea, depending on your persuasion, to anyone who can
point out a bug and provide the solution.&lt;/P&gt;
&lt;P &gt;Just for kicks, here's to 10,000,000,000:&lt;/P&gt;
&lt;UL&gt;
 &lt;LI&gt;max: 9,876,543,210&lt;/LI&gt;
 &lt;LI&gt;max gap: 104,691,357 between 1,098,765,432 and 1,203,456,789&lt;/LI&gt;
 &lt;LI&gt;count: 8,877,690&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Which took 1 minute 23 seconds on my MacBook.  Try that with a
brute-force approach.&lt;/P&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-1055961345112811883?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/1055961345112811883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=1055961345112811883' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/1055961345112811883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/1055961345112811883'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/06/cedrics-code-challenge.html' title='Cedric&apos;s Code Challenge'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-9038658822579269214</id><published>2008-06-23T19:54:00.002-04:00</published><updated>2008-06-23T19:56:37.940-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Google AppEngine</title><content type='html'>&lt;P&gt;There's a lot of buzz out there about how &lt;A HREF="http://code.google.com/appengine/"&gt;Google
AppEngine&lt;/A&gt; is a game changer.  My question is: Which game? 
AppEngine reduces the cost of hosting a web application down to zero.
 Zero is a pretty profound number.  You don't even need to provide a
credit card number in case they might want to charge you some day. 
All you need to a mobile phone number capable of receiving text
messages.  This means that not only is there no up-front cost, but
also that there is no risk that you will suddenly incur huge fees for
exceeding transfer quotas when you are lucky enough to be
&lt;A HREF="http://en.wikipedia.org/wiki/Slashdot_effect"&gt;&lt;/A&gt;&lt;A HREF="http://en.wikipedia.org/wiki/Slashdot_effect"&gt;&lt;/A&gt;&lt;A HREF="http://en.wikipedia.org/wiki/Slashdot_effect"&gt;Slashdotted&lt;/A&gt;&lt;A HREF="http://en.wikipedia.org/wiki/Slashdot_effect"&gt;&lt;/A&gt;&lt;A HREF="http://en.wikipedia.org/wiki/Slashdot_effect"&gt;&lt;/A&gt;.
 Your application will just be temporarily unavailable.  Hey, if that
service level is good enough for &lt;A HREF="http://www.google.com/search?q=twitter+crashes&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8"&gt;&lt;/A&gt;&lt;A HREF="http://www.google.com/search?q=twitter+crashes&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8"&gt;&lt;/A&gt;&lt;A HREF="http://www.google.com/search?q=twitter+crashes&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8"&gt;Twitter&lt;/A&gt;&lt;A HREF="http://www.google.com/search?q=twitter+crashes&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8"&gt;&lt;/A&gt;&lt;A HREF="http://www.google.com/search?q=twitter+crashes&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8"&gt;&lt;/A&gt;,
it's good enough for you, right?&lt;/P&gt;
&lt;H2 &gt;The Open Source Game&lt;/H2&gt;
&lt;P&gt;Starting an open source project has been free for years.  Many
project hosting communities exist, providing projects with source
code management, issue tracking, wikis, mailing lists, other
features, and even a little visibility within their directories.  Web
hosting is not exactly expensive, especially light-weight scripting
languages like &lt;A HREF="http://www.php.net/"&gt;&lt;/A&gt;&lt;A HREF="http://www.php.net/"&gt;&lt;/A&gt;&lt;A HREF="http://www.php.net/"&gt;PHP&lt;/A&gt;&lt;A HREF="http://www.php.net/"&gt;&lt;/A&gt;&lt;A HREF="http://www.php.net/"&gt;&lt;/A&gt;,
&lt;A HREF="http://www.perl.com/"&gt;&lt;/A&gt;&lt;A HREF="http://www.perl.com/"&gt;&lt;/A&gt;&lt;A HREF="http://www.perl.com/"&gt;Perl&lt;/A&gt;&lt;A HREF="http://www.perl.com/"&gt;&lt;/A&gt;&lt;A HREF="http://www.perl.com/"&gt;&lt;/A&gt;,
and &lt;A HREF="http://www.python.org/"&gt;&lt;/A&gt;&lt;A HREF="http://www.python.org/"&gt;&lt;/A&gt;&lt;A HREF="http://www.python.org/"&gt;Python&lt;/A&gt;&lt;A HREF="http://www.python.org/"&gt;&lt;/A&gt;&lt;A HREF="http://www.python.org/"&gt;&lt;/A&gt;;
but it still costs something and therefore requires a sponsor.  Often
times for a fledgling project the sponsor is also the founder, who
also happens to be the lead programmer, help desk, and promoter. 
There are some who do an &lt;A HREF="http://blog.lostlake.org/"&gt;&lt;/A&gt;&lt;A HREF="http://blog.lostlake.org/"&gt;&lt;/A&gt;&lt;A HREF="http://blog.lostlake.org/"&gt;amazing
job of doing this&lt;/A&gt;&lt;A HREF="http://blog.lostlake.org/"&gt;&lt;/A&gt;&lt;A HREF="http://blog.lostlake.org/"&gt;&lt;/A&gt;,
but for the most part I think project founders choose to wait.&lt;/P&gt;
&lt;P&gt;Note:  If I am wrong about the availability of good, free hosting
for open source web applications, please provide links to them in the
comments section.  I would love to be proven wrong on this.&lt;/P&gt;
&lt;H2 &gt;The Startup Game&lt;/H2&gt;
&lt;P&gt;If &lt;A HREF="http://www.paulgraham.com/"&gt;Paul Graham&lt;/A&gt; were to
comment on AppEngine, it probably be that it eliminates one of the
last remaining &lt;A HREF="http://www.paulgraham.com/notnot.html"&gt;excuses&lt;/A&gt;
anyone may have to launching a web startup.  If you have an idea,
some time, and can hack Python – you can launch a web application
with AppEngine.  You don't need money, infrastructure, long-term
commitment, or any of those other things that may scare a person away
from a startup.  With &lt;A HREF="https://www.google.com/adsense"&gt;AdSense&lt;/A&gt;,
you even monetize your application without hardly any effort.&lt;/P&gt;
&lt;P&gt;Of course there are limitations.  For one thing, AppEngine is very
limited in what it can do.  Pretty much any idea with even moderate
&lt;A HREF="http://googleappengine.blogspot.com/2008/05/announcing-open-signups-expected.html"&gt;bandwidth,
storage, or computation requirements&lt;/A&gt; that cannot be delegated to
another web application (e.g. embedding &lt;A HREF="http://www.youtube.com/dev"&gt;YouTube&lt;/A&gt;
functionality) is out.  So, unless you plan on building a business
based on mashing together existing applications, then AppEngine
probably is not your &lt;A HREF="http://en.wikipedia.org/wiki/TANSTAAFL"&gt;free
lunch&lt;/A&gt;.  That being said, I fully expect that Google will
gradually add APIs for all of its &lt;A HREF="http://www.google.com/intl/en/options/"&gt;applications&lt;/A&gt;
to AppEngine, thereby providing a very powerful base for new-but-thin
ideas.&lt;/P&gt;
&lt;H2 &gt;The R&amp;amp;D Game&lt;/H2&gt;
&lt;P&gt;Just for a moment, let's say there was a company that required all
of its employees to spend&lt;A HREF="http://googleblog.blogspot.com/2006/05/googles-20-percent-time-in-action.html"&gt;&lt;/A&gt;&lt;A HREF="http://googleblog.blogspot.com/2006/05/googles-20-percent-time-in-action.html"&gt;&lt;/A&gt;&lt;A HREF="http://googleblog.blogspot.com/2006/05/googles-20-percent-time-in-action.html"&gt;
20% of their time&lt;/A&gt;&lt;A HREF="http://googleblog.blogspot.com/2006/05/googles-20-percent-time-in-action.html"&gt;&lt;/A&gt;&lt;A HREF="http://googleblog.blogspot.com/2006/05/googles-20-percent-time-in-action.html"&gt;&lt;/A&gt;
working on a project other than their primary job.  This is a company
that is betting that it cannot predict which idea is going to be the
next big thing, so it must try lots and lots of things and see what
sticks.  As this company grows, providing infrastructure for those
projects would become a real challenge.  Especially providing
infrastructure that allows them to be testing in the wild as opposed
to simply internally, and allows the projects to instantly scale if
they just happen to turn out to be a success.  This company would
also want to ensure their employees weren't slowed down by having to
deal with &lt;A HREF="http://www.artima.com/weblogs/viewpost.jsp?thread=178569"&gt;&lt;/A&gt;&lt;A HREF="http://www.artima.com/weblogs/viewpost.jsp?thread=178569"&gt;&lt;/A&gt;&lt;A HREF="http://www.artima.com/weblogs/viewpost.jsp?thread=178569"&gt;muck&lt;/A&gt;&lt;A HREF="http://www.artima.com/weblogs/viewpost.jsp?thread=178569"&gt;&lt;/A&gt;&lt;A HREF="http://www.artima.com/weblogs/viewpost.jsp?thread=178569"&gt;&lt;/A&gt;.
 Such a company would need an infrastructure that could scale to
support many, many applications without burdening infrastructure
teams.  Such a company would need AppEngine.&lt;/P&gt;
&lt;P&gt;Now extend the idea further.  Let's say it doesn't really matter
whether the next big thing was developed by an employee or not.  What
matters is that the next big idea is bound to the company, for
example by using the company standard &lt;A HREF="https://www.google.com/accounts/ManageAccount"&gt;authentication
mechanism&lt;/A&gt; or, more importantly, the company standard &lt;A HREF="https://www.google.com/adsense/"&gt;monetization
mechanism&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Ok, so we all know what company I'm talking about.  AppEngine
allows Google to outsource some of their R&amp;amp;D at very low cost,
and given that most successful AppEngine developers will probably
choose AdSense to monetize their creations, Google stands to profit
regardless of whether they ever pay any fees or not.  In cases where
creators do pay hosting fees, the great Google gets paid &lt;I&gt;twice&lt;/I&gt;.&lt;/P&gt;
&lt;H2 &gt;The Recruitment Game&lt;/H2&gt;
&lt;P&gt;Distinguishing among potential recruits is very challenging.  The
accomplished academic is almost certainly smart, may fall apart when
asked to work with a significant team on something important to the
company rather than a research interest.  The industry veteran may
have great corporate experience, but political skills could be
masking shallow or outdated technical skills.  The bottom line is
recruiting is hard because in most cases you never see a direct
sampling of an individual's work.  At best you can see what a team he
was on produced and take at educated guess as to his contribution. 
Open source projects can provide more information, but for most
programmers there is no real motivation to participate in such
projects.&lt;/P&gt;
&lt;P&gt;AppEngine provides more motivation to the programmer, because he
can more readily show his creation to other people without incurring
any cost and there is always a chance that he will make some money. 
There are probably a lot of talented “almost founders” out there
who would start a company, but perhaps lack some of the personality
traits necessary to do so or found themselves in a situation where
they need a steady income stream that simply isn't available for the
founder of an early-stage startup.  These individuals, and others,
will make great pickings for Google.&lt;/P&gt;
&lt;H2 &gt;Conclusion&lt;/H2&gt;
&lt;P&gt;Long term, in order for Google to grow, it has to attract more
people to spend more time on sites displaying AdSense advertisements.
 Over the past few years Google has come out with countless new
online services, most of which on still in beta, and none of which
has yielded anything close to the monetization potential of their
search business.  AppEngine allows them to vicariously service the
long tail without continuously expanding their already highly diverse
R&amp;amp;D efforts.  As a nice added bonus it will provide the
opportunity to acquire future high-value startups before they are
even real startups by simply hiring the developers and maybe tossing
some stock options their way.  On the flip side, I don't think
AppEngine is going to have much effect on mainstream web application
hosting.  The API is too constrained and for a company with resources
the ties to Google are most likely too tight.  So I predict AppEngine
will be more of a muted success for Google.  The infrastructure built
for it will be useful internally, it will help them get more sites up
more quickly addressing eclectic needs without burdening employees,
and it will provide a proving ground for future hires and possibly
very early stage acquisitions.  This could all add up to AppEngine
being a very significant success, but it also means the success may
out of the public eye.&lt;/P&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-9038658822579269214?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/9038658822579269214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=9038658822579269214' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/9038658822579269214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/9038658822579269214'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/06/google-appengine.html' title='Google AppEngine'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-8480594271783702701</id><published>2008-06-18T23:13:00.001-04:00</published><updated>2008-06-18T23:16:34.596-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='parallelism'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>What does I/O bound really mean?</title><content type='html'>&lt;P&gt;There's a lot of old folk wisdom out
there that justifies the use slow languages and runtimes on the basis
that the impact on performance doesn't matter.  Here's a sampling of
them:&lt;/P&gt;
&lt;UL&gt;
 &lt;LI&gt;&lt;P&gt;Most applications are I/O bound so
 the performance of the programming language doesn't matter&lt;/P&gt;
 &lt;LI&gt;&lt;P&gt;The database does all the heavy
 lifting, so performance of the application code doesn't matter&lt;/P&gt;
 &lt;LI&gt;&lt;P&gt;Computer time is cheap compared to
 programmer time&lt;/P&gt;
&lt;/UL&gt;
&lt;P &gt;Like most folk wisdom, these all have
an element of truth.  They are often brought up in discussions about
the merits of strongly-typed compiled languages versus dynamic
languages, and natively compiled languages versus virtual machine
based languages versus interpreted languages.  I could write about
any one of them, and many more, but today I'll address I/O because of
the “work” I've been doing on the &lt;A HREF="http://www.tbray.org/ongoing/When/200x/2008/05/01/Wide-Finder-2"&gt; WideFinder 2&lt;/A&gt; project.&lt;/P&gt;
&lt;H2&gt;WideFinder 2&lt;/H2&gt;
&lt;P&gt;The original WideFinder project was, at
least on first inspection, quite clearly I/O bound (well, if you had
an input file smaller than your main memory...)  The WideFinder 2 is
a little better because it is a little more computationally complex,
but not by much.  The benchmark is really simple:  process a big (42
GB) web server log file and report some basic statistics.  In order
to perform the benchmark, the program must parse the file, store
information from each line on several maps, and finally extract some
statistics out of them.&lt;/P&gt;
&lt;P&gt;Tim &lt;A HREF="http://www.tbray.org/ongoing/When/200x/2008/05/31/WF-First-Results"&gt;benchmarked&lt;/A&gt;
sequential block input on the test system at just shy of 150M/s. This
means that the I/O alone required to process the 42GB file should
take about 5 minutes, meaning that if the benchmark truly is I/O
bound then the program shouldn't take much more than 5 minutes to
run.  Consequently, if we are to judge based on  Tim's &lt;A HREF="http://www.tbray.org/ongoing/When/200x/2008/05/31/WF-First-Results"&gt;reference
implementation&lt;/A&gt; of the WF2 in Ruby then it quite clearly isn't I/O
bound.&lt;/P&gt;
&lt;H2&gt;I/O Takes CPU, too&lt;/H2&gt;
&lt;P &gt;If you look closely at the &lt;A HREF="http://www.textuality.com/bonnie/"&gt;Bonnie&lt;/A&gt;
benchmark results you'll notice that doing raw block I/O – meaning
just reading files into a buffer – consumes almost 80% of the a
single core of the CPU.  That means that I/O alone comes pretty close
to being bound by the CPU as well as being bound by the disk.  In
fact, experimentation uncovered that placing the system high load
&lt;A HREF="http://groups.google.com/group/wide-finder/browse_thread/thread/332f306893b37b0e#"&gt;reduces
maximum I/O throughput&lt;/A&gt;.  In order to achieve maximum throughput,
you actually have to ensure that you keep one core free to manage the
I/O.&lt;/P&gt;
&lt;H2&gt;Application I/O is more than I/O&lt;/H2&gt;
&lt;P&gt;Another key factor is that what most
application programmers think of as I/O involves a lot more than
shuttling bits from disk into memory.  For example, the Java and
other &lt;A HREF="http://en.wikipedia.org/wiki/Unicode"&gt;unicode&lt;/A&gt;
based platforms have to &lt;A HREF="http://java.sun.com/docs/books/tutorial/i18n/text/convertintro.html"&gt;decode&lt;/A&gt;
the character encoding of the file into the native character encoding
of the runtime.  In the case of the JVM, this not only requires that
every byte be processed, but also frequently doubles the memory
consumption of each character and requires the data be copied into a
separate buffer.  Furthermore, application code usually deals with
files line-by-line in the form of some standard (often immutable)
&lt;A HREF="http://java.sun.com/javase/6/docs/api/java/lang/String.html"&gt;string
object&lt;/A&gt;, thereby requiring yet another pass over the data.  So
when your code is simply iterating over lines in a file, it isn't
really just doing I/O.  A fair amount of CPU/memory bound work is
required to deliver those nice, neat, unicode strings.&lt;/P&gt;
&lt;H2&gt;Large datasets change the rules&lt;/H2&gt;
&lt;P&gt;Memory management isn't free, and even
with an industrial strength garbage collector it isn't always simple.
 A common practice with immutable objects is to have them share some
internal state in order to avoid excess data copying.  For example,
when you take a substring of a Java string, the two string objects
share an underlying character array.  Often times this saves memory,
and  it changes generating a substring of a string from a linear time
and space operation (with respect to string length) to a constant
time and space operation.  Unfortunately if the substring is much
longer lived that the original string, and especially if it is much
smaller, you end up with something that feels awful lot like a memory
leak (I think it could be debated whether it is a leak or not).&lt;/P&gt;
&lt;P &gt;Even if you're not carrying around a
lot of excess baggage in the form of substrings, processing gigabytes
of data consumes a lot of memory.  In the case of WF2, a little bit
of pretty much every line needs to be stored for the calculations at
the end.  The cast majority of my “debugging” time for WF2 was
spent figuring out what JVM parameters will actually allow the
program to finish without slowing to a crawl (pre-tuning there were
points were it would spend 90% of its time in GC) or consuming every
bit of memory available (at least a few WF2 solutions hog tons of
memory).&lt;/P&gt;
&lt;P &gt; All this means that when dealing with
large files other parts of the system need to do more work, which
takes away time that could be spent on “real” processing or on
I/O (which we've already seen can be a CPU hog).  Furthermore, I/O
routines and routines commonly used along side  heavy I/O (like
regular expressions) must be very careful about their memory usage.&lt;/P&gt;
&lt;H2&gt;So is WF2 really I/O bound?&lt;/H2&gt;
&lt;P &gt;It depends.  Go take a good hard look
at the &lt;A HREF="http://wikis.sun.com/display/WideFinder/Results"&gt;WF2
results page&lt;/A&gt;.  If you look at Tim Bray's results you would
conclude that no, WF2 clearly is not I/O bound.  However, if you look
at the top you'll see some very impressive numbers that indicate that
WF2 indeed is I/O bound (side note:  I really need to take a hard
look at &lt;A HREF="http://caml.inria.fr/"&gt;OCaml&lt;/A&gt;).   Of course, you
could argue that even in the OCaml case it really is CPU bound,
because making the task take about as long as the required I/O
saturated 8 cores and 32 hardware threads.  Scanning down the list
would seem to indicate that in most cases I/O does not represent a
significant bottleneck, but then it's hard to really tell.  The &lt;I&gt;disk&lt;/I&gt;
may not be the bottleneck, but the &lt;I&gt;I/O routines&lt;/I&gt;
within the libraries or runtime may be.   Consequently, from the
application programmer perspective, WF2 is I/O bound.&lt;/P&gt;
&lt;H2&gt;Redefining “I/O
bound” and future impacts&lt;/H2&gt;
&lt;P&gt;For a long time “I/O bound”
primarily referred to hardware or possibly operating system
limitations.  That was a useful definition, but it is time for it to
change.  Most software being developed today  has a very tall stack
of abstractions sitting between it and the hardware.  Operating
systems schedule I/O and have to split limited resources among many
competing processes.  Virtual machines  sit on top of operating
systems, isolating the programmer from the underlying OS and
hardware.  Libraries and frameworks isolate the programmer from the
virtual machine and even other libraries and frameworks.  I/O from
the programmer's perspective is, or at least should be if he is
working on top of good abstractions, that I/O is “everything that
happens between when my program requests some data and when it
receives it.”  Consequently, libraries and runtimes should go to
great lengths to ensure that being I/O bound is as close to its
original meaning as possible.  Prior to multicore systems becoming
pervasive that was largely true, but today's I/O libraries fail to
take advantage of them, and consequently force I/O into being a
bottleneck when it should not be.&lt;/P&gt;
&lt;P&gt;That's why in my Widefinder
submissions I've worked to separate parallelized I/O into a
library-like module.  It quite clearly is not done, but it is
relatively successful.  I reused my the parallel I/O code that I
developed for WF1 on WF2 without changing any of the logic.  It
doesn't provide many features, and it could use a fair amount of
optimization and simplification (the line joining logic is an
atrocity), but it works.&lt;/P&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-8480594271783702701?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/8480594271783702701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=8480594271783702701' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8480594271783702701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8480594271783702701'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/06/what-does-io-bound-really-mean.html' title='What does I/O bound really mean?'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-482573968724673948</id><published>2008-04-09T21:10:00.005-04:00</published><updated>2008-04-10T07:40:41.895-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Solaris'/><category scheme='http://www.blogger.com/atom/ns#' term='enterprise software'/><title type='text'>Multiprocess versus Multithreaded...</title><content type='html'>&lt;h2&gt;...or why Java infects Unix with the Windows mindset.&lt;/h2&gt;
&lt;p&gt;Recently Paul Murphy, the king of the Sun zealots, &lt;a href="http://blogs.zdnet.com/Murphy/?p=1110"&gt;blogged&lt;/a&gt; about Java bringing the Windows mentality to Windows, all the while slamming Java.  In response, John Carrol, a Microsoft employee, &lt;a href="http://blogs.zdnet.com/carroll/?p=1822"&gt;rose to the defense&lt;/a&gt; of Sun's self-declared crown jewel.  Talk about weird.&lt;/p&gt;
&lt;p&gt;The funny thing is they are both right, although Murph's arguments are pretty weak.&lt;/p&gt;
&lt;h3&gt;A little history&lt;/h3&gt;
&lt;p&gt;Unix and Windows evolved with a very different definition of what the primary unit of isolation should be.  On Windows, it is (or was) the node.  Each Windows user (and DOS user before him) occupied exactly one node.  The worst that could happen is the user destroys his own workspace, so interactive performance reigned supreme over system integrity.  You have a node.  You have a user.  The node does what the user wants as fast as it can.  Initially this applied to running a single application at a time, then to allowing several to be open at once but with the one in the foreground receiving primary resources, and finally to allow several applications to run simultaneously.  Multithreading reigned king because it was lower overhead and focused on making that foreground process more responsive.  Threads were optimized, while processes were neglected.&lt;/p&gt;
&lt;p&gt;Unix evolved to be fundamentally multiuser, and its primary unit of isolation is the process.  Unix systems were intended to be shared, so it was important that one user could not dominate over another.  Furthermore, and slew of processes (daemons) all ran as the same under the same account, while providing services to multiple users, so in order for users to share processes must share.  Unlike on Windows, one process crashing the entire system was not acceptable, because that would destroy multiple users' data.  As a result, processes were designed to represent a strong level of isolation and heavily optimized to make sure people used it.  Threads were largely ignored, or simply treated as processes with a shared heap space, because several cheap processes could simply be chained together to accomplish the same thing in a simpler manner.&lt;/p&gt;
&lt;h3&gt;The Unix Way&lt;/h3&gt;
&lt;p&gt;I want you to consider good old-fashioned CGI programs for a moment.  Imagine one written in C.  First, you may think "Oh my God, running a web application in a non-managed environment.  The resource leaks!  The memory leaks!  The memory consumption of all those processes!  Oh the horror!."  Of course, you would be wrong.  Repeating launching and terminating a Unix process is dirt cheap.  Especially a simple program written in C.  The OS will cache an image of the executable in memory which can be shared among invocations.  The individual process can leak all the resources it wants, because as soon as it terminates all the resources will be automatically freed by the OS, not matter how incompetent the programmer.  If the process fails to terminate your friendly neighborhood sysadmin can kill it without hurting any other process.&lt;/p&gt;
&lt;p&gt;This method works for producing super-available applications despite incredibly crappy code.  I've seen it, both in the for of CGI and in the form of much more sophisticated applications.  It works.  Users get upset about lost transactions, but the application as a whole almost never goes down.&lt;/p&gt;
&lt;h3&gt;Enter Java&lt;/h3&gt;
&lt;p&gt;Java took cheap Unix processes and made them expensive.  To compensate, it provided primitives for multithreading.  It provided a garbage collector to at least slow memory leaks.  It turned all those transient application processes into one big JVM process not only serving all the transactions for a given user, but serving all the transactions for an entire application or even multiple applications.  Java made it more difficult to make destructive program errors, but it also made the consequences much more severe.  Your friendly neighborhood sysadmin is powerless against a runaway thread or a slow memory leak.  All he can do is kill the process, bumping out all of the users, killing all of their sessions.&lt;/p&gt;
&lt;p&gt;It's so bad, the process might as well be a node.  Unix becomes Windows.  The JVM is practically an operating system, but without all of the features of an operating system and a whole lot less mature.&lt;/p&gt;
&lt;h3&gt;Enter Java Frameworks&lt;/h3&gt;
&lt;p&gt;This is really what Murph was railing against, although he didn't name it and he conflated it with the core language by labeling "Business Java."  Frameworks evolved for a myriad of reasons which are often summarized as "taking care of the plumbing to the developer can focus on the business logic."  The "plumbing" is a lot of things, including managing certain resources and generally ensuring the application code executes within a well defined life cycle where it is unlikely to do damage.  In other words, instead of giving the user a simple, uniform mechanism like a process to protect the world from his mistakes, he is given dozens of hooks where he can implement little snippets of focused and hopefully bug-free functionality.  All this involves a lot of learning above and beyond "the Java you learned in school" (meaning the core language and libraries), putting a cognitive load on the programmer and additional runtime load on the machine.&lt;/p&gt;
&lt;h3&gt;Multiprocess versus Multithreaded&lt;/h3&gt;
&lt;p&gt;Most Unixes have evolved efficient threading, and Windows has come a long way in becoming a multiprocess, multiuser environment.  Consequently, developers needs to be able to intelligently decide when to use multiple processes, when to use multiple threads, and when to use a hybrid approach.  For example, Apache httpd has for quite a while now used a hybrid approach.  One one hand on most operating systems threads involve less overhead than processes, so it is more efficient to use multiple threads than multiple processes.  On the other hand multiple processes ultimately will give you better reliability because they can be spawned and killed independently from one another, so making a system that can run for months without stopping doesn't require writing a program that will run for months without stopping.&lt;/p&gt;
&lt;p&gt;So how do you choose?  My rule of thumb is to look at the amount of shared data or messaging required between concurrent execution paths and balance against how long the "process" (not OS process) is expected to live.  Execution paths with lots of shared data or that are chatty will benefit from the lower overhead of threading, and threading allows you to avoid the complexities of shared memory or IPC.  Of course, multiprocessing allows you to avoid the complexities of threading APIs, and there are libraries to address both, so the complexity issue could be a wash depending on your previous experience.&lt;/p&gt;
&lt;h3&gt;So why is Murph so wrong?  Is JC right?&lt;/h3&gt;
&lt;p&gt;I think Murph wants to divide the world along nice clean lines.  System programmers program in C.  They don't need the hand-holding of managed runtimes or languages that treat them like impudent children.  They do need lots of flexibility and lots of rope.  Application programmers, on the other hand, need high-level abstractions that are close to the business domain that they are addressing.  They need to be able to rapidly build software and rapidly change it as requirements evolve.  They don't need lots of flexibility and should stay away from low-level details.  So, in Murph's eyes, the problem with Java is that it doesn't do either particularly well.  The managed runtime and object-orientation get in the system programmer's way, while the general-purpose nature of the language and mish-mash of libraries and frameworks just confuse application developers, or rather distract them from their true purpose.  System programmers need C.  Application developers need 4GLs.&lt;/p&gt;
&lt;p&gt;The fatal flaw in Murph's reasoning is that it ignores the in-between.  What happens when the systems programmer or 4GL creator fails to provide the right abstraction for the application developer?  He's stuck, that's what happens.  Software development is as much about creating abstractions as using them.  Consequently, application developers need general-purpose languages.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-482573968724673948?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/482573968724673948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=482573968724673948' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/482573968724673948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/482573968724673948'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/04/multiprocess-versus-multithreaded.html' title='Multiprocess versus Multithreaded...'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-1513261006511422406</id><published>2008-03-05T21:54:00.003-05:00</published><updated>2008-03-05T22:09:38.340-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AI'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='privacy'/><title type='text'>Does Google Reader read GMail?</title><content type='html'>&lt;p&gt;Up until recently, all my "Top Recommendations" in Google Reader were related to IT, software development, math, and finance.  This makes perfect sense, because that covers all the topics in my subscriptions.  However, today I noticed the Google Reader suggested an RSS feed for a blog about local (kind-of) restaurants, clubs, bars, etc.  This means that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Google Reader has a decent idea about where I live&lt;/li&gt;
&lt;li&gt;Somehow Google Reader figured out that I enjoy dining out&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The best I can figure is that Google Reader is basing my recommendations on the contents of my email.  While I don't have any feeds about such things, I do exchange emails with my wife and friends about making dinner reservations, where to go out to eat, etc.  The other possibility is that it figured it out using my &lt;a href="http://www.techcrunch.com/2007/11/29/google-reader-gets-recommendations-drag-and-drop/"&gt;search history&lt;/a&gt;, except that the contents of my search history look pretty much the same as my subscriptions (I know, I'm a nerd).  This is because usually I'm not logged into Google when I am searching.  Consequently, I think it is reading my GMail.&lt;/p&gt;
&lt;p&gt;Anyone else have any ideas?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-1513261006511422406?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/1513261006511422406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=1513261006511422406' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/1513261006511422406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/1513261006511422406'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/03/does-google-reader-read-gmail.html' title='Does Google Reader read GMail?'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-2186819327354016635</id><published>2008-03-03T17:20:00.003-05:00</published><updated>2008-12-09T06:44:27.810-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>Floating Points Stike CNN!</title><content type='html'>Looks like developers at cnn.com need a lesson in floating point numbers:
&lt;a href="http://4.bp.blogspot.com/_-ZOtVRo0ba8/R8x5_eYw2VI/AAAAAAAAACI/czJYAFcYjEQ/s1600-h/cnn_nan.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_-ZOtVRo0ba8/R8x5_eYw2VI/AAAAAAAAACI/czJYAFcYjEQ/s400/cnn_nan.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5173644203337505106" /&gt;&lt;/a&gt;
&lt;p&gt;Either that or the Democratic primary is truly too close to call...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-2186819327354016635?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/2186819327354016635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=2186819327354016635' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2186819327354016635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2186819327354016635'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/03/floating-points-stike-cnn.html' title='Floating Points Stike CNN!'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_-ZOtVRo0ba8/R8x5_eYw2VI/AAAAAAAAACI/czJYAFcYjEQ/s72-c/cnn_nan.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4727079504466046717</id><published>2008-02-18T22:19:00.006-05:00</published><updated>2008-02-22T19:55:37.601-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>Typesafe Ranged Integers in Scala</title><content type='html'>&lt;p&gt;For the past few weeks I've been working on a basic numeric library for Scala for eventual contribution to the &lt;a href="http://scalax.scalaforge.org/"&gt;Scalax project&lt;/a&gt;.  My goal is to create an extensible, type-safe library that provides numeric types that are easy to use and more closely resemble their mathematical foundations than the primitive operations on which they are built.  My initial focus has been on building a working rational numbers implementation with unlimited precision integers.  However, today on the Scala mailing lists, someone raised the issue that Scala's use of primitive numbers doesn't belong in such a high-level language.  When I read this, I thought "Hmmmm, my library helps with that."&lt;/p&gt;
&lt;h3&gt;Integer Underflow and Overflow&lt;/h3&gt;
&lt;p&gt;First, let's consider integer underflow and overflow.  The standard Java/Scala integer type is a 32-bit twos-complement signed integer.  That means it can representing numbers between 2147483647 and -2147483648 inclusive.  Often times this is plenty range, so what we really want is for exceptions to be thrown when underflow and overflow. So consider the following:&lt;/p&gt;
&lt;code&gt;
scala&gt; import scalax.math.Int32Domain._&lt;br /&gt;
import scalax.math.Int32Domain._&lt;br /&gt;
&lt;br /&gt;
scala&gt; val a: Int32 = 5&lt;br /&gt;
a: scalax.math.Int32Domain.Int32 = 5&lt;br /&gt;
&lt;br /&gt;
scala&gt; val b: Int32 = 7&lt;br /&gt;
b: scalax.math.Int32Domain.Int32 = 7&lt;br /&gt;
&lt;br /&gt;
scala&gt; a + b&lt;br /&gt;
res0: scalax.math.Int32Domain.N = 12&lt;br /&gt;
&lt;br /&gt;
scala&gt; a * b&lt;br /&gt;
res1: scalax.math.Int32Domain.N = 35&lt;br /&gt;
&lt;br /&gt;
scala&gt; val i: Int32 = 2147483647&lt;br /&gt;
i: scalax.math.Int32Domain.Int32 = 2147483647&lt;br /&gt;
&lt;br /&gt;
scala&gt; i + 1&lt;br /&gt;
java.lang.ArithmeticException: result exceeds maximum value: 2147483647&lt;br /&gt;
 at scalax.math.Int32Domain$Int32.checkRange(int32.scala:55)&lt;br /&gt;
 at scalax.math.Int32Domain$Int32.$plus(int32.scala:60)&lt;br /&gt;
 at .&lt;init&gt;(&lt;console&gt;:8)&lt;br /&gt;
 at .&lt;clinit&gt;(&lt;console&gt;)&lt;br /&gt;
 at RequestResult$.&lt;init&gt;(&lt;console&gt;:3)&lt;br /&gt;
 at RequestResult$.&lt;clinit&gt;(&lt;console&gt;)&lt;br /&gt;
 at RequestResult$result(&lt;console&gt;)&lt;br /&gt;
 at sun.reflect.NativeMethodAccess...&lt;br /&gt;
&lt;/code&gt;
&lt;p&gt;Magic!  Overflow has been detected.  Well, not quite magic.  The way it works (and I'm sure it could work much, much better, I just through this together tonight) is that it converts the 32-bit integers into 64-bit integers prior to calculations, performs the calculations, then checks the result to ensure that it is within range.  If it is within range, then the result is converted back into a 32-bit integer and returned.  Between the usage of an object instead of a primitive and all this extra work for range checking, this class is probably at least an order-of-magnitude slower that using primitive Ints.&lt;/p&gt;
&lt;h3&gt;Bounded Ranges&lt;/h3&gt;
&lt;p&gt;Now let's consider bounded ranges.  In order to accomplish this, we simply create an object that extends Int32 and overrides its minimum and maximum value.&lt;p&gt;
&lt;code&gt;
scala&gt; object SmallDomain extends scalax.math.Int32Domain {&lt;br /&gt;
     | override val max: N = 10&lt;br /&gt;
     | override val min: N = -10&lt;br /&gt;
     | }&lt;br /&gt;
defined module SmallDomain&lt;br /&gt;
&lt;br /&gt;
scala&gt; val d = SmallDomain.Integer(5)&lt;br /&gt;
d: SmallDomain.N = 5&lt;br /&gt;
&lt;/code&gt;
&lt;p&gt;Now we have a domain that is limited from -10 to 10 inclusive.  Attempting to mix integers from this domain with integers from other domains will yield a type error:&lt;/p&gt;
&lt;code&gt;
scala&gt; i + d&lt;br /&gt;
&lt;console&gt;:9: error: type mismatch;&lt;br /&gt;
 found   : SmallDomain.N&lt;br /&gt;
 required: scalax.math.Int32Domain.N&lt;br /&gt;
       i + d&lt;br /&gt;
           ^&lt;br /&gt;
&lt;br /&gt;
scala&gt; d + i&lt;br /&gt;
&lt;console&gt;:9: error: type mismatch;&lt;br /&gt;
 found   : scalax.math.Int32Domain.Int32&lt;br /&gt;
 required: SmallDomain.N&lt;br /&gt;
       i + a&lt;br /&gt;
           ^ &lt;br /&gt;
&lt;/code&gt;
&lt;p&gt;Even if you had a Int32 within the range of SmallDomain, you would still receive the type error.  Also, as you can see, Int32 will not allow itself to be mixed with an integer from SmallDomain.  If you look at the code (which I'll publish soon, I promise) for Int32Domain and its superclasses, you will see a lot of complex stuff involving mixins and type constructors.  However, the end class is easily extensible by the user and still provides good type safety.&lt;/p&gt;
&lt;h3&gt;Rationals&lt;/h3&gt;
&lt;p&gt;I mentioned rationals at the beginning of this blog, so I thought I would give a little sneak-peak:&lt;/p&gt;
&lt;code&gt;
scala&gt; import scalax.math.BigRationalDomain._&lt;br /&gt;
import scalax.math.BigRationalDomain._&lt;br /&gt;
&lt;br /&gt;
scala&gt; val a = Integer(3)&lt;br /&gt;
a: scalax.math.BigRationalDomain.IS = 3&lt;br /&gt;
&lt;br /&gt;
scala&gt; val b = Integer(7)&lt;br /&gt;
b: scalax.math.BigRationalDomain.IS = 7&lt;br /&gt;
&lt;br /&gt;
scala&gt; a / b&lt;br /&gt;
res0: scalax.math.BigRationalDomain.N = 3/7&lt;br /&gt;
&lt;br /&gt;
scala&gt; a.inverse&lt;br /&gt;
res1: scalax.math.BigRationalDomain.N = 1/3&lt;br /&gt;
&lt;br /&gt;
scala&gt; a.inverse * a&lt;br /&gt;
res2: scalax.math.BigRationalDomain.N = 1&lt;br /&gt;
&lt;br /&gt;
scala&gt; (a / b)^2345&lt;br /&gt;
res3: scalax.math.BigRationalDomain.N = 70687450412160609527952431393691553815800419127671886519112946722799601077076407951140254943159198319665943578284183744314587093153151823879346566151398437630838022610858501398173872472014103905434680267558985498302895510754430260294086995134629615707980341285332639084519209821403179213183556756416404920769037158823806045214292550723098516538040...&lt;br /&gt;
&lt;br /&gt;
scala&gt; a * b&lt;br /&gt;
res4: scalax.math.BigRationalDomain.I = 21&lt;br /&gt;
&lt;br /&gt;
scala&gt; Integer(3) / Integer(6)&lt;br /&gt;
res5: scalax.math.BigRationalDomain.N = 1/2&lt;br /&gt;
&lt;/code&gt;
&lt;p&gt;Notice how an integer times an integer equals an integer, but an integer divided by an integer equals a rational.  This is because integer is a subtype of rational, because in all integers are rationals, but not all rationals are integers.&lt;/p&gt;
&lt;p&gt;More to come soon!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-4727079504466046717?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4727079504466046717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4727079504466046717' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4727079504466046717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4727079504466046717'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/02/typesafe-ranged-integers-in-scala.html' title='Typesafe Ranged Integers in Scala'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-3123893966186810524</id><published>2008-02-08T13:08:00.000-05:00</published><updated>2008-02-08T13:58:15.565-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><title type='text'>Linguistic Success</title><content type='html'>&lt;p&gt;There's a new favorite pastime on the fringes of the Scala community.  That pastime is blogging about aspects of the Scala language that will prevent it from being a "success" unless they are quickly addressed.  "Success" is roughly defined as "widespread commercial use."  A good metric might be: "How hard is it to find a job programming Scala?"  The premise of the criticism usually revolves around one or more complicated, terse, or "foreign" (relative to the author) constructs that are common Scala, or at least favorites among frequent posters, and how these constructs will prevent "average" programmers from understanding Scala and thereby prevent commercial adoption.  A recent favorite is symbolic function names (/: and :\ for folds).&lt;/p&gt;
&lt;p&gt;The logic of this argument seems relatively sound.  When choosing a technology for a project, it is very important to consider the availability of potential employees who know that technology.  Forcing every new member to scale a potentially steep learning curve is a frightening prospect.  I can imagine development managers lying awake at night fearing that their expert in some obscure technology will leave, and it will take months to replace him.  It's a legitimate, although I think slightly exaggerated, fear.&lt;/p&gt;
&lt;p&gt;That being said, I think it has little to do with the adoption of a new language.  The majority of programmers simply do not spend their free time learning new languages.  Many, maybe most, won't even use their free time to learn languages that they know have ready pre-existing demand.  They learn when they are paid to learn, or when failing to learn will lead to immediate negative consequences for their career.  I think the same can be said of most professions.  Most people work because they have to, not because they want to.&lt;/p&gt;
&lt;p&gt;Consequently, I think expanding beyond a core of enthusiasts is very difficult, if not impossible, simply be attracting people to the language.  Right now some leading-edge Java people are taking a look at Scala, because they think it might be the next big thing in Java-land.  These people are different than enthusiasts.  Enthusiasts will learn a language for the sake of learning it.  The leading-edge folks learn it as a high risk investment.  If they can get a head start on the next big thing, it will be great for their careers (and businesses).  These people constantly think "can I sell using this technology?" and "if I do sell it, while it come back to haunt me?"  This is a very pragmatic perspective, and it is the perspective I take when I'm at work.&lt;/p&gt;
&lt;p&gt;Confusing, odd-ball language features make the sell a lot harder.  Pitching them as features increases personal risk.&lt;/p&gt;
&lt;p&gt;But it doesn't matter.&lt;/p&gt;
&lt;p&gt;Why?  Because the vast majority of developers are not going to learn a new language because they want to, they are going to learn it because they have to.  Not to mention that there are countless languages out there, so going after the enthusiasts and leading-edgers (who are mostly lookers anyway) is just fishing in an already over-fished pond.&lt;/p&gt;
&lt;p&gt;So how does a language become a success?&lt;/p&gt;
&lt;p&gt;Enough people use it for real projects.  Let's say a consultant rapidly prototypes an application using the technology, and that application makes it into production.  Now maintenance programmers have to learn that technology.  Sure, it's complicated, but unlike the guy learning it on free weekends, the maintenance programmers have all-day every-day.  It's hard to learn complex concepts a hour or two at a time, but these guys have all day, and the next day.  It's hard to memorize something by looking at it a couple hours a week, but spend all day staring and it and it will click.  Not to mention that their livelihoods depend on it.  Any sort of "cowboy" development team can cause this to happen, and frankly such teams are pretty common.&lt;/p&gt;
&lt;p&gt;So maybe one-in-five maintenance programmers actually like the technology, and admire the cowboys, so when they go get a chance to do new development, they use it, too.&lt;/p&gt;
&lt;p&gt;The same thing can happen with products from startups.  Let's say a startup builds a piece of enterprise software using Scala.  They sell it to big, conservative companies by emphasizing the Java aspect.  They sell customization services, too.  And then it's back to the maintenance programmer, who has no choice.&lt;/p&gt;
&lt;p&gt;Notice a pattern?  The key to language success is making it powerful enough for a couple cowboys to do the work of an entire team in a shorter period of time.  Selling fast and cheap is easy.  If you have enough fast and cheap, the business people won't care if you are making it out of bubble-gum and duct-tape, because you are giving them what they want.&lt;/p&gt;
&lt;p&gt;The key to success is making the reward justify the risk.  Judging by what some people using Scala for real-world projects are saying, and my one hands-on experience, I think Scala offers it.  It's just a matter of time before it sneaks its way into enterprises, just like Ruby has.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-3123893966186810524?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/3123893966186810524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=3123893966186810524' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3123893966186810524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3123893966186810524'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/02/linguistic-success.html' title='Linguistic Success'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4142292585102526364</id><published>2008-01-21T21:35:00.000-05:00</published><updated>2008-12-09T06:44:28.121-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Programming Language Continuum</title><content type='html'>&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Ever since I started getting into less-than-mainstream programming languages, I've pondered how to go about classifying them according to their attributes in the hopes that it would yield insight into what an ideal programming language would be.  There is the &lt;a href="http://merd.sourceforge.net/pixel/language-study/diagram.html"&gt;genealogical&lt;/a&gt; way that traces roots and influences, but that doesn't break down attributes or make any qualitative judgements.  Here I intend to mostly frame the context for debate, rather than draw significant conclusions.  I believe bringing some more structure to the discussion is necessary before much more can be gleaned from it.&lt;/p&gt;
&lt;p&gt;So what I've done is attempt to break the essence of a programming language down into two dimensions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enforced Structure / Dynamism&lt;/li&gt;
&lt;li&gt;Engineered Foundations / Mathematical Foundations&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here's a loose attempt at classifying some languages:&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_-ZOtVRo0ba8/R5VrTwxB4zI/AAAAAAAAACA/6xpb_aatmzg/s1600-h/prog_lang_class_diag.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_-ZOtVRo0ba8/R5VrTwxB4zI/AAAAAAAAACA/6xpb_aatmzg/s400/prog_lang_class_diag.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5158146935475004210" /&gt;&lt;/a&gt;
&lt;h3&gt;Enforced Structure vs Dynamism&lt;/h3&gt;
&lt;p&gt;Recent debates have focused heavily on the difference between statically typed and dynamically typed languages.  I believe that this is a specific case of the more general issue of "how much structure should the programming language force on the programmer?"  Today we see &lt;a href="http://en.wikipedia.org/wiki/Java_(programming_language)"&gt;Java&lt;/a&gt; &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=37121"&gt;versus&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Ruby_(programming_language)"&gt;Ruby&lt;/a&gt;, but it could just as easily be &lt;a href="http://en.wikipedia.org/wiki/Ada_(programming_language)"&gt;Ada&lt;/a&gt; &lt;a href="http://portal.acm.org/citation.cfm?id=319568.319655"&gt;versus&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Lisp_programming_language"&gt;Lisp&lt;/a&gt;.  On you side of the debate you have people who believe that heavily structured languages are essential for scaling and helping ensure correctness.  One of my college professors once said (paraphrased) "the compiler is your friend, help it catch your errors for you."  Also, a well defined and compiler checked structure can help scale programming projects up to large teams by ensuring that all team members are working to the same program structure.  Finally, they point out the sophisticated tools that available for many statically typed languages, particularly refactoring tools, but also code generators and static validators.
&lt;/p&gt;
&lt;p&gt;On the other side of the debate you have dynamic language advocates.  They claim that statically typed languages are too constraining and require more up-front design than is practical, especially given the vague and changing requirements typical of software development projects.  Furthermore, robust code an be achieved through automated testing and by significantly reducing the amount of code required to deliver the required functionality.  Finally, they point out the quicker feedback cycles that dynamic languages enable by shortening the change-&gt;compile-&gt;deploy-&gt;test loop to change-&gt;test.  There was a time when this loop was actually figured into software development cost and schedule estimates, but today outside of very large projects it is simply a cognitive disruption.
&lt;/p&gt;
&lt;h3&gt;Engineered vs Mathematical Foundations&lt;/h3&gt;
&lt;p&gt;Most of the mainstream programming languages have been "engineered" or "designed" to better enable some group of programmers to better achieve some objective.  For example, Ada was engineered to enable the development of very large, complicated and highly reliable systems by huge teams.  &lt;a href="http://en.wikipedia.org/wiki/Smalltalk"&gt;SmallTalk&lt;/a&gt; was designed to enable the construction of modular software in a more natural or "human" manner.  &lt;a href="http://en.wikipedia.org/wiki/COBOL"&gt;COBOL&lt;/a&gt; was designed to enable business analysts to program.  The list goes on and on, but the common theme is that most of these languages were designed or engineered with very specific design goals, and those goals were largely disconnected from strong mathematical foundations.
&lt;/p&gt;
&lt;p&gt;On the other side of the spectrum you see languages that are very strongly influenced by computer science theory.  &lt;a href="http://en.wikipedia.org/wiki/Lisp_programming_language"&gt;Lisp&lt;/a&gt; started out as an executable implementation of the untyped lambda calculus and has stayed fairly true to that origin.  &lt;a href="http://en.wikipedia.org/wiki/Haskell_(programming_language)"&gt;Haskell&lt;/a&gt; combines the typed lambda calculus with category theory and focuses on functional purity.  Prolog is based on logic, and SQL on relational theory.  What these languages offer, especially strongly typed ones like Haskell, is that they enable computer programs to be much more easily reasoned about by theorem provers (and similar) and therefore can provide a much higher degree of safety.  To the initiated, they also provide much more natural and elegant abstractions.&lt;/p&gt;
&lt;h3&gt;Hybrid Languages&lt;/h3&gt;
&lt;p&gt;The idea of dynamic languages with option type annotations is often raised as a potential means to bridge the divide between the advocates of static and dynamic languages.  Common Lisp provides &lt;a href="http://www.lisp.org/table/types.htm"&gt;optional compile-time type checking&lt;/a&gt;, but in practice is seems to be used mostly as an optimization in special cases rather than as a means of ensuring correctness.  Some touted &lt;a href="http://www.strongtalk.org/"&gt;StrongTalk&lt;/a&gt; as an answer, especially when Sun released it as open source, but it seems to have sputtered out.  There was much &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=86641"&gt;talk&lt;/a&gt; about adding optional type annotations to Python, but I believe (please correct me if I am wrong) it is still absent from &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=208549"&gt;Python 3000&lt;/a&gt;.  So while optional static typing is a favorite debate topic, its not popular in the languages that have it and attempts to add it to languages that don't have yet to reach fruition, despite considerable effort.&lt;/p&gt;
&lt;p&gt;A recent phenomena, or perhaps simply recently receiving attention, are hybrid languages that attempt to blend concepts from strongly-typed functional languages such as Haskell with more mainstream object-oriented underpinnings.  In my opinion, Scala is probably the best of these, as it offers innovative OO features in addition to functional ones, but others such as &lt;a href="http://research.microsoft.com/fsharp/fsharp.aspx"&gt;F#&lt;/a&gt; and &lt;a href="http://caml.inria.fr/ocaml/"&gt;OCaml&lt;/a&gt; certainly deserve mentioning, as do no doubt countless others that I am unfortunately going to neglect.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;I think that hybrid static/dynamic languages will never really become popular - or more accurately that the capability will not be extensively used in the languages that offer it.  There are a couple reasons for this.  Primarily, I think that making static typing optional almost completely eliminates the benefits of static typing.  Second, I think the primary advantage of dynamic languages is that they allow partially formed thoughts to be quickly expressed in "working" (meaning running, not correct) code, and that static typing is a major barrier to this.  I personally find doing exploratory programming in dynamic languages to be much more pleasant and productive, but once ideas are concrete I prefer the compile-time checks and completeness of static typing.&lt;/p&gt;
&lt;p&gt;I personally believe that languages that blend the engineered structure of OO with mathematical formalism represent the future of programming.  Scala and F# are here, and both Java and C# are gradually acquiring features from strongly typed functional languages.  What's going to be interesting is how it shakes out.  If you peruse the &lt;a href="http://www.nabble.com/Scala-Programming-Language-f20934.html"&gt;Scala mailing list archives&lt;/a&gt;, you will notice that there is a marked tension between those from an object-oriented (engineered) perspective who enjoy the extra power that functional programming provides them, versus those from a more pure functional programming background (mathematical).  Ultimately, at least from a popularity perspective, I think the more OO approach will win, as historically languages engineered to provide specific advantages have won out over languages with robust mathematical underpinnings.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-4142292585102526364?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4142292585102526364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4142292585102526364' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4142292585102526364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4142292585102526364'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/01/programming-language-continuum.html' title='Programming Language Continuum'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_-ZOtVRo0ba8/R5VrTwxB4zI/AAAAAAAAACA/6xpb_aatmzg/s72-c/prog_lang_class_diag.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7206026782320465069</id><published>2008-01-21T07:49:00.000-05:00</published><updated>2008-01-21T08:19:36.473-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>I hate Apple and HP</title><content type='html'>&lt;p&gt;A couple months ago I bought a new MacBook.  For the most part I've loved it, but last night I ran into a problem.&lt;/p&gt;

&lt;p&gt;When I bought my Mac, Apple was offering a $100 rebate on the purchase of a new printer to go with it.  The sales guy pointed out that there are  number of printers that cost around $100, so the printer would be essentially free.  I chose an &lt;a href="http://store.apple.com/1-800-MY-APPLE/WebObjects/AppleStore.woa/wa/RSLID?mco=89561D41&amp;fnode=home/shop_mac/mac_accessories/printers&amp;nplm=TM785LL/A"&gt;HP C4280 All-in-One&lt;/a&gt;.  Look at that!  If it wasn't for sales tax I would have made five cents off of the purchase.  Well, you get what you pay for&lt;/p&gt;
&lt;p&gt;As a printer it's worked fine.  I didn't even need to install any drivers.  I plugged it in and it just worked.  Of course, that's what I expect from Apple.  But last night my wife wanted to scan a document and make it into a PDF.  I figured, "Ok, that should be easy."  Boy was I wrong.&lt;/p&gt;
&lt;p&gt;So I launch Image Capture on my Mac to scan the document.  It tells me that I don't have any attached devices.  Hmmm.  I printed a few minutes ago.  Why don't I have any attached devices?  So maybe I'm using the wrong application.  There's a "scan" button on the printer, so I press that, hoping that the right application will magically open up (see what Apple has done to me!).  The printer thinks for a minute, and then tells me that it's not connected through USB.  Well, of course it is, because I just printed over USB.  I decide to do some Googling&lt;/p&gt;
&lt;p&gt;It turns out that while the printer drivers come pre-installed with Leopard, the scanner drivers do not.  It's a &lt;a href="http://h10025.www1.hp.com/ewfrf/wc/softwareDownloadIndex?softwareitem=mp-55008-1&amp;lc=en&amp;cc=us&amp;dlc=en&amp;product=3192753&amp;os=219&amp;lang=en"&gt;192 MB download&lt;/a&gt; full of crapware.  I hate Apple for making me think that I didn't need to install drivers, and then consuming a chunk of my Sunday evening installing drivers.  They set an expectation and then disappointed.  It would have been much better to just make me install all the drivers up front.&lt;/p&gt;
&lt;p&gt;But why did I say it was full of crapware?  Well, let's see.  So I scanned the document as a PDF with text (so it has to do OCR) using "HP Scan Pro."  That worked.  Kind of.  I did get a decent looking PDF document with the text correctly converted into text.  I also got a completely locked up HP Scan Pro application, and I mean &lt;b&gt;completely&lt;/b&gt; locked up.  I tried to log out of my Mac, figuring that would clean up the crashed process.  Nope!  It sat there for a minute, then complained that an application wouldn't exit and asked if it should do it forcefully.  I of course said yes, and then it just sat there for a few minutes longer.  I got the same result from trying to shut down.  At least when you tell Windows that it can violently kill, it violently kills the processes.  Apparently MacOSX is too polite, or at least has more patience than I do.&lt;/p&gt;
&lt;p&gt;That's another reason to hate Apple.  It was worse than Windows, and using a product purchased from the Apple Store no less.&lt;/p&gt;
&lt;p&gt;Fortunately I'm a Unix guy and I know how to violently kill processes.&lt;/p&gt;
&lt;code&gt;
su
ps -ef | grep HP
kill -9 pid1 (pidX is the process id of an HP process)
kill -9 pid2
&lt;/code&gt;
&lt;p&gt;Until they are all dead.  That worked.  Of course in the process of doing this I discovered that there are a couple HP processes running as root, which disturbs me to no end.&lt;/p&gt;
&lt;p&gt;What I'd like to ask Steve Jobs is:  How many Mac users would know to drop down to a terminal, su to root, and violently kill the processes?  I just can't see your average non-techie Mac user doing that.  Apple should really do a better job &lt;a href="http://store.apple.com/1-800-MY-APPLE/WebObjects/AppleStore.woa/wa/RSLID?fnode=home/shop_mac/mac_accessories/printers&amp;revw=TM785LL/A"&gt;screening the products &lt;/a&gt;it sells with new computers.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7206026782320465069?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7206026782320465069/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7206026782320465069' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7206026782320465069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7206026782320465069'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/01/i-hate-apple-and-hp.html' title='I hate Apple and HP'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7029443758307140521</id><published>2008-01-02T22:49:00.000-05:00</published><updated>2008-12-09T06:44:28.810-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Finance'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>Slightly Less Double (Im)precision</title><content type='html'>&lt;p&gt;Anonymous writes&lt;/p&gt;
&lt;blockquote&gt;You may want to try evaluating the polynomial using a different form. For example, given the polynomial:

A*x^3 + B*x^2 + C*x + D

one is often tempted to just enter it "as is". However it can also be expressed this way:

((A*x+B)*x+C)*x+D

Generally speaking polynomials often work better using floating point this alternate way. Some programming languages/systems know this and convert the expression before evaluating it. &lt;/blockquote&gt;
&lt;p&gt;
...and he is absolutely right.  It makes the code of heck of a lot more efficient, too, because it eliminates the calls to Math.pow.  That being said, it does not completely fix the problem.  The polynomial line is a lot smoother, and the fitting algorithm yields a lower degree polynomial for the same mean error, but I still think the results are too fuzzy compared to the higher precision floating point.  Here's a graph to show the difference:&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_-ZOtVRo0ba8/R3xdBAxB4xI/AAAAAAAAABw/dTNBz0xnxUg/s1600-h/double_deg39.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_-ZOtVRo0ba8/R3xdBAxB4xI/AAAAAAAAABw/dTNBz0xnxUg/s400/double_deg39.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5151094345771901714" /&gt;&lt;/a&gt;
&lt;p&gt;Compared to the previous result:&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R3mIPgxB4uI/AAAAAAAAABY/XC-nDztVZew/s1600-h/double_deg44.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R3mIPgxB4uI/AAAAAAAAABY/XC-nDztVZew/s400/double_deg44.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5150297448949867234" /&gt;&lt;/a&gt;
&lt;p&gt;Further improvement could probably be obtained by taking a close look at the QR Decomposition algorithm used to do the least-squares fitting. &lt;/p&gt;
&lt;p&gt;In my opinion, the problem here is not so much the double-prevision floating points are bad.  They are not.  For many applications, especially with carefully crafted algorithms, they are great.  They are certainly much higher performance than their higher-precision object-oriented kin.  I'll warn you:  Don't do high precision matrix operations with your MacBook in your lap - it gets really hot.  The double-precision version finishes in a blink.  It also takes a several orders of magnitude longer than using doubles.  The problem is that, as an abstraction for real numbers, doubles are extremely leaky.  Of course, this could be extended to any fixed-prevision, floating-point representation of numbers, depending the application.&lt;/p&gt;
&lt;p&gt;Basically, I think in most applications doubles represent a premature optimization.  Higher-precision numbers should be used by default, and then the precision reduced in order to improve performance, rather than doubles being used by default and then higher-precision numbers being considered if the programmer realizes that he has a problem due to lack of precision.&lt;/p&gt;
&lt;p&gt;Of course, the problem is I don't know how precise is enough, because it depends entirely on the application.  I'm tempted so say that, whenever possible, exact representations should be used.   I've done a little research into it, and I'll do some more.  There's tons of papers on the subject, but everything I've encountered so far seems to require intimate knowledge of floating points, the algorithm using the, and possibly the data being fed into the algorithm.  That could help with library functions, such as matrix decomposition and solving, which could automatically scale up the precision of their internal operations in order to meet the expected resulting precision of the calling code, but that would still be leaky for "user-implemented" algorithms.  What I really want is something that will work in the general case with reasonable performance characteristics, which can then be tuned for specific applications by reducing precision.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7029443758307140521?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7029443758307140521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7029443758307140521' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7029443758307140521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7029443758307140521'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/01/slightly-less-double-imprecision.html' title='Slightly Less Double (Im)precision'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_-ZOtVRo0ba8/R3xdBAxB4xI/AAAAAAAAABw/dTNBz0xnxUg/s72-c/double_deg39.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4176031732773885140</id><published>2008-01-02T20:13:00.001-05:00</published><updated>2008-01-02T21:38:11.079-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><category scheme='http://www.blogger.com/atom/ns#' term='enterprise software'/><title type='text'>Open Source, Cost, and Enterprise Product Adoption</title><content type='html'>&lt;p&gt;This is a relatively common topic, and today is was raised on &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=47973"&gt;TSS&lt;/a&gt;, as a result of a &lt;a href="http://gevaperry.typepad.com/main/2008/01/are-developers.html"&gt;blog by Geva Perry&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;Are developers and architects becoming more influential in infrastructure software purchase decisions in large organizations?&lt;/blockquote&gt;
&lt;p&gt;...with an implied "as a result of open source software."  It's an interesting question, and I think it can be generalized to:  What effect does license costs have on the acquisition of enterprise software?&lt;/p&gt;
&lt;p&gt;In considering this question, it is important to remember that:
&lt;ol&gt;
&lt;li&gt;In large organizations, money often comes in many colors, such as: expense, capital, and internal labor&lt;/li&gt;
&lt;li&gt;The level of authority an individual has depends on both the amount and the color of the money involved&lt;/li&gt;
&lt;li&gt;Certain colors of money are easier to obtain than others, and sometimes it varies dependent on the amount&lt;/li&gt;
&lt;li&gt;Accounting rules, both standard and self imposed, effect what can and cannot be purchased with a given color of money&lt;/li&gt;
&lt;/ol&gt;
In a nutshell, the budgeting process for large organizations can be extremely idiosyncratic.  Not only do the official processes vary, but individual personalities and budget cycles can have profound effects.
&lt;/p&gt;
&lt;p&gt;So the first effect the cost of a piece of enterprise software has is to limit the various buckets of money that can be used to pay for it.  However, this can be a very complex process.  Let's assume any given piece of software typically has the following types of cost:
&lt;ol&gt;
&lt;li&gt;One-time license cost (both for the application and support infrastructure, such as the OS and DBMS)&lt;/li&gt;
&lt;li&gt;Recurring maintenance and support cost&lt;/li&gt;
&lt;li&gt;Hardware cost (e.g. a server)&lt;/li&gt;
&lt;li&gt;Internal labor for development and deployment&lt;/li&gt;
&lt;li&gt;External labor for development and deployment&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;
&lt;p&gt;The lower the costs involved, the less approval is required.   Driving down license costs pushes the initial acquisition decision closer to the users and/or developers.  This is a big win for open source applications.  It's probably a bigger win for application vendors.  For example, most enterprise applications require a DBMS, such as Oracle.  Oracle is not famous for being cheap.  So let's say your potential customer can readily obtain $100k to spend on software licenses.  If you are a software application company, do you want that money as revenue, or do you want 2/3 of it to go to Oracle and IBM?&lt;/p&gt;
&lt;p&gt;I'll give you a hint.  You want a department to be able to deploy your software without cutting a check to the big boys, but you want to be able to say "Yes, we support your enterprise standards" to the big-wigs in the IT department who think that there isn't a major conference for a piece of software, then it shouldn't be on the network.  That way your product can be approved, and then the running it on Oracle can be deferred until "usage levels warrant it."&lt;/p&gt;
&lt;p&gt;Hardware costs are even more interesting.  At my employer, equipment that costs $5k or more is "capital," and less than that is expense.  Capital is generally easier to obtain if (1) you know you need it a year in advance, or (2) it's the end of the year and there's still money laying around.  It is impossible to obtain at the beginning of the year, when everyone thinks that they will actually spend their allocation, unless of course it was approved last year.  Conversely, expense money is much more plentiful at the beginning of the year, when managers are still dreaming of sticking to their budgets, and becomes more and more difficult to obtain as reality sets in.  So what's the point?  Well, you want your product to require a small enough amount of hardware so that a first or second line manager can purchase it on expense without obtaining approval, but also have a recommended configuration that costs enough to be purchased on capital&lt;/p&gt;
&lt;p&gt;This is interesting because big-iron Unix guys will often lament about how their systems have such a lower TCO than x86 Wintel or Lintel systems, so all the arguments about x86 systems being "cheaper" is bunk.  What they are ignoring is that it is much easier to spend $5k on twenty small things (plus setup labor on each of those twenty items) than it is to spend $50k on one big item, because the $50k either has to be approved a year in advance or it has to wait until someone else's project falls apart so they can't spend the $50k.  The "total" in TCO is completely ignored, because very few people think about the few hours that each of those servers requires to setup.&lt;/p&gt;
&lt;p&gt;Now, about labor costs.  Managers generally have at least some discretion over how their direct reports spend their time.  If you actually think about it in terms of the fully burdened hourly cost of an employee, managers often have significantly more "budget" under their control by their means to direct how time is spent than they do for purchasing licenses and services.  Again, this is a big win for open source.&lt;/p&gt;
&lt;p&gt;The bottom line is that the best way to get your foot in the door is to have the lowest marginal cost of deployment as possible.  I'll offer as evidence the countless wikis that have popped up around my workplace, very few of which are even officially approved.&lt;/p&gt;
&lt;p&gt;Of course, this makes you wonder why the marginal cost of deploying a piece of enterprise software tends to be so high.  Why aren't more vendors practically giving their software away for small deployments?  Well, many do, such SQL Server Express and Oracle XE.  But there's still more that don't.  The problem is that it's really hard to get the total cost of initial deployment down to below the point where the bureaucracy kicks in, and once in kicks in it helps to be more expensive.&lt;/p&gt;
&lt;p&gt;Yes, that's right, I said more expensive.&lt;/p&gt;
&lt;p&gt;You see, these days one of the great ways to make your career in IT is to be a good negotiator.  The combination of off-the-shelf software and outsources have shifted IT expenses from being dominated by internal labor to being dominated by procurement contracts.  However, you don't build and illustrious career by negotiating $10k contracts.  Likewise, once you pass a relatively small threshold someone decides that the project needs a "real" project manager, instead of just an "interested" manager or a technical lead, and project managers measure are unfortunately measure more by the size of their projects than the value that they deliver.  (yes, that's right, screwing up a multi-million ERP implementation is better for your career than successfully deploying some departmental application under budget and on schedule)&lt;/p&gt;
&lt;p&gt;In other words, once the signatures of additional people are required, you have to have something big enough for those people to consider it worth their time.  So, if you are a software vendor, or an internal employee planning a deployment project, then you either need to go really small and viral or really big.  Medium size projects are simply too hard to push through.&lt;/p&gt;
&lt;p&gt;And, in my opinion, that's really a shame, because medium sized projects tend to have the best value proposition.  Small ones involve too little of the organization to have a significant impact, and large ones become two unwieldy to meeting objectives.  Projects need to be large enough to do things right in terms of technology and engage future users, but small enough have readily apparent benefits and incremental deliveries that provide real value (not simply "look, it's a login screen!").&lt;/p&gt;
&lt;p&gt;Maybe it's different in other organizations, but somehow I doubt it.  However, I'd be really interested in knowing what others' experiences are.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-4176031732773885140?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4176031732773885140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4176031732773885140' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4176031732773885140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4176031732773885140'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2008/01/open-source-cost-and-enterprise-product.html' title='Open Source, Cost, and Enterprise Product Adoption'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7509891673458663774</id><published>2007-12-31T14:18:00.000-05:00</published><updated>2008-12-09T06:44:29.258-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Finance'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>Double (Im)precision</title><content type='html'>&lt;p&gt;
Most computer users have, at one time or another, received an odd result from a spreadsheet or other program that performs calculations.  Most programmers know that this is because of the impedance mismatch between the most common way for computers to "think" about numbers (base 2) and the way most people and businesses think about numbers (base 10).  This issue receives a fair amount of attention, probably because we've all (we being programmers) have had to explain to users why a piece of software can't seem to do arithmetic properly.  If you're scratching your head right now, or want to know more, I suggest reading this &lt;a href="http://www2.hursley.ibm.com/decimal/decifaq1.html"&gt;FAQ&lt;/a&gt; about decimal arithmetic.
&lt;/p&gt;
&lt;p&gt;
However, as I've long know but rarely contemplated, there if another form of floating point error that can cause significant problems.  Standard floating point numbers only store so many digits of precision.  The result is that if you add a very large number to a very small number, the very small number simply vanishes.  Let me demonstrate:
&lt;/p&gt;
&lt;pre&gt;
scala&gt; 10000000000000000.0 + 1.0
res62: Double = 1.0E16
scala&gt; 
&lt;/pre&gt;
&lt;p&gt;
The 1.0 simply vanished, because standard double-precision floating point numbers don't have enough digits to store the 1.0 part of such a large number.  Doubles are an approximation, and that's fine, because often times all we're approximating things, anyway, and the roughly 15 decimal digits of precisions provided by a double is plenty, right?  
&lt;/p&gt;
&lt;p&gt;
Well, actually, no.  It depends on what you're doing with them.  A month or so ago my father convinced me that instead of spending my free time playing with AI problems and studying fringe programming languages, I should do something useful like predict stock price movements.  Of course I can use AI and fringe programming languages to do this...
&lt;/p&gt;
&lt;p&gt;
The first thing I decided to do was to smooth out stock price history and make it continuous by fitting a polynomial.  So I wrote a quick polynomial class, grabbed Jama (a Java matrix library), downloaded some data, wrote a function to search for the appropriate degree, and this is what I got (supposedly with about 4% error):
&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R3mIPgxB4uI/AAAAAAAAABY/XC-nDztVZew/s1600-h/double_deg44.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R3mIPgxB4uI/AAAAAAAAABY/XC-nDztVZew/s400/double_deg44.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5150297448949867234" /&gt;&lt;/a&gt;
&lt;p&gt;Hmmm...that looks kind of funny.  The blue line is the actual price.  The red line is the polynomial, which has a degree of 44.  That's a rather large degree, but certainly not enough to generate all those squiggles.  Those squiggles are an artifact of double precision numbers not being precise enough to be used in calculating a degree-44 polynomial.  They don't work that well for the matrix calculations that produce the polynomial, either.&lt;/p&gt;
&lt;p&gt;I think that red squiggly line is a very good illustration of what happens when you don't pay enough attention to how your software works under-the-hood.  Anyway, here's what the results look like using floating point numbers (courtesy of &lt;a href="http://www.jscience.org"&gt;JScience&lt;/a&gt;) with 80 digits of precision (keeping the error at about 4%).&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_-ZOtVRo0ba8/R3mOEAxB4wI/AAAAAAAAABo/Q4ySr4gnIm0/s1600-h/deg13prec80.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_-ZOtVRo0ba8/R3mOEAxB4wI/AAAAAAAAABo/Q4ySr4gnIm0/s400/deg13prec80.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5150303848451138306" /&gt;&lt;/a&gt;
&lt;p&gt;Looks a lot better, doesn't it?  One interesting thing is that the resulting polynomial has a much, much lower degree than what was produced by the same algorithm using double precision numbers.  With double precision numbers, 4% error was about as good as it could get with this dataset.  However, using the higher-precision numbers it can go much lower.  Below is a graph at about 2% error:&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R3mLigxB4vI/AAAAAAAAABg/QmAB8eE122U/s1600-h/prec80.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R3mLigxB4vI/AAAAAAAAABg/QmAB8eE122U/s400/prec80.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5150301073902265074" /&gt;&lt;/a&gt;
&lt;p&gt;At this point you might be wondering why anyone would use double precision numbers for this type of thing, or perhaps thinking I'm a moron for trying.  I certainly felt a little stupid.  But using doubles is relatively common.  &lt;a href="http://www.mathworks.com/access/helpdesk/help/techdoc/index.html?/access/helpdesk/help/techdoc/matlab_prog/f2-12135.html&amp;http://www.google.com/search?client=safari&amp;rls=en-us&amp;q=matlab+numeric+precision&amp;ie=UTF-8&amp;oe=UTF-8"&gt;Matlab&lt;/a&gt; and everyone's favorite &lt;a href="http://support.microsoft.com/kb/78113"&gt;Excel&lt;/a&gt; use doubles.  Many of the other toolkits and libraries that I found do as well.&lt;/p&gt;
&lt;p&gt;Overall I think I'm either missing something (because the use of doubles is so common), or I find this very frightening.  I'm not an expert in this area.  I know the doubles use much, much less memory and computational resources.  They are also "just there" in pretty much all programming environments, so they are the default.   Making arbitrary precision floating points work right wasn't a cakewalk, either.  I spent the better part of a day tracing through my code, only to discover a &lt;a href="https://jscience.dev.java.net/issues/show_bug.cgi?id=75"&gt;bug in JScience.&lt;/a&gt;  Also, once you have everything working, you have to figure out what precision to use.  The default of 20 digits precision in JScience wasn't noticeably better than regular doubles.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7509891673458663774?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7509891673458663774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7509891673458663774' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7509891673458663774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7509891673458663774'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/12/double-imprecision.html' title='Double (Im)precision'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_-ZOtVRo0ba8/R3mIPgxB4uI/AAAAAAAAABY/XC-nDztVZew/s72-c/double_deg44.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7735787605395941273</id><published>2007-12-11T07:43:00.000-05:00</published><updated>2007-12-11T08:21:02.336-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sun'/><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><title type='text'>Data Center Meltdown</title><content type='html'>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://blogs.zdnet.com/projectfailures/?p=527" rel="bookmark" title="Permalink"&gt; Denial and the coming “data meltdown”&lt;/a&gt; by &lt;a href="http://zdnet.com"&gt;ZDNet&lt;/a&gt;'s Michael Krigsman -- Subodh Bapat, Sun Microsystems eco-computing vice president, believes we’ll soon see the first world-class data center meltdown. According to News.com: “You’ll see a massive failure in a year,” Bapat said at a dinner with reporters on Monday. “We are going to see a data center failure of that scale.” “That scale” referred to the problems [...]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now let's think about that.  How can a datacenter fail?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It can lose power for an &lt;a href="http://www.pbs.org/newshour/updates/power_8-15.html"&gt;extended period&lt;/a&gt;.  It takes a lot of backup generators to keep a 50 megawatt datacenter humming.&lt;/li&gt;
&lt;li&gt;A virus or &lt;a href="http://en.wikipedia.org/wiki/Sasser_worm"&gt;worm&lt;/a&gt; can &lt;a href="http://en.wikipedia.org/wiki/SQL_slammer_(computer_worm)"&gt;shut it down&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A natural disaster can destroy it or &lt;a href="http://www.crn.com/it-channel/18830985"&gt;force a shutdown&lt;/a&gt;.  Often times this is due to a power failure rather than destruction.&lt;/li&gt;
&lt;li&gt;It can have its WAN/Internet connection(s) severed.  This isn't quite catastrophic unless you're on the other side of the WAN.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Michael has pointed out that Subodh Bapat doesn't point to the expected cause of a major data center meltdown, he just says one is coming.  That's because it's not really a matter of one cause.  There are so many risks, and you multiply them by the growing number of data centers, and what you come up with is that there's bound to be a major failure soon.  We just don't know what the precise cause will be.&lt;/p&gt;
&lt;p&gt;Most of the threats involve a geographically localized destruction or disabling of the data center.  This means you need off-site recovery, and it probably needs to be fast.  That means you probably need more than recovery, you need one or more hot sites that can take over the load of one that fails.  This is extremely expensive for a "normal" data center.  I can hardly imagine how much it would cost for a 50+ megawatt facility.  Basically what we have is too many eggs in one basket, with economies of scale pushing us to keep on putting more eggs in the same basket.&lt;/p&gt;
&lt;p&gt;What surprises me is that Subodh Bapat didn't say, oh, well, Sun has the solution.  Considering that Jonathan Schwartz put it forward over a year ago.  Ok, well, he didn't exactly suggest Blackbox as a means of easily distributing data centers.  But think about it.  If you're a large corporation you are probably already geographically distributed.  If you expand your data center in cargo-container sized units across the nation (or world), you are half..err..maybe one quarter of the way there.  You still have to figure out how to make them be hot sites for each other, or at least recovery sites.  But at least losses at any given site would be minimized.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7735787605395941273?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7735787605395941273/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7735787605395941273' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7735787605395941273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7735787605395941273'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/12/data-center-meltdown.html' title='Data Center Meltdown'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7061969517388827097</id><published>2007-12-09T16:16:00.000-05:00</published><updated>2007-12-10T07:58:07.655-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='enterprise software'/><title type='text'>Why isn't enterprise software sexy?</title><content type='html'>&lt;p&gt;
Robert Scoble asks: &lt;a href="http://scobleizer.com/2007/12/09/why-enterprise-software-isnt-sexy/"&gt;Why isn't enterprise software sexy?&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
A couple of the &lt;a href="http://blogs.zdnet.com/projectfailures/?p=524"&gt;Enterprise&lt;/a&gt; &lt;a href="http://blogs.zdnet.com/projectfailures/?p=524"&gt;Irregulars&lt;/a&gt; and several commentors respond:  Because it's supposed to be reliable and effective, not sexy.
&lt;/p&gt;
&lt;p&gt;
I think the reasons are more fundamental than that.  Consider:
&lt;ol&gt;
&lt;li&gt;Most enterprise software customers have mutual non-disclosure agreements with the software vendors.&lt;/li&gt;
&lt;li&gt;Most bloggers have day jobs&lt;/li&gt;
&lt;li&gt;Most companies do not want their employees violating the terms of contracts.&lt;/li&gt;
&lt;li&gt;Most companies do not want their employees airing the company's dirty laundry in a public forum&lt;/li&gt;
&lt;li&gt;Many of the most interesting pieces of information surrounding enterprise software involve dirty laundry.&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;
&lt;p&gt;Personally, I have two ground rules for blogging:
&lt;ol&gt;
&lt;li&gt;Keep it professional.  No personal matters, politics, etc.&lt;/li&gt;
&lt;li&gt;Keep my employer, coworkers, and my employer's customers and suppliers out of it.&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;
&lt;p&gt;Let's face it.  Most IT and software development projects don't go right.  The commercial software that you use doesn't perform half as well as the salesman said it would.  Consultants have mixed motives, and more importantly aren't miracle workers.  The internal team if often over extended and working outside their core area of expertise.  Goals are unclear, completely undefined, or changing on a regular basis.  Politics are everywhere on all sides.&lt;/p&gt;
&lt;p&gt;This is the reality of business, and talking about it in the general case is OK.  People read it, nod their heads, and this "Been there, done that, doing it again right now."  But specifics are quite different.  Specifics can lead to embarrassment, contract violations, and lost sales.&lt;/p&gt;
&lt;p&gt;More people don't blog about enterprise software because it strikes too close to home.  I don't think it has anything to do with whether enterprise software is sexy or not.&lt;/p&gt;
&lt;p&gt;&lt;h3&gt;Update:&lt;/h3&gt;&lt;/p&gt;
&lt;p&gt;It just occurred to me that I probably wasn't very clear here on a few points.  What is mean by "enterprise software" is enterprise &lt;i&gt;application&lt;/i&gt; software, like SAP, Oracle's various applications, PeopleSoft, etc.  I don't mean infrastructure software like DBMSes, application servers, operating systems, etc.  There is plenty of good information freely available on infrastructure, and people blog about it all the time.&lt;/p&gt;
&lt;p&gt;Also, if you look at a lot of the blogs that are out there for, for example, SAP, they are almost all too high level to be particularly useful.  It's pretty easy to find platitudes about how you need the right team, buy-in, executive sponsorship, etc and how those (or a lack of them) caused an implementation to succeed or fail.  That's all (for the most part) true but everyone already knows it.  But there's not a lot of people (that I know of, please post links in the comments if I am wrong) out there posting technical discussions about implementations.  Google for "ABAP programming blog"  (ABAP is the programming language for SAP), and then do the same for Scala and Lisp.  I bet there are more people earning their living off of ABAP than Scala and Lisp combined.  Probably an order of magnitude more.  So why aren't there more people writing about it?  Ok, so Scala and Lisp are both interesting languages.  So do the same for Ada and COBOL.&lt;/p&gt;
&lt;p&gt;&lt;h3&gt;Update: December 10, 2007:  Feedback on enterprise software&lt;/h3&gt;&lt;/p&gt;
&lt;p&gt;Enterprise software does receive feedback.  Often times significant amounts in forms much better thought out than most blogs.  The difference is that the feedback is private between the customer and the software provider.  Occasionally it is shared among customers through conferences or other types of "user group" meetings.&lt;/p&gt;
&lt;p&gt;If the software supplier will listen (including acting), then this can work fairly well for software that is already deployed.  The problem is that there is no information solid information available to support purchasing decisions.  There are no readily available sources of "tips and tricks" or "common pitfalls" for deployment or customization efforts. For example someone could write:&lt;/p&gt;
&lt;blockquote&gt;We've spent the last 3 months trying to make Foomatic run on top of Oracle.  All the sales material touts the Oracle support.  But then your deployment tanks, the consultants come in, and they ask you why the heck you aren't using SQL Server.  The software is developed against SQL Server and then "ported" to Oracle, and the Oracle port never works right.&lt;/blockquote&gt;
&lt;p&gt;Fill in your favorite or least favorite infrastructure products there, the name of an enterprise application, and there you have some useful information.  The sales material lies.  Once you deviate from their default stack you are screwed.  That's the type of information that would be useful - before buying the software or before trying to run it on your "enterprise standard."  Not from an over-priced consultant.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7061969517388827097?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7061969517388827097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7061969517388827097' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7061969517388827097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7061969517388827097'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/12/why-isnt-enterprise-software-sexy.html' title='Why isn&apos;t enterprise software sexy?'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-1194238677139366559</id><published>2007-12-09T10:58:00.000-05:00</published><updated>2008-12-09T06:44:30.737-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><title type='text'>Running Linux apps on a Mac using X</title><content type='html'>John asks:
&lt;blockquote&gt;Please can you post something about how you set up and use X to run your linux apps from your mac?

I've been using X to login and use my linux desktop on my mac laptop for a few things but what I would really love to know how to do is to run individual programs which I cannot get running on my mac or haven't got room for.&lt;/blockquote&gt;

Certainly!  I'll start from the beginning.  The Linux distribution I'm using is Fedora Core 6.  The instructions should be similar for any other Unix variant.  I used the GUI administration screens to do the configuration (I know - LAME!)  so that's what I'm going to use here.

&lt;h3&gt;1.  Make sure your Linux box has a static IP address.&lt;/h3&gt;

This step largely depends on your network setup, and technically isn't 100% necessary.  In order to access your Linux box, you must either know its IP address or have a domain name for it that will be translated into an IP address.  If you are on a corporate network there's a good chance that there's already a DNS entry for your Linux box so you just need to know its name.  Here's what I did for my home network.

&lt;h4&gt;1.1  Login your router and reserve a range of IP addresses so that they will not be assigned out by DHCP.&lt;/h4&gt;

Please refer to your router's manual for details on how to do this.  Depending on your router you may be able to assign a static IP address explicitly to your Linux box based on its MAC address.  I could not.

&lt;h4&gt;1.2  Configure your Linux box to use a static IP address.&lt;/h4&gt;

Launch the network config utility.  This will require the root password.
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R1wgv6gBGEI/AAAAAAAAAAg/oL6W6Ftulio/s1600-h/network_config.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R1wgv6gBGEI/AAAAAAAAAAg/oL6W6Ftulio/s400/network_config.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5142020882079750210" /&gt;&lt;/a&gt;

Edit your ethernet adapter and configure it for a static IP address instead of DHCP.  Choose an IP address within the range that you reserved in your router, or one that your network admin has provided.
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_-ZOtVRo0ba8/R1whkKgBGGI/AAAAAAAAAAw/PrZwXu5a3MU/s1600-h/ip_config.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_-ZOtVRo0ba8/R1whkKgBGGI/AAAAAAAAAAw/PrZwXu5a3MU/s400/ip_config.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5142021779727915106" /&gt;&lt;/a&gt;

&lt;h3&gt;2. Enable sshd on your Linux box.&lt;/h3&gt;
You can do this using the "Services" applet or by editing your /etc/rcN.d (where N is the desired runlevel) scripts.  Enable the service and start it.
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R1wkQ6gBGHI/AAAAAAAAAA4/EjprXTN3ulA/s1600-h/services_config.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R1wkQ6gBGHI/AAAAAAAAAA4/EjprXTN3ulA/s400/services_config.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5142024747550316658" /&gt;&lt;/a&gt;
Notice that I am at runlevel 3.  This is because I'm now running my Linux box in headless mode, so I just want it to boot up to a console login prompt, not a graphical prompt.  If you your Linux box boots up to a graphical prompt, and you intend to keep in that way, then you want runlevel 5.

&lt;h3&gt;3. Setup a DNS entry on your Mac.&lt;/h3&gt;
As root, edit your /etc/hosts file and add an entry for your Linux box.  So open a terminal window and type:
&lt;pre&gt;
  cd /etc
  emacs hosts
&lt;/pre&gt;
The line for "gondolin" is the entry that I added:
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R1wok6gBGII/AAAAAAAAABA/gEdm6WsIyDg/s1600-h/hosts.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_-ZOtVRo0ba8/R1wok6gBGII/AAAAAAAAABA/gEdm6WsIyDg/s400/hosts.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5142029489194211458" /&gt;&lt;/a&gt;

Save the file by hitting Control-X Control-S, then exit emacs by hitting Control-X Control-C.

&lt;h3&gt;4.  On your Mac, launch X and ssh as follows to your Linux box.&lt;/h3&gt;
&lt;pre&gt;  ssh -X gondolin&lt;/pre&gt;
 The "-X" flag tells ssh to automatically setup your DISPLAY environment variable.  Once you are logged in, simply type the name of the application that you want to run, followed by an ampersand.
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_-ZOtVRo0ba8/R1wrVagBGJI/AAAAAAAAABI/zo0LMvBpRVA/s1600-h/launch_ssh.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_-ZOtVRo0ba8/R1wrVagBGJI/AAAAAAAAABI/zo0LMvBpRVA/s400/launch_ssh.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5142032521441122450" /&gt;&lt;/a&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_-ZOtVRo0ba8/R1wrVqgBGKI/AAAAAAAAABQ/c4cikc390iw/s1600-h/firefox.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_-ZOtVRo0ba8/R1wrVqgBGKI/AAAAAAAAABQ/c4cikc390iw/s400/firefox.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5142032525736089762" /&gt;&lt;/a&gt;
&lt;h3&gt;5. Be careful about some applications.&lt;/h3&gt;
Most applications work fine when started from the command line, but starting the full KDE or GNOME desktop sessions does not work properly for me.  I'm pretty sure that's because on my Linux box they are configured to run locally.  There are some applications, such as Nautilus and Konqueror that are setup (and least on my FC6 box) to plug themselves into the desktop manager session.  This results in all sorts of weirdness when there is no KDE or GNOME session running.  Nautilus tries to start a GNOME session, which brings up an unusable desktop, and Konqueror just acts weird.  However, Nautilus works fine if you give pass it the "--no-desktop" command-line option.  The following opens Nautilus in your home directory.
&lt;pre&gt;  nautilus --no-desktop ~/&lt;/pre&gt;

That's it!  Feel free to post any questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-1194238677139366559?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/1194238677139366559/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=1194238677139366559' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/1194238677139366559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/1194238677139366559'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/12/running-linux-apps-on-mac-using-x.html' title='Running Linux apps on a Mac using X'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_-ZOtVRo0ba8/R1wgv6gBGEI/AAAAAAAAAAg/oL6W6Ftulio/s72-c/network_config.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-2126949981155699527</id><published>2007-12-06T20:36:00.000-05:00</published><updated>2007-12-06T21:17:40.856-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='parallelism'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='widefinder'/><title type='text'>Adventures in Widefinding:  Performance</title><content type='html'>I've done some  basic performance tests against:&lt;div&gt;&lt;ol&gt;&lt;li&gt;Scala Actor-based parallel Widefinder&lt;/li&gt;&lt;li&gt;Scala serial Widefinder using a BufferedReader&lt;/li&gt;&lt;li&gt;Tim Bray's Ruby Widefinder&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;The test platform was my 2.2 GHz MacBook with 4GB of RAM using a 6 million line file.  The times were as follows:&lt;/div&gt;&lt;div&gt;

Scala Parallel:
&lt;ul&gt;&lt;li&gt;real 0m14.588s
&lt;/li&gt;&lt;li&gt;user 0m24.541s
&lt;/li&gt;&lt;li&gt;sys 0m1.383s
&lt;/li&gt;&lt;/ul&gt;
Scala Serial:
&lt;ul&gt;&lt;li&gt;real 0m20.095s
&lt;/li&gt;&lt;li&gt;user 0m18.821s
&lt;/li&gt;&lt;li&gt;sys 0m1.441s
&lt;/li&gt;&lt;/ul&gt;
Ruby:
&lt;ul&gt;&lt;li&gt;real 0m14.301s
&lt;/li&gt;&lt;li&gt;user 0m12.485s
&lt;/li&gt;&lt;li&gt;sys 0m1.813s
&lt;/li&gt;&lt;/ul&gt;
The good news is that the parallel Scala version is noticeably faster than the serial version.  The bad news is that it is roughly the same speed as the Ruby version, and takes significantly more CPU.  The Scala versions are doing substantially more work, because they have to transcode the 8-bit ASCII contained in the input file into 16-bit Unicode strings.  This requires a full scan of the data.  I believe a fair amount of performance could be gained by combining the transcoding pass over the input with the line-splitting pass.&lt;/div&gt;
&lt;div&gt;For those that are curious, the source code for the parallel widefinder is available here:

&lt;a href="http://mysite.verizon.net/erik.engbrecht/pio.scala.html"&gt; the parallel IO code&lt;/a&gt;
&lt;a href="http://mysite.verizon.net/erik.engbrecht/widefinder.scala.html"&gt;the actual widefinder code&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-2126949981155699527?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/2126949981155699527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=2126949981155699527' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2126949981155699527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2126949981155699527'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/12/adventures-in-widefinding-performance.html' title='Adventures in Widefinding:  Performance'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-3004683555275506856</id><published>2007-12-05T08:12:00.000-05:00</published><updated>2007-12-06T21:38:46.060-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='parallelism'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='widefinder'/><title type='text'>Adventures in Widefinding:  Complexity</title><content type='html'>For the moment I'm going to ignore the complexity of my widefinder "under the hood," and just focus on the complexity of it at the top level.   The following is Tim Bray's goal.  The red asterisk indicates that the loop should be processed in parallel instead of in serial.&lt;div&gt;
&lt;pre&gt;&lt;code&gt;counts = {}
counts.default = 0

ARGF.each_line&lt;span style=" font-weight: bold; font-size:130%;color:#f00;"&gt;*&lt;/span&gt; do |line|
if line =~ %r{GET /ongoing/When/\d\d\dx/(\d\d\d\d/\d\d/\d\d/[^ .]+) }
counts[$1] += 1
end
end

keys_by_count = counts.keys.sort { |a, b| counts[b] &lt;=&gt; counts[a] }
keys_by_count[0 .. 9].each do |key|
puts "#{counts[key]}: #{key}"
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;So here's the first part of my Scala solution:
&lt;div&gt;
&lt;pre&gt;
   val pat = Pattern.compile("GET /ongoing/When/\\d\\d\\dx/(\\d\\d\\d\\d/\\d\\d/\\d\\d/[^ .]+ )")
   val map = new ConcurrentHashMap[String, AtomicInteger]()
   for (file &lt;- args; line &lt;- LineReader(file)) {
       val mat = pat.matcher(line)
       if (mat.find()) {
         val s = mat.group().substring(23)
         map.putIfAbsent(s, new AtomicInteger(0))
         map.get(s).incrementAndGet()
       }
     }
 &lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Notice that this is not a map-reduce based solution.  This is because I tried to make it look as similar to the original Ruby as possible.  There are some minor differences due to the fact that regular expressions are not special in Scala the way they are in Ruby.  The big, and in my opinion most intrusive difference, is that a ConcurrentHashMap has to be used to store the results, AtomicIntegers must be used for the counts, and that weird "putIfAbsent" call needs to be used for pulling counts out of the map.&lt;/p&gt;
&lt;p&gt;So while the concurrency itself is implicit, and the code is certainly succinct, the programmer still needs to be very much aware of the fact that the block inside the for loop will be executed in a concurrent fashion.  This is certainly less elegant than a pure functional approach such as map-reduce, where no synchronization would be necessary, but I also think it is less intrusive to a programmer accustomed to imperative programming.&lt;/p&gt;
&lt;p&gt;Here's an ugly part.  This is largely due to an impedance mismatch between Java collections and Scala collections.  It would look a lot better if Scala had an equivalent to ConcurrentHashMap in its library.  There's also probably lots of other ways to make it cleaner.  I tried several different approaches and always ran into some problem.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre&gt;
    val array = new Array[(String, Int)](map.size)
    val iter = map.entrySet.iterator
    var i = 0
    while (iter.hasNext) {
      val e = iter.next
      array(i) = (e.getKey, e.getValue.intValue)
      i += 1
    }
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
And here's the final part, once the ugliness is done:
&lt;/div&gt;
&lt;div&gt;
&lt;pre&gt;
    quickSort(array)((e) =&gt; OrderedTuple(e))
    val limit = if (array.length &lt; 10) array.length - 1 else 9
    for(i &lt;- 0 to limit) {
      print(array(i)._2)
      print(": ")
      println(array(i)._1)
    }
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Notice having less that ten results is cleanly handled, unlike in TB's code (unless Ruby magically ignores invalid indices).&lt;/p&gt;
&lt;p&gt;Overall I would say I came pretty close to TB's goal without without requiring a fundamental change in programming methodology.  I didn't alleviate the need for the programmer to be aware of concurrency, but I don't think that's possible.  Sure, people can learn to program in ways that are fundamentally parallelizable, and that probably is what universities should start teaching, but that's going to require a major shift on of part of millions of programmers, or for several generations to retire and be replaced by ones trained in functional programming.  Lots of cores are here NOW, so it's not practical to wait until skills catch up.  We need to work with what we have.&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/19725519-3004683555275506856?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/3004683555275506856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=3004683555275506856' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3004683555275506856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3004683555275506856'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/12/adventures-in-widefinding-complexity.html' title='Adventures in Widefinding:  Complexity'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-6030967812061700425</id><published>2007-12-03T22:44:00.001-05:00</published><updated>2007-12-03T23:21:01.136-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><title type='text'>Switch</title><content type='html'>After about two years of running Linux-only (Fedora, to be exact) at home I've switched to a Mac.  I wanted a laptop, needed a new computer desperately (the old one is almost 6 years old), didn't want Windows, and was tired of messing with Linux configuration stuff.&lt;div&gt;
&lt;/div&gt;&lt;div&gt;This weekend I bought a Macbook.  So far I love it.  I was hesitant about the keyboard, which is odd, but I actually like it.  I was nervous about using a touchpad instead of a pointer stick, but somehow the touch pad on the Macbook works substantially better than the one on the HP I use at work.  I was worried about quality problems...we'll see about that one.  I just read about some Macbooks and Macbook Pros having defective harddrives, but the model number on mine is different.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;So what have I done so far?&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Booted the first time.  Wireless worked flawlessly on the first try.  I've spent way too much time making Windows PCs (my wife's, my work laptop, visitors' machines) work with my wireless network.  One of my friends tried to make his Linux laptop work with it and after many hours never succeeded.&lt;/li&gt;&lt;li&gt;Installed Eclipse and the Scala plugin, played around with that.&lt;/li&gt;&lt;li&gt;Installed AquaMacs - IMHO much better than Emacs on Linux.&lt;/li&gt;&lt;li&gt;Surfed the net, poked around, reconfigured some stuff to my liking, etc.&lt;/li&gt;&lt;li&gt;Setup NFS mounts to my old Linux box. This was amazingly painless on both sides.  The only hiccup was that I had to change my UID on my Mac from 501 to 500, which created some oddities before I logged out and back in, but nothing horrible.  The whole process probably took about 15-30 minutes, compared to hours I spent to make Samba work properly with with wife's Windows XP Thinkpad.&lt;/li&gt;&lt;li&gt;Setup sshd on my Linux box and then ran XWindows applications on my Linux box from my Mac.  This whole process took about 10 minutes, and the XWindows apps actually looked good and were very responsive.  Possibly more responsive than running them locally.  Note that this and the above are a tribute to both Fedora and MacOS X.&lt;/li&gt;&lt;li&gt;Upgraded my RAM from the stock 1GB to 4GB.&lt;/li&gt;&lt;li&gt;Ran my Scala widefinder from Eclipse.  It spikes both CPUs once everything is cached.  Puts both at about half if it has to read from disk.&lt;/li&gt;&lt;li&gt;Wrote this blog.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;So all that is very positive.  And the UI is so beautiful.  The fonts all look just right...although if I didn't have good eyes I think a lot of them might be too small.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Ok, so what's wrong:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;I haven't figured out the keyboard shortcut to switch between windows of an open application.  Command tab switches between applications.&lt;/li&gt;&lt;li&gt;No page down, page up, home, end, etc keys on the laptop keyboard.&lt;/li&gt;&lt;li&gt;The caps lock key is WAY too big.  Keys sizes should be proportionate to usefulness/frequency of use.  Spacebar is huge.  Enter and delete are big.  Caps lock being the size of enter makes not sense.&lt;/li&gt;&lt;li&gt;I had to install ~200MB worth of updates fresh out of the box...over half of that for Leopard.  Why can't a new computer to all up-to-date?  Seems like that "genius" who sold it to me could have given me one that was up-to-date.&lt;/li&gt;&lt;li&gt;After the reboot for the Leopard updates, everything froze.  Just a blue-grey screen with no cursor.  That's a bad first impression.  But I turned it off and back on again and everything was fine.&lt;/li&gt;&lt;li&gt;I had to install codecs for video various video formats.  That's mildly annoying.  Why can't they be preinstalled?  It's not like I had to pay to download and install them.  But what's more annoying is that the first link presented to me for XVid didn't seem to have any appropriate install files for Mac.  I used DivX instead, which worked.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;So overall I am very impressed.  I think I'm going to keep my old Linux box around as a server and to run Linux-only stuff over X.  If anything goes wrong I'll be sure to complain about it.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-6030967812061700425?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/6030967812061700425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=6030967812061700425' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6030967812061700425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6030967812061700425'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/12/switch.html' title='Switch'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-8337839971170137170</id><published>2007-11-25T16:39:00.000-05:00</published><updated>2007-11-25T18:49:48.569-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='parallelism'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='widefinder'/><title type='text'>Adventures in Widefinding</title><content type='html'>Over the past few weeks in my copiuos free time I've been trying to come up with a &lt;span style="font-style: italic;"&gt;fast&lt;/span&gt; &lt;a href="http://www.tbray.org/ongoing/When/200x/2007/09/20/Wide-Finder"&gt;Widefinder&lt;/a&gt; using &lt;a href="http://lamp.epfl.ch/%7Ephaller/doc/ActorsTutorial.html"&gt;Scala Actors&lt;/a&gt; where the parallelization magic is hidden behind what looks like a nice friendly API.  Based on timings on my oh-so-fast Athlon XP 1900+ I seem to have failed on the first account (Ruby is faster) and the second part requires some awareness of parallel programming.  But I'm hopeful that when Tim runs it on the &lt;a href="http://www.sun.com/servers/coolthreads/t5120/"&gt;T5120&lt;/a&gt; it will be competive with the other solutions, although I doubt that it will be the fastest.

For those of you who don't want to listen to me ramble, &lt;a href="http://mysite.verizon.net/vze2rswi/scala-widefinder.jar"&gt;here's a jar&lt;/a&gt; containing all of the class files needed to run my solution along with the Scala source code.  It's so big because I put the Scala libraries in there for Tim so he wouldn't have to worry about CLASSPATH error or installing Scala.

Ok, so why isn't it the fastest?  What's the point?  Well, first let me define what I think a good widefinder solution should demonstrate.

&lt;ol&gt;&lt;li&gt;The "application code" should be similar in complexity and readability to &lt;a href="http://www.tbray.org/ongoing/When/200x/2007/09/29/WF-Goal"&gt;Tim Bray's example in Ruby&lt;/a&gt;.  Anything else should be hidden behind a general purpose API, preferably an out-of-the-box one.
&lt;/li&gt;&lt;li&gt;It should be environmentally friendly.  This means that it shouldn't hog all the available RAM and make other processes start paging.  It should also be well behaved on a machine under load.  This is not relative to input file size.  It should ALWAYS be environmentally friendly.
&lt;/li&gt;&lt;li&gt;It should maintain the abstractions to which programmers are accustomed.  For example, it shouldn't bypass regexes or use non-standard string types.  Also, if a language normally deals well with unicode and the potential for multiple encodings, it should deal well with unicode and multiple encodings as well.&lt;/li&gt;&lt;li&gt;The person running it shouldn't have to tell it about details like how many worker processes to spawn.  It should figure it out based on its environment.  Ideally the programmer shouldn't have to worry about it either.
&lt;/li&gt;&lt;li&gt;It should be sufficiently performant on a single processor box.
&lt;/li&gt;&lt;li&gt;It should run faster as more processors are made available.&lt;/li&gt;&lt;/ol&gt;I think my solution is reasonable according to all of these measure.  Hopefully we'll see about execution on lots of cores shortly.  #1 is a little tricky, because the using a concurrent map was tricky and there is a definite impedance mismatch between Java collections and idiomatic Scala.  Depending on your perspective a map-reduce based solution would have been more elegant, but unless map-reduce becomes required learning for all professional programmers then I'm not so sure.

#2 is one area where, in my opinion, many of the current leading solutions fall down.  A favorite way of achieving easy parallel IO (well, IO on most disk can't really be done in parallel) is to spawn a bunch of processes (or threads) and have them each mmap a large chunk of the input file and process it.  The issue with this is that, as &lt;a href="http://effbot.org/zone/wide-finder.htm"&gt;Fredrik Lundh &lt;/a&gt;noticed (BTW - he has an excellent discussion - go read it), this can cause serious paging on some operating systems.  Other solutions allocate buffers measured in megabytes for each worker thread/process.  I personally don't see this as very environmentally friendly when only kilobytes are really needed.  My solution reads the file sequentially using one set of buffers per worker (about 128k total per worker).  Each worker reads in 32k and then passes the FileChannel to the next worker.

#3 is the real kicker, and what kicked down the performance of Scala (and, I believe, any other JVM based solution).  Java strings are unicode and based on 16 bit characters.  The input file is ASCII and based on 8 bit characters.  Consequently, a String-oriented solution on the JVM has to transcode the characters.  Futhermore, it should be able to transcode the characters from any common file format, not just ASCII or UTF8.  This turns out to take a lot of cycles, around 10% depending on the charset and the cost of some other functions.  The good news is that each buffer can be transcoded in parallel.

#4 is more about maintaining abstractions.  My solution does it automatically, the other solutions don't seem to...although adding it probably wouldn't be a big deal.

#5 is probably true of most of the solutions...or true if you substitute dual-core for uniprocessor, because that's what most of the people used to develop their solutions.  In the case of my solution I think there is about a 30% performance penalty on a single processor box (that and transcoding are enough to make it slower than Ruby).

#6 is interesting because this is an I/O bound task.  Assuming the data is actually being read from disk (I believe it is cached in all or most of his trials), then this task should only be able to keep a small handful of processors busy.  But that's not to say it isn't important.

The reason it's important is because from the normal programmer's point of view, file I/O isn't just shuttling information from the disk to a buffer, it's everything that happens between him making the request and a string representing a line being returned.  There's a lot of work that goes into making that string.  Here's a list (more or less) for Java and Scala.
&lt;ol&gt;&lt;li&gt;Read the data into a direct ByteBuffer.&lt;/li&gt;&lt;li&gt;Copy the data into a heap ByteBuffer**
&lt;/li&gt;&lt;li&gt;Transcode the ByteBuffer into a CharBuffer&lt;/li&gt;&lt;li&gt;Find the characters that represent a line&lt;/li&gt;&lt;li&gt;Make a String from those characters&lt;/li&gt;&lt;/ol&gt;Your operating system probably uses something called readahead to asynchronously fetch the next N bytes of a file before you actually request it, on the assumption that you will.  The Java or Scala library could asynchrously fill a fixed-sized queue of lines, assuming concurrency is cheap enough.

I learned a lot in this excersise, but my two big takeways are:
&lt;ol&gt;&lt;li&gt;Abstraction has a real cost in terms of CPU cycles, and existing abstractions in mainstream languages (ok, Scala isn't mainstream yet, but Java is) are not optimized for multi-core environments.  This will need to change.
&lt;/li&gt;&lt;li&gt;Abstraction has a big cost in terms of programmer cycles if the programmer wants something different.  Without the source available from OpenJDK I would have been lost when I was trying to figure out why approaches that seem like they require less CPU work actually require more.  The Client and Server VMs make a huge difference in performance that varies widely depending on file size and program structure.  With the libraries, JVM, and OS all trying different things to make your code go faster it is extremely difficult to figure out exactly what is happening and why.
&lt;/li&gt;&lt;/ol&gt;
**I looked at the OpenJDK source and if you use NIO to read into a non-direct buffer, what actually happens is the Java library reads into an available direct buffer and then copies it into a direct buffer.  This is essentially what happens with a regular FileInputStream as well.  At first I thought I could speed things up by skipping the copy from the direct buffer to the non-direct buffer, but it doesn't.  You see, decoders are optimized to use the array backing the buffer if it is available because direct array accesses are much faster than function calls.  Array copies are done using low-level native code.  Consequently, copying the direct buffer and the transcoding the in-heap copy is much faster than directly transcoding the direct buffer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-8337839971170137170?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/8337839971170137170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=8337839971170137170' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8337839971170137170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8337839971170137170'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/11/adventures-in-widefinding.html' title='Adventures in Widefinding'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4900768749828090497</id><published>2007-10-10T06:46:00.000-04:00</published><updated>2007-12-06T21:39:28.426-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='parallelism'/><category scheme='http://www.blogger.com/atom/ns#' term='widefinder'/><title type='text'>Why test parallelism on a simple function?</title><content type='html'>On my &lt;a href="http://erikengbrecht.blogspot.com/2007/10/dangerous-monads.html"&gt;last blog&lt;/a&gt; anonymous asked:
&lt;blockquote&gt;would a more expensive line-match-function make it more obvious if you are working in parallel?&lt;/blockquote&gt;I would say that one should be able to demonstrate that transparently supporting the potential for parallelism should be near free.  If you can use a parallel algorithm to solve a problem that doesn't benefit much from parallelism with roughly the same or better performance characteristics as the serial code then it should be a lot better when you actually give it a more complex problem.

Basically, parallelism should be free.

A lot of people have commented on Tim Bray's blogs that his test is unsuited for demonstrating the benefits of parallelism because it is IO bound.  Tim claims this isn't true, and I suspect there's some truth to that if you have really optimized IO, but I do think the benefits of parallelization for him problem are very limited.

That being said, one thing that it he has clearly demonstrated is that parallelism isn't free.  His &lt;a href="http://www.tbray.org/ongoing/When/200x/2007/09/22/Erlang"&gt;"obvious" newbie solution in Erlang&lt;/a&gt; performed horribly and was considerably longer than the Ruby solution.  Others have greatly improved the performance with extremely long, complicated chunks of code, but have yet to match Ruby.  I find that really sad.  So I would like to prove that parallelism can be almost free, meaning:
&lt;ol&gt;&lt;li&gt;Leveraging it does not impose a significant additional cognitive load on the programmer.&lt;/li&gt;&lt;li&gt;Problems that are not effectively parallelizable should execute "about as fast" when parallel functionality is used as with serial code.&lt;/li&gt;&lt;/ol&gt;From an interface perspective I think I have it with the monadic interface to the file.  I just need to work out some bugs or change the interface to make them go away.  I'll write more on this when I've worked out some of the wrinkles.

So that leaves the performance problem.  One of the big challenges with parallelization is that spawning new threads or processes is very expensive, and synchronization is somewhat expensive, so it's very easy for the cost of parallelization to overwhelm the cost of the actual solution.  The most straight forward way to address this problem is to not parallelize when the function is not complex enough or the input data set isn't large enough to justify it, but that is back to imposing a cognitive load on the programmer because he has to figure that out.  Either that or always "start serial" and use runtime profiling tricks to detect if the problem is worth parallelizing, which sounds expensive put probably has merit.

Another challenge is knowing how to divide up the problem to avoid excessive synchronization and/or messaging.  When processing a file line-by-line, one could send each line out to be processed independently, but that requires a lot of messaging and synchronization if you don't have lock-free messaging.  So really you want to break the problem into properly sized chunks and send each chunk as a message rather than simply use the most natural division.  Figuring out how big a chunk should be (or how many chunks you should have) is a challenge because it is problem and runtime dependent.  Again, this creates the potential to burden the programmer, use complex and potentially expensive runtime profiling, or somehow come up with a magic cheap hueristic.

So you can either solve the problems above, or you can have sufficiently cheap parallelism that you don't need good solutions.  Right now I'm going after the sufficiently cheap approach.

What I have so far is a mapreduce-style function using Scala Actors that breaks a file into chunks of lines and sends them off to be processed by an Actors.  I plan on adding a parallel foreach function that could be used for problems like Widefinder using a parallel hash map.

Performance wise it's looking promising.  Here's some numbers (using my 5+ year old machine):

Serial:
&lt;blockquote&gt;Count: 185300
Serial: 11592

real    0m12.107s
user    0m11.254s
sys     0m0.784s
&lt;/blockquote&gt;Parallel:
&lt;blockquote&gt;Count: 185300
Serial: 11722

real    0m12.225s
user    0m11.441s
sys     0m0.723s&lt;/blockquote&gt;As you can see the parallel code is slightly slower than the serial code.  Across runs their times actually overlap a bit, but serial generally times to be a tad faster.   One thing I've noticed is that the deltas between the serial and parallel implementations don't really grow - and to some extent shrink - with increasing input sizes.  I believe this is because there is a fixed penalty for setting up the thread pool for the actors.  This only has to be done once per process invokation, and appears to cost about 200ms on my machine.

In other words, parallelization for file processing can be almost free.  I actually think it could be better-than-free, even on a single processor box, if IO was more efficient.  My current solution is using a BufferedReader to read in the file one line at a time.

This means the IO is probably being done in a less-than-optimal way, and that a lot of work is being done in serial for each line (converting from 8bit ASCII to 16-bit Unicode strings, splitting it into lines).  I'd like to use nio to read the file in a block at a time, and then let all this work be done in separate threads.  I think then there would be a performance increase because one thread would be doing nothing but reading in buffers as fast as the OS and JVM and provide them, and others would be doing all the computation while the IO thread is blocking.  But before that I'm going to get the interface cleaned up and solve the memory problem on large files.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-4900768749828090497?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4900768749828090497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4900768749828090497' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4900768749828090497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4900768749828090497'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/10/why-test-parallelism-on-simple-function.html' title='Why test parallelism on a simple function?'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4036477947167817138</id><published>2007-10-07T18:21:00.000-04:00</published><updated>2007-10-07T23:06:15.266-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><title type='text'>Dangerous Monads?</title><content type='html'>I've been trying to write a parallelized version of Tim Bray's &lt;a href="http://www.tbray.org/ongoing/When/200x/2007/09/20/Wide-Finder"&gt;Widefinder&lt;/a&gt; problem in Scala where the parallization is "hidden" in some library-like code so that the programmer can write something that looks as clean...nay...cleaner than Tim's Ruby code using Scala.

I'm also trying to figure out what the heck a monad is, and thinking about how I'll have to use ugly, imperative Java IO classes, so I decided to write some classes to make a file look like a list of strings, with each element representing one line.  One critical aspect of this list is that it is lazily generated, so you don't have the wait for the entire file to be loaded to start working with it.  Another critical trait is that there are no "back references" from subsequent lines, so that if you no longer hold a reference to previous nodes in the list, those nodes can be garbage collected.  The interface supports all the required methods for "for" comprehensions - map, foreach, filter, and flatMap.  I think it qualifies as a monad, or at least is something close.

I ended up with something where usage looked kind of like this:

&lt;pre&gt;
def main(args : Array[String]) : Unit = {
  val pat = Pattern.compile("GET /ongoing/When/")
  for (file &lt;- args; line &lt;- Line.open(file) if pat.matcher(line).find) cnt = cnt + 1  } &lt;/pre&gt;

Note that I'm  just counting lines there, not performing the full Widefinder functionality.  But still, that's pretty concise and easy on the eyes.  The "for" comprehension is translated into calls to foreach.  It works great for a lot of files, but it blows up with a OutOfMemoryError on large files.  So why is that?  I'll give you a hint, fully expanded it would look kind of like this:
&lt;pre&gt;
args.foreach((file) =&gt; Line.open(file).filter((line) =&gt; pat.matcher(line).find).foreach((line) =&gt; cnt = cnt + 1))
&lt;/pre&gt;
Can you see the problem?  No?  Try this:
&lt;pre&gt;
args.foreach((file) =&gt; {
 val firstLine = Line.open(file)
 firstList.filter((line) =&gt; pat.matcher(line).find).foreach((line) =&gt; cnt = cnt + 1))
})
&lt;/pre&gt;
Can you see it now?  The problem is that there's a reference to the first line hanging around.  Even if you don't declare the variable it's still there, lurking as the implicit "this" parameter for filter.  That reference makes it so the first line is not collectable, and as a result none of the lines are collectable because they are all reachable from the first line.  So the whole file is loaded into memory, resulting in an OutOfMemoryError.  That seems pretty dangerous to me.

So how can we solve this problem?  Well, we have to make it so that references to lines disappear as we get done with them.  There are a couple ways to do it.  The obvious imperative way is the use a var and a while loop, but then you might was well use BufferedReader directly or use an iterator.  The functional way is to use tail recursion, so you write:
&lt;pre&gt;
def scanLines(line: Line, pat: Pattern, cnt: Int): Int = {
  if (line == EndOfFile) cnt
  else {
    val v = if (pat.matcher(line.value).find) 1 else 0
    scanLines(line.next, pat, cnt + v)
  }
}
&lt;/pre&gt;
...and call it for each file like this:
&lt;pre&gt;
for(file &lt;- args) cnt = cnt + scanLines(Line.open(file), pat, 0)   &lt;/pre&gt;
Notice that there is no val declaration holding the first line.  This is critical, because if there is, it will run out of memory.

So what do we do about it?  Well, it would be easy enough to refactor methods like foreach that trigger immediate file traversal out of the normal interface and into a tail-recursive method on the companion object.  Unfortunately that would break usage in for comprehensions, be inconsistent with other collection-like objects, and in general feel like poor OO.  Another way to fix it would be to fix Scala so it supported full tail call optimization.  Of course, that would also require adding full tail call support to the JVM.  That way the unneeded "this" reference could silently disappear from the stack.  This would also allow many methods to be expressed in a much cleaner way.  For example:
&lt;pre&gt;
  final def foreach(f: (String) =&gt; Unit): Unit = {
    def fe(line: Line): Unit = {
      if (line != EndOfFile) {
        f(line.value)
        fe(line.next)
      }
    }
    fe(this)
  }
&lt;/pre&gt;
Could be simplified down to:
&lt;pre&gt;
  final def foreach(f: (String) =&gt; Unit): Unit = {
    f(value)
    next.foreach(f)
  }
&lt;/pre&gt;
For those of you who want to take a look at the code I have so far, &lt;a href="http://mysite.verizon.net/vze2rswi/linereader.zip"&gt;here it is&lt;/a&gt; as an Eclipse project.  I've tried to comment it a bit, but it's still a work-in-progress.  There is a working (at least I think it works) mapreduce function hiding in there that allows lines to be parallel processed using actors.  Unfortunately it is slower (but not substantially slower) than just processing the lines serially.  But then I'm running it on an old uniprocessor PC, so maybe with more cores it would do better.  If I get some free time at work I'll try it out on a multicore machine and see what happens, but I suspect that unless (or until) I hack together something that uses &lt;a href="http://java.sun.com/javase/6/docs/api/java/nio/package-summary.html"&gt;nio&lt;/a&gt; in an optimal way the task will remain IO bound...and even then it may remain IO bound.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-4036477947167817138?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4036477947167817138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4036477947167817138' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4036477947167817138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4036477947167817138'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/10/dangerous-monads.html' title='Dangerous Monads?'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-8003336268373727003</id><published>2007-09-17T21:50:00.000-04:00</published><updated>2008-12-09T06:44:30.953-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='innovation'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><title type='text'>The Tar Pit</title><content type='html'>The editor of &lt;a href="http://www.theserverside.com/"&gt;TSS&lt;/a&gt; has decided to &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=46925"&gt;run a series&lt;/a&gt; discussing &lt;a href="http://www.amazon.com/Mythical-Man-Month-Software-Engineering-Anniversary/dp/0201835959/ref=pd_bbs_sr_1/002-4772004-1328801?ie=UTF8&amp;amp;s=books&amp;amp;qid=1190030956&amp;amp;sr=8-1"&gt;The Mythical Man Month&lt;/a&gt;, by Frederick Brooks.  Hopefully it will produce some good discussion.  There are a lot of Agile advocates that hang out on TSS that really could use to (re)learn some of the lessons of software development.  I make a point of rereading it every few years lest I forget the lessons learned by computing's pioneers.

The first chapter - The Tar Pit - contains on of my favorite concepts, as illustrated by the graphic below (slightly changed from original):


&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_-ZOtVRo0ba8/Ru8yvNiaVkI/AAAAAAAAAAU/AvK0BYWbk4M/s1600-h/progproduct.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_-ZOtVRo0ba8/Ru8yvNiaVkI/AAAAAAAAAAU/AvK0BYWbk4M/s400/progproduct.png" alt="" id="BLOGGER_PHOTO_ID_5111359888758036034" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:180%;"&gt;Programs&lt;/span&gt;

Let me explain.  A program is what we all have developed.  It's simple piece of software that is useful to the programmer and/to some set of users who are directly involved in defining its requirements.  Most bespoke departmental and a substantial portion of enterprise applications fall into this category.  They are sufficiently tested and documented to be useful within their originating context, but once that context is left their usefulness breaks down quickly.  In addition, they are not solidly designed to be extensible and certainly not to be used as a component in a larger system.  Obviously this is a range, and I've really described a fairly well developed program - one almost bordering on a programming product.  That script you wrote yesterday to scan the system log for interesting events that has to be run from your home directory using your user account in order to work is also just a program.
&lt;span style="font-size:180%;"&gt;
Programming Products&lt;/span&gt;

Moving up the graph, we hit programming product.  In theory, all commercial applications and mature bespoke applications are programming products.  In practice this isn't really the case - but we'll pretend because they are supposed to be and I increased the standard over what Brooks originally described.

The big challenge with programming products is that, according to Brooks, they cost three times as much to develop than simple fully-debugged programs yet they contain the same amount of functionality.  This is why it's so hard to get sufficient budget and schedule to do a project right.  The difference between a solid piece of software and something just cobbled together is very subtle (you can't tell in a demo) yet the cost difference is quite astounding.  Consequently, I think most commercial applications are released well before they hit this stage, and bespoke ones require years to mature or a highly disciplined development process to reach this point.
&lt;span style="font-size:180%;"&gt;
Programming Systems&lt;/span&gt;

Programming systems are programs intended to be reused as parts of larger systems.  In modern terms, they are libraries, frameworks, middleware, and other such components that are all the rage in software development.  Like programming products, programming systems are thoroughly tested, documented, and most importantly are useful outside of the context in which they were created.  And, like programming products, according to Brooks they take three times as long to develop as a regular program.

Developing programming systems for bespoke applications or niche use can be a tar pit all its own.  For one, many programmers like building libraries and frameworks.  The problems are more technically challenging, and there is no strange-minded user to consider.  The programmer and his colleagues are the user.

Programming systems are relatively common in groups that execute a lot of similar projects and/or that contain programmers who really want to build components.

&lt;span style="font-size:180%;"&gt;Programming System Products&lt;/span&gt;

Amazingly, programming systems products are relatively common - even if there really aren't that many of them.  As you've probably guessed, a programming system product has all the traits of both a programming product and a programming system.  It is useful to a wide range of users and can be effectively extended and/or embedded for the creation of larger systems.  It has complete documentation and is extensively tested.

Where are these wondrous things?  Well, you are using one right now (unless you printed this).  Your operating system is one.  It both provides useful user-level functions and a huge amount of infrastructure for creating other programs.  MS Office is one as well, because it has a pretty extensive API.

Most commercially developed enterprise systems should be programming system products, because:
&lt;ol&gt;&lt;li&gt;They provide off-the-shelf functionality for regular users
&lt;/li&gt;&lt;li&gt;Customers always customize them&lt;/li&gt;&lt;li&gt;They often must be integrated with other products&lt;/li&gt;&lt;li&gt;Simply integrating their own components would go better with a programming system&lt;/li&gt;&lt;/ol&gt;The problem is that they are not, because of:

&lt;span style="font-size:180%;"&gt;The Tar Pit&lt;/span&gt;

Brooks didn't explicitly write this definition of The Tar Pit but I think he would agree.  Put yourself in the position of a development manager at a startup or in a larger company about to launch on a new product.  On on hand, you want to make the product as good as possible.  You know that what you develop today will serve as the base for the company/product line for years to come.  It needs to be useful.  It needs to be extendable.  It needs to be thoroughly tested and documented...

It needs to be cheap and delivered yesterday.  The differences between a programming system product and a simple programming product are far more subtle than the differences between a program and a programming product.  But the programming system product costs a full NINE TIMES as much to develop as the program with essentially the same "outward functionality" - at least if you are a sales guy or a potential customer sitting in a demo.

I think this is the struggle of all engineering teams.  If the product is long lived, doing it right will pay major dividends down the line.  But it can't be long lived if it is never released.  It stands a worse chance if it comes out after the market is flooded with similar products (actually, that's debatable...).  The ultimate result is a mish-mash of tightly coupled components that, as individuals, fall into one of the lesser categories but as a whole fall down.  There is a documented API, but the documentation isn't really that good and the application code bypasses it all the time.  The user documentation is out-of-date.  Oh, and the application isn't really that general - hence why all the major customers need the API so they can actually make it work.
&lt;span style="font-size:180%;"&gt;
Escaping the Tar Pit&lt;/span&gt;

Ok, so if you develop a large system  you are destined to fall into the tar pit because cheap-and-now (well, overbudget and past schedule) will override right-and-the-next-decade.  You need a programming system product, but budget and schedule will never support much more than a program.  So how do you escape it?

&lt;span style="font-size:130%;"&gt;Accept It&lt;/span&gt;

Products that give the outward impression of being far more than they are often sorely lacking in conceptual integrity.  If you are building an application - build it right for the users.  Remember you can build it three times for the cost of building a programming system product.  Maybe by the third time there will be budget and schedule for it.  Or maybe, just maybe, you can evolve your current system.  But pretending will just make a mess while wasting significant amounts of time and money.

&lt;span style="font-size:130%;"&gt;Partition It&lt;/span&gt;

Some pieces of your system are probably more important than others.  There are places where requirements will be volatile or highly diverse amoung customers - those are the places where you need a truly extensible system.  You should also be able to reuse strong abstractions that run through your system.  The code associated with those abstractions should be top-notch and well documented.

Other pieces just need to be great for the users, while a few that remain need to be convenient for yourself to extend or or administrators.
&lt;span style="font-size:130%;"&gt;
Open Source It&lt;/span&gt;

Find yourself developing yet another web framework because what exists just isn't right?  Open source it.  This isn't really my idea.  It's what &lt;a href="http://blog.circleshare.com/"&gt;David Pollak&lt;/a&gt; of &lt;a href="https://www.circleshare.com/"&gt;CircleShare&lt;/a&gt; is doing with the &lt;a href="http://liftweb.net/"&gt;&lt;span style="font-style: italic;"&gt;lift&lt;/span&gt;&lt;/a&gt; web framework for Scala (actually, I'm guessing at David's reasoning, I could be wrong).  The infrastructure for your application is essential, but it isn't your application.  It is what &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=178569"&gt;Jeff Bezos refers to as muck&lt;/a&gt;.  You have to get it right, but it's distracting you from your core mission.  So why not recruit others with similar needs to help you for free?  That way you don't have completely give up control but also don't have to do it alone.

Theoretically the same could be done for applications.  Many large customers of software companies have significant software development expertise - sometimes more than the software companies.  I think it would be entirely feasible for a consortium of such companies to develop applications that would better serve them than commercial alternatives.  But I have yet to convince someone of that...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-8003336268373727003?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/8003336268373727003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=8003336268373727003' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8003336268373727003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8003336268373727003'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/09/tar-pit.html' title='The Tar Pit'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_-ZOtVRo0ba8/Ru8yvNiaVkI/AAAAAAAAAAU/AvK0BYWbk4M/s72-c/progproduct.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-2211572492738691062</id><published>2007-09-04T07:36:00.000-04:00</published><updated>2007-09-04T07:44:22.682-04:00</updated><title type='text'>Is implementation important to a startup?</title><content type='html'>I'm not entirely qualified to answer this question, but here it goes.

Taken from the Scala mailing list:
&lt;blockquote&gt;&lt;table style="width: 679px; height: 38px;" class="mhc" id="mm" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr class="fhr"&gt;&lt;td class="au"&gt;&lt;span id="_user_amichail@gmail.com" style="color: rgb(0, 104, 28);"&gt;Amir Michail&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/blockquote&gt;&lt;table style="width: 100%;" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;td class="cbln"&gt;&lt;div class="mb"&gt;&lt;div id="mb_4"&gt;&lt;div style="direction: ltr;"&gt;On 9/2/07, Erik Engbrecht
&gt; ...
&lt;/div&gt;&lt;script&gt;&lt;!-- D(["mb","\u003cdiv style\u003d\"direction:ltr\"\&gt;\u003cspan class\u003dq\&gt;&gt;   All-in-all I would say Scala would be perfect for a small team of\u003cbr /\&gt;&gt; extraordinarily smart developers, but I wouldn\'t turn your average Java or\u003cbr /\&gt;&gt; C# programmer pulled off the street loose on it.  Not because they couldn\'t\u003cbr /\&gt;&gt; write working Scala code, they could, it would just be a more concise\u003cbr /\&gt;&gt; Java/C#.  But I wouldn\'t start a company based on programmers grabbed off\u003cbr /\&gt;&gt; the street (or leased across the ocean), either.\u003cbr /\&gt;&gt;\u003cbr /\&gt;\u003cbr /\&gt;\u003c/span\&gt;\u003c/div\&gt;",1] );  //--&gt;&lt;/script&gt;&lt;div style="direction: ltr;"&gt;&lt;span class="q"&gt;&gt;   All-in-all I would say Scala would be perfect for a small team of
&gt; extraordinarily smart developers, but I wouldn't turn your average Java or
&gt; C# programmer pulled off the street loose on it.  Not because they couldn't
&gt; write working Scala code, they could, it would just be a more concise
&gt; Java/C#.  But I wouldn't start a company based on programmers grabbed off
&gt; the street (or leased across the ocean), either.
&gt;

&lt;/span&gt;&lt;/div&gt;&lt;script&gt;&lt;!-- D(["mb","\u003cdiv style\u003d\"direction:ltr\"\&gt;I actually don\'t think implementation is much of an issue for internet\u003cbr /\&gt;startups, particularly for Facebook apps.\u003cbr /\&gt;\u003cbr /\&gt;This is off topic, but I would be interested in knowing what you think of it:\u003cbr /\&gt;\u003cbr /\&gt;\u003ca onclick\u003d\"return top.js.OpenExtLink(window,event,this)\" href\u003d\"http://weblog.fortnow.com/2007/08/impact-of-facebook-platform-on-cs.html\" target\u003d_blank\&gt;http://weblog.fortnow.com/2007\u003cwbr /\&gt;/08/impact-of-facebook-platfor\u003cwbr /\&gt;m-on-cs.html\u003c/a\&gt;\u003cbr /\&gt;\u003ca onclick\u003d\"return top.js.OpenExtLink(window,event,this)\" href\u003d\"http://weblog.fortnow.com/2006/07/science-and-art-of-computation.html\" target\u003d_blank\&gt;http://weblog.fortnow.com/2006\u003cwbr /\&gt;/07/science-and-art-of-computa\u003cwbr /\&gt;tion.html\u003c/a\&gt;\u003cbr /\&gt;\u003c/div\&gt;",1] ); D(["mb","\u003cdiv style\u003d\"direction:ltr\"\&gt;\u003cspan class\u003dsg\&gt;\u003cbr /\&gt;Amir\u003cbr /\&gt;\u003c/span\&gt;\u003c/div\&gt;",1] );  //--&gt;&lt;/script&gt;&lt;div style="direction: ltr;"&gt;I actually don't think implementation is much of an issue for internet
startups, particularly for Facebook apps.

This is off topic, but I would be interested in knowing what you think of it:

&lt;a onclick="return top.js.OpenExtLink(window,event,this)" href="http://weblog.fortnow.com/2007/08/impact-of-facebook-platform-on-cs.html" target="_blank"&gt;http://weblog.fortnow.com/2007&lt;wbr&gt;/08/impact-of-facebook-platfor&lt;wbr&gt;m-on-cs.html&lt;/a&gt;
&lt;a onclick="return top.js.OpenExtLink(window,event,this)" href="http://weblog.fortnow.com/2006/07/science-and-art-of-computation.html" target="_blank"&gt;http://weblog.fortnow.com/2006&lt;wbr&gt;/07/science-and-art-of-computa&lt;wbr&gt;tion.html&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
So here's what I wrote (off-list) in response:
&lt;blockquote&gt;
Amir,
  I'm not really qualified to comment on the skills required to write Facebook apps because not only have I never written one, I've never even accessed Facebook.  However, I think one of the most effective ways of achieving long-term success for a business is to have a product that is in demand (obviously) and others find very difficult to replicate - or at least replicate to the point where people have difficulty deciding whether to use the new product or the old.  The best way I can think of to do that is for the product to have an inherent internal complexity - meaning it requires either hard-core CS skills, substantial domain knowledge, or both to grok it.  For example, Google is really an AI company.  They don't actively publicize it (nor do they hide it), and I bet the majority of their employees aren't working on anything AI related, but ultimately that's what the company is - and that's why they'll stay ahead.  Replicating the core of their business is simply too hard.  It certainly could be done, but you'd need to get a sufficiently large group of self-motivated geniuses together who would both cooperate and have enough entrepreneurial spirit to not be lured away by Google.

  I'm not saying you can't build a successful startup simply by creating something cool and getting a lot of people to use it.  You certainly can.  In fact, I would say the vast majority of successful startups were built that way.  But I also think the vast majority of startups don't have long-lasting products.  They have products that fill a (possibly transient) need for a larger player and get acquired.  They spend hundreds of thousands for maybe a few million dollars building something that would take a larger player &gt;$10x plus months to replicate, not because the startup is better at engineering or product design - it may or may not be - but because the startup is 1 of 100 or even 1000 so the larger player would have to fund &gt;10 initiatives a pick the somehow pick the best result in order to replicate what the startup did, and it can't do that because it can't release &gt;10 similar products all at the same time without looking stupid to investors and confusing its customers.

  From what I've read about Facebook apps they are relatively easy to build.  If you build a business around one, then essentially you are either trying to be that 1 in &gt;100 that people latch onto long enough for a larger player to be acquired, or so are going to launch yourself on a never ending cycle of re-inventing your application as people duplicate it and trends change.  Of course, that's not to say you can't have something really sophisticated at the core of your Facebook app.  I'm sure you can.  But if you do, implementation matters a whole lot.  Implementation tends to lag theory by years if not decades.  Your ability to implement is your competitive discriminator.

  As for the blog articles...well...I think the CS should remain more pure.  CS is not programming, but programming is an essential skill for computer scientists (as I actually believe it is for most scientists, but in CS is is a much stronger need).  So I think adapting CS to "Web 2.0" is a rather foolhardy exercise.  By the time programs adapt we'll be on Web 4.0, so the programs will be behind the times and will have lost the theoretical goodness of CS.  That's not to say those programs are bad ideas, I just don't think they should be labeled CS.  It dilutes the brand, so-to-speak.  I would say CS programs should offer far more electives that are cross-listed with other disciplines, such as business, economics, or the sciences.  But these can't replace fundamental courses or even upper level technical electives, so they would need to be framed as to replace what my alma mater called "humanities requirements."

-Erik&lt;/blockquote&gt;That's just my opinion, and to tell the truth my opinion has changed over the years.  But this is closely related to the ongoing debate about whether a CS backrgound is or is not important for being a software developer.  I actually think it is, but I also think a good CS program is overkill (in the CS theory and programming sense) for what most software developers do and grossly inadequate from a communications/requirements analysis sense.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-2211572492738691062?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/2211572492738691062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=2211572492738691062' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2211572492738691062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/2211572492738691062'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/09/is-implementation-important-to-startup.html' title='Is implementation important to a startup?'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-3878068016132936055</id><published>2007-08-28T16:13:00.000-04:00</published><updated>2007-08-28T16:14:35.719-04:00</updated><title type='text'>Scala Code for GPS</title><content type='html'>The link to the source code in the previous blog didn't work.   I put it in the wrong directory.  It's fixed now.  You can get the code here:  &lt;a href="http://mysite.verizon.net/vze2rswi/scala-gps.zip"&gt;scala-gps.zip&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-3878068016132936055?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/3878068016132936055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=3878068016132936055' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3878068016132936055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3878068016132936055'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/08/scala-code-for-gps.html' title='Scala Code for GPS'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4957844601802040837</id><published>2007-08-21T07:19:00.000-04:00</published><updated>2007-08-29T23:01:24.193-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='AI'/><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Scala vs Lisp for GPS: Part I: Expressivity</title><content type='html'>&lt;span style="font-size:130%;"&gt;Introduction&lt;/span&gt;

Before I found Scala I was looking for a language with the following characteristics:
&lt;ol&gt;&lt;li&gt;Expressivity on par with Python or Lisp&lt;/li&gt;&lt;li&gt;Performance on par with Java&lt;/li&gt;&lt;li&gt;Has a REPL or at least an interpreter&lt;/li&gt;&lt;li&gt;Compiled&lt;/li&gt;&lt;li&gt;Object-oriented&lt;/li&gt;&lt;li&gt;Large number of modern libraries and frameworks&lt;/li&gt;&lt;li&gt;Cross platform, including think-client GUIs&lt;/li&gt;&lt;li&gt;Open Source&lt;/li&gt;&lt;/ol&gt;
Now I've found Scala and I think I have my language, but unfortunately it's hard to tell about the expressivity without doing a real project and doing a real project involves a measure of risk.  Instead, I decided to port some Lisp programs from Norvig's &lt;a href="http://norvig.com/paip.html"&gt;Paradigms of Artificial Intelligance Programming&lt;/a&gt; to Scala and compare them to the original Lisp programs.  As as second step, I'll "Scala-ize" each program to be more idiomatic Scala (mostly increasing object orientation) to see the result.  Finally, I'll attempt to do some sort of performance comparison.
&lt;span style="font-size:130%;"&gt;
Background - What is GPS&lt;/span&gt;

GPS stands for "General Problem Solver."  The algorithm here comes from Alan Newell and Herbet Simon way back in 1957.  The original attempt was to create a computer program that could solve any problem.  It fell quite short of its goal, but the algorithm is still interesting and its expression in Lisp or Scala quite concise.  Those of you familiar with planning problems will recognize the basic structure and the sample problems.

For more information, see Chapter 4 of PAIP.

&lt;span style="font-size:130%;"&gt;The Algorithm&lt;/span&gt;

A problem is described using a set of initial conditions, a set of operators that can change those conditions, and a set of goal conditions.  Each operator has a name, a list of preconditions (conditions that most be true for it to be invoked), an add list (conditions it will add to the state when invoked), and a delete list (conditions it will remove from the state with invoked).  Note that these conditions are simple.  They are not based on on propositional or predicate logic.

The GPS uses a technique called means-ends analysis.  A brief explanation is contained &lt;a href="http://www.it.bton.ac.uk/staff/rng/teaching/notes/ProbSolvMethods.html"&gt;here&lt;/a&gt; about half way down the page.  In a nutshell, the algorithm tries to achieve each goal one at a time, until it fails to a achieve a goal or it has achieved all the goals.  The preconditions for each action are achieved by recusively invoking the algorithm on them.  For a detailed description of the implementation of the algorithm, see PAIP or look at the comments in my &lt;a href="http://mysite.verizon.net/vze2rswi/scala-gps.zip"&gt;Scala code&lt;/a&gt;.

&lt;span style="font-size:130%;"&gt;Comparison of Implementations&lt;/span&gt;

There are some substantial differences between the Lisp implementation and the Scala implementation.  They are:
&lt;ol&gt;&lt;li&gt;The Scala implementation is more explicitly structured.  Some of the structure, such as the static typing, is forced by Scala.  Others, such as using classes instead of conventions on list contents to distinguish between normal conditions and "executing conditions," are not forced by Scala but are simply easier and more natural.&lt;/li&gt;&lt;li&gt;The resulting plan is a list of operators rather than a list of lists obeying a convention.  This is straightforward because "executing conditions" are a special class of condition and are explicitly tied back to the operators they represent.&lt;/li&gt;&lt;li&gt;The core algorithm in Scala is completely and explicitly devoid of mutable state.  The Lisp solution makes only one small use of mutation in achieve-all, and that occurrence could easily be removed in the same was as it was from Scala.  However, cons cells, and the lists they form, are mutable and therefore it is much more difficult to prove that the algorithm uses no mutable state.&lt;/li&gt;&lt;li&gt;The Scala solution required fewer utility functions.  This is due to both the richer standard library and case classes.&lt;/li&gt;&lt;li&gt;The problem-definition DSL required significantly more code in Scala, especially in order to make it interpreter-friendly.&lt;/li&gt;&lt;li&gt;The syntax of the problem-definition DSL in Scala is statically checked.  For example, you cannot use preconditions in the place of the add list.  Achieving this took a fair amount of work, and I almost just went with a looser version that was equally easy to type and read but less validated.&lt;/li&gt;&lt;li&gt;In my subjective opinion, the Scala version is much easier to read.  I find the fact that Lisp control structure like "if" implicitly return nil on failure if not "else" is provided to be quite confusing.
&lt;/li&gt;&lt;/ol&gt;General observations:
&lt;ol&gt;&lt;li&gt;At least for this problem (which didn't use macros), Lisp code could be almost directly converted to Scala.&lt;/li&gt;&lt;li&gt;Scala implicits make an effective substitute for special variables (i.e. defparameter) in Lisp.&lt;/li&gt;&lt;li&gt;Overall LOC count is too close to matter.&lt;/li&gt;&lt;li&gt;Lisp development is far more interactive that Scala.&lt;/li&gt;&lt;li&gt;The Scala compiler catches a lot of "stupid" mistakes that the Lisp compiler does not (but the Lisp compiler catches some, much more than Python, Ruby, et. al.), reducing the number of edit/run cycles by a fair margin.&lt;/li&gt;&lt;li&gt;Case classes are really useful.  They allow you to add structure to your program without going to all the work of implementing all the support methods, such as &lt;span style="font-family: courier new;"&gt;equals&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;hashCode&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;toString&lt;/span&gt;, and &lt;span style="font-family: courier new;"&gt;unapply&lt;/span&gt; for pattern matching.  Lisp is worse than Java et. al. because it has four different equals functions (&lt;span style="font-family: courier new;"&gt;eq&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;eql&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;equal&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;equalp&lt;/span&gt;) all with subtle (and not so subtle) differences.  In Scala, if you are wise and don't have to deal with Java libraries (hah!), you pretend &lt;span style="font-family: courier new;"&gt;eq&lt;/span&gt; (reference equality) doesn't exist (indeed, pretending references don't exist, and null doesn't exist, seems like a good idea to me).  In fact, I find case classes so useful, I think I'm going to write a Python metaclass so I can use them in Python, too.
&lt;/li&gt;&lt;li&gt;I retract previous negative statements about pattern matching on lists.  It's useful.  I get it now.  But I still wouldn't convert a string to a list just for pattern matching.&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-style: italic;"&gt;Updated - Finished point 6.&lt;/span&gt;

&lt;span style="font-size:130%;"&gt;Conclusion&lt;/span&gt;

I'm not going to conclude anything yet.  So far, Scala seems to be as expressive as Lisp, and its added structure and compiler definitely reduce the number of errors made while coding.  However, this comparison was on a relatively simple piece of code and the Scala implementation was mostly a port.  This means that I can't say one way or another whether the added structure of Scala would be a help or a hindrance to the early stages of flushing out code.  Based on my experience with Python, I think without case classes the added structure would definitely be a hindrance.  Keeping all the basic functions (comparison, hash, toString) up-to-date on rapidly changing objects is a real pain.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-4957844601802040837?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4957844601802040837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4957844601802040837' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4957844601802040837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4957844601802040837'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/08/scala-vs-lisp-for-gps-part-i.html' title='Scala vs Lisp for GPS: Part I: Expressivity'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-221925000179417738</id><published>2007-08-17T12:36:00.000-04:00</published><updated>2007-08-17T15:33:56.746-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Syntactic Sugar for Composition/Delegation</title><content type='html'>Composition/Delegation is a common pattern in object oriented software.  There are a lot of different definitions floating around for both composition and delegation, but basically it amounts to this, as demonstrated in Java code:

&lt;span style="font-family:courier new;"&gt;
&lt;pre&gt;
class MyStringList implements List&amp;lt;String&amp;gt; { 
    private List&amp;lt;String&amp;gt; backingList;
    public MyStringList(List&amp;lt;String&amp;gt; backingList) {
        if (backingList == null) throw new NullPointerException();
        this.backingList = backingList;
    }
    public String get(int i) { return backingList.get(i); }
    public boolean isEmpty() { return backingList.isEmpty(); }
    // ... lots of other methods like the ones above
    public void add(String s) {
        if (s == null || s.length() == 0)
           throw new IllegalArgumentException();
        backingList.add(s);
    }
    // and some more slightly modified methods to complete List
}
&lt;/pre&gt;
&lt;/span&gt;

So &lt;span style="font-family:courier new;"&gt;MyStringList&lt;/span&gt; is &lt;span style="font-style: italic;"&gt;composed&lt;/span&gt; of &lt;span style="font-family:courier new;"&gt;backingList&lt;/span&gt; and it &lt;span style="font-style: italic;"&gt;delegates&lt;/span&gt; most of its methods to it.  Furthermore, in this case it is using &lt;span style="font-family:courier new;"&gt;backingList&lt;/span&gt; to implement the interface &lt;span style="font-family:courier new;"&gt;List&lt;string&gt;&lt;/string&gt;&lt;/span&gt;.  There are other ways to use composition and delegation, both together and separately, but this is the pattern with which I'm concerned.  If I had full written out the code, the first thing you would notice is that there is a painfully large amount of boiler-plate code (the &lt;span style="font-family:courier new;"&gt;List&lt;e&gt;&lt;/e&gt;&lt;/span&gt; interface requires 25 methods) to accomplish very little.  If you know Java or a similar language, you would then probably think that it would be easier to use inheritance as follows:

&lt;span style="font-family:courier new;"&gt;
&lt;pre&gt;
class MyStringList extends ArrayList&amp;lt;String&amp;gt; {
    public MyStringList() {}
    public void add(String s) {
        if (s == null || s.length() == 0)
            throw new IllegalArgumentException();
        super.add(s);
    }
    // do something for the other add methods as required...
}
&lt;/pre&gt;
&lt;/span&gt;

That's a lot less typing.  It's also strongly coupled to &lt;span style="font-family:courier new;"&gt;ArrayList&lt;e&gt;&lt;/e&gt;&lt;/span&gt;.  Depending on what you're trying to do, that may or may not be a problem.  For example, let's say you are developing a web application using &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt;, and you want Hibernate to lazily fetch the contents of the list.  The only way would be to extend Hibernate's list instead, thereby breaking any code you already wrote that assumed &lt;span style="font-family:courier new;"&gt;ArrayList&lt;/span&gt; and strongly coupling you to a specific ORM.  The other problem is that Java only supports single inheritance, so you can only save typing for one interface.  If you have several, you are out of luck.  Trust me, these are not good things.

So, with Java at least, you are stuck between a rock and a hardplace.  You either get strong coupling or a lot of typing boilerplate code.  If you don't believe me, ask &lt;a href="http://www.google.com/search?q=java+boilerplate&amp;start=0&amp;amp;amp;ie=utf-8&amp;oe=utf-8&amp;amp;client=firefox-a&amp;rls=org.mozilla:en-US:official"&gt;Google&lt;/a&gt;.

But problem is very solveable.  On one hand there's &lt;a href="http://www.scala-lang.org/intro/mixin.html"&gt;mixins&lt;/a&gt;, but these introduce their own set of restrictions, oddities, and coupling.  It would be better to add something simple that preserves the pattern in an easily understandable way while eliminating the boilerplate code.  Delegation should be made part of the language.  So instead of writing the initial piece of code, you would write:

&lt;span style="font-family:courier new;"&gt;
&lt;pre&gt;
class MyStringList implements List&amp;lt;String&amp;gt; { 
    private delegate List&amp;lt;String&amp;gt; backingList;
    public MyStringList(List&amp;lt;String&amp;lt; backingList) {
        if (backingList == null) throw new NullPointerException();
        this.backingList = backingList;
    }
    public void add(String s) {
        if (s == null || s.length() == 0)
           throw new IllegalArgumentException();
        backingList.add(s);
    }
    // and some more slightly modified methods to complete List
}
&lt;/pre&gt;
&lt;/span&gt;

The &lt;span style="font-family:courier new;"&gt;delegate&lt;/span&gt; keyword tells the compiler that any methods from &lt;span style="font-family:courier new;"&gt;List&lt;e&gt;&lt;/e&gt;&lt;/span&gt; that are not already implemented should be generated by delegating responsibility to the member &lt;span style="font-family:courier new;"&gt;backingList&lt;/span&gt;.  This eliminates the boilerplate code without introducing excess coupling, reducing flexibility, or even being particularly confusing.  Furthermore, this scheme could work in many languages.

I'm not a compiler hacker, but concepts like this are always better with a demonstration.  So I've thrown together some &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt; that enables this behavior.  Code is &lt;a href="http://mysite.verizon.net/vze2rswi/delegation.py"&gt;here&lt;/a&gt;.  It's far from production-quality.  I'm sure people will find plenty of flaws.  But it does demonstrate the concept (along with showing how easily extensible Python is.&lt;/put&gt;&lt;/put&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-221925000179417738?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/221925000179417738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=221925000179417738' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/221925000179417738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/221925000179417738'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/08/syntactic-sugar-for-compositiondelegati.html' title='Syntactic Sugar for Composition/Delegation'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-8882242411213736751</id><published>2007-08-14T22:45:00.000-04:00</published><updated>2007-08-15T00:03:50.792-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='innovation'/><category scheme='http://www.blogger.com/atom/ns#' term='management'/><title type='text'>Business Engagement and IT Project Failure</title><content type='html'>&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;CIO&lt;/span&gt;.com recently ran an &lt;a href="http://www.cio.com/article/128300/Beware_These_Hazards_to_Functional_Engagement_in_IT_Projects/1"&gt;article&lt;/a&gt; by the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;CIO&lt;/span&gt; of GE &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Fanuc&lt;/span&gt; regarding "functional engagement" (i.e. "the business" or more commonly "the users") and project failure.  Michael &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Krigsman&lt;/span&gt; later posted a more succinct &lt;a href="http://blogs.zdnet.com/projectfailures/?p=342"&gt;summary&lt;/a&gt; on his &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;ZDNet&lt;/span&gt; blog.

Here's a even shorter version:
&lt;ol&gt;&lt;li&gt;Make sure a single business-side has significant capability, responsibility, and authority for project success.&lt;/li&gt;&lt;li&gt;Don't short-circuit important parts of the project
&lt;/li&gt;&lt;li&gt;Make that person understands the "laws of IT" and defends them to his peers, subordinates, and superiors&lt;/li&gt;&lt;/ol&gt;#1 is just plain common sense.

#3 amounts to establishing a scape goat for the inevitable failure caused by short-circuiting appropriate systems engineering or architectural activities.

Notice that there is neither a definition of "failure" nor a definition of "success."  I think it can be inferred that he's defining "failure" as "exceeding project or maintenance budget and/or schedule."  Not once does he mention delivering real innovation to the business or even real value - just avoiding causing massive amounts of pain.

Consider the following statement:

&lt;blockquote&gt; Enterprise platforms like &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Siebel&lt;/span&gt;, &lt;a title="More stories related to Oracle Corporation" href="http://www.cio.com/article/128300/subject/Oracle+Corporation"&gt;Oracle&lt;/a&gt; and SAP are not intended to be heavily customized. When going from a niche, custom application to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;Siebel&lt;/span&gt;, you need a strong functional leader to push back on every “Yeah, but” statement. They must start at zero and make the business justify every customization. Saying “no” to customization is bitter medicine for your business partners. They will make contorted faces and whine &lt;em&gt;ad &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;nauseum&lt;/span&gt;&lt;/em&gt;. But it is for their own good.&lt;/blockquote&gt;
Let's think for a moment.  Your customer (internal or external) wants to spend millions of dollars implementing a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;CRM&lt;/span&gt; (or &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;ERP&lt;/span&gt;, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;PLM&lt;/span&gt;, etc.) package.  Earlier, it went to the trouble of building one from scratch.  That probably means it considers &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;CRM&lt;/span&gt; to be an extremely important part of its business, and it expects to derive a competitive advantage from having a &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_12"&gt;shiny&lt;/span&gt; new system.  The best way to be competitive is to copy what everyone else is doing, right?  Also, repeatedly receiving "no" as an answer will &lt;span style="font-style: italic;"&gt;really&lt;/span&gt; make your customer want to take an active role in the implementation, right?

&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;Hmmm&lt;/span&gt;....somehow I don't think so.  Introducing a strong impedance mismatch between the organization and the software it uses is failure.  Standing in the way of innovation is failure.  Mr. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;Durbin&lt;/span&gt; wants you to fail.

There is actually a simple, albeit occasionally painful, solution to this problem: don't buy an off-the-shelf application that neither meets the business's requirements nor can be cost-effectively extended to meet them.

First, you have to understand your business processes and requirements.   I mean really understand them, not just understand the official process documentation that no one follows.  All those &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_15"&gt;winces&lt;/span&gt; and "yes buts" are requirements and process details that absolutely must be understood and addressed.

Second, you do a trade study.  This is a key part of systems engineering.  Replacing enterprise systems is expensive, often prohibitively expensive, so do a thorough analysis.  Take some of your key users to training sessions and write down every &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_16"&gt;wince&lt;/span&gt; and vaguely answered question, because those are all either issues that will stand in the way to delivering value or will require customization.

Finally, keep your pen in your pocket.  Don't be tempted to write checks, buy licenses, and sign statements-of-work before your really understand the product.  Just ignore those promises of discounts if you get a big order in before the end of the quarter.  The next quarter isn't that far away, and the end of the fiscal year may even be approaching.  The discounts will reappear then.  Instead, make sure the vendor really understands the requirements and business process, and structure any contracts in a way that they must be met or the vendor will face significant penalties.  It's amazing what comes out of the woodwork when you do this.  All of a sudden that 3x cost overrun from the &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_17"&gt;original&lt;/span&gt; projection is sitting right there in front of your eyes in the form of a quote, all before you've sunk any real money into the project.

The purpose of engaging "the business" in an IT project is not to create a personal shield for all the deficiencies in the system you are deploying.  It is to make sure you identify those deficiencies early enough in the project cycle to avoid cost and schedule overruns.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-8882242411213736751?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/8882242411213736751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=8882242411213736751' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8882242411213736751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/8882242411213736751'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/08/business-engagement-and-it-project.html' title='Business Engagement and IT Project Failure'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-6946549939193866999</id><published>2007-08-03T10:10:00.000-04:00</published><updated>2007-08-03T16:49:49.567-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><title type='text'>Minimal Software Development Process</title><content type='html'>It's not uncommon for me to find myself in debates regarding what constitutes a sufficient software development process.  On one side, there are the Agile folks who argue that code-and-fix, with user representatives determining what should be fixed.  Of course they have lots of rules to regulate the code-and-fix, some of which are quite sensible and some of which are quite dubious, to make it appeal to closet process engineers.  On the other side you have old-school developers who believe in such rarities as requirements signed in blood and requiring human sacrifice to alter.

Ok, so perhaps I'm exaggerating a little bit.  But that's how it often feels.  So I'm going to propose my own process that is every bit as simple as what the Agile crowd pushes while being more all-encompassing than traditionalists.  Here it is:

&lt;ol&gt;&lt;li&gt;Define the problem&lt;/li&gt;&lt;li&gt;Define the solution&lt;/li&gt;&lt;li&gt;Apply the solution&lt;/li&gt;&lt;li&gt;Validate the result&lt;/li&gt;&lt;/ol&gt;Now you are probably thinking that this is nothing novel.  I'm just using weird words for:

&lt;ol&gt;&lt;li&gt;Develop requirements&lt;/li&gt;&lt;li&gt;Design and Code to the Requirements&lt;/li&gt;&lt;li&gt;uhh....Test?
&lt;/li&gt;&lt;li&gt;Customer Acceptance Testing&lt;/li&gt;&lt;/ol&gt;Wrong!  Even if you were more creative than me, or pulled out RUP's phases or anything like that.  But that's expected, as I rarely see steps 1 and 4 completed.  Let me explain.

&lt;span style="font-weight: bold;font-size:130%;" &gt;Define the Problem&lt;/span&gt;

This is where most projects get in trouble.  Their problem definitions looks kind of like this:
&lt;ul&gt;&lt;li&gt;We need to rollout a corporate standard ERP system.
&lt;/li&gt;&lt;li&gt;We need to web-based foo tracking database accessible to the entire corporation.
&lt;/li&gt;&lt;li&gt;We need an automated workflow for the bar process.&lt;/li&gt;&lt;/ul&gt;I could go on-and-on.  Sometimes these are followed by phrases like "will save X million dollars" or "will reduce cycle time by X%."  Really the problem is someone said that a competitor was saving money by applying an automated workflow to the bar process in order to track foos in the ERP system with a web-based frontend, the company at hand doesn't have one, so that's a problem.

Anyway, often times these statements are really masking genuine problems such as:
&lt;ul&gt;&lt;li&gt;My old college roommate is an ERP salesmen and wants a new boat&lt;/li&gt;&lt;li&gt;We have a ton of foo, but no one really knows where it is or if it's being used.  So we keep on buying more foo, even though we probably have enough.  The problem is when we find so foo, the people with the foo always claim that they need all of it, even though often times they clearly aren't using it.  We have some data, but it's massive and impossible to interpret.  We need a way to find unused foo and prove that it is unused so that we can transfer it where it is needed.
&lt;/li&gt;&lt;li&gt;Some cowboys in department X keep on ignoring the bar process.  They think they are heros because it saves time and money upfront, but really they just end up creating costly, time consuming problems down the line (for me).  I need a way for force them to follow the bar process, but it can't be too hard otherwise they'll convince upper management to let them ignore it.&lt;/li&gt;&lt;/ul&gt;So why is the difference important?  Don't you just end up with the first set of statements as your project charter, anyway?

No.

A couple months ago I faced a situation similar to the second item.  A consultant had (unfortunetly) convinced a couple senior managers that they wanted a big, fancy database integrated to half of our internal systems and requiring a whole bunch of data maintenance.  Fortunately the consultant also directed them to me.  They had tons of data, and had spent countless hours fiddling with spreadsheets trying to turn it into actionable information.  Having failed, they decided they needed a huge database that would cost hundreds of thousands of dollars to develop and then require staff to keep up-to-date.  They also needed something in about a couple weeks.

So I poked a proded until I finally understood what they needed to know, what data they had, and what they needed to decide based on that data.  Then I wrote a few hundred lines a Python to analyze the data and make pretty graphs, along with a couple dozen lines of VBA to stick the outputs of the Python program into a PowerPoint presentation.  They were thrilled with the result.  Hundreds of thousands of datapoints were transformed into actionable charts that even the most impatient executive could correctly interpret.

This took me about 2 weeks effort.  Their original requirements would have taken a couple man years effort to implement, and the result would not have solved their problem.  Traditionalists would have wasted the time to implement the requirements (which were actually fairly well developed), or at least a portion of them.  Agilists would have fiddled around for a while and achieved the same result.

Now I'll admit that on the majority of projects it's the other way around.  Understanding the problem makes that cost of the solution grow by an order-of-magnitude, rather than shrink.  My guess is only 1 in 4 can actually be simplified by understanding the problem, and 2 in 4 become significantly more complex.   But solid estimates that can be tied to solid business cases are extremely important.  Delivering a cheap solution that doesn't deliver value is a waste of money.

In my experience development teams assume that "the customer" or "the business" already understand their problem and are defining requirements that will solve it.  When in reality, the problem is usually vaguely understood at best, and the description of requirements is every bit a design activity as coding is.

&lt;span style="font-weight: bold;font-size:130%;" &gt;Define the Solution&lt;/span&gt;

This is where most of the traditional software engineering activities occur.  You have a customer (or marketing) who has given you some high level requirements defining the general shape of the system, and then you go about gathering more detailed requirements, followed by architecture, design, code, and test.  Or maybe you are agile so you do all of those activities at once and only bother writing down code (in the form of application code and test code).  Either way, knowing the problem really helps.

Some people probably object to lumping all of these activities under one heading because they take so much time.  I would agree, but they rarely done entirely sequentially.  Prototyping is every bit as valid of a method for eliciting requirements as interviews.  Sometimes it is a lot more effective.  Also, there are strong feedback loops among all of the elements.  So really, they are all done pretty much at the same time.  It just happens that requirements kick off the process and testing finishes it up.

Others would object because "the completed system is the solution."  Well, no.  It's not.  You don't really know if you have a solution until after you've deployed and run the system long enough for the business to adjust itself.

&lt;span style="font-weight: bold;font-size:130%;" &gt;Apply the Solution&lt;/span&gt;

This is just another way to saying "deploy," plus all the other things you have to do like training.  If you think of it at a really high level (too high for effective engineering), the organization is the problem, and you apply the software to the organization to see if the organization gets better.
&lt;span style="font-weight: bold;font-size:130%;" &gt;
Validate the Result&lt;/span&gt;

This is where you measure the impact of deploying the software on the problem so see if indeed the problem has been solved.  I don't think anyone will disagree that a piece of software can meet all of its requirements and fail to make a positive impact.  So you need to measure the impact of the deployed system.

In practice, success is declared as soon as a piece of software that meets "enough" of its requirements is rolled out.  This puts the organization in a very bad position, because if the software subsequently fails to deliver value, then the declaration of success and those who made it are called into question.  In most cases the organization will just end up either ignoring the system or limping along until enough time has passed to call the system a problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-6946549939193866999?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/6946549939193866999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=6946549939193866999' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6946549939193866999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/6946549939193866999'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/08/minimal-software-development-process.html' title='Minimal Software Development Process'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-4861997438102853487</id><published>2007-07-17T23:08:00.000-04:00</published><updated>2007-07-18T08:39:47.743-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='innovation'/><category scheme='http://www.blogger.com/atom/ns#' term='user interface'/><title type='text'>More Efficient User Interfaces</title><content type='html'>Over the weekend I ran into the following &lt;a href="http://video.google.com/videoplay?docid=-6856727143023456694&amp;q=tech+talk&amp;amp;total=1092&amp;start=10&amp;amp;num=10&amp;so=0&amp;amp;type=search&amp;plindex=7"&gt;video&lt;/a&gt; about changing user user interface paradigms.  I found the language based interface really interesting, but didn't much care for the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;ZUI&lt;/span&gt;.  Unfortunately, the language based interface reminds me of old games from about the time personal computers became powerful enough to run &lt;a href="http://en.wikipedia.org/wiki/ELIZA"&gt;Eliza-like&lt;/a&gt; software (for hackers, go &lt;a href="http://www.norvig.com/paip/eliza1.lisp"&gt;here&lt;/a&gt; for code, and &lt;a href="http://www.gigamonkeys.com/book/lispbox/"&gt;here&lt;/a&gt; for an easy environment on Windows).  Basically you typed in "natural language" commands, and the characters were supposed to carry them out.  Personally, I thought it was about the most awful way to play a game.  Maybe in the past couple decades technology has &lt;a href="http://www.humanized.com/products/enso/launcher/"&gt;progressed&lt;/a&gt;.  It looks like it has potential.

Anyway, the first thing that struck me was it reminded me of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;SciFi&lt;/span&gt; books where they describe any advanced computer use "programming," possibly because I largely stick to classic &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;SciFi&lt;/span&gt;.  Of course the vast majority computer users, who indeed perform relatively complex tasks, are not &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;progammers&lt;/span&gt;.  Not by a long shot.  But I think the language-based interface concept could bring "programming" one step closer to the masses (whether that is good or bad is an &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;excercise&lt;/span&gt; for the reader).

The second thing I noticed was a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;stricking&lt;/span&gt; similarity to &lt;a href="http://www.squeak.org/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;SmallTalk&lt;/span&gt;&lt;/a&gt;, only &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;SmallTalk&lt;/span&gt; is a lot better.  You see, if all of your software was inside of a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;SmallTalk&lt;/span&gt; image, then you could easily interact with it &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;programmatically&lt;/span&gt;.  Furthermore, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;SmallTalk's&lt;/span&gt; syntax and dynamic nature make it fairly approachable for those who have not been corrupted by years of experience with less lofty languages (in other words, me).  Given a "humanized," if you will, object model I could see some real potential.  At a minimum it would be a realization of much more &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;componentized&lt;/span&gt; software.  Alas, we can dream...

The paradigm for such a system would be something like this:  Someone builds an &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;API&lt;/span&gt; that translates human-language like typed commands into Smalltalk code.  It could quite possibly be an internal &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;DSL&lt;/span&gt;.  Then you build the interface so that an easy keystroke let's you "talk" to the computer by typing.  AI would be optional, but I think essential for really advanced use by lay users.  As time progresses, the user and the computer would learn more and more complex tasks - the user would essentially be programming the computer, but it would feel more like training.  Ultimately this could facilitate much more efficient and sophisticated computer use.

Maybe.  There are counter points.
&lt;a href="http://blogs.zdnet.com/Murphy/?p=913"&gt;
Paul Murphy&lt;/a&gt; seems to think that everyone should learn keyboard shortcuts and Unix command-line utilities.  While I agree in the utility of both, somehow I don't think the every-day computer user is ever going to do it.

The more convincing counter point was made by my wife, an attorney, who wasn't even really trying to make a counter point.  The exchange went something like this:

Me:  I saw this video the other day about changing user interface paradigms to  consist of unified functionality instead of distinct applications.

Her:  Why would you want that?

Me:  Well, difference applications do different things, and so often times you have to use more than one to get it done.

Her:  Word is complicated enough already.  Wouldn't that make it more complicated?

Me:  Yeah, that's why this guy advocated switching to text-based commands instead of menus and dialogs and stuff.

Her:  Huh?

Me:  You know how Word has a ton of menus, and those have sub-menus, and those launch dialog boxes with a bunch of tabs in them?

Her:  Yeah.  It's confusing.

Me:  Well, if there were easy text commands that resembled natural language, then you could just tell the computer what to do and not worry about the menus.

Her:  Wouldn't that mean I have to learn all that?  What's wrong with what we've got.  It works.  I know how to use it.  Why change?  People won't like the change.  It will confuse them.

Me:  Well, how about intelligent search....

And go on to another defeat of the engineer.   But that's the point.  We dream of novel new things.  We dream of users who care to really learn applications.  We get people who want consistency.  They've learned it, and they don't want to learn it again.

So why is this important?

Well, two reasons.  One is that people are amazingly hampered by most application.  By people, I mean everyone.   How many of you have spent hours fighting Word or PowerPoint to get some document to look right?  I know I've done it plenty of times.  That's wasted time, and time is money.

But there's a more important reason.  I think we've hit a &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_14"&gt;plateau&lt;/span&gt; in terms of technology innovation.  We have all this shiny new processing power and networks, and most "innovation" seems to consist of thing like "social networking" (many were doing that a 1200bps or less years ago), sharing pictures (ditto), playing media (replacing TV/VCR isn't innovation), and other such pursuits that while may be very beneficial, hardly represent technology advancements.

Why?   There are a lot of reasons.  I think one of them is that computers are so complicated already that getting a user to accept them doing something complicated is incredibly low.  You can do it in specialized fields that have a technical leaning (science, engineering, finance, economics), but doing it for others is another ballgame.

In the long run, in order to keep innovating, we have to be able to bring innovative software to people who today do not want it, because what they have today is complex enough.   We have to change the user interface paradigm, and we have to do it in a way that doesn't scare people who already "know something" away.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-4861997438102853487?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/4861997438102853487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=4861997438102853487' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4861997438102853487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/4861997438102853487'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/07/more-efficient-user-interfaces.html' title='More Efficient User Interfaces'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-3105555654789152425</id><published>2007-07-16T22:24:00.000-04:00</published><updated>2007-07-17T07:26:39.005-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><category scheme='http://www.blogger.com/atom/ns#' term='Sun Ray'/><category scheme='http://www.blogger.com/atom/ns#' term='Sun'/><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='Solaris'/><title type='text'>Sun Ray Thin Clients</title><content type='html'>Last week I made a &lt;a href="http://talkback.zdnet.com/5208-11202-0.html?forumID=1&amp;threadID=36003&amp;amp;messageID=662835&amp;amp;start=-9976"&gt;comment on Paul Murphy's blog&lt;/a&gt; about how the thin-ness of Sun Rays is really up to interpretation. Today he's decided to dedicate an entire &lt;a href="http://blogs.zdnet.com/Murphy/?p=917"&gt;blog&lt;/a&gt; to explaining why I'm wrong, because he figures if I have an incorrect understanding of Sun Rays, then a lot of people have an incorrect understanding of Sun Rays. He's probably right, although I don't think my understanding is that far off base, and he's been kind enough to let me see a draft copy of his blog so I can get a head start on the response.

Here's what I said:
&lt;blockquote&gt;Smart, Thick, Thin, Display &lt;p&gt;It's all word games. Depending on how you define "processing," there is processing going on. It still has to render graphics, translate keyboard and mouse events, etc. A SunRay is just a compacted Sun workstation of yesteryear without a harddrive and special firmware designed to work solely as an X-Windows server. &lt;/p&gt;&lt;p&gt;The problem is the attempt to make "smart displays" seem more fundamentally different from other similar solutions just muddies the waters. People like me groan because yet another term has been introduced that means almost the same as other terms that will need to be explained to the higher-ups. The higher-ups get confused and either latch onto it or, more likely, have their eyes glaze over. &lt;/p&gt;&lt;p&gt;Anyway, enough with our industry's incredible ability to make sure words are completely meaningless... &lt;/p&gt;&lt;p&gt;The problem with Sun Ray and other similar solutions is that they are really a local optimum based on today's technology and practices for a relatively narrow range of priorities. Change the priorities and the solution is no longer optimum. Introduce distributed computing techniques with the same low administrative overhead and they lose out entirely. &lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;As far as I can tell, the first part is technically accurate. Older Sun Rays ran a 100Mhz UltraSparc II, had 8mb of RAM, and ran a microkernel. See &lt;a href="http://blogs.sun.com/jclingan/entry/define_thin"&gt;here&lt;/a&gt; and &lt;a href="http://sunsolve.sun.com/handbook_pub/Systems/SunRay100/spec.html"&gt;here&lt;/a&gt;. &lt;a href="http://www.sun.com/sunray/sunray2/specs.xml#anchor3"&gt;Newer ones&lt;/a&gt; use an even beefier &lt;a href="http://www.razamicro.com/products_alchemy/au1550_overview.htm"&gt;system-on-a-chip&lt;/a&gt;.&lt;/p&gt;So the Sun Ray client is obviously processing something, and actually has a fair amount of processing power. Just because it is not maintaining any application state, doesn't mean it's not doing anything.

Murph asserts that a Sun Ray is not an X-Terminal, but he'll have to explain the difference to me. He could be right...I don't know. It's been about 7 years since I've used a Sun Ray, but from what I remember it felt just like using &lt;a href="http://connectivity.hummingbird.com/products/nc/exceed/index.html?cks=y"&gt;Exceed&lt;/a&gt; on a PC under Windows, which is quite common at my employer. He did mention this:
&lt;blockquote&gt;
Notice that the big practical differences between the Sun Ray and PC all evolve from the simplicity of the device in combination with the inherently multi-user nature of Unix. In contrast the differences between the Sun Ray and X-terminal arise because the X-terminal handles graphics computation and network routing -making it more bandwidth efficient, but marginally less secure.&lt;/blockquote&gt;But the Sun Ray quite clearly has a graphics accelerator and talks over the network, so while there is probably a subtle difference in there that I'm not grasping, it doesn't seem particularly marterial.

But that's not really the meat of the debate, it's just a technical quibble over what consitutes processing and an operating system. He's dilluting the debate by calling Sun Ray's "smart displays" instead of "thin clients" and thus drawing a false dichotomy, and I'm doing the same by pointing at internal technical specs that have little to do with actual deployment.

The real debate is: "Where should processing take place?"

I'll give you a contrite answer - as close to the data as possible. Any computation involves a set of inputs and a set of outputs. It makes no sense to shuttle a million database rows from a database server to an application server or client machine in order to sum up a couple fields. It makes much more sense to do it where the data is, and then ship the result over the network. Likewise, if you have a few kilobytes of input data and several megabytes/gigabytes of results, it makes sense to do the computation wherever the results are going to be needed.

So this is my first issue with the centralized computing paradigm. Right now I'm typing this blog in Firefox on Linux, and my computer is doing a fair amount of work to facilitate that interaction with Blogger. I've also got a dozen other Windows open. Most of the memory and CPU I'm consuming is dedicated to the local machine interacting with me, the local user. Only a couple pages of text are being exchanged back-and-forth with blogger.

So why not let the Sun Ray run Firefox (and an email client, a word processor, etc.)? The new ones have the processing power. They probably would need $100 worth of RAM or so to keep a stripped-down Unix variant in RAM, which could be loaded from the network. Intelligent configuration could make the client smart about whether to run an app locally, on a server, or on an idle workstation down the hall.

Murph gives seven reasons:
1. portability
Murph asserts that with Sun Rays you gain portability, because you can halt a session one place and immediately resume it another place. I don't doubt that is true, but I don't see any technical reason why the same could not be accomplished with a distributed architecture. All that happens is your terminal becomes the processing server for a remote application. Remember, in Unix, there isn't a fundamental difference between a client and a server.

I'm not going to address the laptop debate right now. Murph has made some very good arguments against laptops in the past based on the security concerns of them being stolen, despite strong encryption. I think he underestimates the value of laptops and is probably wrong, but there are a substantial number of people who could live with a "portable terminal" because their homes and hotels have sufficient bandwidth.

2. reliability
This is where the distributed model really shines. In my experience, networks just are generally one of the less reliable portions of the computing environment, especially WANs and my own internet connection. A pure thin-client solution simply stops working when the network goes down. In the past, Murph has asserted that everyone needs network connectivity to work, so this doesn't matter. But in my opinion most professionals can continue working for several hours, possibly at reduced productivity, when disconnected from the network. That buys time for IT to fix the network before the business starts bleeding money in terms of productivity. Keeping processing local, along with caching common apps and documents, increases the effective reliability of the system.

3. flexibility
Murph lists nothing that cannot be done with a locally-processing workstation.

4. security
Don't use x86 workstations, especially running Windows. The security gains are from a more secure operating system on a processor architecture designed for security and reliability. Eliminating permanent storage from the client does buy some security, because there is then no way to walk out the door with all the data, but distributed processing doesn't preclude centralized permanent storage.

There are, of course, substantial advantages to having local storage, like being able to make a laptop that can be used in an entirely disconnected fashion. But I think that's a separate debate.

5. processing power
There's nothing about a distributed computing model that says you can't install compute servers. Heck, this is done all the time with Windows (both to Windows servers and more commonly to Unix servers).

Murph's example of a high-performance email server has nothing to do with the thin-client architecture, and everything to do with properly architecting your mail server.

6. cost
There aren't significant cost savings in terms of hardware when switching to Sun Rays. Hardware is cheap, and you can throw out a lot of pieces in the common PC to reduce the cost. In fact, I bet Sun Rays cost more because of the servers. I don't doubt that when effectively administrated they cost less to keep running than a Windows solution, but that's mostly because of Unix. I'll admit that it is probably cheaper to administer Sun Rays than my distributed model because I think it will require greater skill and discipline (meaning higher paid admins), so in abscense of detailed numbers I'll say it's a wash.

7. user freedom
This is partially a consequence of using Unix instead of Windows, and mostly a consequence of changing culture.

So as I said before, Sun Rays, and centralized computing in general, represent a kind of a local optimum for a given solution and today's practices. But I don't think they make a solid generalized approach. Distributed computing can be successfully with all the advantages of Murph's Sun Ray architecture using today's technology, it just isn't common.

Now I've ignored the elephant in the room: Much essential software only runs on Windows, and the minute you introduce Windows into the mix (local or centralized), you start compromising many of the advantages outlined above. Of course, what good is a computing environment if it won't run the desired software? Consequently, I think it will be a long time before anything like this flies in most enterprise environments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-3105555654789152425?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/3105555654789152425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=3105555654789152425' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3105555654789152425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/3105555654789152425'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/07/sun-ray-thin-clients.html' title='Sun Ray Thin Clients'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7181221104197683795</id><published>2007-07-02T09:47:00.000-04:00</published><updated>2007-07-02T11:39:10.930-04:00</updated><title type='text'>Creators, Hounders, and Processors</title><content type='html'>There are three types of people in a corporate environment:
&lt;ol&gt;&lt;li&gt;Creators&lt;/li&gt;&lt;li&gt;Hounders&lt;/li&gt;&lt;li&gt;Processors&lt;/li&gt;&lt;/ol&gt;These are really a continuous spectrum, and people can occupy more than one location on the spectrum, but I think those are the large buckets into which most people fall.

I'm very tempted to say that creators are the people who produce most of the value, but that probably would be my creator-self talking.  Creators are the people who create something of value from almost nothing.  They are the engineers, scientists, researchers, and marketers who create the ideas that advance an organization.  They are both the most coveted and most annoying employees, and generally compse a very small percentage of an organization.  Within an IT organization, creators tend to be architects, analysts, and software developers; although most people in those roles aren't really creators.

I'll talk about hounders later.

Processors are the people who take something, apply some known method to it, and spit out something of greater value.  In law, a litigator is most likely a creator.  The guy who puts together your will is a processor.  A processor's job is to keep things neat, complete, well organized, and most of all conformant to any important rules and regulations.  Without processors we would live and work in total chaos.  Processors are the people who take the mess produced by creators and turn it into something that is geniunely useful and widely appliable.  They are the people who continually apply it so that is becomes part of our lives.  In IT, QA people, system administrators, database administrators, application administrators, configuration managers, help desk staff, and countless others are generally processors.  Management often wishes everyone (except them) could be a processor, because they are predictable and their work usually has immediately apparent value.  Processors make up a very large portion of most organizations.

So creators like shiny new things.  They hate forms and anything else that seems to constrain their ideas.  They only really believe in deadlines for other people, because creativity cannot be hurried, and often times even have trouble pushing deadlines on others because the last thing they want are half-baked ideas.  They don't want to be bothered with the extraneous details required by processors.  Processors often claim to believe in deadlines, and to be very predictable in the time it takes to process work.  However, they exclude from this time they spend waiting for responses that the need from others.  If you don't believe me, go see how many help desk tickets your IT organization has that are in a state like "waiting for user response," quite likely to a question like "Is your computer plugged in?"

The result is processors are only concerned about deadlines when they can't blame someone else, and creators are prima donnas who can be bothered neither by deadlines nor by a processor's need for additional information.  Consequently creators are the perfect scapegoat for processors (he hasn't responded to my email asking for more information), and processors for creators (I sent it to him last week, what do you mean he needs more information?  I'm busy.  It's his fault this is late, not mine.)

Now enter hounders to solve this problem.  They exist to overcome the impedance mismatch between creators and processors, and they may be as numerous as the other two groups combined.  Salespeople are all hounders.  Most managers are hounders.  Everyone who emphasizes (or randomly inserts) the word "manager" in their role or title is a hounder.  Hounders are the people who constantly talk about action items and religiously send out meeting minutes.  They are also often the people who lack the technical skills to be creators and detail orientation to be processors.

Just like you need some bacteria in your body, you need some hounders in your organization.  But too many is a sign that your organization is diseased, as most don't directly produce anything.  Also, without day-to-day observation, it can be very difficult to distiguish a hounder from a creator or processor, because they tend to confuse (intentionally or otherwise) making somebody do something with doing it themselves.  And they tend to make organizational problems worse.

Often times if the creators and the processors are having a really hard time communicating, it's because one or both sides has been allowed to become too extreme.  When processors get in trouble, their first instinct is to create more rules for getting tasks out of their queue and off their clock.  Creators, when they get in trouble, tend to avoid disclosing details, especially when they aren't yet sure of them.  Consequently, all the hounder has to do is encourage these behaviors, and the hounder becomes (in the short term) more critical to the organization, because now the only place the processor can get his details is from the hounder, who either tricks the creator into providing them or takes responsibility for any problems that may arise.  In extreme circumstances, processors may even stop communicating with other processors, by simultaneously declaring items in each-others' queues, making hounders necessary to make what should be a smooth interaction work.

All three types are needed in any organization.  When properly balanced they compliment each other.   I've picked on hounders here, because I think they are the most opportunistic, but creators and processors can be quite detrimental as well when they gain too much influence.

P.S.
Now, you might be wondering what happens to the people who lack the technical skills and creativity to be creators, detail orientation and technical skills to be a processor, and the personality to be a hounder.  Some fake it, usually by obscuring their lack of skill or creativity, for example by parroting something they heard/read or calling "buy IBM" an IT strategy.  It's amazing how smart a person will think you are if you consisntely agree with them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7181221104197683795?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7181221104197683795/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7181221104197683795' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7181221104197683795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7181221104197683795'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/07/creators-hounders-and-processors.html' title='Creators, Hounders, and Processors'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-7375924490859251479</id><published>2007-06-27T00:06:00.000-04:00</published><updated>2007-06-27T00:18:29.790-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Random thought on functional programming</title><content type='html'>Right now I'm trying to learn &lt;a href="http://www.scala-lang.org"&gt;Scala&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Functional_programming"&gt;functional programming&lt;/a&gt;, particularly not using any mutable state.  I'm going cold-turkey on mutable state.  It's hard.

I've noticed a few things:
&lt;ol&gt;&lt;li&gt;It takes me forever to work out functions that build collections despite the fact that I can clearly envision to mutating-version of the algorithm&lt;/li&gt;&lt;li&gt;Once the functions actually compile, they tend to "just work," or at least any flaws are design flaws, not simple coding mistakes.  This is very much like the Python experience, only it takes longer.
&lt;/li&gt;&lt;li&gt;The functions continue to work, unlike the Python experience where a combination of edge cases and type errors generally crop up as the complexity of inputs increases&lt;/li&gt;&lt;/ol&gt;I'm not sure if this means I'm more or less productive.  Right now I'd say probably not, but maybe I'll learn to "think functional" and stop thinking in terms of how I would mutate a collection to make it what I want.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19725519-7375924490859251479?l=erikengbrecht.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://erikengbrecht.blogspot.com/feeds/7375924490859251479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19725519&amp;postID=7375924490859251479' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7375924490859251479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19725519/posts/default/7375924490859251479'/><link rel='alternate' type='text/html' href='http://erikengbrecht.blogspot.com/2007/06/random-thought-on-functional.html' title='Random thought on functional programming'/><author><name>Erik Engbrecht</name><uri>http://www.blogger.com/profile/11174963559600768092</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19725519.post-638807819145007287</id><published>2007-06-13T22:36:00.000-04:00</published><updated>2007-06-27T00:19:11.163-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Engineering'/><title type='text'>Software Engineering and IT Professionalism</title><content type='html'>A few weeks ago I was reading the chapter on Philip Greenspun and &lt;a href="http://en.wikipedia.org/wiki/ArsDigita"&gt;ArsDigita&lt;/a&gt; in &lt;a href="http://www.foundersatwork.com/"&gt;Founders at Work&lt;/a&gt; and some of his comments really rang true for me.  On a number of occasions I've been in debates with advocates of both agile and traditional software development methods, as well as people from other IT-related disciplines.  In my opinion, the argument usually boils down to this question:

&lt;blockquote&gt;How important is it that an IT Profesional take responsibility for ensuring his work delivers value to his customer/client/employer in a cost effective manner?&lt;/blockquote&gt;
No one would argue with the idea that it is important to deliver value.  No one would argue that it is important to be cost effective.  So why would this be such a contentious topic?  Well, I think it boils down to an old addage to predates information technology by an awfully long timer...
&lt;blockquote&gt;The customer is always right.&lt;/blockquote&gt;The glaring problem with this is that he is not always right.  Not by a longshot.  If he were, he would most certainly not be hiring you to apply your brain to create something for him.  He would simply apply his omnipotence to quickly creating the perfect software, running on the perfect operating system, on failure-proof hardware.  Ok, yes, we all know that.  The customer has hired us for our technology expertise.  He knows what he needs, and we know how to create it.  Right???

Nope.  He doesn't.  And no one is surprised by that.  No self-respecting text on requirements development starts with "The customer/user knows exactly what he needs.  All the analyst needs to do is take detailed notes, and the customer/user will precisely, consistently, and completely describe the application that will be his needs."  It's all about how users don't know what they want, they have conflicting desires, they tell you what they think you want to hear instead of what they really mean, and so on.

I doubt there's any disagreement so far.  So what did Mr. Greenspun say?
&lt;blockquote&gt;We had this idea that programmers could be professionals, like doctors or lawyers, and, to that end, we wanted the programmers to be real engineers - to sit down face to face with the customer, find out what was needed, come up with some suggestions or changes based on the programmer's experience with similar services, and then take a lot of responsibility for making it happen.&lt;/blockquote&gt;So what does this mean?  Here's my take:
&lt;ol&gt;&lt;li&gt;A professional will tell a customer when he has reason to believe that the customer needs something different from what he is asking for.&lt;/li&gt;&lt;li&gt;A professional will inform his customer when he believes his services will not deliver value in a cost effective manner.
&lt;/li&gt;&lt;li&gt;A professional will speak in the customer's language, or at least close enough so that the customer can understand.&lt;/li&gt;&lt;li&gt;A professional will take the time to understand the customer's need, not just the customer's request.&lt;/li&gt;&lt;li&gt;A professional will express "engineering trades" in terms that the customer can understand
&lt;/li&gt;&lt;li&gt;A professional will make commitments in terms of cost and schedule, and take responsibility for meeting them.&lt;/li&gt;&lt;/ol&gt;Most "IT Professionals" I know regularly practice at least a couple of these.  Very few practice all.  Most don't have much trouble trying to make helpful suggestions, and are very conscious of cost and schedule.  They try their "best" to communicate effectively, but usually are too concerned with their own specialty than learning the basics of their customers'.  Very rarely will they state that their services are not really required, especially in consulting or contracting situations.

The end result is exchanges kind of like this:
&lt;blockquote&gt;Customer:  We would like our customers to be able to order replacement parts and lookup technical information securely over the internet.  Under no circumstances do we want unauthorized people ordering parts or viewing information.  Do you have anything for that?
IT Guy:  We have this piece of off-the-shelf software called WebSphere.   It can be used to create an integration hub among enterprise applications.  It can also be used to host portals, and can be combined X and Y to implement federated security using two-factor authenitcation and strong encryption.
&lt;/blockquote&gt;So let me translate into something the customer would actually understand:

&lt;blockquote&gt;IT Guy:  We know of the technology required to do what you want, and have some of the infrastructure already in place.  However, we will have to build the website, which we call a "portal," along with the software to connect is to Z, which is our internal system that handles orders.  Fully automating these transactions will cost an arm and a leg, and data regarding who is authorized to order parts and access data will have to be extremely well maintained to prevent inapprioriate transactions.  The last thing you want is for the factory to build something that the customer won't pay for, because the person who ordered it shouldn't have been able to.  Do you think it would be better if we enabled customers to communicate with internal representatives in a highly structured way?  Perhaps if that worked well we could add more automation later on.  This would be both safer and much less expensive.  What do you think?
Customer:  Oh my God!  Of course I want a real person to be involved.&lt;/blockquote&gt;Now the IT Guy just passed up a resume building project in favor of something rather unglamorous.  I can think of many other situations where customers have asked for applications dependent on data that didn't exist, direly flawed mathematics, grossly unrealistic assumptions about intended users, and highly exaggerated availability needs stated by customers who didn't want their application to seem unimportant.

Faced with this problem, many IT providers hide the techie from the customer.  Instead of placing someone who can't communicate in front of the customer, they place someone with no technical skills in front of the customer and have that person communicate with the techies.  The problem is this is just miscommunication via proxy.  In other words, it is worse.

The problem is that professionals are inherently at least partially generalists, while the IT industry has a nasty habit of trying to create line workers.

A lawyer can be disbarred for pursuing a frivolous lawsuit (ok, the bar the frivalous is pretty low, but it can still happen).  A doctor can be sued for malpractice and lose his license for ordering inappropriate treatments.  Entire accounting firms can be destroyed for allowing financial numbers to be misrepresented.  These are professionals.  They are responsible for their clients, even if it means acting against their client's immediate wishes.

But a programmer who hacks together a barely functional piece of software is rewarded for be
