tag:blogger.com,1999:blog-47972773200899762792024-02-20T14:18:37.043+01:00Diamond InheritanceDeveloping view of a late-adopter. Voice of your average developer from your run-of-the-mill outsourcing company. Too young to know multiple inheritance, too old to catch up with Ruby On Rails. Too ironic to be not unreal.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.comBlogger23125tag:blogger.com,1999:blog-4797277320089976279.post-87513374179627636362009-12-14T19:09:00.002+01:002009-12-14T19:27:40.896+01:00From Bully to BitchI'm not easily disgusted by plagarism, but <a href="http://blog.plurk.com/2009/12/14/microsoft-rips-plurk/">Microsoft China blatantly stealing the IP of another company</a> takes me far far down rodeo drive.<br /><br />I'm not really into IP law, don't even give too much credit to it. Don't even think you can really enforce it. I mean come on. Whatever's reproducible will be reproduced, that's what life is all about, and software is an easy prey in this territory.<br /><br />I don't even care about Microsoft getting some slashdot-love again, though I really hope this story would generate more buzz than usual!<br /><br />And I wouldn't even want to be a bitch about acts of stealing, because different societies have different standards and ways on identifying and punishing it.<br /><br />But come on. Big guys stealing from the little guys on the open street in the darned daylight? That's like unacceptable no matter what, right?Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-85845042165875634402009-01-03T22:49:00.002+01:002009-01-03T23:02:39.395+01:00apt-messBeing totally new to Debian, this surely will sound funny to my future self, but still, I'm pretty confused by apt/Debian's package management.<br /><br />So I want to go from stable to testing, which is easy right, it's all <a href="http://www.debian.org/doc/manuals/reference/ch-woody.en.html">laid out</a> in the docs: do an <span style="font-style:italic;">apt-setup noprobe</span> to prepare for your install. Hm. Except that there is no apt-setup on my current system (which is Etch stable). Go look for such, with <span style="font-style:italic;">apt-cache search</span> and <span style="font-style:italic;">dpkg -S</span> and <a href="http://www.debian.org/doc/manuals/apt-howto/ch-search.en.html#s-cache">what not</a> -- no luck. Then there's this Google-thing, that leads me to <a href="http://www.pendrivelinux.com/2007/10/06/how-to-upgrade-from-etch-to-lenny/">this nice page</a> the content of which is a bit misleading but gives me a good kickstart. Turns out, all I have to do is replace my "stable" entries to "testing" in my source.lst file. Now, do I have to do an apt-get upgrade before my dist-upgrade or is it unnecessary. Official docs <a href="http://www.debian.org/doc/manuals/reference/ch-woody.en.html">say I better do</a> a genuine upgrade before the dist-upgrade, but hell, they even say I should use aptitude instead of apt-get and then I don't know a bit about the difference between the to.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-12713318183379427782009-01-03T21:19:00.003+01:002009-01-03T22:09:01.563+01:00Linux From Scratch -- Success!!After nearly <a href="http://diamondinheritance.blogspot.com/2008/11/linux-from-scratch.html">a month of fiddling</a> with <a href="http://www.linuxfromscratch.org/lfs/">LFS</a> I finally got it working! It's really amazing to finally see the prompt that I built. :)<br /><br />This is where exactly the journey begins. But before going <a href="http://www.linuxfromscratch.org/blfs/">beyond</a> there are some issues to cope with:<br /><br />1. An 'iso-8859-1 invalid identified' error after login -- I hope this would not lead to too severe <a href="http://www.linuxfromscratch.org/blfs/view/svn/introduction/locale-issues.html">locale-related issues</a> <br /><br />2. Drives that were hdaX on my previous host system are now named sdaX in the LFS system -- this may have to do something with udev? <br /><br />3. There is no working eth0 interface which is the most painful part. Maybe this has something to do with the fact that I've compiled the kernel with <span style="font-style:italic;">make defconfig</span>?<br /><br />Before really starting to do BLFS, I will investigate these issues, which will be easy since I have a snapshot inside the chroot environment with the livecd.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-17053866877896693892008-12-12T21:07:00.005+01:002008-12-14T10:56:54.222+01:00Linux From Scratch -- RevisitedStuff me in a pink gown and call me Paris Hilton.<br /><a href="http://diamondinheritance.blogspot.com/2008/12/linux-from-scrach-failure.html">Last time</a> my LFS build failed it wasn't even binutils but glibc! After 15 minutes of <a href="http://www.linuxfromscratch.org/hints/downloads/files/errors.txt">RMTFing</a> I realized that it's called <span class="Apple-style-span" style="font-family: 'courier new'; ">configparms</span> not <span class="Apple-style-span" style="font-family: 'courier new'; ">configparams</span>, dummy.<div><br /></div><div>So next on is <a href="http://www.linuxfromscratch.org/lfs/view/stable/chapter05/adjusting.html">adjusting the toolchain</a>!<br /><div><br /><br /></div></div>Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-745630869240564602008-12-02T10:42:00.007+01:002008-12-03T20:06:52.640+01:00Linux From Scratch -- FailureOh well, binutils build has failed. I suppose it has something to do with <a href="http://www.linuxfromscratch.org/lfs/view/stable/chapter05/gcc-pass1.html">GCC Pass 1</a>? The wording about the first GCC compilation in the book is a bit misleading, because they are talking about bootstrapping but the make target nowhere tells it to bootstrap.<br />I guess I will have to come back to this one and contact the good guys on the mailing list. Of course I will do my <a href="http://www.linuxfromscratch.org/lfs/view/stable/chapter01/askforhelp.html">RTFM</a> before flooding public channels.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-35001402097834058662008-11-29T17:40:00.004+01:002008-12-01T01:22:38.319+01:00Linux From Scratch -- Host SystemSo I have <a href="http://diamondinheritance.blogspot.com/2008/11/linux-from-scratch.html">downloaded the minimal</a> LFS LiveCD and popped it into my virtual machine under VMWare Player.<br /><br />As it is advertised it is definitely a valid host environment for the build process, as checked by <a href="http://www.linuxfromscratch.org/lfs/view/stable/prologue/hostreqs.html">version-check.sh</a> <br /><br />After setting up my main file systems, we need to get the source packages. There is a wget input file in the <a href="http://www.linuxfromscratch.org/lfs/downloads/stable/">stable book download directory</a> which comes very handy. My slow internet connection makes me have to wait for all of them to arrive.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-41661620803801274082008-11-29T16:42:00.007+01:002008-12-01T01:07:26.087+01:00Linux From Scratch -- IntroductionI've been a long time casual Linux/Unix user. Back before Ubuntu was hype, I got into Gentoo, but never really got too far beyond installing it and emerging some packages. At my work we use Debian, and on my Vista I sure have Cygwin cause bash and the command line stuff is awesome.<br /><br />But it always bothered me that I'm not <span style="font-weight:bold;">really</span> into Linux. Not <span style="font-style:italic;">into</span> like "I use Ubuntu for my daily browsing and document editing chores" or "I'm the sysadmin of a 50-server heterogeneous *nix farm" but somewhere in between.<br /><br />I'm pretty much tied to Windows as my main working environment, and can't really afford the hassle to migrate all my stuff to Linux (yeah, going from XP 32-bit to Vista 64-bit was a big enough deal already, thank you), so what do I do?<br /><br />This is where <a href="http://www.linuxfromscratch.org/">Linux From Scratch</a> comes into play. I mean. If I just <span style="font-style:italic;">really</span> could build a whole Linux system from scratch, well it would really mean at least something, right?<br /><br />Well. Jump right into it.<br /><br />Because I'm a newbie, I start with the <a href="http://www.linuxfromscratch.org/lfs/view/stable/">latest stable version</a> of the <a href="http://www.linuxfromscratch.org/lfs/read.html">LFS book</a>.<br /><br />First of all I need a host systems which is a simple 2.6 generic Linux VMware Image created by <a href="http://www.easyvmx.com/">EasyVMX!</a> and booted up with the <a href="http://www.linuxfromscratch.org/livecd/download.html">LFS LiveCD</a>. Since the latest book version is 6.4 and the latest LiveCD version is 6.3 and I don't need no X and stuff, I'm gonna pick the <span style="font-weight:bold;">32-bit</span> <span style="font-style:italic;">"-min"</span> image. <br /><br />Since I have a slow internet connection, I guess I will have to hook up on things later.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-38956071841615833112008-09-25T21:15:00.021+02:002008-09-30T16:49:43.434+02:00Sling Blade Runner<p><a href="http://itasoftware.com/">ITA Software</a> could be an <a href="http://www.paulgraham.com/carl.html">interesting</a> place to work at. They sure have some interesting <a href="http://www.itasoftware.com/careers/hiringpuzzles.html">puzzles</a> on their career site serving as tools for resume selection / recruitment. One of such puzzles has just gone to their <a href="http://www.itasoftware.com/careers/puzzle_archive.html">archives</a> which is a big green flag for an open discussion.</p> <p>The puzzle is called <a href="http://www.itasoftware.com/careers/puzzle_archive.html#Sling%20Blade%20Runner">Sling Blade Runner</a>, and it is specified as follows:</p> <blockquote> <p>"How long a chain of overlapping movie titles, like Sling Blade Runner, can you find?"</p> <p>Use the following listing of movie titles: MOVIES.LST. Multi-word overlaps, as in "License to Kill a Mockingbird," are allowed. The same title may not be used more than once in a solution. Heuristic solutions that may not always produce the greatest number of titles will be accepted: seek a reasonable tradeoff of efficiency and optimality.</p> </blockquote> <p>Let's go and try to solve it!</p> <h2>The General Algorithm</h2> <p>The task suggests a reduction to the graph-traversal domain. By translating the specification to a bit more technical level, we can lay ground for an actual implementation. The highest level description of the proposed solution is as follows:</p> <ol> <li><p>Take the input of a set <strong>S</strong> of sentences </p></li> <li><p>Build the overlap-graph <strong>D</strong> of <strong>S</strong> which is a directed graph <strong>D</strong>(<strong>V</strong>, <strong>A</strong>); where </p> <ul> <li><strong>V</strong>=<strong>S</strong>, </li> <li><strong>A</strong> = {arc(<span style="font-family: monospace; color:black;">s1</span>, <span style="font-family: monospace; color:black;">s2</span>) if <span style="font-family: monospace; color:black;">s2</span> overlaps <span style="font-family: monospace; color:black;">s1</span> and both elements of <strong>S</strong>}</li> </ul></li> <li><p>Find the longest (vertex disjoint) path <strong>P</strong> in <strong>D</strong></p></li> <li><p>Output <strong>P</strong></p></li> </ol> <p>Breaking down above steps takes us more closer to an actual realization. Following are the main steps in greater detail:</p> <h2>1. Take the input</h2> <p>The input is given as a stream of sentences (titles) separated by line breaks, where</p> <ul> <li>a <em>sentence</em> is a non-empty sequence of words separated by non-breaking whitespace, and</li> <li>a <em>word</em> is a non-empty sequence of non-whitespace characters.</li> </ul> <p>For simplicity we won't care too much about different character sets and encodings and casing, and let the implementation environment decide about the proper meaning of whitespaces and characters.</p> <p>What we do care about is that the input can possibly containt empty sentences that we ignore and multiple instances of the same sentence which we treat as a single value. Note that a sentence does not contain any of the whitespaces which appeared in the original line of input.</p> <h2>2. Build the overlap-graph</h2> <p>The meaning of "overlapping" is outlined in the original description of the task. A more formal definition would be that the sentence <span style="font-family: monospace; color:black;">s2</span> overlaps sentence <span style="font-family: monospace; color:black;">s1</span> iff any of the (non-empty) suffixes of <span style="font-family: monospace; color:black;">s1</span> (including <span style="font-family: monospace; color:black;">s1</span>) is the prefix of <span style="font-family: monospace; color:black;">s2</span> (including <span style="font-family: monospace; color:black;">s2</span>), where <span style="font-family: monospace; color:black;">s1</span> is not <span style="font-family: monospace; color:black;">s2</span>.</p> <p>The overlap-graph <strong>D</strong> then is made up by enumerating each possible <span style="font-family: monospace; color:black;">p</span>=(<span style="font-family: monospace; color:black;">s1</span>, <span style="font-family: monospace; color:black;">s2</span>) pair of <strong>S</strong> and putting an arc (<span style="font-family: monospace; color:black;">s1</span>, <span style="font-family: monospace; color:black;">s2</span>) into <strong>D</strong> for each <span style="font-family: monospace; color:black;">p</span> if <span style="font-family: monospace; color:black;">s2</span> overlaps <span style="font-family: monospace; color:black;">s1</span>.</p> <h2>3. Find longest path</h2> <p>An <span style="font-family: monospace; color:black;">L</span>-long vertex disjoint path in the directed graph <strong>G</strong> is a sequence of vertices <span style="font-family: monospace; color:black;">v</span>[1], <span style="font-family: monospace; color:black;">v</span>[2], ..., <span style="font-family: monospace; color:black;">v</span>[<span style="font-family: monospace; color:black;">L</span>-1], <span style="font-family: monospace; color:black;">v</span>[<span style="font-family: monospace; color:black;">L</span>] with the following properties:</p> <ul> <li>for each 1 <= i <= <span style="font-family: monospace; color:black;">L</span>, i != j it holds thats <span style="font-family: monospace; color:black;">v</span>[i] != <span style="font-family: monospace; color:black;">v</span>[j]</li> <li>for each 1 <= i < <span style="font-family: monospace; color:black;">L</span> it holds that <span style="font-family: monospace; color:black;">v</span>[i] is the predecessor of <span style="font-family: monospace; color:black;">v</span>[i+1] in <strong>G</strong> (ie. there is an arc (<span style="font-family: monospace; color:black;">v</span>[i], <span style="font-family: monospace; color:black;">v</span>[i+1]) in <strong>G</strong>)</li> </ul> <p>The longest vertex disjoint path <strong>P</strong> from a source vertex <span style="font-family: monospace; color:black;">v</span> in <strong>G</strong> is found by the following <a href="http://en.wikipedia.org/wiki/Breadth-first_search">BFS</a>-like recursive algorithm:</p> <pre><span style="font-family: monospace; color:black;">let n = the source of the search, initially n = v<br />let visited = vertices already visited by the algorithm, initially empty<br />define function longest_path(G, n, visited) as<br /> if n is in visited then <br /> return empty_list<br /> for each successor m of n do<br /> path_candidates[m] = longest_path(G, m, visited ++ n)<br /> let mpc = one of the longest paths in path_candidates<br /> return v ++ mpc // the list of nodes on one of the longest paths from n in G<br /><br /></span></pre> <p>To get the global longest path <strong>GLP</strong> in <strong>D</strong>, one of the best results of <span style="font-family: monospace; color:black;">longest_path</span>(<strong>D</strong>, <span style="font-family: monospace; color:black;">n</span>, <span style="font-family: monospace; color:black;">empty_list</span>) over each <span style="font-family: monospace; color:black;">n</span> in <strong>D</strong> must be chosen.</p> <p>The "one of..." clauses are present because two distinct paths can have the same length.</p> <h2>4. Write output</h2> <p>Print vertices of <strong>GLP</strong> each vertex on a line.</p> <h2>5. Test</h2> <p>Distinct parts of the algorithm can be tested as separate units: overlap-detection, termination-of-traversal in a cyclic graph, proper graph-building, etc. -- but I'm gonna skip describing those. As far as testing the whole algorithm goes I'm only interested in two things:</p> <ul> <li>That any results fed back to the input are given back unchanged.</li> <li>That I would pick the most naive benchmark implementation and every optimization is subject give the same results as this benchmark.</li> </ul> <p>These are the main concerns regarding the evolution of my implementations. I will present actual implementations in future posts, but I won't talk about testing: publishing of any code will imply a that it has passed above tests.</p>Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-70584040764367580562008-09-12T16:38:00.015+02:002008-09-15T02:53:29.014+02:00Google Chrome -- The Evil User InterfaceI really can't believe things went so far that I'm going to put this kind of rant in ink. I really have to state that I'm still gonna take the Google pill over Microsoft on any day, but heck, maybe they don't <a href="http://www.pbs.org/cringely/pulpit/2007/pulpit_20071102_003354.html">learn from the master that well</a> after all. I'm talking about Google Chrome. It may well be that Google did revolutionize things on the server side and took on very well on the web-client side, but God are they unprofessional on the desktop. Unprofessional may not be the most suitable word here, but if they are doing those <a href="http://www.25hoursaday.com/weblog/2008/06/29/TheGOOGMSFTExodusWorkingAtGoogleVsWorkingAtMicrosoft.aspx">amateurish things</a> on the desktop on purpose, well, that just makes it sound <a href="http://en.wikipedia.org/wiki/Don%27t_be_evil">downright evil</a>. <br /><br />First of all, I didn't even keep Google Desktop on my machine for more than an hour because frankly, having a web server to let me get easier access to my <span style="font-style:italic;">desktop</span> kinda sounds freaky to me. Turns out that <a href="http://www.watchfire.com/resources/Overtaking-Google-Desktop.pdf">I wasn't</a> overly <a href="http://download.watchfire.com/googledesktopdemo/index.htm">paranoid at all</a>.<br /><br />Now they came out with a browser, the user interface of which isn't a very likely candidate to be served by, well a web server -- and I was truly frantic about it. Even got sold on the <a href="http://www.google.com/googlebooks/chrome/">Chrome comic</a> in a snap. Soon as it was available to download I gave it a run, even took a look at the source code (though not as deep as <a href="http://www.hanselman.com/blog/">Scott Hanselman</a> here -- more on this in a minute). I was truly excited only to find out in five minutes that this stuff is not for me, and I believe it's not even for the casual user. Of course there is at least one solid conspiracy theory stating that this browser <a href="http://www.pbs.org/cringely/pulpit/2008/pulpit_20080905_005415.html">is not meant for the users</a>. Anyhow, I think that messing up the user experience won't really help a product to be embraced by anybody regardless of the creators' original intent. <br /><br />All my enthusiasm just vaporized in 30 seconds after the download. <span style="font-weight:bold;">Why</span>, the installer shoves the damn thing under "%USERPROFILE%\Local Settings\Application Data". I mean <span style="font-weight:bold;">they put the program into a data folder</span>, which not only makes it friggin counterintuitive but raises a bunch of management issues in any sanely managed environment, be it a shared family computer or a corporate environment. (Yeah I know Google support's this von Neumann mindset of everything being just data, but hey...)<br /><br />Next thing is the implementation of the user interface. Chrome gives you a bigger client area <a href="http://sandeep-aparajit.blogspot.com/2008/09/all-new-google-chrome.html">which is good</a>, but this obviously means the removal of the nonclient stuff like the title bar, which is nice for an instant messenger's buddy window or a media player but is kinda frivolous for a web browser which you constantly have in the foreground. It kills interoperability with a whole slew of applications like <a href="http://draginol.joeuser.com/article/322977/WindowBlinds_and_Google_Chrome">WindowBlinds</a> or <a href="http://lifehacker.com/software/productivity/download-of-the-day-gridmove-windows-199404.php">GridMove</a>, and not playing nice with other applications won't make good to your reputation in the hood.<br /><br />The last thing might sound like nitpicking -- that is even more nitpicking than the previous ones :) but as I've said I went to see the Chrome source <a href="http://www.hanselman.com/blog/TheWeeklySourceCode33MicrosoftOpenSourceInsideGoogleChrome.aspx">through the eyes of Scott Hanselman</a> and found out that Google went down the too-clever path and released a client software which relies on undocumented features of an operating system. Call me a old-fashion but I think this wouldn't even be appropriate for a tiny 2-man shop, let alone for GOOG. It's just bad karma.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-50984815917108714342008-09-09T22:28:00.002+02:002008-09-09T23:09:47.347+02:00Microsoft CloudThe Microsoft Cloud is to be seen drifting by. There has been a lot of buzz about clouds in general and about Microsoft's upcoming cloud strategies (see <a href="http://www.readwriteweb.com/archives/peering_into_microsofts_cloud.php">this very neat overview</a>) Of course lot of these conversations have been vague, which is understandable in light of MS being very quiet about technical details regarding the Cloud. I mean, Their Cloud, because it very well seems like they're coming late to the game just to try and <a href="http://en.wikipedia.org/wiki/OS/2">pull an IBM</a> on the other players -- which I think would come together for them very nicely.<br />Why do I think so?<br />Well. Coupla months into the <a href="http://www.microsoftpdc.com/Default.aspx">PDC</a> and <a href="http://www.davidchappell.com/blog/">David Chappell </a> comes up with a <a href="http://www.davidchappell.com/blog/2008/08/short-introduction-to-cloud-platforms.html">Clouding Platforms Paper</a> and it finally makes sense. MS is going to give a flying damn about <a href="http://www.mesh.com/">cloud services</a>. They're building a platform, baby. You see? What's better than locking you into a development environment than ultimately locking you into a deployment environment? Hell, they may even give away free cookies, developer-developer-developer t-shirts and "Microsoft Patterns and Practices" handouts, oh just come and run your application straight on their infrastructure. <br />And oh why, they're pushing <a href="http://msdn.microsoft.com/en-us/magazine/cc163344.aspx">DLR</a> like crazy which would make enterprise development even more opaque: expect <a href="http://blog.headius.com/2008/09/elephant.html">hardcore rubysts go crazy</a> when their code is ultimately put into the same appdomain with some cheesy vb.net code -- and communicating.<br /><br />Nevertheless. I guess I've never been looking forward this much to the PDC (if ever) -- mainly because <a href="http://blogs.msdn.com/oldnewthing/archive/2008/09/08/8931564.aspx">Raymond Chen</a> and secondly because of the unveiling of the MS cloud stuff.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-22164560210405827282008-06-09T14:30:00.000+02:002008-06-09T14:35:14.665+02:00You still have to sell me on WPFThere is an interesting <a href="http://www.itjobswatch.co.uk/jobs/uk/wpf.do">tendency</a> visible on ITJobsWatch regarding Windows Presentation Foundation. It's that the demand for WPF workforce has grown significantly in the past 6 months (as of 2008Q2). I don't really got around peeking into the actual job descriptions there but three quarters of a year has grown the demand for WPF-developer up to 1,2%. Compare this do WinForms' (plumetting) <a href="http://www.itjobswatch.co.uk/contracts/uk/winforms.do">3,9%</a> you may wonder if WPF is really ready to replace WinForms or maybe it has so many pioneering features that it generates a whole lot of new expectations about user interfaces. I must say that <a href="http://en.wikipedia.org/wiki/Homey_D._Clown#H">I Don't Thnik So</a>. Of course I'm biased towards Line Of Business applications, I'm really hesitant about WPF when it comes to LOB because I can't really believe that people won't miss WinForm's DataGridView, the tabbed interfaces, the Masked Textbox or the MDI. No sir. <a href="http://blogs.telerik.com/ZhivkoDimitrov/Posts/06-05-28/WPF_in_action_-_part_1_Designer_s_look_on_WPF.aspx">It's true</a> that <a href="http://www.itwriting.com/blog/?p=455">there has </a>been <a href="http://mdavey.wordpress.com/2007/09/05/wpf-vs-windows-forms/ ">a lot</a> of <a href="http://www.danielmoth.com/Blog/2007/10/wpf-and-windows-forms-integration.html">debate </a>on WPF <a href="http://blogs.msdn.com/jaimer/pages/WPFLobWhy.aspx">LOB usage</a> and <a href="http://blogs.msdn.com/jaimer/pages/WPFForme.aspx">WPF vs. Winforms</a> and WPF <a href="http://www.pbs.org/cringely/pulpit/2007/pulpit_20070629_002360_comments.html ">credibility</a> and a lot of <a href="http://weblogs.asp.net/bsimser/archive/2008/02/25/wpf-or-winforms-choose-wisely.aspx ">promoting </a>of WPF (albeit some spectators say not enough of it) <a href="http://visualstudiomagazine.com/features/article.aspx?editorialsid=1788">from Microsoft</a>, and I believe that WPF is still sorrounded by a lot of FUD, and I don't really want to name the guilty parties. Let me just highlight one of the highlight featues of <a href="http://neverindoubtnet.blogspot.com/2008/01/prism-camp-reflections-on-composite-wpf.html">WPF-based development</a>: the fact that designers can work more closely with programmers on a WPF project. I can't see why and how this could be a very big achievement in a time where people have learned that designers don't give a heck about functionality and <a href="http://diamondinheritance.blogspot.com/2008/06/ui-design-for-programmers.html">programmer's don't give a heck about user interface design</a>. Not because they are evil, simply because there is a whole impendance mismatch between being the designer-world and the developer-world (and the software usability world before we forget what the game is about) so unless you can spend a lot of money on designing and usability testing your user interface, you're effectively busted. And if you're really busted, it doesn't make too much of a difference which technology you actually use.<br /><br />Of course there's a lot of value in WPF which has soon to be explored, but I think that <a href="http://joshsmithonwpf.wordpress.com/2008/04/21/why-use-wpf-if-it-is-not-rad-yet/">we're not there yet</a>. It's really cool tho to have a framework which encourages separation of concerns in an area really really prone to produce ugly and smelly code.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-28873494588660049872008-06-09T14:17:00.002+02:002008-06-09T14:32:15.387+02:00UI design for programmersI've long been wanting to read <a href="http://www.amazon.com/exec/obidos/ASIN/1893115941">User Interface Desing For Programmers</a> by <a href="http://www.joelonsoftware.com/">Joel Spolsky</a>. Which is absolutely positively a must-read for every developer who is concerned about developing great user interfaces. Start by learning that "great" == "highly usable" not "bells and whistles all over the place".<br /><br />The only issue I had with the book was that somehow I thought it indicates that copying an already estabilished design could do you more good than trying to invent something really cool. The notable example here is the <a href="http://office.microsoft.com/en-us/default.aspx">Microsoft Office</a> user interface which is the product of hundreds thousand dollars of careful design and usability screening at Microsoft, which magically justifies of Office UI as great. While this might be true, I really don't want people to believe that The One Microsoft Way is always the great way, because Microsoft employees are people too and they can produce <a href="http://www.joelonsoftware.com/uibook/chapters/fog0000000059.html">shitty user interaction design too</a>.<br /><br />Anyways, UIDfP is a great book, and if you're interested even more in UI design, then you should definitely also read <a href="http://www.amazon.com/About-Face-Essentials-Interaction-Design/dp/0470084111">About Face</a> too.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-79274591479254930662008-05-23T11:32:00.012+02:002008-06-05T08:51:04.311+02:00I Love EmacsI bought a new laptop last week, and when migrating my data over from the old one, I did realize that information vital to manage my stuff (like time and money and projects and stuff) is scattered around in so many places (Outlook, plain text files, <a href="http://www.technorati.com/tag/wickedcoolemacs">ToDoList</a>, <a href="http://www.mechcad.net/products/acemoney/">AceMoney</a>, various timesheets in Excel, etc) that it's starting to look unprofessional. :-)<br />I must admit that I was content with AceMoney, but my project/time-tracking system was what bothered me: <br />- Use a ToDoList to decompose my projects to a tree of tasks.<br />- Track my project-time in a Word table (I know it's cheesy, but Word let's you enter current time very quick)<br />- Cross-reference ToDoList's autogenerated ID's with Word's table<br />- Report with a little WinForms program, using AntiWord to extract the Word table.<br />Boy, there's a whole lot of dependencies there, and a whole lot of clumsyness, but well, that's what I got used to.<br />And that's all past now, because I've found out about Emacs's Org Mode and I'm the happiest person alive to do <a href="http://members.optusnet.com.au/~charles57/GTD/orgmode.html">organize *ALL* my stuff</a> and <a href="http://sachachua.com/wp/2007/12/30/clocking-time-with-emacs-org/">clock my time</a> with it.<br /><br />Plus, becoming the Emacs-enthusiast I always only hoped I would become, I'm even migrating my personal accounting from AceMoney to <a href="http://sachachua.com/wp/2003/10/07/john-wiegleys-ledger/trackback/">Ledger</a> which has an Emacs mode.<br /><br />I must say again, that I was content with AceMoney itself, and I think it's a very handy and clean application. For personal finance, it's far better I my book than jGnash or GnuCash, BUT <a href="http://www.newartisans.com/software/ledger.html">Ledger</a> is the ultimate lean-and-mean solution for you if you live by "less dependencies and more openness the better"-code. And I think you should.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com1tag:blogger.com,1999:blog-4797277320089976279.post-84132423328199882992008-05-15T12:27:00.021+02:002008-05-15T12:54:38.742+02:00Jython StringTemplate un(shallow)copyableI've started porting to Jython a Python application, which uses the Python version of StringTemplate. Right after the start I've bumped into an error when using StringTemplateGroup.<br />The Python code looks like this:<br /><pre><br />def go():<br /> g = stringtemplate.StringTemplateGroup("A","B")<br /> g.getInstanceOf("A_TEMPLATE")<br /></pre><br />When calling <span style="font-style: italic;">go()</span> from Java/Jython, the following exception is raised:<br /><pre><br />Exception in thread "main" Traceback (innermost last):<br /> ...<br /> ...<br /> File "C:\DEV\stringtemplate3\groups.py", line 363, in getInstanceOf<br /> File "C:\DEV\stringtemplate3\templates.py", line 391, in getInstanceOf<br /> File "C:\DEV\stringtemplate3\templates.py", line 369, in dup<br /> File "C:\DEV\jython2.2.1\Lib\copy.py", line 78, in copy<br />Error: un(shallow)copyable object of type <class 'stringtemplate3.errors.DefaultStringTemplateErrorListener'><br /></pre><br /><a href="http://cammacrae.com/blog/2007/09/05/django-jython/">Others</a> have bumped into this error too. It's because Jython doesn't fully implement object copying (in the same sense that CPython doesn't implement it fully -- you cannot just copy arbitraty C objects). It turns out, that this isn't a problem for me, because as soon as I've changed the StringTemplateGroup error listener to my own (copyable) listener, the problem went away. <br /><br />But there's one caveat. I actually choose to NOT use any custom error listener, because console errors are okay for me, so I've tried and put <span style="font-style:italic;">errors=None</span> in the StringTemplateGroup constructor, which is a no-no, because None means "use the default one", which is exactly what I didn't want right now. <br /><br />So the final solution was to redefine go like so:<br /><pre><br />def go():<br /> g = stringtemplate.StringTemplateGroup("A","B")<br /> g.errorListener = None<br /> g.getInstanceOf("A_TEMPLATE")<br /></pre><br />Works like a charm, so far.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-11220472346076979712008-05-04T05:32:00.006+02:002008-05-23T12:23:20.863+02:00Know (not) One EditorI've just started to read the original <a href="http://www.pragprog.com/the-pragmatic-programmer">Pragmatic Programmer</a> book (talk about late-adopting, when did it just came out? last decade??) and there truly is some clever stuff therein. But the nitpicker I am, I've immedieately found something I don't really agree with: the One Editor Tip (#22) The authors say they think is better to know one editor very well, and use it for all editing tasks, which I personally don't think is too clever. At least for me. Because you already know that <a href="http://diamondinheritance.blogspot.com/2008/05/i-love-emacs.html">I Love Emacs</a>, you should also know that every tool has it's place and I don't really want to give up Eclipse's or Visual Studio's services so well tailored to Java/C#. Pragmatic Programmer comes up with this very contrived example, where they indicate that being able to alphabetically sort import statements automatically is a major programmer productivity booster. Give me a break. Use Emacs to <a href="http://orgmode.org/">organizer your life</a> but use a Java IDE that <a href="http://www.eclipse.org/projects/project_summary.php?projectid=eclipse.jdt">understands your code</a>, refactors it, generates stubs for you, and such.<br /><br />Of course I'm just totally mean here, because back in '99 Eclipse and VS weren't even conceived. What I really wanted to point out was, that the more advanced technology becomes, the more specialized knowledge you have to embrace. Back in the days, you were <a href="http://www.technorati.com/tag/wickedcoolemacs">wicked cool with Emacs</a> as an IDE. Nowadays you should <a href="http://www.madcat.com/AboutUs/TedsBlog/tabid/73/EntryID/4/Default.aspx">switch</a> if you want to avoid unneeded complexity when working with enterprise(y) stuff. And you better know some nano/joe/vi cause it's damn sure not all of your clients will have emacs installed on their machine you have to quickfix *now*Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-34816460419363593352008-04-25T09:28:00.063+02:002008-04-28T12:57:18.470+02:00awk vs. Python performanceThere are a lot of debates where people (try to) compare the relative performance of programming languages. These conversations range from producing extensive benchmarks to coming up with esoteric metrics about code complexity/maintainability to deriving even more esoteric metrics from (perceived) language/platform popularity.<br /><br />I thought I would put my two cents into this game by describing a microbenchmark inspired by an actual task of mine: convert a file of delimited values to <a href="http://www.csie.ntu.edu.tw/%7Ecjlin/libsvm/">LIBSVM</a>'s data format. That is transform each line of<br /><pre><br />num1 num2 num3 num4 ...<br /></pre><br />to<br /><pre><br />num1 1:num2 2:num3 3:num4 ...<br /></pre><br />I'm omitting details about (LIB)SVM here, but this isn't relevant now. The point is that the first field is kept in the output, but the rest of them are prefixed with 'number of field in line minus one' and a colon. Note that columns may be omitted in the output, but field indexes must be ascending within a line (this is the so-called sparse matrix format).<br /><br />Of course my first solution is in Python:<br /><pre><br />for line in file:<br /> cols = line.strip().split()<br /> print " ".join(["%i:%s" %(i, x.strip()) <br /> for (i, x) in enumerate(cols)])[2:]<br /></pre><br />For a file with 100k lines and 128 columns, this runs in 38 seconds on my WINDOWS box.<br /><br />Not too bad, but there is an itching disturbance, which does not let the urge to rewrite it in awk escape me. I never wrote a single line in awk, so this should be a good start.<br />And lo, my first awk program:<br /><pre><br />{<br /> printf("%s", $1)<br /> for (i = 2; i <= NF; i++) <br /> {<br /> printf(" %i:%s", i-1, $i)<br /> }<br /> printf("\n")<br />}<br /></pre><br />Let's run it on my WINDOWS box, under CYGWIN, with the same 100k/128cols file as above. <br /><br />...<br /><br />Ouch, this took more than 5 and a half minutes!! Shame <a href="http://bitboost.com/people/intro-to-python-tcs/intro-to-python--2002-11--special-topic--runspeed--002.html">for awk, go Python</a>. Still it sounds like nonsense. Let's see. Both Python and awk are interpreted, so iterations are supposed to be slow(?) The Python code iterates over the columns with a library string function (join), which is implemented in C so it's blazing. awk uses 'for' extensively, so let's optimize it by unwinding the loop:<br /><pre><br />{<br /> print $1, "1:"$2 , "2:"$3 , "3:"$4 , [...]<br /> [...] , "125:"$126 , "126:"$127 , "127:"$128<br />}<br /></pre><br />This is a common technique used in compiler optimization, see how it works in this case. It WORKS, it runs MUCH faster. Same test file, same WINDOWS box and CYGWIN, 45 seconds. Wow, a 7-fold speedup, but still slower than Python. Is this for real? I don't think so. <br /><br />Enter GNU/Linux, just for kicks, another box. The Python program runs in 31 seconds, and hey, wait a minute, we didn't have to wait a minute: the awk program is done in 17 seconds. I say, wow...<br /><br />In a problem this little the use of Python was not too justified. In awk you even get mixable standard input / file handling for free, whereas in Python you must implement it by yourself. But when script portability is a concern, you still should consider Python even for a trivial task like this, because you could get more balanced performance. Of course you could give a try to <a href="http://psyco.sourceforge.net/">Psyco</a>, the Python optimizer, but you will have another dependency, and it may as well turn out that you're performance will even be much worse! More on this later.<br /><br />Right tool for the right task, but know you environment too.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com2tag:blogger.com,1999:blog-4797277320089976279.post-68390574103741069312008-02-25T01:52:00.033+01:002008-05-01T16:50:17.167+02:00Shake Ya Tailfeathers (A Haskell Puzzle)Deciding that the <a href="http://diamondinheritance.blogspot.com/search/label/scala">Scala</a> bandwagon is far too hot right now (in the sense that I should wait a bit till I'll be eligible to late-adopt it) I've started learning <a href="http://www.haskell.org/">Haskell</a> instead.<br /><br />After reading and processing the first some chapters of <a href="http://en.wikibooks.org/wiki/Haskell/YAHT">YAHT</a> and still not getting <a href="http://en.wikibooks.org/wiki/Haskell/CPS">CPS</a>, I nevertheless wanted to produce <span style="font-style:italic;">something</span>, so came up with this:<br /><br />It's a puzzle I've learned a long time ago called Tailfeather.<br />Tailfeather is a number-sequence, where the very first element is lress than the last one, the second element is lress than the second to last element and so on.<br />The task is to write a function with the specification:<br /><pre><br />tailfeather :: Int -> Int<br />{- tailfeather n = b<br /> where 'b' > 1 is the smallest radix in which<br /> the digits written of 'n' <br /> form a Tailfeather sequence of numbers <br />-}<br /></pre><br />A very nice, very entry-level stuff. And the very beauty of it all is that implementing this solution was absolutely straighforward: I was able to focus on the actual problem without worrying about the underlying details (like how to represent a number-sequence -- is that an ArrayList or and array?) <br />Actually there are two sub-problems: <span style="font-weight:bold;">A</span>) rewriting a decimal number to another radix and <span style="font-weight:bold;">B</span>) determining whether a sequence is a Tailfeather.<br /><br />Starting with the latter subtask, all you have to do is break a list into three parts, and solve the task recursively, like so:<br /><pre><br />tailfeather0 (x:xs) = <br /> (x < last xs) && <br /> (tailfeather0 (init xs))<br /></pre><br />First we check if the Tailfeather property holds for the first and the last elements, then cut those elements from the list (that is take the init of the tail) and check the remaining part.<br /><br />Of course the recursion must be terminated (and this next code MUST appear before the previous fragment):<br /><pre><br />tailfeather0 [] = True<br />tailfeather0 [x] = True<br /></pre><br />DONE.<br /><br />Let's see problem A. If you don't know the proper algorithm for converting from decimal to another radix, it is given <a href="http://www.cs.nmsu.edu/~pfeiffer/classes/273/notes/binary.html">here</a> (if the site is down use Wikipedia). <br />My first naive rewrite of the example provided on the linked page yielded the following:<br /><pre><br />convert2base2 0 = []<br />convert2base2 n = (mod n 2) : convert2base2 (div n 2)<br /></pre><br />Looks tight, the only problem is that it returns the digits in reverse order (starting with the least significant bit). Reversing the list after the whole computation would be an option, instead I do it in place:<br /><pre><br />convert2base2 n = convert2base2 (div n 2) ++ [mod n 2]<br /></pre><br />Generalizing the converter to accept any base (don't use this one with b <= 1):<br /><pre><br />convert2base _ 0 = []<br />convert2base b n = convert2base b (div n b) ++ [mod n b]<br /></pre><br />Now that we have our building blocks, let's combine them:<br /><pre><br />tailfeather n = tailfeather1 2 n<br /><br />tailfeather1 b n = <br /> if (b == n)<br /> then b+1<br /> else if tailfeather0 (convert2base b n)<br /> then b<br /> else tailfeather1 (b+1) n<br /></pre><br />That's it.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-22035387238211380652007-12-19T04:07:00.000+01:002007-12-20T11:28:54.646+01:00Scala: Tail-Recursive Higher-Order FunctionLast time I showed a simple handbook <a href="http://diamondinheritance.blogspot.com/2007/12/scala-tail-recursive-factorial.html">tail recursion solution</a>. Digging deeper into <a href="http://www.scala-lang.org/">Scala</a> and functional programming, I've bumped into more interesting stuff. Introduce some new terminology:<br /><br />1. A <span style="font-style: italic;">higher-order function</span> is a function which takes other functions as parameters or returns another function. For example<br /><pre><br /> def sum(f: Int => Int, a: Int, b: Int): Int =<br /> if (a > b) 0 else f(a) + sum(f, a + 1, b)<br /></pre><br />defines a higher-order function which takes a function f plus two integers, and returns the sum of every f(x) in the interval (a, b).<br /><br />2. An <span style="font-style: italic;">anonymous function</span> is simply a function with no name. It's really just syntactic sugar but comes in handy when fiddling with higher-order functions, see:<br /><pre><br /> sum(x => x * x, 10, 20)<br /></pre><br />is a call to the above-defined function, with the (unnamed) square-function as the first argument. <br />Watch how the compiler automagically infers the type of <code>x</code> here.<br /><br />3. <span style="font-style: italic;">Currying</span> is another interesting concept, nicely described <a href="http://moonbase.rydia.net/mental/blog/programming/currying-in-ruby.html">here</a>. Currying lets you decompose argument lists arbitrarily, hence serving a nice ground to refactoring. Taking the sum example, we could rewrite it in a way that we factor out the interval-parameters from it's argument-list, and make it just pass back another function, which in turn deals with the intervals. Like so:<br /><pre><br /> def sum(f: Int => Int): (Int, Int) => Int = {<br /> def sumF(a: Int, b: Int): Int =<br /> if (a > b) 0 else f(a) + sumF(a + 1, b)<br /> sumF<br /> }<br /></pre><br />Try it out:<br /><pre><br /> sum(x => x*x)(10, 20)<br /> def s = sum(x => x*x)<br /> s(10,20)<br /> s(20,30)<br /></pre><br />Putting it in a more concise form, we are currying:<br /><pre><br /> def sum(f: Int => Int)(a: Int, b: Int): Int =<br /> if (a > b) 0 else f(a) + sum(f)(a + 1, b)<br /></pre><br />This is just a more compact form, but means the same as the previous one, you can still go<br /><pre><br /> sum(x => x*x)(10, 20)<br /> def s = sum(x => x*x) _ // note the underscore!<br /> s(10,20)<br /> s(20,30)<br /></pre><br /><br />To wrap it all up, take exercise 5.2.1 from <a href="http://www.scala-lang.org/docu/files/ScalaByExample.pdf">Scala By Example</a>: rewrite <code>sum</code> (the curried version) to use tail-recursion.<br />Converting linear recursion to tail-recursion shouldn't be too hard: instead of recursively calling your method and then applying the iterating function in every step, you accumulate and recursively call on the partial results. Looking at <a href="http://diamondinheritance.blogspot.com/2007/12/scala-tail-recursive-factorial.html">the previous solution</a> you would find it's really easy, and it goes like this:<br /><pre><br /> def sum(f: Int => Int)(a: Int, b: Int): Int = {<br /> def sum1(a: Int, result: Int): Int = {<br /> if (a > b) result<br /> else sum1(a + 1, f(a) + result)<br /> }<br /> sum1(a, 0)<br /> }<br /></pre>Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-10590435028257117062007-12-18T16:40:00.001+01:002007-12-19T04:06:37.679+01:00Scala: Tail-Recursive Factorial<a href="http://www.scala-lang.org/docu/files/ScalaByExample.pdf">Scala By Example</a> has a smallish exercise (4.6.1) to desing the tail-recursive version of the following function:<br /><pre><br /> def fact(n: Int): Int = if (n == 0) 1 else n * fact(n - 1)<br /></pre><br />Tail-recursion means that the recursive call is the last call in the body of the function. In other words, the last operation computed is a recursive function application. In this cited example, the last expression is a multiplication, which renders the body non-tail-recursive.<br /><br />To make the implementation more efficient, we have to turn the body inside-out and accumulate each step's result of the multiplication. This can be nicely done with the great <span style="font-style: italic;">nested function</span> feature, see:<br /><pre><br /> def fact(n: Int) = {<br /> def fact1(n: Int, acc: Int): Int = {<br /> if (n == 0) acc<br /> else fact1(n - 1, n * acc)<br /> }<br /> fact1(n, 1)<br /> }<br /></pre><br />Notice how in this version I didn't mention the return type. The compiler can infer it, but I would consider it good practice to explicitly declare the intended type. <span style="font-weight:bold;">However</span>, recursive methods must always declare their return type (you get a neat compiler error should your forget it).Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-3415345314065361942007-12-17T15:53:00.001+01:002008-04-25T11:34:42.371+02:00Shale, Struts, Spring, Tapesty, Stripes, Wicket, Whatever, RailsI believe I've <a href="http://diamondinheritance.blogspot.com/2007/12/why-3-tier-is-easier-than-2-tier.html">stated</a> my dislike regarding web applications before. And again. I'm not being Luddite here. I like interesting and <a href="http://developers.facebook.com/">exciting stuff</a>, as I told.<br /><br />But taking J2EE and Java as an example, well, web development really can be painful. There are a helluva lot of frameworks, and you really have to learn a stack of stuff before you even can start working. And you really have to figure out the best way to go. As for me, I wish I hadn't gone with <a href="http://www.amazon.com/exec/obidos/ASIN/0131422464/corej2eepatte-20">Core J2EE Patterns: Best Practices</a> first, but <a href="http://www.amazon.com/J2EE-Best-Practices-Performance-Application/dp/0471228850">J2EE Best Practices</a> instead -- or better yet, with <a href="http://www.oreilly.com/catalog/j2eedp/">J2EE Design Patterns</a>. Those worked out the best in may case, at last. For the learning part. As for the Getting The Job Done part, well, I'm still not convinced I went for the best route. I had to create a very simple web app: very little functionality, no persistence, very lean state-machine. KISS being one of my two main principles I've gone with implementing all of it on top of JSP/JSTL: no frameworks attached. DRY being the other principle I came to the conclusion I had to implement the <a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/CompositeView.html">Composite View pattern</a>. Dug up the aforementioned (and a lot of other) books, read everything back and forth, and never got it.<br /><br />And that's when I realized <span style="font-weight: bold;">why we see a ploriferation of opensource Java web application frameworks:</span> Because nobody ever understood what the fuck people were talking about when describing the J2EE patterns, so newcomers had to roll their own framework. Then they had to identify some design considerations in the new framework, so they just simply invented some new patterns, and which started everything all over again. As long as there is no general mindset about which framework(s) to use, people are doomed to the framework-boom. This is why Rails being the <span style="font-style: italic;">de facto</span> web-framework for Ruby is doing so good for the Ruby community.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-46634844030313367342007-12-17T02:04:00.000+01:002007-12-17T02:37:02.616+01:00Event handling in C# for the Java developerFor months now I've been working on a C# WinForms project. Things are supposed to be easy for me, cause C# is just a copy of Java, <a href="http://www.oreilly.com/catalog/beyondjava/">right</a>? Well sure, ok, I'm using C# 2.0, so I'm not supposed to see so much divergence from Java. True enough. There are grave differences however in a lot of areas, generics and events for example. Right this time, I've to delve into the latter.<br /><br />Event-based programming is a powerful mechanism to enable two-way and multiplexed communication between interested parties. Event-based programming is main usage of the <a href="http://en.wikipedia.org/wiki/Observer_pattern">Observer pattern</a>. Events are used extensively in GUI programming. That's why in Java, the events-mechanism is part of the AWT package of the standard library. In .Net world however, it's part of the core framework, which makes it a tad harder to comprehend -- although it allows for more diverse usage of them. For advanced examples check the very useful <a href="http://www.apress.com/book/view/9781590594193">Pro C# 2005 and the .NET 2.0 Platform, Third Edition</a> book from Apress. For a simple, Java-C# side-by-side comparison see <a href="http://www.25hoursaday.com/CsharpVsJava.html#events">Dare's post</a>.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-88274676766625679052007-12-09T21:12:00.000+01:002007-12-09T21:35:35.035+01:00Why 3-tier is easier than 2-tier?I really hate webapps. I'm not talking about fun and hip things like <a href="http://oracleappslab.com/2007/11/21/mix-jruby-on-rails-small-teams-agile-and-its-effects-on-the-world/">JRuby on Rails</a> or (more) exotic and interesting things like <a href="http://www.seaside.st/">Seaside</a>. Pure "enterprise" pretty-graphical-decorations-over-a-relational-database class of stuff makes me cringe really. It's repetitive, unexciting, dull. I hate the way AJAX tries to reinvent the wheel, by relaying logic to the client, once again. More on this later.<br />There is one strong benefit on <span style="font-style: italic;">theserverside</span> tho: web architecture forces you to use some kind of layering. However good you might be in mingling presentation logic with business logic, you will be always given contextual boundaries between the DB the webserver and your client. You can't just grab something from a backend, parse it into an object, and drag it around your 2-tier app as long as the user turns off her machine before Winter Holidays. Endulging yourself into saving a few hours by not caring about immutability, proper encapsulation et al. Not good.<br />Take your webdeveloper hat and present users a real interface.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0tag:blogger.com,1999:blog-4797277320089976279.post-78806206901725881022007-12-08T03:55:00.000+01:002007-12-09T20:01:39.414+01:00IntroductionHi everybody. My name is... Umm. Nevermind. I'm In-House Developer #342 (out of 900) at ABigCompany Inc., or maybe just Developer #1 (out of 1) at StillBornStartup Co., nevermind.<br />I'm the <a href="http://www.joelonsoftware.com/items/2005/01/27.html">bottom 99.9801%</a> and proud of it. Well, not really. Do I represent a population? Maybe. We're the ones who get their hands dirty, because we are tied to clumsy technologies, struggle with dated software, fight bad managing decisions, dump through ex-coworkers' shitty code <a href="http://worsethanfailure.com/">every day</a>, and still we get the job done. And we admire <a href="http://www.artima.com/weblogs/index.jsp?blogger=beckel">the</a> <a href="http://blogs.msdn.com/oldnewthing/">big</a> <a href="http://martinfowler.com/">guys</a>, 'cause boy, they're oh so exciting to read. And we don't even have time to consider <a href="http://www.paulgraham.com/avg.html">beating the averages</a>, 'cause you know, we are them.<br />But still, we get the job done, and sometimes it feels like we have some bragging rights, too.<br />Or sometimes we just must take a quick note, and publish it.<br />And this is perfectly my duty here, to put us on the map --<br /> -- You're welcome.Bob Foltrigghttp://www.blogger.com/profile/03202117636111164368noreply@blogger.com0