<?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-4514957582005722888</id><updated>2011-08-07T08:21:39.842-04:00</updated><category term='math'/><category term='plpgsql'/><category term='postgresql'/><category term='webstandards'/><category term='javascript'/><category term='sql'/><category term='git'/><category term='php'/><category term='html'/><category term='intro'/><category term='microsoft'/><category term='github'/><category term='database'/><title type='text'>/dev/neal</title><subtitle type='html'>Thoughts about software development.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>20</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-1038760447947585082</id><published>2011-07-01T08:42:00.003-04:00</published><updated>2011-07-01T09:00:42.140-04:00</updated><title type='text'>ECMAScript test262 - Awesome, But...</title><content type='html'>&lt;p&gt;Today the IE blog linked to &lt;a href="http://test262.ecmascript.org/"&gt;ECMAScript test262&lt;/a&gt;, a test suite to verify conformance to the JavaScript spec.&lt;/p&gt;
&lt;p&gt;First, kudos to ECMA for coming out with a test suite - having a benchmark for compatibility will drive the browser vendors to improve their interoperability. Everyone wins there. Also, the visual design of the page is very nice - something we don't always get from standards bodies.&lt;/p&gt;
&lt;p&gt;Second, kudos to the IE team for getting the top score with their IE 10 preview! And IE 9 is way up there also. Seriously, good job guys. We know that I have my problems with Microsoft's browser policies, but nobody can deny that the IE team is doing great work over there.&lt;/p&gt;
&lt;p&gt;Now, the bad news (emphasis mine):&lt;/p&gt;
&lt;blockquote&gt;Test262 is being developed by the members of Ecma TC39. &lt;em&gt;Ecma's intellectual property policies, permit only Ecma members to directly contribute code to the project.&lt;/em&gt; However, a public mailing list is used to coordinate development of Test262. If you wish to participate in the discussion please subscribe. Bug reports and suggestions should be sent to the mailing list.&lt;/blockquote&gt;
&lt;p&gt;(I can't link you directly to that quote because they didn't use a separate URL - it's revealed by JavaScript when you click on the "Development" link in the top navigation. They didn't even use a hash-bang link!)&lt;/p&gt;
&lt;p&gt;If those are your policies, guys, &lt;em&gt;change your policies&lt;/em&gt;. This is exactly the kind of thing that should be open source. You're not trying to sell it. Lots of talented people have incentive to contribute to it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-1038760447947585082?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/1038760447947585082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=1038760447947585082' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/1038760447947585082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/1038760447947585082'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2011/07/ecmascript-test262-awesome-but.html' title='ECMAScript test262 - Awesome, But...'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-2955224490741755350</id><published>2011-06-14T23:36:00.002-04:00</published><updated>2011-06-14T23:59:24.856-04:00</updated><title type='text'>Why do developers hate IE?</title><content type='html'>&lt;p&gt;It has to be a tough gig being on the Internet Explorer team at Microsoft. Mention IE in a room full of web developers and the best reaction you can probably expect is a sigh. You&amp;#8217;re more likely to see fists shaken at the sky or hear muttered curses. But why?&lt;/p&gt; &lt;p&gt;Some people explain the IE hate as just part of an anti-Microsoft prejudice. That&amp;#8217;s sort of a non-answer. Why do people have negative feelings toward Microsoft? There are reasons for those anti-Microsoft feelings. One of those reasons is certainly just discomfort people have toward large companies that have power over them. But those kind of feelings apply to Google and increasingly Apple as well. In the case of Microsoft, though, web developers can look back at an incident where that power was wielded against something they loved - Netscape.&lt;/p&gt; &lt;h2 id='the_ghost_of_netscape'&gt;The Ghost of Netscape&lt;/h2&gt; &lt;p&gt;For many web developers today, Netscape was their first web browser. Think about that. Netscape &lt;em&gt;was&lt;/em&gt; the web at a time when a lot of us fell in love with the web. What are we today? Web developers. Turns out we liked the web quite a bit. And we liked Netscape.&lt;/p&gt; &lt;p&gt;Microsoft killed Netscape in a way that seemed very unfair.&lt;/p&gt; &lt;p&gt;Microsoft bundled IE with its near-ubiqutous operating system. This was in the bad old days of the &amp;#8220;Browser Wars&amp;#8221; when there were no web standards to speak of. If you wanted to do anything fancy at all (and standards for &amp;#8220;fancy&amp;#8221; were much lower), you had to think very hard about which browser you were on. Microsoft&amp;#8217;s move to tie the browser to the OS said: &amp;#8220;Target what you want, but everybody&amp;#8217;s going to have IE. They might not have Netscape.&amp;#8221;&lt;/p&gt; &lt;p&gt;It still pains me to say it, but Microsoft pushed the state of the art for web browsers forward a lot in those years. A lot of the great browser features we have today came from IE. Internet Explorer became the better browser. But what we remember is what Microsoft did to Netscape. We remember how they betrayed our trust and killed something we loved.&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;But that&amp;#8217;s all in the past, right? Ancient history in Internet years. Microsoft got slapped by the DoJ and some European anti-trust stuff also - they&amp;#8217;ve done their time. What about the IE of today? Well, not so fast.&lt;/p&gt; &lt;h2 id='the_ie_of_yesterday'&gt;The IE of Yesterday&lt;/h2&gt; &lt;p&gt;Microsoft had won the browser wars by the time it released IE 5.5. Netscape 5 was never released. When Netscape gave its source code to the community, the community decided: &amp;#8220;uh, let&amp;#8217;s just start from scratch.&amp;#8221; Netscape 6 was released as just a re-branded copy of a pre-1.0 version of Mozilla. It was buggy and a resource hog.&lt;/p&gt; &lt;p&gt;It&amp;#8217;s not surprising that Microsoft released IE 6 and declared victory. Netscape had been vanquished. Microsoft had proven that they could come from behind and create a better browser. I imagine there were ticker-tape parades in Redmond.&lt;/p&gt; &lt;p&gt;The year was 2001. Little did anyone suspect that the year would stay 2001 for more than a decade.&lt;/p&gt; &lt;h2 id='support_cycles'&gt;Support Cycles&lt;/h2&gt; &lt;p&gt;Complex software tends to have bugs. The more complex, the more chance for bugs. Bugs in network-connected software tend to get exploited and turned into security holes. The web browser is simultaniously one of the most complex and one of the most network-connected pieces of software on any given computer. If you don&amp;#8217;t keep your browser up-to-date with the latest security patches, you&amp;#8217;re going to get exploited.&lt;/p&gt; &lt;p&gt;So Microsoft supported IE 6. Patches came out at regular intervals. But they were mostly just security fixes. Microsoft wouldn&amp;#8217;t fix rendering bugs because they didn&amp;#8217;t want to rock the boat. Sites out there depended on the sometimes quirky (to put it politely) rendering that IE gave them.&lt;/p&gt; &lt;p&gt;Meanwhile Mozilla hit 1.0. Then Firefox grew out of Mozilla. Then it turned out people really liked Firefox. Even Apple got in to the browser race with Safari. Microsoft decided they had to step up their game, so they got the team back together and came out with IE 7 around the same time Firefox 2.0 was coming out - late 2006.&lt;/p&gt; &lt;p&gt;IE 7 was a huge improvement over IE 6. It had a tab-based interface that had become popular - that was nice for users. Developers cheered because a lot of the rendering bugs they had been tearing their hair out over with IE 6 had been fixed. &amp;#8220;Finally,&amp;#8221; we thought, &amp;#8220;these IE 6 bugs we have been wrestling with for five years are no more!&amp;#8221;&lt;/p&gt; &lt;p&gt;Microsoft put IE 7 out through Windows Update&amp;#8230; but as an optional update. Optional? It turns out that some &amp;#8220;enterprises&amp;#8221; didn&amp;#8217;t want to update to IE 7. They all had internal apps that depended on the rendering bugs in IE 6.&lt;/p&gt; &lt;p&gt;And enterprises weren&amp;#8217;t the only IE users that stayed on IE 6. Lots of Windows users never consider installing optional updates. They&amp;#8217;re barely comfortable installing the required updates - an optional update just sounds like an invitation to break their computer.&lt;/p&gt; &lt;p&gt;So at the end of 2006 Microsoft was supporting two browsers - IE 6 and IE 7. And that meant that web developers had to support IE 6 and 7 also. All our cheers at the release of IE 7 turned to cries of frustration.&lt;/p&gt; &lt;p&gt;The pattern repeated when IE 8 came out in 2009 - optional updates. Microsoft started supporting three browsers - web developers supported three versions of IE.&lt;/p&gt; &lt;p&gt;Earlier this year Microsoft released IE 9. It is a huge improvement over IE 8. It supports nice things like box-shadows and rounded corners. It has a vastly improved JavaScript engine. It is still an optional update for all IE users. Actually not all IE users - users on Windows XP &lt;em&gt;can&amp;#8217;t&lt;/em&gt; update to IE 9 - the browser requires Windows Vista or 7. Now we are all supporting four very different versions of IE and nobody is happy.&lt;/p&gt; &lt;p&gt;Why is IE 6 still supported?! It is apparently Microsoft&amp;#8217;s policy to keep supporting the major browser version that was current when the operating system was released. For Windows XP, that browser was IE 6. And when will Windows XP support end? I think it&amp;#8217;s not until 2014. At that point IE 6 will have been on the market for thirteen years. Thirteen years!&lt;/p&gt; &lt;p&gt;This should have never happened. Microsoft bowed to the wishes of some of its big business clients by supporting old major releases of IE. In doing so they decided to screw over web developers. Does that piss us off? You bet it does!&lt;/p&gt; &lt;p&gt;When IE 7 came out, IE 6 should have ended. You want a security patch for IE 6? Here - it&amp;#8217;s called IE 7. Sure it would have been painful for a lot of companies, but guess what - supporting multiple versions of IE is a hell of a lot more painful to a lot more companies. And those companies that still haven&amp;#8217;t broken out of IE 6-land? They are in for one hell of a rude awakening when XP support ends. All this &amp;#8220;don&amp;#8217;t rock the boat&amp;#8221; policy has gotten us is a really unstable boat.&lt;/p&gt; &lt;p&gt;And Microsoft hasn&amp;#8217;t changed their policy. They&amp;#8217;re still going to support IE 7 until Vista falls out of support. And IE 8 until Windows 7 is no more. How long will that be? How many different versions of IE will we have to worry about?&lt;/p&gt; &lt;p&gt;Make no mistake - IE is a giant dick in the eye of all web developers. And Microsoft has chosen to make it so.&lt;/p&gt; &lt;p&gt;How can they fix it? They can stop supporting major releases for so long. Just support the latest version! What the hell is a &amp;#8220;major&amp;#8221; release anyway? Google increases the version number of Chrome any time someone sneezes. It doesn&amp;#8217;t matter. Call the next version of IE 9.0.1 and make it a required update to all 9.0 users! Do not make an IE 10 that you support along side IE 6, 7, 8 and 9! What the fuck is wrong with you people?&lt;/p&gt; &lt;h2 id='a_big_problem'&gt;A Big Problem&lt;/h2&gt; &lt;p&gt;Remember Steve Ballmer&amp;#8217;s &amp;#8220;Developers, developers, developers&amp;#8221; speech? He was right. Developers are important. It is not good business for Microsoft to be hated by the developer community. And guess what - a large percentage of developers are web developers. And Microsoft has fucked us over for years.&lt;/p&gt; &lt;p&gt;Could they make us happy now? I don&amp;#8217;t know. Maybe Microsoft&amp;#8217;s best strategy would be to continue fucking us over forever. Eventually all developers will hate Microsoft and never build on one of their platforms again. But in the meantime they can squeeze all their locked-in customers to the fullest.&lt;/p&gt; &lt;p&gt;I really can&amp;#8217;t imagine a Microsoft that could win me over now. A more useful web just makes Microsoft&amp;#8217;s main products less important. Why would they help it? But the web is moving forward weather Microsoft comes along or not. And in spite of anything Microsoft does, it&amp;#8217;s a wonderful ride.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-2955224490741755350?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/2955224490741755350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=2955224490741755350' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/2955224490741755350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/2955224490741755350'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2011/06/why-do-developers-hate-ie.html' title='Why do developers hate IE?'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-8086995395122788664</id><published>2011-06-03T07:48:00.002-04:00</published><updated>2011-06-03T07:51:41.332-04:00</updated><title type='text'>Vim-Columbus</title><content type='html'>I'm really excited about the new Vim user group we're starting up in Columbus: &lt;a href="http://vim-columbus.github.com"&gt;Vim-Columbus&lt;/a&gt;. I started the page while we were talking about it at Code and Coffee yesterday. That evening after work, inspiration struck and I decided to make the page itself look like Vim.

I am inordinately pleased with myself (I get like that sometimes).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-8086995395122788664?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/8086995395122788664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=8086995395122788664' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/8086995395122788664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/8086995395122788664'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2011/06/vim-columbus.html' title='Vim-Columbus'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-7728064946708536754</id><published>2011-03-12T07:23:00.005-05:00</published><updated>2011-03-12T08:30:41.130-05:00</updated><title type='text'>Is Ruby the Best Language?</title><content type='html'>&lt;p&gt;I was noodling around with some Ruby the other day, and all of a sudden I ran into a situation where I wanted to do a partial function application. But how do you do that in Ruby? It can certainly be done, but it felt very awkward to me and made my code less readable than the non-partially-applied alternatives. So I didn't do it.&lt;/p&gt;

&lt;p&gt;For me, higher-order functions in Ruby are the language's only blemish. It seems almost unfair to ding Ruby for that, because Ruby (at least since 1.9.x) does higher-order functions pretty admirably. It's just not as elegant as the rest of the language.&lt;/p&gt;

&lt;p&gt;Ruby has set an extremely high bar. The lack of ceremony in the language makes it extremely readable. The purity of its "everything is an object" stance makes it very writable. And its pervasive methods of introspection make it amazingly powerful.&lt;/p&gt;

&lt;p&gt;But why did I even have the urge to make a partially applied function? Because I've been doing a lot of JavaScript lately, and JavaScript is all about the functions.&lt;/p&gt;

&lt;p&gt;Ruby and JavaScript take sort of opposite approaches to object properties vs. methods. When you want to reach into an object in Ruby, you always talk to a method. So-called "properties" on Ruby objects are really just getter and setter methods with a little syntactic sugar applied.&lt;/p&gt;

&lt;p&gt;In JavaScript, objects mostly only have properties. A "method" in JavaScript is just a property that happens to be a function. (You can define real getters and setters in modern versions of JavaScript, but browser support is not yet pervasive.)&lt;/p&gt;

&lt;p&gt;Which approach is better? I would have to say Ruby's. JavaScript seems more fragile in its property-centricity. For example, if you want to pass a method as a callback in JavaScript you have to think about weather it needs to be called &lt;em&gt;as&lt;/em&gt; a method or if it is OK to be called as a stand-alone function. If it needs to be called on a particular object you end up wrapping it in another function.&lt;/p&gt;

&lt;p&gt;When it comes to JavaScript's advantage - higher-order functions - Ruby sort of cheated. By making a special case of passing a single function (a block), Ruby made the 80% use case extremely easy and simple.&lt;/p&gt;

&lt;p&gt;So is Ruby the best language? Well, I probably wouldn't have worried about higher-order functions so much if I wasn't using JavaScript. What other blemishes might Ruby have that I just never run into? I guess it's not surprising that you can only compare languages that you have really used.&lt;/p&gt;

&lt;p&gt;But Ruby is definitely the best language that I know.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-7728064946708536754?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/7728064946708536754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=7728064946708536754' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/7728064946708536754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/7728064946708536754'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2011/03/is-ruby-best-language.html' title='Is Ruby the Best Language?'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-7212934063569381872</id><published>2009-12-03T23:41:00.003-05:00</published><updated>2009-12-04T00:27:50.446-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>node.js</title><content type='html'>&lt;p&gt;I can't stop thinking about &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;node.js is &lt;a href="http://code.google.com/p/v8/"&gt;Google's V8 JavaScript engine&lt;/a&gt; tied together with some non-blocking IO libraries. Those libraries include DNS, TCP, HTTP and file access.&lt;/p&gt;
&lt;p&gt;Now, I've been dreaming about a good server-side JavaScript solution for quite a while. JavaScript is an excellent language, and chances are you're using it already on the client side. Why not use it on the server side also? That's not the main reason that node's author (Ryan Dahl) chose it though. He chose it because JavaScript is already very callback-centric, and node is designed to use callbacks in place of multi-threading. Whenever you do something that might take a little while (like hitting the network or disk), you set it up and then pass it a callback. Your callback will know how to handle the data that gets returned. Meanwhile, code keeps executing. This is much better than having one thread running for each connection, because those threads are usually waiting for the network or the database or even disk. When you have all those idle threads you pay a penalty in context-switching and memory overhead.&lt;/p&gt;
&lt;p&gt;If you still need more convincing, check out &lt;a href="http://s3.amazonaws.com/four.livejournal/20091117/jsconf.pdf"&gt;Ryan's slides from his JSConf.eu talk (PDF)&lt;/a&gt;. They're very readable slides.&lt;/p&gt;
&lt;p&gt;It's still early days for node.js. The project (what do you even call it - a server, I guess?) can serve up HTTP very well, but it doesn't give you a framework by itself. Consequently there are frameworks popping up all over for it, following all the patterns of frameworks implemented for other languages. One thing the server is genuinely missing is database support. A PostgreSQL binding is in the works, which sounds great to me. MySQL might be harder because it doesn't have a non-blocking library, but who needs MySQL when you have Postgres? :-P&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-7212934063569381872?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/7212934063569381872/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=7212934063569381872' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/7212934063569381872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/7212934063569381872'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2009/12/nodejs.html' title='node.js'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-3026991398420043665</id><published>2009-05-29T13:39:00.002-04:00</published><updated>2009-05-29T13:54:37.431-04:00</updated><title type='text'>Network Printer</title><content type='html'>&lt;p&gt;If you're trying to set up a printer that is attached to the network, do you think you should select the option that says "Local printer attached to this computer" or the option that says "A network printer, or a printer attached to another computer"? Hint: this is Windows.&lt;/p&gt;&lt;p&gt;Scroll down to the bottom of the dialog box for the answer. I can't understand why they don't just relabel the options. I would make a guess, but Al Gore tells me that my sarcasm footprint is already too high.&lt;/p&gt;&lt;a href="http://www.flickr.com/photos/neallindsay/3575814171/" title="addprinter by bitsronaut, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3628/3575814171_2d8394c25e_o.png" width="500" height="385" alt="addprinter" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-3026991398420043665?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/3026991398420043665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=3026991398420043665' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/3026991398420043665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/3026991398420043665'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2009/05/network-printer.html' title='Network Printer'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-8348189947865771949</id><published>2008-10-15T11:48:00.004-04:00</published><updated>2008-10-15T11:54:53.545-04:00</updated><title type='text'>The Forgotten Half of Computer Literacy</title><content type='html'>&lt;p&gt;&lt;a href="http://daringfireball.net"&gt;Gruber&lt;/a&gt; today &lt;a href="http://daringfireball.net/linked/2008/10/15/nyt-campaign-api"&gt;noted&lt;/a&gt; that the New York Times is &lt;a href="http://open.blogs.nytimes.com/2008/10/14/announcing-the-new-york-times-campaign-finance-api/"&gt;adding an API&lt;/a&gt; to their campaign finance data (bravo!). He also pointed to an article from 2006 titled "&lt;a href="http://www.ojr.org/ojr/stories/060605niles/"&gt;The programmer as journalist: a Q&amp;amp;A with Adrian Holovaty&lt;/a&gt;".&lt;/p&gt;
&lt;p&gt;The interview is pretty concise and lays out how and why journalism can better be accomplished with help from software. Holovaty breaks down the journalistic process of collecting, filtering and disseminating information and how computer automation can be applied to each step, leading to better journalism. Near the end, he argues that all journalists should have at least some experience with programming, if for no other reason than just to know what is possible.&lt;/p&gt;
&lt;p&gt;His points are persuasive, but they're also applicable to almost any field - not just journalism. I believe that everyone should at least know how to write software in the same way that everyone should be able to write in general.&lt;/p&gt;
&lt;p&gt;Literacy describes the ability to read and write. When we talk about computer literacy, we usually think of the ability to use software - which I would liken to the "reading" part. We often ignore the "writing" part - the ability to make software. But writing software is incredibly powerful. If you write a page-turning novel, it inspires the imagination of everyone who reads it. If you write an informative article, all its readers are enlightened. Likewise, great software entertains and/or empowers every person who makes use of it.&lt;/p&gt;
&lt;p&gt;The analogy holds up pretty well. No - it holds up too well - it's not an analogy at all! Writing software &lt;em&gt;is&lt;/em&gt; writing. It might have an apparently arcane grammar, but making software is merely writing down instructions that a computer can understand. And the language is not more complicated than English. Have you seen English? It's the most bastardized, crazy language on the planet! The languages we use to talk to computers are incredibly simple - necessarily so. Computers aren't going to pick the correct meaning of a word out of a dozen possibilities based on context. They're not going to detect our sarcasm in step two of the instructions we give them. They need to be told exactly what to do in the simplest way possible, and programming languages are the way we do that. Consequently, programming languages have only gotten simpler over the years. Strong typing is going the way of the dodo. How often do you need to know what a pointer is any more? All the complicated things are getting hidden away in libraries or abstracted by the VM. There has never been a easier time to become a programmer than today.&lt;/p&gt;
&lt;p&gt;I don't believe that everyone has to become a "programmer" any more than everyone has to become a "writer". But everyone should be able to write; a sentence, a paragraph, an essay, a script that their computer executes.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-8348189947865771949?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/8348189947865771949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=8348189947865771949' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/8348189947865771949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/8348189947865771949'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2008/10/forgotten-half-of-computer-literacy.html' title='The Forgotten Half of Computer Literacy'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-9066809166156264098</id><published>2008-10-14T23:24:00.004-04:00</published><updated>2009-09-02T09:29:10.525-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='github'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>Exercising Git</title><content type='html'>&lt;p&gt;At work I use SVN for source control, but I've been itching to try out Git. I also recently stumbled across &lt;a href="http://projecteuler.net"&gt;Project Euler&lt;/a&gt;, a series of math problems intended to be solved by writing small programs. I think you see where this is going. So - as of a few minutes ago - my Project Euler solutions (such as they are) are up on &lt;a href="http://github.com/neall/"&gt;my github account&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I am a complete Git newb, so I followed some instructions on setting up Git and a new github repository. Since I can see all the code on github, I guess it's working.&lt;/p&gt;
&lt;p&gt;My Project Euler solutions have been very fun so far. You're allowed to implement your solution in whatever language you want. I chose Ruby because it is the most expressive language I've found.&lt;/p&gt;
&lt;p&gt;My solutions involving factoring primes have been a mixed bag. I think I did ok finding the largest prime factor of 600851475143 (problem 3), but my solution to problem 10 (sum all the primes below two million) was an ugly brute force. I really should have known a better algorithm (I won't say it by name here, but it was referenced in one of the Dark Tower books).&lt;/p&gt;
&lt;p&gt;Some of the problems have been quite easy, but I'm only up to problem 17. I've peeked ahead and it looks like they get pretty tough. Sometimes it feels like using Ruby is cheating - for instance, problem 16 is "sum all the digits of 2^1000". Pity the poor C++ programmer!&lt;/p&gt;
&lt;p&gt;The tricks I have up my sleeve are mainly inject, memoization and recursion. Recursion is especially helpful in simplifying problems. Memoization can be invaluable when you're performing expensive math. Inject is just plain fun - who wants to write all that boring loop code?&lt;/p&gt;
&lt;p&gt;One reason that people might shy away from Ruby in Project Euler is the perceived performance benefit of more low-level languages. That is a complete red herring. When I was writing assembly language in high school, I read Michael Abrash's &lt;a href="http://www.byte.com/abrash/"&gt;"Graphics Programming Black Book"&lt;/a&gt;. One thing I learned was that extremely optimized assembly language will only net you a 2x to 10x improvement over compiled code. "Isn't that a lot?" you say? No - it is nothing compared to the gains you can usually get from improving your algorithms - often orders of magnitude. Using an expressive high-level language like Ruby allows you to concentrate on the high-level algorithms. I was especially proud of my solution to &lt;a href="http://projecteuler.net/index.php?section=problem&amp;amp;id=15"&gt;problem 15&lt;/a&gt;. I first broke the problem down with recursion. When that ran for more than a minute I realized I was solving the same problem more than once so I memoized it. Now it runs in less than a second even on my super-slow EeePC. Of course, there are much more elegant solutions out there - my solution that I was so proud of was far from the best. It just goes to show how far a good algorithm can take you.&lt;/p&gt;
&lt;p&gt;This turned out to be a rambling post - sorry about that. In conclusion, Git and github are great, Project Euler is fun and algorithms matter. Good night!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-9066809166156264098?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/9066809166156264098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=9066809166156264098' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/9066809166156264098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/9066809166156264098'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2008/10/exercising-git.html' title='Exercising Git'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-3401348499135640430</id><published>2008-08-28T22:18:00.000-04:00</published><updated>2008-08-28T22:19:38.614-04:00</updated><title type='text'>Banish XSS Forever!</title><content type='html'>&lt;p&gt;The two biggest classes of web site vulnerabilities are SQL injection and Cross-Site Scripting (XSS). The ever-vigilant programmer can reduce the occurence of these problems, but proper architecture can eliminate them completely.&lt;/p&gt;
&lt;h3&gt;The SQL Problem Has Been Solved&lt;/h3&gt;
&lt;a href="http://xkcd.com/327/"&gt;&lt;img src="http://imgs.xkcd.com/comics/exploits_of_a_mom.png" style="border: 0;" title="You've probably seen this already." /&gt;&lt;/a&gt;
&lt;p&gt;I couldn't stop myself from referencing the XKCD SQL injection example. But for coders using prepared statements or parameterized SQL, SQL injection is already a bad memory. The problem of unsanitized data getting into your SQL can be avoided by following one rule: Never put &lt;strong&gt;any&lt;/strong&gt; data into SQL. Instead of this:&lt;/p&gt;
&lt;pre class="code"&gt;$sql = "SELECT id FROM usertable WHERE username = '".$uname."';";
$result = pg_query($sql);&lt;/pre&gt;
&lt;p&gt;You do this:&lt;/p&gt;
&lt;pre class="code"&gt;$sql = 'SELECT id FROM usertable WHERE username = $1';
$result = pg_query_params($sql, array($uname));&lt;/pre&gt;
&lt;p&gt;Now when a script kiddie pastes some exploit code into my account sign-up page, he can't drop my tables or read all my password hashes. Little Bobby Tables can grow up to live a rich life without incurring the wrath of any more schools.&lt;/p&gt;
&lt;h3&gt;The XSS Problem is the Same Problem&lt;/h3&gt;
&lt;p&gt;SQL injection happens when unescaped data is interpreted by your SQL parser. XSS happens when unescaped data is interpreted by the client web browser. It's really the same problem, and the solution is pretty much the same.&lt;/p&gt;
&lt;p&gt;I said "pretty much" because in the case of SQL, all the main relational databases have added APIs to allow "data" to be sent seperately from the "query". I don't see browser makers doing anything analogous. But you don't need your database to support parameterized queries natively - you can use a wrapper library that does it for you. Likewise, web site developers can adopt web frameworks that enforce the seperation of markup and text on the server side.&lt;/p&gt;
&lt;h3&gt;DOM View to the Rescue?&lt;/h3&gt;
&lt;p&gt;Stay with me here. The "traditional" way to build web pages programmatically was top-to-bottom. First you send your http headers, your DTD, your opening &amp;lt;html&amp;gt; and &amp;lt;head&amp;gt; tags, etc. until you finally send the closing &amp;lt;/html&amp;gt; tag at the end. We're treating the web page as a string of text. Just because it is text on the wire doesn't mean we need to treat it that way. We should treat it as a tree, just like the browser on the other end does after it parses all that HTML.&lt;/p&gt;
&lt;p&gt;Anyone who writes JavaScript is familiar with the Document Object Model (DOM) that is the web browser's internal representation of the web page. The page is a tree, with the &amp;lt;html&amp;gt; element at the root, and every element or chunk of text as a node. I propose that we write web frameworks that build web pages as trees - never having the programmer output any markup.&lt;/p&gt;
&lt;p&gt;This system would start out with a basic empty web page.&lt;/p&gt;
&lt;pre&gt;html
|-head
| \-title
\-body&lt;/pre&gt;
&lt;p&gt;Set the title (please don't mind the syntax of my psuedo-code):&lt;/p&gt;
&lt;pre class="code"&gt;head.title.appendtext("Hello World")&lt;/pre&gt;
&lt;pre&gt;html
|-head
| \-title
|   \-textnode value="Hello World"
\-body&lt;/pre&gt;
&lt;p&gt;Add a footer&lt;/p&gt;
&lt;pre class="code"&gt;body.appenddiv(class="footer").appendtext("&amp;copy; 2008 Me")&lt;/pre&gt;
&lt;pre&gt;html
|-head
| \-title
|   \-textnode value="Hello World"
\-body
  \-div class="footer"
    \-textnode value="&amp;copy; 2008 Me"&lt;/pre&gt;
&lt;p&gt;Add our main content:&lt;/p&gt;
&lt;pre class="code"&gt;maindiv = body.prependdiv(class="maincontent")
maindiv.appendh1.appendtext("Hello World!")&lt;/pre&gt;
&lt;pre&gt;html
|-head
| \-title
|   \-textnode value="Hello World"
\-body
  |-div class="maincontent"
  | \-h1
  |   \-textnode value="Hello World!"
  \-div class="footer"
    \-textnode value="&amp;copy; 2008 Me"&lt;/pre&gt;
&lt;p&gt;And so on. When you're done, your framework generates the HTML or XHTML or what-have-you from the tree and spits it out to the client. No markup is ever generated by hand and text can only go into text nodes or attribute values. The markup generator will automatically make the "&amp;amp;copy;" for the copyright symbol and knows how to escape quotes embedded in attribute values as well.&lt;/p&gt;
&lt;p&gt;This is the solution I propose - not the sisyphean task of "remember to escape your strings". Maybe I'll build it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-3401348499135640430?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/3401348499135640430/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=3401348499135640430' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/3401348499135640430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/3401348499135640430'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2008/08/banish-xss-forever.html' title='Banish XSS Forever!'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-9071493414461667632</id><published>2008-08-28T11:12:00.002-04:00</published><updated>2008-08-28T11:12:00.984-04:00</updated><title type='text'>Stack Overflow</title><content type='html'>&lt;p&gt;I have been having so much fun with the beta of Stack Overflow - a new programmer help site by &lt;a href="http://www.codinghorror.com/blog/"&gt;Jeff Atwood&lt;/a&gt; and &lt;a href="http://www.joelonsoftware.com/"&gt;Joel Spolsky&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you're interested in the beta, you can get in &lt;a href="http://blog.stackoverflow.com/2008/08/bad-news-good-news/"&gt;here&lt;/a&gt; (scroll down a bit). Hopefully it will be live to the world soon. I expect scaling issues (not that it's had any yet, but I expect massive popularity).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-9071493414461667632?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/9071493414461667632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=9071493414461667632' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/9071493414461667632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/9071493414461667632'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2008/08/stack-overflow.html' title='Stack Overflow'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-89771687580318076</id><published>2008-07-30T13:56:00.000-04:00</published><updated>2008-07-30T13:58:21.081-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>In Praise of jQuery</title><content type='html'>&lt;p&gt;At work I'm starting to weave &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; into the interface to our job database. Until now my Javascript needs have been limited to a menu at the top of the screen. Now I am trying to create a time entry interface, and it is complicated.&lt;/p&gt;&lt;p&gt;Each employee needs to be able to say "I worked on task alpha from 8:00 to 10:10, beta from 10:10 to 12:00 and gamma from 13:00 to 17:00". It needs to be easy to use, give them a list of the tasks that they are working on to choose from and make sure that their times don't overlap. This is all to say that some more advanced scripting is called for. I hacked around with vanilla Javascript for a while, but soon decided to check out one of the free libraries available.&lt;/p&gt;&lt;p&gt;Enter jQuery, and I could not be happier. The core feature of jQuery is that you can select elements in your document by xpath or CSS-style selectors. &lt;strong&gt;This alone is well worth the price of entry.&lt;/strong&gt; For instance, originally I had to do a "&lt;code&gt;document.getElementById("timebar")&lt;/code&gt;", use "&lt;code&gt;.getElementsByTagName("div")&lt;/code&gt;" on that, and then check each element's class as I looped through them to remove a class. Now I just write: "&lt;code&gt;$("#timebar .selentry").removeClass("selentry")&lt;/code&gt;". That's an if statement, a loop and a lot of long DOM method names I didn't need.&lt;/p&gt;&lt;p&gt;jQuery gives you all sorts of additional nice things - most of which I haven't tried yet. It includes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Easy creation and insertion of new elements into your document tree.&lt;/li&gt;&lt;li&gt;Add, modify and remove attributes.&lt;/li&gt;&lt;li&gt;Modify styles on an element without wiping out unrelated styles.&lt;/li&gt;&lt;li&gt;Easily add event handlers with cross-browser problems smoothed out for you.&lt;/li&gt;&lt;li&gt;Iterators.&lt;/li&gt;&lt;li&gt;Handle ajax requests easily.&lt;/li&gt;&lt;li&gt;&lt;a href="http://ui.jquery.com"&gt;Plugins&lt;/a&gt; to handle even more things. (I was able to easily drop the date picker into my existing date fields.)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I resisted using a Javascript library for a long time. I thought they were just for fancy ajax and slide-in effects. I also worried that they would force all my scripts to work inside their framework. With jQuery at least, my fears were unfounded. Even if you just use it to find elements in your document tree it will be extremely helpful.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-89771687580318076?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/89771687580318076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=89771687580318076' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/89771687580318076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/89771687580318076'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2008/07/in-praise-of-jquery.html' title='In Praise of jQuery'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-6112234363500786267</id><published>2008-03-25T14:23:00.002-04:00</published><updated>2008-03-25T14:23:57.740-04:00</updated><title type='text'>Bug Zero</title><content type='html'>&lt;p&gt;Bug zero is that the program does not exist. Fix that bug first.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-6112234363500786267?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/6112234363500786267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=6112234363500786267' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/6112234363500786267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/6112234363500786267'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2008/03/bug-zero.html' title='Bug Zero'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-4459428457367032013</id><published>2008-03-25T11:35:00.004-04:00</published><updated>2008-03-25T12:44:57.639-04:00</updated><title type='text'>The Legacy of Microsoft Office</title><content type='html'>&lt;p&gt;I'm a little bit late to this particular dance, but I feel like I have to say something about it.&lt;/p&gt;&lt;p&gt;Last month, Microsoft released the specs for its old binary Microsoft Office file formats. Lots of people thought this would usher in a new age of competing office suites. It will not. Microsoft Office binary file formats are monumentally, hopelessly complex.&lt;/p&gt;&lt;p&gt;Joel (&lt;a href="http://www.joelonsoftware.com/"&gt;on Software&lt;/a&gt;) Spolsky is a veteran of the Excel team, and he wrote a &lt;a href="http://www.joelonsoftware.com/items/2008/02/19.html" title="Why are the Microsoft Office file formats so complicated? (And some workarounds)"&gt;wonderfully insightful post&lt;/a&gt; about why this is so. He writes:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;A normal programmer would conclude that Office's binary file formats:&lt;ul&gt;&lt;li&gt;are deliberately obfuscated&lt;/li&gt;&lt;li&gt;are the product of a demented Borg mind&lt;/li&gt;&lt;li&gt;were created by insanely bad programmers&lt;/li&gt;&lt;li&gt;and are impossible to read or create correctly.&lt;/li&gt;&lt;/ul&gt;You'd be wrong on all four counts.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The crux of Joel's point is that the formats were: designed around hardware constraints two decades ago; grown to account for every new feature since; all while maintaining 100% backward compatibility.&lt;/p&gt;&lt;p&gt;Joel is absolutely right about how the file formats got that way, of course. That doesn't change the fact that they are absolutely terrible file formats today. The startling thing is that Microsoft's new XML-based file formats are really just as bad. Microsoft has gone through a lot of trouble to translate all the data structures into new XML equivalents, but they still have all of the cruft of the old formats. &lt;em&gt;This is not a system that can continue indefinitely.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;All software with a long enough life faces this demon eventually. Backwards compatibility is a feature. It is an asset to software users who have old data. As with any feature, it is a trade-off, and comes at a price. That price in Microsoft Office passed the "too high" mark for me a long time ago. Likewise with Windows. I am more willing than most users to move to different systems, but everyone has a limit.&lt;/p&gt;&lt;p&gt;The greater lesson is that the cost of backwards compatibility should be carefully considered. In the end, extremely backwards-compatible software is just... extremely backwards software.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-4459428457367032013?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/4459428457367032013/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=4459428457367032013' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/4459428457367032013'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/4459428457367032013'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2008/03/legacy-of-microsoft-office.html' title='The Legacy of Microsoft Office'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-3037168484362701420</id><published>2008-03-03T22:44:00.003-05:00</published><updated>2008-03-03T22:47:57.991-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='webstandards'/><category scheme='http://www.blogger.com/atom/ns#' term='microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>A Dramatic Reversal</title><content type='html'>&lt;p&gt;Microsoft's plan with IE8 was to make it use IE7's less-correct rendering by default, unless developers asked for "IE8 mode" explicitly. This was bad. They have now &lt;a href="http://blogs.msdn.com/ie/archive/2008/03/03/microsoft-s-interoperability-principles-and-ie8.aspx"&gt;reversed their position&lt;/a&gt;. Money quote:&lt;/p&gt;
&lt;blockquote&gt;Now, IE8 will show pages requesting “Standards” mode in IE8’s Standards mode. Developers who want their pages shown using IE8’s “IE7 Standards mode” will need to request that explicitly&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-3037168484362701420?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/3037168484362701420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=3037168484362701420' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/3037168484362701420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/3037168484362701420'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2008/03/dramatic-reversal.html' title='A Dramatic Reversal'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-5093029823761781462</id><published>2008-02-13T20:37:00.001-05:00</published><updated>2008-02-14T14:59:10.949-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='plpgsql'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><category scheme='http://www.blogger.com/atom/ns#' term='postgresql'/><title type='text'>Maintainting Heirarchies in SQL</title><content type='html'>&lt;p&gt;I've refined my thinking a little about the optimal way to keep track of tasks in a relational database. Here is the newer version:&lt;/p&gt;
&lt;pre class="source sql"&gt;CREATE TABLE task (
 id BIGSERIAL PRIMARY KEY,
 parentid BIGINT REFERENCES task (id),
 taskname varchar(50) NOT NULL
 CONSTRAINT name_not_empty
 CHECK (taskname &amp;lt;&amp;gt; '')
);
CREATE TABLE leaftask (
 id BIGINT PRIMARY KEY REFERENCES task (id),
 weight INT4 NOT NULL DEFAULT 1000,
 starttime TIMESTAMPTZ,
 endtime TIMESTAMPTZ,
 CONSTRAINT startbeforefinish
 CHECK ((starttime &amp;lt; endtime) or (endtime IS NULL))
);&lt;/pre&gt;
&lt;p&gt;I want my tasks to follow certain rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All sub-tasks of a given parent task should add up to 100% of the parent task.&lt;/li&gt;
&lt;li&gt;A task can never have exactly one sub-task because - according to the rule above - the subtask would by synonymous with its parent.&lt;/li&gt;
&lt;li&gt;All tasks that have no descendants - and none that don't - should have a corresponding "leaftask" record.&lt;/li&gt;
&lt;li&gt;All tasks must have a final root that has no parent - i.e. no looping back on your descendants.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I want to build structures into the database that will prevent invalid states (as defined by the above rules) from occurring. Today I am going to tackle the problem of a task descending from itself. To prevent that case, I need what in PostgreSQL is called a trigger. I'm getting ahead of myself though. First I need a way to list the descendants of a given task. Since I want it to happen all in the database, I need a stored function.&lt;/p&gt;
&lt;p&gt;Stored functions in PostgreSQL can be written in &lt;em&gt;many&lt;/em&gt; languages. I'm going to write mine in PL/pgSQL, a sort of SQL-related procedural language, because it is included by default with PostgreSQL. (PL/pgSQL is intentionally similar to Oracle's PL/SQL, if you're an Oracle person.)&lt;/p&gt;
&lt;pre class="source sql"&gt;CREATE OR REPLACE FUNCTION taskdescendants(parenttaskid bigint, OUT decid bigint)
 RETURNS SETOF bigint AS $fun$
BEGIN
 FOR decid IN SELECT id FROM task WHERE parentid = parenttaskid LOOP
  RETURN NEXT;
  FOR decid IN SELECT * FROM taskdescendants(decid) LOOP
   RETURN NEXT;
  END LOOP;
 END LOOP;
 RETURN;
END;
$fun$ LANGUAGE plpgsql;&lt;/pre&gt;
&lt;p&gt;This function will return the ids (each as a separate row) of any descendants a given task might have. I can use it in my SQL statements as if it were a table. For example, this will select all tasks descending from task 57:&lt;/p&gt;
&lt;pre class="source sql"&gt;SELECT decid, taskname FROM taskdescendants(57) INNER JOIN task ON decid = id;&lt;/pre&gt;
&lt;p&gt;That's all well and good for a generic function, but trigger functions have slightly different requirements. This will check that the new parentid doesn't show up in the list of descendants:&lt;/p&gt;
&lt;pre class="source sql"&gt;CREATE OR REPLACE FUNCTION taskrecursioncheck() RETURNS trigger AS $fun$
BEGIN
 IF NEW.parentid IN (SELECT decid FROM taskdescendants(NEW.id)) THEN
  RAISE EXCEPTION 'task cannot descend from one of its own descendants';
 END IF;
 IF NEW.parentid = NEW.id THEN
  RAISE EXCEPTION 'task cannot descend from itself';
 END IF;
 RETURN NEW;
END;
$fun$ LANGUAGE plpgsql;

CREATE TRIGGER parent_trap BEFORE UPDATE ON task
 FOR EACH ROW EXECUTE PROCEDURE taskrecursioncheck();&lt;/pre&gt;
&lt;p&gt;There - now it raises an error on invalid relationships and I got a handy function that my front end can call. Later I will have to figure out some way to ensure my other rules are followed.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-5093029823761781462?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/5093029823761781462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=5093029823761781462' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/5093029823761781462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/5093029823761781462'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2008/02/ive-refined-my-thinking-little-about.html' title='Maintainting Heirarchies in SQL'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-5760291446102739344</id><published>2007-11-30T21:40:00.000-05:00</published><updated>2007-11-30T21:54:39.804-05:00</updated><title type='text'>Amazon or... Amazing?</title><content type='html'>&lt;p&gt;I am completely blown away by &lt;a href="http://amazon.com/aws"&gt;Amazon Web Services&lt;/a&gt;. S3 is wonderful in its simplicity and EC2 is revolutionary.&lt;/p&gt;
&lt;p&gt;S3 stands for Simple Storage Service, and it lives up to its name. Put stuff up there and take it back down again. You can also have it generate auto-expiring URLs that others can access. Pay based on upload amount, download amount and storage amount.&lt;/p&gt;
&lt;p&gt;EC2 stands for Elastic Compute Cloud. It is just a pay-by-the-hour server service. You provide the Linux image you want to run (or use one of their pre-built ones) and tell them to fire it up. The service assigns an IP address to the newly created machine and the rest is up to you. Pricing is such that it could destroy the dedicated server hosting business with a couple of small changes (basically a load balancer with a static IP would do it). It's biggest strength now is on-demand number crunching. Great for development/demo servers too.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-5760291446102739344?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/5760291446102739344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=5760291446102739344' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/5760291446102739344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/5760291446102739344'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2007/11/amazon-or-amazing.html' title='Amazon or... Amazing?'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-7556686987210867181</id><published>2007-11-11T10:49:00.002-05:00</published><updated>2008-03-25T07:52:33.106-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='postgresql'/><title type='text'>Creating a Tree-based Task List in a Relational Database</title><content type='html'>&lt;p&gt;Things we want:
&lt;ul&gt;
  &lt;li&gt;tasks&lt;/li&gt;
  &lt;li&gt;subtasks&lt;/li&gt;
  &lt;li&gt;task owners (responsible for that task)&lt;/li&gt;
  &lt;li&gt;task start time&lt;/li&gt;
  &lt;li&gt;task end time&lt;/li&gt;
  &lt;li&gt;prerequisite tasks&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;How do we represent these things in a relational database? Tasks are represented as a tree. Only leaf tasks will have owners and start/end times. This is because any non-leaf task will be made up entirely of its subtasks. In other words, when all the subtasks are done, the parent task is done. The start time of a non-leaf task is the earliest start time from among its descendants. Likewise, its end time equals the last end time from among its descendants (null if any are not yet finished).&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Note: "bigserial" and "serial" are PostgreSQL abstractions for 8-byte and 4-byte integers that have an auto-incrementing default. They're mostly used for primary keys.&lt;/i&gt;&lt;/p&gt;
&lt;pre class="source sql"&gt;CREATE TABLE task (
    taskid BIGSERIAL NOT NULL PRIMARY KEY,
    parentid BIGINT REFERENCES task(taskid),
    jobid INTEGER NOT NULL REFERENCES job(jobid),
    taskname VARCHAR(200) NOT NULL
);

CREATE TABLE taskleaf (
    taskid BIGINT NOT NULL PRIMARY KEY
      REFERENCES task(taskid),
    employeeid INTEGER NOT NULL
      REFERENCES employee(employeeid),
    starttime TIMESTAMPTZ,
    endtime TIMESTAMPTZ
);&lt;/pre&gt;
&lt;p&gt;Problems:&lt;/p&gt;
&lt;p&gt;Every task has a "jobid" - only the root task really needs this. Make the jobs themselves the root tasks? That wouldn't work in my pre-existing job scheme. Also, if performance was database-bound in my application, I could shift the tree-decoding work to the web server by selecting all the tasks by jobid.&lt;/p&gt;
&lt;p&gt;Prevent circular references? I could make a trigger or rule in the database that would check the path back to a root node before allowing a parentid to be assigned. While I am at it, I can check to make sure the parent's "jobid" matches.&lt;/p&gt;
&lt;p&gt;I looked at the "adjacency list" method, but I don't think it would work well for my needs.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-7556686987210867181?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/7556686987210867181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=7556686987210867181' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/7556686987210867181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/7556686987210867181'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2007/11/creating-tree-based-task-list-in.html' title='Creating a Tree-based Task List in a Relational Database'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-6586364302419200141</id><published>2007-11-08T17:53:00.000-05:00</published><updated>2007-11-08T18:06:59.019-05:00</updated><title type='text'>Are You Watching These?</title><content type='html'>&lt;p&gt;Every time I watch one of the &lt;a href="http://video.google.com/videosearch?q=Google+techtalks"&gt;Google techtalks&lt;/a&gt;, I am blown away. As far as I can tell, this is how these things get made:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Google chooses a subject related to their business.&lt;/li&gt;
&lt;li&gt;They find someone who knows that subject to give a talk.&lt;/li&gt;
&lt;li&gt;They distribute the video so employees who couldn't attend can still get the info.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is especially good because:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All subjects are related to their business.&lt;/li&gt;
&lt;li&gt;They always seem to get the foremost authority on any subject (I bet they would reanimate Lincoln if they had a techtalk on the Civil War).&lt;/li&gt;
&lt;li&gt;They give the video out to everybody.&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/4514957582005722888-6586364302419200141?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/6586364302419200141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=6586364302419200141' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/6586364302419200141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/6586364302419200141'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2007/11/are-you-watching-these.html' title='Are You Watching These?'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-7012450963347433056</id><published>2007-11-06T21:19:00.001-05:00</published><updated>2008-02-22T13:43:02.780-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='php'/><title type='text'>PHP is Funny</title><content type='html'>&lt;p&gt;There are a lot of things that I like about PHP. For instance, the addition operator (+) is different from the concatenation operator (.). This prevents the common ambiguity in weakly-typed languages of "'1' + 1".&lt;/p&gt;
&lt;p&gt;PHP has a lot of quirks though - due to its highly "organic" development. &lt;a href="http://us2.php.net/manual/en/language.variables.variable.php"&gt;Variable variable names&lt;/a&gt; are a prime example:&lt;/p&gt;
&lt;pre class="source"&gt;$a = 'hello';
$$a = 'world';
echo "$a $hello"; // prints "hello world"&lt;/pre&gt;
&lt;p&gt;Confusing, no? Also, the object-oriented stuff seems tacked on (probably because it was tacked on) and the function to escape text so that it is HTML-safe is called "htmlspecialchars()". For a language whose main function is to output web pages, couldn't they have thought up a shorter function name?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-7012450963347433056?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/7012450963347433056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=7012450963347433056' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/7012450963347433056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/7012450963347433056'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2007/11/php-is-funny.html' title='PHP is Funny'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4514957582005722888.post-1732014142314677810</id><published>2007-11-06T17:00:00.000-05:00</published><updated>2007-11-06T21:28:23.760-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='intro'/><title type='text'>Intro</title><content type='html'>&lt;p&gt;This will be my space to dump my software development thoughts. Welcome to a piece of my mind.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4514957582005722888-1732014142314677810?l=devneal.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devneal.blogspot.com/feeds/1732014142314677810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4514957582005722888&amp;postID=1732014142314677810' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/1732014142314677810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4514957582005722888/posts/default/1732014142314677810'/><link rel='alternate' type='text/html' href='http://devneal.blogspot.com/2007/11/intro.html' title='Intro'/><author><name>Neal</name><uri>http://www.blogger.com/profile/14650597547051117207</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://bp0.blogger.com/_GpWLrlCgyCc/SAiTnw1DOGI/AAAAAAAAAAk/r9QpArQCN6s/S220/409450224_2160729925.jpg'/></author><thr:total>0</thr:total></entry></feed>
