<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><title>Krzysztof Kowalczyk blog</title><link href="http://blog.kowalczyk.info/atom.xml" rel="alternate" /><id>http://blog.kowalczyk.info/atom.xml</id><updated>2011-12-10T00:47:56Z</updated><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/KrzysztofKowalczykBlog" /><feedburner:info uri="krzysztofkowalczykblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry><title>A list of chm readers/viewers for Windows</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/EcUMaJvPC7U/A-list-of-chm-readersviewers-for-Windows.html" rel="alternate" /><updated>2011-12-10T00:47:56Z</updated><id>tag:blog.kowalczyk.info,2011-12-10:/article/gqmj/A-list-of-chm-readersviewers-for-Windows.html</id><summary type="html">	&lt;p&gt;I&amp;#8217;ve compiled a list of &lt;a href="http://blog.kowalczyk.info/articles/chm-reader-viewer-for-windows.html"&gt;&lt;span class="caps"&gt;CHM&lt;/span&gt; readers for windows&lt;/a&gt;. It&amp;#8217;s a surprisingly long list.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/EcUMaJvPC7U" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/gqmj/A-list-of-chm-readersviewers-for-Windows.html</feedburner:origLink></entry><entry><title>SumatraPDF 1.9 released</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/JLYHLFIreog/SumatraPDF-19-released.html" rel="alternate" /><updated>2011-11-24T08:44:29Z</updated><id>tag:blog.kowalczyk.info,2011-11-24:/article/fyuh/SumatraPDF-19-released.html</id><summary type="html">	&lt;p&gt;&lt;a href="http://www.ohloh.net/p/4623/contributors"&gt;We&lt;/a&gt; are pleased to announce 1.9 release of &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf"&gt;SumatraPDF&lt;/a&gt;, a small, fast, free &lt;span class="caps"&gt;PDF&lt;/span&gt;, &lt;span class="caps"&gt;CHM&lt;/span&gt;, DjVu, &lt;span class="caps"&gt;XPS&lt;/span&gt;, &lt;span class="caps"&gt;CBZ&lt;/span&gt; and &lt;span class="caps"&gt;CBR&lt;/span&gt; reader for Windows.&lt;/p&gt;

	&lt;p&gt;The most significant addition in this release is support for &lt;span class="caps"&gt;CHM&lt;/span&gt; documents. Sumatra is slowly getting support for more and more document formats.&lt;/p&gt;

	&lt;p&gt;Robert Prouse contributed support for touch gestures (available on Windows 7 or later, if you have the right hardware i.e. touch-enabled screen).&lt;/p&gt;

	&lt;p&gt;Audio and video files linked from &lt;span class="caps"&gt;PDF&lt;/span&gt; documents are now opened in an external media player.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve also improved support for &lt;span class="caps"&gt;PDF&lt;/span&gt; transparency groups.&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/JLYHLFIreog" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/fyuh/SumatraPDF-19-released.html</feedburner:origLink></entry><entry><title>App Engine price hike - not so bad after all</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/ArBHuilaMZo/App-Engine-price-hike-not-so-bad-after-all.html" rel="alternate" /><updated>2011-10-05T06:13:35Z</updated><id>tag:blog.kowalczyk.info,2011-10-05:/article/evht/App-Engine-price-hike-not-so-bad-after-all.html</id><summary type="html">	&lt;p&gt;This blog is hosted on App Engine. At first it looked that recent App Engine price hike will push my blog from free tier to a paid one.&lt;/p&gt;

	&lt;p&gt;The increase would come only because of change from charging per cpu hours to charging for instance hours.&lt;/p&gt;

	&lt;p&gt;However, after making a small change in Application Settings to set Max Idle Instances to 1, I&amp;#8217;m back in free tier. I haven&amp;#8217;t noticed a performance degradation.&lt;/p&gt;

	&lt;p&gt;In conclusion, App Engine still seems like a good choice for hosting small to medium sized websites for free.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/ArBHuilaMZo" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/evht/App-Engine-price-hike-not-so-bad-after-all.html</feedburner:origLink></entry><entry><title>Introducing Volante - a database for C# (.NET)</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/3pinehd2tLo/Introducing-Volante-a-database-for-C-NET.html" rel="alternate" /><updated>2011-09-23T00:12:27Z</updated><id>tag:blog.kowalczyk.info,2011-09-23:/article/epbm/Introducing-Volante-a-database-for-C-NET.html</id><summary type="html">	&lt;p&gt;&lt;a href="http://blog.kowalczyk.info/software/volante/database.html"&gt;Volante&lt;/a&gt; is a small, fast, object-oriented, embeddable database designed for seamless integration with C# (and other .&lt;span class="caps"&gt;NET&lt;/span&gt; languages). Today I&amp;#8217;ve made a first public release.&lt;/p&gt;

	&lt;p&gt;Almost every program needs to persist some data. There are many ways to do that: serialize data as &lt;span class="caps"&gt;XML&lt;/span&gt; or &lt;span class="caps"&gt;JSON&lt;/span&gt;, use SQLite etc.&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve been recently writing desktop .&lt;span class="caps"&gt;NET&lt;/span&gt; applications in C# and existing (free) options didn&amp;#8217;t meet my needs well.&lt;/p&gt;

	&lt;p&gt;The closest best solution is SQLite, but it doesn&amp;#8217;t integrate with C# well: you have to convert your object to/from &lt;span class="caps"&gt;SQL&lt;/span&gt; tables.&lt;/p&gt;

	&lt;p&gt;If I was the world&amp;#8217;s toughest programmer I would write  an object-oriented database engine from scratch and it would be designed from the beginning for seamless integration with .&lt;span class="caps"&gt;NET&lt;/span&gt; framework.&lt;/p&gt;

	&lt;p&gt;Thankfully, I didn&amp;#8217;t have to do that. What I needed already existed in the form of &lt;a href="http://en.wikipedia.org/wiki/Perst"&gt;Perst&lt;/a&gt; project.&lt;/p&gt;

	&lt;p&gt;There was one wrinkle: while early versions of Perst were under &lt;span class="caps"&gt;BSD&lt;/span&gt; license, with version 2.50 the code was acquired by a company McObject and is now distributed under &lt;span class="caps"&gt;GPL&lt;/span&gt; and those who can&amp;#8217;t use &lt;span class="caps"&gt;GPL&lt;/span&gt; can purchase commercial license from McObject.&lt;/p&gt;

	&lt;p&gt;Not so great for one person who doesn&amp;#8217;t yet make money from his software.&lt;/p&gt;

	&lt;p&gt;I decided to adopt the Perst code base. I picked the latest 2.49 version that was still licensed under &lt;span class="caps"&gt;BSD&lt;/span&gt; (copyright cannot be change retroactively) and I&amp;#8217;ve spent the last couple of months writing comprehensive documentation, writing tests, fixing bugs discovered by tests, modernizing the code base.&lt;/p&gt;

	&lt;p&gt;Today I&amp;#8217;ve reached a point where I&amp;#8217;m comfortable releasing this code publicly as version 0.9.&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve retained the &lt;span class="caps"&gt;BSD&lt;/span&gt; license of early Perst versions so the code is free to use in both open-source and commercial projects.&lt;/p&gt;

	&lt;p&gt;Volante database serves the same niche as SQLite: an embedded database engine for your desktop C# applications. Like with SQLite, the database is in a single file. &lt;/p&gt;

	&lt;p&gt;There are significant differences from SQLite.&lt;/p&gt;

	&lt;p&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; is an object-oriented framework. Volante is an object-oriented database to offer the best integration with .&lt;span class="caps"&gt;NET&lt;/span&gt;. Volante uses B-Trees to implement indexes, which allows quickly finding objects with desired properties.&lt;/p&gt;

	&lt;p&gt;Volante is extremely small: Volante.dll is only 180 KB.&lt;/p&gt;

	&lt;p&gt;I distribute Volante.dll for Microsoft&amp;#8217;s .&lt;span class="caps"&gt;NET&lt;/span&gt; (works in .&lt;span class="caps"&gt;NET&lt;/span&gt; 2.0 and later) but it can also be compiled from sources and used under Mono.&lt;/p&gt;

	&lt;p&gt;I was dogfooding Volante from day one in my three .&lt;span class="caps"&gt;NET&lt;/span&gt; applications and it&amp;#8217;s been performing great.&lt;/p&gt;

	&lt;p&gt;I hope you&amp;#8217;ll find it useful too.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/3pinehd2tLo" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/epbm/Introducing-Volante-a-database-for-C-NET.html</feedburner:origLink></entry><entry><title>SumatraPDF 1.8 released</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/0vfqNeh5j1s/SumatraPDF-18-released.html" rel="alternate" /><updated>2011-09-19T02:41:14Z</updated><id>tag:blog.kowalczyk.info,2011-09-19:/article/ej5e/SumatraPDF-18-released.html</id><summary type="html">	&lt;p&gt;&lt;a href="http://www.ohloh.net/p/4623/contributors"&gt;We&lt;/a&gt; are pleased to announce 1.8 release of &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf"&gt;SumatraPDF&lt;/a&gt;, a small, fast, free &lt;span class="caps"&gt;PDF&lt;/span&gt;, DjVu, &lt;span class="caps"&gt;XPS&lt;/span&gt;, &lt;span class="caps"&gt;CBZ&lt;/span&gt; and &lt;span class="caps"&gt;CBR&lt;/span&gt; reader for Windows.&lt;/p&gt;

	&lt;p&gt;This is a smallish release.&lt;/p&gt;

	&lt;p&gt;We improved support for &lt;span class="caps"&gt;PDF&lt;/span&gt; form text fields.&lt;/p&gt;

	&lt;p&gt;We did speed up handling of some types of djvu files.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve made a bunch of minor improvements and bug fixes.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/0vfqNeh5j1s" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/ej5e/SumatraPDF-18-released.html</feedburner:origLink></entry><entry><title>SumatraPDF 1.7 released</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/XLCjw20WvYg/SumatraPDF-17-released.html" rel="alternate" /><updated>2011-07-18T01:28:26Z</updated><id>tag:blog.kowalczyk.info,2011-07-18:/article/cbo9/SumatraPDF-17-released.html</id><summary type="html">	&lt;p&gt;&lt;a href="http://www.ohloh.net/p/4623/contributors"&gt;SumatraPDF developers&lt;/a&gt; are pleased to announce 1.7 release of &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf"&gt;SumatraPDF&lt;/a&gt;, a &lt;span class="caps"&gt;PDF&lt;/span&gt;, DjVu, &lt;span class="caps"&gt;XPS&lt;/span&gt;, &lt;span class="caps"&gt;CBZ&lt;/span&gt; and &lt;span class="caps"&gt;CBR&lt;/span&gt; reader for Windows.&lt;/p&gt;

	&lt;p&gt;In this release we&amp;#8217;ve added user-defined favorites (i.e. bookmarks). You can create one or more favorites for a given file, navigate to a favorite and delete them.&lt;/p&gt;

	&lt;p&gt;Favorites are accessed either via a menu items in Favorites top-level menu or displayed as a tree in the sidebar.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve improved support for right-to-left languages, like Arabic.&lt;/p&gt;

	&lt;p&gt;Logical page numbers are displayed and used, if document provides them (such as i, ii, iii, etc.).&lt;/p&gt;

	&lt;p&gt;We allow to restrict SumatraPDF&amp;#8217;s features with more granularity; see &lt;a href="http://code.google.com/p/sumatrapdf/source/browse/trunk/docs/sumatrapdfrestrict.ini"&gt;this document&lt;/a&gt; for more information.&lt;/p&gt;

	&lt;p&gt;Command-line argument -named-dest now also matches strings in table of contents.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve improved support for &lt;span class="caps"&gt;EPS&lt;/span&gt; files (requires Ghostscript)&lt;/p&gt;

	&lt;p&gt;Installer is now more robust. Previously an installation could fail if a web browser using Sumatra&amp;#8217;s web browser dll was running. Now installer detects this and will ask to close the browser before proceeding.&lt;/p&gt;

	&lt;p&gt;Until next release.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/XLCjw20WvYg" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/cbo9/SumatraPDF-17-released.html</feedburner:origLink></entry><entry><title>How to make software crash less</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/GdOv43ijmHM/How-to-make-software-crash-less.html" rel="alternate" /><updated>2011-06-30T22:32:59Z</updated><id>tag:blog.kowalczyk.info,2011-06-30:/article/c4qb/How-to-make-software-crash-less.html</id><summary type="html">	&lt;p&gt;You don&amp;#8217;t want your software to crash, do you? This post describes my experiences in making desktop Mac and Windows software crash less.&lt;/p&gt;

	&lt;h2&gt;Know thy crashes&lt;/h2&gt;

	&lt;p&gt;The most important step to fixing your crashes is to know about them. &lt;/p&gt;

	&lt;p&gt;Given how complex and varied our desktop operating systems are (3 major version of Windows in active use, thousands of minor and major ways that each installation of Windows or Mac can be different) our ability to comprehensively test software is not good.&lt;/p&gt;

	&lt;p&gt;Sure, if you&amp;#8217;re Microsoft or Adobe you can reinvest some of the revenue to hire an army or testers, setup compatibility labs etc. but for a small company or a single developer this is not realistic. &lt;/p&gt;

	&lt;p&gt;Bugs most often lurk in untested code and even a very good testing effort is unlikely to encounter all the many things that can go wrong in real life.&lt;/p&gt;

	&lt;h2&gt;Get the crash reports automatically&lt;/h2&gt;

	&lt;p&gt;Very few people bother to tell software vendors about crashes. They just shrug and restart. The only realistic way to be informed about crashes is to automatically gather crash reports without user involvement.&lt;/p&gt;

	&lt;p&gt;This is a proven idea. Microsoft was one of the pioneers of using this technique for Windows OS and they publicly praise it for letting them fix the most frequent crashes and increase stability of Windows. Many clued in organization do it as well: Apple, Mozilla, Google.&lt;/p&gt;

	&lt;h2&gt;Getting the crashes &amp;#8211; the mechanics&lt;/h2&gt;

	&lt;p&gt;Regardless of the platform, the solution involves two parts:
	&lt;ul&gt;
		&lt;li&gt;a server, which accepts crash reports from the software&lt;/li&gt;
		&lt;li&gt;code inside the software itself. It gets activated when a crash happens and sends crash report to the server&lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;h3&gt;The server&lt;/h3&gt;

	&lt;p&gt;The server part is simple. You can use any technology to write it, any protocol you want.&lt;/p&gt;

	&lt;p&gt;Personally I use &lt;a href="https://appengine.google.com/"&gt;App Engine&lt;/a&gt;, re-use &lt;span class="caps"&gt;HTTP&lt;/span&gt; &lt;span class="caps"&gt;POST&lt;/span&gt; protocol and run on standard &lt;span class="caps"&gt;HTTP&lt;/span&gt; port (80) for maximum compatibility with client-side firewall software.&lt;/p&gt;

	&lt;p&gt;It&amp;#8217;s literally few lines of code to parse incoming &lt;span class="caps"&gt;POST&lt;/span&gt; requests, store them in the database and provide a basic web interface for easy browsing. As an additional bonus, App Engine is free if your traffic is small enough,&lt;/p&gt;

	&lt;p&gt;If you write in &lt;span class="caps"&gt;PHP&lt;/span&gt; and run on a small &lt;span class="caps"&gt;VPS&lt;/span&gt;, it&amp;#8217;ll work just as well.&lt;/p&gt;

	&lt;h3&gt;Client side on Windows in C# apps&lt;/h3&gt;

	&lt;p&gt;In C# I setup a global exception handler (in &lt;span class="caps"&gt;WPF&lt;/span&gt; it means setting up handlers for App.DispatcherUnhandledException and AppDomain.CurrentDomain.UnhandledException). &lt;/p&gt;

	&lt;p&gt;I then use HttpWebRequest class to send exception message and callstack as &lt;span class="caps"&gt;HTTP&lt;/span&gt; &lt;span class="caps"&gt;POST&lt;/span&gt; (using multipart/form-data).&lt;/p&gt;

	&lt;p&gt;The code is less than hundred lines and took mere hours to write.&lt;/p&gt;

	&lt;h3&gt;Client side on Windows in C++ apps&lt;/h3&gt;

	&lt;p&gt;In C++ everything is substantially harder. The big picture is similar: 
	&lt;ul&gt;
		&lt;li&gt;install global handler for unhandled exceptions (with SetUnhandledExceptionFilter())&lt;/li&gt;
		&lt;li&gt;in that handler generate the crash report and &lt;span class="caps"&gt;HTTP&lt;/span&gt; submit it to the server&lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;p&gt;The details are substantially more complicated. The code is more than a thousand lines and took me days to perfect.&lt;/p&gt;

	&lt;p&gt;The biggest issue was that, unlike in C#, you don&amp;#8217;t get readable callstack in native code. You need symbols (.pdb files) for that. My solution is convoluted, but works:
	&lt;ul&gt;
		&lt;li&gt;during build process, I archive .pdb files on the server (I use S3, but any web server will do)&lt;/li&gt;
		&lt;li&gt;in the crash handler I download the symbols locally, on demand&lt;/li&gt;
		&lt;li&gt;I create crash report containing human-readable callstacks of all threads and some other useful information&lt;/li&gt;
		&lt;li&gt;I &lt;span class="caps"&gt;HTTP&lt;/span&gt; &lt;span class="caps"&gt;POST&lt;/span&gt; it to the server&lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;p&gt;You can re-use my work. The code is part of my &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf/"&gt;SumatraPDF&lt;/a&gt; open-source project. Most of it is in &lt;a href="http://code.google.com/p/sumatrapdf/source/browse/trunk/src/CrashHandler.cpp"&gt;CrashHandler.cpp&lt;/a&gt; and, unlike most of Sumatra, is under liberal &lt;span class="caps"&gt;BSD&lt;/span&gt; license.&lt;/p&gt;

	&lt;h3&gt;Client side on Mac OS X&lt;/h3&gt;

	&lt;p&gt;The good thing about Mac is that it already creates human-readable crash reports for you. They are stored in ~/Library/Logs/CrashReporter/ directory.&lt;/p&gt;

	&lt;p&gt;There&amp;#8217;s no need to handle crashes yourself. I just check at startup if there&amp;#8217;s a new crash report for my app (the files are named after your application) from a previous run. If there is, I submit it to the server (and delete so that it&amp;#8217;s not sent multiple times).&lt;/p&gt;

	&lt;h2&gt;The alternatives&lt;/h2&gt;

	&lt;p&gt;While the general idea is always the same, there are different ways of implementing it.&lt;/p&gt;

	&lt;p&gt;On Windows a simpler solution is to capture so-called minidumps (using MiniDumpWriteDumpProc() Windows &lt;span class="caps"&gt;API&lt;/span&gt;) instead of going to the trouble of generating human-readable crash reports client side.&lt;/p&gt;

	&lt;p&gt;I did that too. The problem with that approach is that you have to inspect each crash dump manually in the debugger (e.g. WinDBG). I wrote a python script that automated the process (you can script it by launching cdb debugger with the right parameters and making it run !analyze -v)).&lt;/p&gt;

	&lt;p&gt;Unfortunately, cdb is buggy and was hanging on some dump files. It&amp;#8217;s probably possible to work around with a timeout in the python script, but at that point I stopped caring.&lt;/p&gt;

	&lt;p&gt;Windows provides native support for minidumps. Google took minidump design and provided cross-platform implementation for Windows, Mac and Linux, as part of &lt;a href="http://code.google.com/p/google-breakpad/"&gt;breakpad&lt;/a&gt; project.&lt;/p&gt;

	&lt;p&gt;Breakpad is the crash reporting system used by Google for Chrome and Mozilla for Firefox. It contains both client and server parts for native (C/C++ or Objective C) code.&lt;/p&gt;

	&lt;p&gt;I used it once for a Mac app. For Objective C I prefer the approach described above as it&amp;#8217;s simpler to implement, but I&amp;#8217;m sure that&amp;#8217;s a solid and well tested approach.&lt;/p&gt;

	&lt;p&gt;On Windows, crash reports from your app are already sent to Microsoft as part of &lt;a href="http://en.wikipedia.org/wiki/Windows_Error_Reporting"&gt;Windows Error Reporting&lt;/a&gt;. Apparently, it&amp;#8217;s possible to for third party developers to get access to those reports but I never did that, so don&amp;#8217;t know what&amp;#8217;s involved in the process.&lt;/p&gt;

	&lt;h2&gt;The SumatraPDF experience&lt;/h2&gt;

	&lt;p&gt;So how well does it work in practice?&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve implemented the system described here in Sumatra 1.5. Sumatra is a rather complicated piece of C++ code and quite popular (several thousand of downloads per day).&lt;/p&gt;

	&lt;p&gt;Before 1.5 we had a system where we would save the minidump to a disk and after a crash we would ask the user to report it in our bug tracker and attach minidump to the bug report.&lt;/p&gt;

	&lt;p&gt;It became obvious that almost no one did that. We&amp;#8217;ve only gotten few crash reports from users in few months. Our automated system was sending us tens of crash reports per day.&lt;/p&gt;

	&lt;p&gt;Once we knew about the problems, we could attempt to fix them. Some problems we could fix just by looking at crash report. Some required writing stress tests to make them easier to reproduce locally. Some of them we can&amp;#8217;t fix (e.g. because they are caused by buggy printer drivers or other software that injects buggy dlls into our process).&lt;/p&gt;

	&lt;p&gt;We do know that we fixed some of the bugs. We can see that a new release generates less crashes and by looking at crash reports we can tell that some crashes that happened frequently in previous releases do not happen anymore.&lt;/p&gt;

	&lt;p&gt;Building automated crash reporting system was the best investment we could have made for improving reliability of SumatraPDF.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/GdOv43ijmHM" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/c4qb/How-to-make-software-crash-less.html</feedburner:origLink></entry><entry><title>Experience porting 4k lines of C code to go</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/4fk6GkpeUv8/Experience-porting-4k-lines-of-C-code-to-go.html" rel="alternate" /><updated>2011-06-02T06:40:38Z</updated><id>tag:blog.kowalczyk.info,2011-06-02:/article/af1h/Experience-porting-4k-lines-of-C-code-to-go.html</id><summary type="html">	&lt;p&gt;I&amp;#8217;ve been recently interested in &lt;a href="http://golang.org"&gt;Go&lt;/a&gt;, a new programming language.&lt;/p&gt;

	&lt;p&gt;The best way to learn a language is to use it in a small but real project.&lt;/p&gt;

	&lt;p&gt;I needed a program that generates &lt;span class="caps"&gt;HTML&lt;/span&gt; from textile format. The way of least resistance would be to implement it in Python, as I&amp;#8217;ve coded a similar thing in the past. Instead I decided to use this as an opportunity to get more familiar with Go.&lt;/p&gt;

	&lt;p&gt;The biggest part of the problem was the textile to &lt;span class="caps"&gt;HTML&lt;/span&gt; conversion. There is no existing Go code for that so I decided to port &lt;a href="https://github.com/tanoku/upskirt"&gt;upskirt&lt;/a&gt; C library, as it does the job in the most performant way (it has a hand-written, disciplined parser as opposed to most other solutions that just throw cryptic regular expression at the problem).&lt;/p&gt;

	&lt;p&gt;The bottom line is: porting C code, at least in this case, was fast, boring, mechanical process (and that is a good thing).&lt;/p&gt;

	&lt;p&gt;Go&amp;#8217;s syntax is heavily inspired by C. The differences that I&amp;#8217;ve encountered most frequently:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;syntax for declaring variables is different (and better)&lt;/li&gt;
		&lt;li&gt;while keyword is missing, replaced by a more versatile for syntax&lt;/li&gt;
		&lt;li&gt;function declaration syntax is different&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;Fortunately, the transformations were simple and mostly mechanical.&lt;/p&gt;

	&lt;p&gt;It took me just few days to manually translate around 4000 lines of C code into ~3200 lines of Go code.&lt;/p&gt;

	&lt;p&gt;Saving ~800 lines of code (20%) is good, but the interesting part is: where do the savings come from?&lt;/p&gt;

	&lt;p&gt;The core parsing/html generating logic didn&amp;#8217;t shrink much. The big savings came from the fact that Go has a built-in growable array type and upskirt C code had to spend 924 lines re-implementing that in C.&lt;/p&gt;

	&lt;p&gt;An unexpected advantage of Go was its safety. The C code implements parsing by partying on char * pointers. Such code is notorious for causing lots of subtle, hard to test for bugs. Go doesn&amp;#8217;t allow this kind of pointer arithmetic and instead provides slices, which are a view into an underlaying array.&lt;/p&gt;

	&lt;p&gt;Slices provide out-of-bounds checks. Just by recoding in Go I found out-of-bounds access bug in the &lt;a href="https://github.com/tanoku/upskirt/issues/24"&gt;original C code&lt;/a&gt;.&lt;/p&gt;

	&lt;p&gt;Thanks to similarity of Go and C syntax, porting algorithmic code from C is simple.&lt;/p&gt;

	&lt;p&gt;All things considered, Go is quickly becoming my new preferred language (taking the crown away from Python). It combines the good attributes of Python (lightweight syntax, garbage collection) with good attributes of C (fast execution thanks to compilation to native code and programmer&amp;#8217;s control over memory layout) and adds some unique capabilities of its own (concurrency via gorutines and channels).&lt;/p&gt;

	&lt;p&gt;BTW: if you want markdown implementation for Go, use &lt;a href="https://github.com/russross/blackfriday"&gt;blackfriday&lt;/a&gt;. It&amp;#8217;s also direct port of upskirt and I abandoned my port in favor of contributing to blackfriday, since it was slightly ahead and there&amp;#8217;s no need for two nearly identical projects.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/4fk6GkpeUv8" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/af1h/Experience-porting-4k-lines-of-C-code-to-go.html</feedburner:origLink></entry><entry><title>SumatraPDF 1.6 released</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/-BrLr_FwsrM/SumatraPDF-16-released.html" rel="alternate" /><updated>2011-05-31T04:42:25Z</updated><id>tag:blog.kowalczyk.info,2011-05-31:/article/ao9k/SumatraPDF-16-released.html</id><summary type="html">	&lt;p&gt;&lt;a href="http://www.ohloh.net/p/4623/contributors"&gt;SumatraPDF developers&lt;/a&gt; are quite pleased to announce 1.6 release of &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf"&gt;SumatraPDF&lt;/a&gt;, a &lt;span class="caps"&gt;PDF&lt;/span&gt;, &lt;span class="caps"&gt;XPS&lt;/span&gt;, DjVu, &lt;span class="caps"&gt;CBZ&lt;/span&gt; and &lt;span class="caps"&gt;CBR&lt;/span&gt; reader for Windows.&lt;/p&gt;

	&lt;p&gt;In this release we&amp;#8217;ve added support for &lt;a href="http://djvu.org/"&gt;DjVu&lt;/a&gt; file format.&lt;/p&gt;

	&lt;p&gt;When no document is open, we display a list of frequently read document as thumbnails. This functionality is inspired by new tab page in Chrome.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added support for displaying Postscript documents. This requires recent Ghostscript version to be already installed &amp;#8211; we don&amp;#8217;t bundle it ourselves.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added support for displaying a folder containing images: drag the folder to SumatraPDF window&lt;/p&gt;

	&lt;p&gt;We now support clickable links and a Table of Content for &lt;span class="caps"&gt;XPS&lt;/span&gt; documents.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added printing progress and allow canceling printing process.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added Print toolbar button.&lt;/p&gt;

	&lt;p&gt;Experimental: we&amp;#8217;ve added previewing of &lt;span class="caps"&gt;PDF&lt;/span&gt; documents in Windows Vista and 7. This creates thumbnails and displays documents in Explorer&amp;#8217;s Preview pane. Needs to be explicitly selected during install process. We&amp;#8217;ve had reports that it doesn&amp;#8217;t work on 64-bit Windows which is why we call it experimental.&lt;/p&gt;

	&lt;p&gt;This is how &amp;#8220;frequently read&amp;#8221; list looks like:&lt;/p&gt;

	&lt;p&gt;&lt;img src="http://kjkpub.s3.amazonaws.com/blog/sumatra/sum-shot-03-small.png" style="text-align:center;" alt="" /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/-BrLr_FwsrM" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/ao9k/SumatraPDF-16-released.html</feedburner:origLink></entry><entry><title>Easy vs. probable or how to make money with software</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/qrm2dtEtxPY/Easy-vs-probable-or-how-to-make-money-with-softw.html" rel="alternate" /><updated>2011-05-15T00:15:17Z</updated><id>tag:blog.kowalczyk.info,2011-05-15:/article/ahcj/Easy-vs-probable-or-how-to-make-money-with-softw.html</id><summary type="html">	&lt;h2&gt;It it hard to make $1000 a month?&lt;/h2&gt;

	&lt;p&gt;There&amp;#8217;s a question on Quora: &lt;a href="http://www.quora.com/Is-it-hard-to-build-market-and-maintain-a-web-app-that-makes-at-least-1000-a-month"&gt;Is it hard to build, market and maintain a web app that makes at least $1000 a month?&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;Most of the answers are happily saying &amp;#8220;no, it&amp;#8217;s not hard at all&amp;#8221;, usually justifying it with wishful thinking (&amp;#8220;it&amp;#8217;s not hard to get 50 people pay you $20 a month&amp;#8221;).&lt;/p&gt;

	&lt;p&gt;Those answers are misleading.&lt;/p&gt;

	&lt;p&gt;I don&amp;#8217;t blame the respondents. They answered the question the way it was asked. &lt;/p&gt;

	&lt;h2&gt;What you ask vs. what you want to know&lt;/h2&gt;

	&lt;p&gt;The problem is that the person who asked the question really wanted to know how probable it is, not how hard. There&amp;#8217;s a big difference.&lt;/p&gt;

	&lt;h2&gt;A personal anecdote&lt;/h2&gt;

	&lt;p&gt;Many years ago, in the early days of Palm PDAs I wrote an English dictionary for Palm OS. For  more than 2 years I made several thousands dollars per months from it.&lt;/p&gt;

	&lt;p&gt;Was it hard? Not at all. It took me about 2 weeks to write the first version and there was nothing especially difficult about it &amp;#8211; there are thousands of programmers that could have done it.&lt;/p&gt;

	&lt;p&gt;My website was simplistic, my marketing skills limited to uploading my app to an app store-like website (PalmGear) which handled selling the app.&lt;/p&gt;

	&lt;p&gt;Nothing I did was difficult. However, my success wasn&amp;#8217;t very probable.&lt;/p&gt;

	&lt;p&gt;I wrote one of the first (if not the first) dictionaries. Things were different in 2001. Today everyone and their mother jumps on building iPhone or Android apps bandwagons but back then I had no competition from known dictionary publishers (publishers are not risk taking, future embracing organizations).&lt;/p&gt;

	&lt;p&gt;For a while I had the market to myself and that helped to establish my program as one of the most popular programs for Palm OS. Eventually competition arrived and it did have negative effect on my sales, but they had a really hard time catching up with me.&lt;/p&gt;

	&lt;p&gt;Lesson number 1: timing matters.&lt;/p&gt;

	&lt;p&gt;Getting timing right is not hard or easy, it&amp;#8217;s simply not likely that you&amp;#8217;ll get the timing right. If the right timing is obvious, it&amp;#8217;ll be obvious for many people and, paradoxically, means it&amp;#8217;s too late. If it&amp;#8217;s not obvious, there&amp;#8217;s a big probability that whatever you think the right timing is, you&amp;#8217;re wrong.&lt;/p&gt;

	&lt;p&gt;The right timing is only obvious in retrospect. &lt;/p&gt;

	&lt;p&gt;In my case, I didn&amp;#8217;t write my dictionary because I thought it&amp;#8217;s the right time to do it if I wanted to make money. I was just excited about new technology (Palm Pilots), wanted to write some program for it and a dictionary seemed like a good choice.&lt;/p&gt;

	&lt;h2&gt;Do it once vs. do it many times&lt;/h2&gt;

	&lt;p&gt;Another way to look at it is repeatability.&lt;/p&gt;

	&lt;p&gt;The easy success of my app wasn&amp;#8217;t lost on me. If I could replicate that success several times, I would get quite rich with little effort. &lt;/p&gt;

	&lt;p&gt;So I&amp;#8217;ve made more apps for Palm OS. They were more complex than my dictionary. They took longer to write, but still weren&amp;#8217;t hard to write.&lt;/p&gt;

	&lt;p&gt;I assume that my marketing, sales and other business skills were at least as good as before. And yet, the other apps were all failures. &lt;/p&gt;

	&lt;p&gt;My first success was easy but it wasn&amp;#8217;t easily repeatable.&lt;/p&gt;

	&lt;p&gt;Many people who answered the Quora question did build successful websites making $1000 or more a month. Does that mean that their experience is good enough to declare that achieving what they did is easy?&lt;/p&gt;

	&lt;p&gt;No. Just like me, they all have only one or two successful products. If it&amp;#8217;s easy, then why don&amp;#8217;t they re-invest their capital in making more products? After all, if you have 100 products each making $1000 per month, you&amp;#8217;ll make more than a million a year.&lt;/p&gt;

	&lt;p&gt;The answers are a good example of selection bias. Even if something has 1% probability of happening, if there are 100 people who tried, 1 of them will succeed. Given the popularity of Quora, it&amp;#8217;s not hard to find lots of people who tried something with low probability of success and did it successfully. When they see someone asking if doing it was hard, they jump in saying that it wasn&amp;#8217;t.&lt;/p&gt;

	&lt;p&gt;They are truthful and trying to be helpful and encouraging but we don&amp;#8217;t get the complete picture because we don&amp;#8217;t hear from much bigger number of people who tried and failed.&lt;/p&gt;

	&lt;p&gt;The successes might have been easy, but they were not likely.&lt;/p&gt;

	&lt;h2&gt;Just ship it&lt;/h2&gt;

	&lt;p&gt;Making software (be it a web site, a mobile app, a desktop app) that makes money is something with low probability of success. It&amp;#8217;s not as bad as you think: making money in any self-directed business (as opposed to being employed) has low probability of success.&lt;/p&gt;

	&lt;p&gt;More importantly: you have the biggest influence on that probability.&lt;/p&gt;

	&lt;p&gt;The person who asked this question probably won&amp;#8217;t be successful. The answer is unknowable and knowing it would not make a difference.&lt;/p&gt;

	&lt;p&gt;You&amp;#8217;ll succeed or you&amp;#8217;ll fail but you&amp;#8217;ll not ever know it until you&amp;#8217;ve tried. Spending any time calculating your chances actually decreases the probability because it takes away time and energy from things that matter.&lt;/p&gt;

	&lt;p&gt;The single most important thing when building money making software product is this: ship it.&lt;/p&gt;

	&lt;p&gt;My success might have been accidental, but it wouldn&amp;#8217;t have happen if I didn&amp;#8217;t write the code, the website, the documentation and made my program available for people to buy.&lt;/p&gt;

	&lt;p&gt;If the product fails, either improve it or make another one. The more times you try, the more likely you&amp;#8217;re to succeed.&lt;/p&gt;

	&lt;p&gt;When you start getting sales, double down. The unassailable logic of software business is that it&amp;#8217;s easier to make a successful product even more successful than to create another one that is just as successful.&lt;/p&gt;

	&lt;p&gt;Look at any software business. Even the biggest successes, like Microsoft or Google, have only few extremely profitable products and despite having the brightest developers, mountains of money, cross-promotional opportunities, they struggle to create more money making products.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/qrm2dtEtxPY" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/ahcj/Easy-vs-probable-or-how-to-make-money-with-softw.html</feedburner:origLink></entry><entry><title>90% of success is showing up - a proof</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/Tk3Or33aEtM/90-of-success-is-showing-up-a-proof.html" rel="alternate" /><updated>2011-05-08T01:05:04Z</updated><id>tag:blog.kowalczyk.info,2011-05-08:/article/afrv/90-of-success-is-showing-up-a-proof.html</id><summary type="html">	&lt;p&gt;Woody Allen said that 90% of success is showing up. &lt;a href="http://www.nytimes.com/2011/05/08/technology/08class.html"&gt;This article&lt;/a&gt; is a proof of that.&lt;/p&gt;

	&lt;p&gt;In 2007 a Standford professor gave his student a taks: build a Facebook application and get people to use it.&lt;/p&gt;

	&lt;p&gt;The result? Some applications became so popular that students made good money out of them. Some even turned into companies.&lt;/p&gt;

	&lt;p&gt;The important part is that none of those student particularly wanted to build that app. It was simply something they were told to do.&lt;/p&gt;

	&lt;p&gt;The challenge in life is that no one tells us to do things that we&amp;#8217;ll own. Sure, at work bosses tell us what to do but the company owns the result of the work and all potential windfalls.&lt;/p&gt;

	&lt;p&gt;What the article shows that just by doing something and shipping it to the world, we might create an unexpected success.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/Tk3Or33aEtM" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/afrv/90-of-success-is-showing-up-a-proof.html</feedburner:origLink></entry><entry><title>SumatraPDF 1.5 released</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/zXIVsfOBYV0/SumatraPDF-15-released.html" rel="alternate" /><updated>2011-04-24T02:37:04Z</updated><id>tag:blog.kowalczyk.info,2011-04-24:/article/9ile/SumatraPDF-15-released.html</id><summary type="html">	&lt;p&gt;A new version of &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf/free-pdf-reader.html"&gt;SumatraPDF&lt;/a&gt;, a free, small, fast, open-source &lt;span class="caps"&gt;PDF&lt;/span&gt; reader for Windows, is ready.&lt;/p&gt;

	&lt;p&gt;What&amp;#8217;s new in version 1.5?&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added support for &lt;span class="caps"&gt;XPS&lt;/span&gt; documents.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve also added support for &lt;span class="caps"&gt;CBZ&lt;/span&gt; and &lt;span class="caps"&gt;CBR&lt;/span&gt; files (popular formats for comic book files).&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added File/Save Shortcut menu item to create a shortcut to a specific place in a document.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added right-click context menu for copying text, link addresses and comments. In browser plugin context menu also has items for saving and printing.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added folder browsing. Ctrl+Shift+Right opens next &lt;span class="caps"&gt;PDF&lt;/span&gt; in the current folder, Ctrl-Shift+Left opens previous &lt;span class="caps"&gt;PDF&lt;/span&gt; in the current folder. Current folder is the one where currently opened &lt;span class="caps"&gt;PDF&lt;/span&gt; documents is located.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve also fixed handling of large &lt;span class="caps"&gt;PDF&lt;/span&gt; files in browser plugin in FireFox.&lt;/p&gt;

	&lt;p&gt;SumatraPDF is a creation of &lt;a href="http://www.ohloh.net/p/4623/contributors"&gt;SumatraPDF developers&lt;/a&gt;.&lt;/p&gt;

	&lt;p&gt;Let the downloads begin.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/zXIVsfOBYV0" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/9ile/SumatraPDF-15-released.html</feedburner:origLink></entry><entry><title>SumatraPDF 1.4 released</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/fUP893J1imY/SumatraPDF-14-released.html" rel="alternate" /><updated>2011-03-13T00:18:46Z</updated><id>tag:blog.kowalczyk.info,2011-03-13:/article/95h6/SumatraPDF-14-released.html</id><summary type="html">	&lt;p&gt;Good news everyone: a new version of &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf/free-pdf-reader.html"&gt;SumatraPDF&lt;/a&gt;, a free, small, fast, open-source &lt;span class="caps"&gt;PDF&lt;/span&gt; viewer for Windows, is ready.&lt;/p&gt;

	&lt;p&gt;What&amp;#8217;s new in this version?&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added browser plugin for Firefox/Chrome/Opera (Internet Explorer is not supported).&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added IFilter that enables full-text search of &lt;span class="caps"&gt;PDF&lt;/span&gt; files in Windows Desktop Search (i.e. search from Windows Vista/7&amp;#8217;s Start Menu).&lt;/p&gt;

	&lt;p&gt;Browser plugin and IFilter are not installed by default so you need to use options in the installer and check the appropriate checkboxes. You can uninstall them by re-running the installer and de-selecting the options.&lt;/p&gt;

	&lt;p&gt;In 1.3 we&amp;#8217;ve improved text selection to use left mouse button. The downside of that was that left mouse button couldn&amp;#8217;t be used for scrolling when mouse cursor is over text. To compensate for that, in 1.4 you can scroll with right mouse button.&lt;/p&gt;

	&lt;p&gt;In 1.3 we&amp;#8217;ve introduced a new installer. Some of you missed the ability of choosing a custom installation directory that was not implemented in 1.3. We&amp;#8217;ve re-introduced support for non-standard installation directory in 1.4.&lt;/p&gt;

	&lt;p&gt;SumatraPDF focuses on reading PDFs and doesn&amp;#8217;t implement some more advanced functionality like filling out forms or making annotations. If you need this functionality, we&amp;#8217;ve made it easy to re-open current document via File menu in Adobe Reader (if it&amp;#8217;s installed). In 1.4 we also support Foxit and PDF-XChange.&lt;/p&gt;

	&lt;p&gt;To make SumatraPDF files smaller, we used to compress the executable with mpress. Unfortunately that caused some anti-virus programs to falsely report Sumatra as a virus. We no longer compress the executables that ship with the installer version, so don&amp;#8217;t be surprised that the files are now bigger. The portable, .zip version still ships as a single, compressed executable (so don&amp;#8217;t be surprised if it&amp;#8217;s flagged by some anti-virus software).&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve removed -title cmd-line option.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ve added support for AES-256 encrypted &lt;span class="caps"&gt;PDF&lt;/span&gt; files, fixed an integer overflow reported by Jeroen van der Gun and and made other fixes and improvements to &lt;span class="caps"&gt;PDF&lt;/span&gt; handling.&lt;/p&gt;

	&lt;p&gt;If you wonder why we don&amp;#8217;t have browser plugin for Internet Explorer, the explanation is simple: no-one has written the necessary code.&lt;/p&gt;

	&lt;p&gt;SumatraPDF has been brought to you by &lt;a href="http://www.ohloh.net/p/4623/contributors"&gt;SumatraPDF developers&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/fUP893J1imY" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/95h6/SumatraPDF-14-released.html</feedburner:origLink></entry><entry><title>XML is really, really slow</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/1aJ0nM4qqtw/XML-is-really-really-slow.html" rel="alternate" /><updated>2011-03-11T02:25:56Z</updated><id>tag:blog.kowalczyk.info,2011-03-11:/article/935t/XML-is-really-really-slow.html</id><summary type="html">	&lt;p&gt;It&amp;#8217;s about 8 years late but W3C finally produced a standard for &lt;a href="http://www.readwriteweb.com/archives/new_xml_standard_for_super-fast_lightweight_applic.php"&gt;efficient &lt;span class="caps"&gt;XML&lt;/span&gt; representation&lt;/a&gt;. They call it somewhat opaquely &lt;a href="http://www.w3.org/TR/2011/REC-exi-20110310/"&gt;Efficient &lt;span class="caps"&gt;XML&lt;/span&gt; Interchange&lt;/a&gt; (&lt;span class="caps"&gt;EXI&lt;/span&gt;). I guess it sounds better than what we used to call such things back in the day: binary &lt;span class="caps"&gt;XML&lt;/span&gt; (which is a better description what it&amp;#8217;s about).&lt;/p&gt;

	&lt;p&gt;The money quote from the announcement:&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;They&amp;#8217;ve achieved over 100-fold performance improvements&amp;#8230;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;One way to interpret this is: wow, those guys are really smart.&lt;/p&gt;

	&lt;p&gt;There is much simpler explanation: &lt;span class="caps"&gt;XML&lt;/span&gt; is really, really slow.&lt;/p&gt;

	&lt;h2&gt;Speed comes from architecture&lt;/h2&gt;

	&lt;p&gt;I&amp;#8217;m somewhat performance oriented in my programming work. One of the reasons I disliked the popularity of &lt;span class="caps"&gt;XML&lt;/span&gt; was that I saw how often it blinded people to engineering realities. Choosing &lt;span class="caps"&gt;XML&lt;/span&gt; was often a reason for dramatic performance issues that then had to be heroically recovered.&lt;/p&gt;

	&lt;p&gt;Those performance problems were, however, mostly self inflicted. &lt;span class="caps"&gt;XML&lt;/span&gt; is only one of the possible ways to store or exchange data but it certainly is one of the slowest.&lt;/p&gt;

	&lt;p&gt;You cannot get 100x speed up over technology that wasn&amp;#8217;t incredibly inefficient to begin with.&lt;/p&gt;

	&lt;p&gt;Sometimes you don&amp;#8217;t have the choice (when you have to inter-operate with systems that only offer &lt;span class="caps"&gt;XML&lt;/span&gt;) but I&amp;#8217;ve seen many cases where people did have the choice and made the wrong one.&lt;/p&gt;

	&lt;p&gt;&lt;span class="caps"&gt;XML&lt;/span&gt; isn&amp;#8217;t such a hot buzzword anymore so I don&amp;#8217;t see that problem as often but I still do see it.&lt;/p&gt;

	&lt;p&gt;For example, more than one text editor decided to store the syntax highlighter definitions as &lt;span class="caps"&gt;XML&lt;/span&gt; while it can be trivially stored in simple text format that can be parsed much faster, using less memory and, as a bonus, can actually be edited by human beings.&lt;/p&gt;

	&lt;p&gt;A bigger point is: speed comes from architecture. It&amp;#8217;s not that choosing the right architecture will make you dramatically better but choosing the wrong architecture will make you dramatically worse. &lt;/p&gt;

	&lt;p&gt;Choosing &lt;span class="caps"&gt;XML&lt;/span&gt; over more efficient ways of storing data is just one, but particularly frequent, example of that rule.&lt;/p&gt;

	&lt;h2&gt;Binary &lt;span class="caps"&gt;XML&lt;/span&gt; (&lt;span class="caps"&gt;EXI&lt;/span&gt;) is too little too late&lt;/h2&gt;

	&lt;p&gt;As to the standard itself: don&amp;#8217;t pay attention to it. It&amp;#8217;s too little, way too late.&lt;/p&gt;

	&lt;p&gt;About 8 years ago I did my small part in expanding &lt;span class="caps"&gt;XML&lt;/span&gt; capabilities of &lt;span class="caps"&gt;SQL&lt;/span&gt; Server. At the time &lt;span class="caps"&gt;XML&lt;/span&gt; was hot so Oracle, Microsoft, &lt;span class="caps"&gt;IBM&lt;/span&gt; raced to add native &lt;span class="caps"&gt;XML&lt;/span&gt; handling to their databases. It was going to be the next big thing. Possibly even bigger than big.&lt;/p&gt;

	&lt;p&gt;Trust me, the ridiculous inefficiency of &lt;span class="caps"&gt;XML&lt;/span&gt; wasn&amp;#8217;t lost on developers working on &lt;span class="caps"&gt;XML&lt;/span&gt; technologies 8 years ago. Coming up with a more efficient binary &lt;span class="caps"&gt;XML&lt;/span&gt; format is easy. Microsoft had its version (if not several of them) and other companies had theirs.&lt;/p&gt;

	&lt;p&gt;The real problem was: politics prevented people agreeing on a standard so no standard emerged.&lt;/p&gt;

	&lt;p&gt;There was an eruption of creating standards based on &lt;span class="caps"&gt;XML&lt;/span&gt; (&lt;span class="caps"&gt;SOAP&lt;/span&gt;, &lt;span class="caps"&gt;XML&lt;/span&gt; Schema, XQuery). If you don&amp;#8217;t know what those terms mean it&amp;#8217;s because they all failed (despite the fact that everyone was convinced they&amp;#8217;re going to be the next big thing).&lt;/p&gt;

	&lt;p&gt;In hindsight it was a terrible mistake to work on those big standards of speculative value but not solve a real problem people already had: an efficient, binary, standard format for storing &lt;span class="caps"&gt;XML&lt;/span&gt;.&lt;/p&gt;

	&lt;p&gt;If W3C came up with &lt;span class="caps"&gt;EXI&lt;/span&gt; 8 years ago, maybe people wouldn&amp;#8217;t feel the need to invent Protocol Buffers or Thrift and it would have won.&lt;/p&gt;

	&lt;p&gt;But solving this problem today is almost comically late. It has no chance of adoption. &lt;/p&gt;

	&lt;p&gt;If you&amp;#8217;re planning to use a custom, binary way of storing &lt;span class="caps"&gt;XML&lt;/span&gt;, using &lt;span class="caps"&gt;EXI&lt;/span&gt; is probably better but there&amp;#8217;s no way &lt;span class="caps"&gt;EXI&lt;/span&gt; will become so universally supported as &lt;span class="caps"&gt;XML&lt;/span&gt; and universal support (in software libraries, books etc.) is really the main thing &lt;span class="caps"&gt;XML&lt;/span&gt; has going for it (speed or human-readable syntax, on the other hand, are not XML&amp;#8217;s strengths).&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/1aJ0nM4qqtw" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/935t/XML-is-really-really-slow.html</feedburner:origLink></entry><entry><title>My social marketing failure</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/ZrnD66B4K6I/My-social-marketing-failure.html" rel="alternate" /><updated>2011-02-08T23:00:09Z</updated><id>tag:blog.kowalczyk.info,2011-02-08:/article/8nqe/My-social-marketing-failure.html</id><summary type="html">	&lt;h2&gt;Me, a social marketer&lt;/h2&gt;

	&lt;p&gt;Four months ago I started an experiment in social marketing of &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf/free-pdf-reader.html"&gt;SumatraPDF&lt;/a&gt;, my free &lt;span class="caps"&gt;PDF&lt;/span&gt; viewer for Windows.&lt;/p&gt;

	&lt;p&gt;Let me rephrase that without the buzzwords: four months ago I added Google buzz, tweet and Facebook like buttons to Sumatra&amp;#8217;s web pages:&lt;/p&gt;

	&lt;p&gt;&lt;img src="http://kjkpub.s3.amazonaws.com/blog/sumatra/sum-tweet-like.png" style="text-align:center;" alt="" /&gt;&lt;/p&gt;

	&lt;p&gt;This is a reflection on changing habits of how people share what they find on the web. Blogs used to be the medium to write about products and services people found useful. Blogs are still going strong but tweeting/buzzing/liking is much easier than writing a blog post so it became a dominant way of sharing cool finds.&lt;/p&gt;

	&lt;p&gt;It took me about an hour to add the 3 most popular buttons, so there was no reason not to try it.&lt;/p&gt;

	&lt;p&gt;A button promotes a given page (as identified by a url). In case of Sumatra, they promote the main (landing) page.&lt;/p&gt;

	&lt;p&gt;When I installed the buttons on 9-19-2010, I already had 529 Buzz posts (a suspiciously large number), 44 tweets and 16 Facebook likes (those services track number of mentions for a given page even if they originate from other places which gave me a jump start).&lt;/p&gt;

	&lt;h2&gt;Me, a failed social marketer&lt;/h2&gt;

	&lt;p&gt;As far as I can tell, it was a dismal failure.&lt;/p&gt;

	&lt;p&gt;The purpose of marketing is to make people more aware of your software. The theory is that a tweet or a like shows up on people&amp;#8217;s twitter or facebook streams whcih leads them to click on the link and visit your website.&lt;/p&gt;

	&lt;p&gt;You can track the effectiveness of such marketing by counting how many people come to your website from twitter.com or Facebook.com (I do it with Google Analytics).&lt;/p&gt;

	&lt;p&gt;The results are terrible. In the last month, I got 82 visits from facebook.com (out of 350.000 pageviews), which makes it 116th referal source. Inexplicably twitter.com doesn&amp;#8217;t even show up in the list of first 500 referal sources.&lt;/p&gt;

	&lt;p&gt;In those four months I got 314 facebook likes (78 per month) and 29 tweets (7 per month).&lt;/p&gt;

	&lt;p&gt;To give some perspective: before installing those buttons Sumatra averaged around 4.000 downloads a day and getting more than 300.000 page views a month. &lt;/p&gt;

	&lt;p&gt;That means that insignificant number of the people downloading the software or visiting SumatraPDF website use the tweet or like buttons. &lt;/p&gt;

	&lt;p&gt;I also know from monitoring twitter for mentions of Sumatra that people tweet about it on their own.&lt;/p&gt;

	&lt;p&gt;Incremental traffic from Twitter or Facebook to my website is negligible.&lt;/p&gt;

	&lt;h2&gt;Why so failure?&lt;/h2&gt;

	&lt;p&gt;I didn&amp;#8217;t expect miracles but I also didn&amp;#8217;t expect such a massive failure.&lt;/p&gt;

	&lt;p&gt;One possibility is that I horribly botched interpretation of the results.&lt;/p&gt;

	&lt;p&gt;Another possibility is that those things don&amp;#8217;t work well for software. Unlike a cute picture or a blog post, software cannot be evaluated by just looking at the website. You need to use it for a while to decide if it&amp;#8217;s good or not so it doesn&amp;#8217;t lend itself to impulsive tweets of admiration.&lt;/p&gt;

	&lt;p&gt;On the other hand, I&amp;#8217;ve seen  web pages for software that I&amp;#8217;m pretty sure is less popular than Sumatra and had way more than my measly 44 tweets.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/ZrnD66B4K6I" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/8nqe/My-social-marketing-failure.html</feedburner:origLink></entry><entry><title>SumatraPDF 1.3 released</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/vL2DC6q4tuA/SumatraPDF-13-released.html" rel="alternate" /><updated>2011-02-07T21:26:41Z</updated><id>tag:blog.kowalczyk.info,2011-02-07:/article/8p9u/SumatraPDF-13-released.html</id><summary type="html">&lt;img src="http://kjkpub.s3.amazonaws.com/blog/sumatra/sum-shot-02-small.png" align="right" title="Sumatra screenshot" style="margin-left:8px; margin-bottom:4px" alt="Sumatra screenshot" /&gt;
 
SumatraPDF team is happy to announce a 1.3 release of our free, small, fast, open source &lt;span class="caps"&gt;PDF&lt;/span&gt; reader for Windows.
 
	&lt;p&gt;Sumatra was capable of text selection for some time but this feature was hard to discover (you had to press Ctrl and select the area with a mouse). We improved text selection and copying by emulating the way a browser (and Adobe Reader) work: just select text with a mouse and use Ctrl-C to copy it to a clipboard.&lt;/p&gt;
 
	&lt;p&gt;Shift + Left Mouse now scrolls the document and Ctrl + Left mouse continues to create a rectangular selection (for copying images).&lt;/p&gt; 
 
	&lt;p&gt;We added more keyboard and mouse shortcuts:
	&lt;ul&gt; 
		&lt;li&gt;'c&amp;#8217; shortcut toggles continuous mode&lt;/li&gt; 
		&lt;li&gt;'+&amp;#8217; / '*&amp;#8217; on the numeric keyboard now do zoom and rotation&lt;/li&gt; 
		&lt;li&gt;back/forward mouse buttons for back/forward navigation&lt;/li&gt; 
	&lt;/ul&gt;&lt;/p&gt; 
 
	&lt;p&gt;We added toolbar icons for Fit Page and Fit Width and updated the look of toolbar icons&lt;/p&gt; 
 
	&lt;p&gt;In version 1.2 we introduced a new full screen mode and made it the default full screen mode. Old mode was still available but not easily discoverable. To make it more discoverable we&amp;#8217;ve added View/Presentation menu item for new full screen mode and View/Fullscreen menu item for the old full screen mode.&lt;/p&gt; 
 
	&lt;p&gt;We &lt;a href="/article/8nqb/Writing-a-custom-installer-for-windows-software.html"&gt;rewrote the installer&lt;/a&gt;&lt;/p&gt; 
 
	&lt;p&gt;We improved zoom performance and fixed crashiness caused by high zoom levels.&lt;/p&gt; 
 
	&lt;p&gt;We improved searching for text to use less memory.&lt;/p&gt; 
 
	&lt;p&gt;We improved printing.&lt;/p&gt; 
 
	&lt;p&gt;We&amp;#8217;ve updated translations contributed by our &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf/translators.html"&gt;translators&lt;/a&gt;&lt;/p&gt; 
 
	&lt;p&gt;We updated to latest &lt;a href="http://mupdf.com/"&gt;mupdf&lt;/a&gt; code for various improvements and bugfixes.&lt;/p&gt; 
 
	&lt;p&gt;We now use &lt;a href="http://libjpeg-turbo.virtualgl.org/"&gt;libjpeg-turbo&lt;/a&gt; library instead of libjpeg, for faster decoding of some PDFs.&lt;/p&gt; 
 
	&lt;p&gt;We updated &lt;a href="http://www.openjpeg.org/"&gt;openjpeg&lt;/a&gt; library to version 1.4 and &lt;a href="http://freetype.sourceforge.net/"&gt;freetype&lt;/a&gt; to version 2.4.4.&lt;/p&gt; 
 
	&lt;p&gt;We fixed 2 integer overflows reported by Stefan Cornelius from Secunia Research.&lt;/p&gt; &lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/vL2DC6q4tuA" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/8p9u/SumatraPDF-13-released.html</feedburner:origLink></entry><entry><title>Writing a custom installer for Windows software</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/uPLyb4U8-g0/Writing-a-custom-installer-for-Windows-software.html" rel="alternate" /><updated>2011-02-06T22:43:27Z</updated><id>tag:blog.kowalczyk.info,2011-02-06:/article/8nqb/Writing-a-custom-installer-for-Windows-software.html</id><summary type="html">	&lt;h2&gt;A tale of 2 installers&lt;/h2&gt;

	&lt;p&gt;For version 1.3 of &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf/free-pdf-reader.html"&gt;SumatraPDF&lt;/a&gt; I&amp;#8217;ve created a new installer.&lt;/p&gt;

	&lt;p&gt;The old installer:&lt;/p&gt;

	&lt;p&gt;&lt;img src="http://kjkpub.s3.amazonaws.com/blog/sumatra/sum-installer-old.png" title="Old installer" alt="Old installer" /&gt;&lt;/p&gt;

	&lt;p&gt;New installer:&lt;/p&gt;

	&lt;p&gt;&lt;img src="http://kjkpub.s3.amazonaws.com/blog/sumatra/sum-installer-new.png" title="New installer" alt="New installer" /&gt;&lt;/p&gt;

	&lt;p&gt;This post explains why I spent the time rewriting perfectly functional installer.&lt;/p&gt;

	&lt;h2&gt;How people write installers&lt;/h2&gt;

	&lt;p&gt;If you write Windows software, you need to provide an installer. Almost all installers are created by a tool (e.g. &lt;a href="http://wix.sourceforge.net/"&gt;WiX&lt;/a&gt;, &lt;a href="http://nsis.sourceforge.net"&gt;Nsis&lt;/a&gt;, &lt;a href="http://www.jrsoftware.org/isinfo.php"&gt;Inno Setup&lt;/a&gt; and many others).&lt;/p&gt;

	&lt;p&gt;Apparently people think that writing an installer is so difficult that it has to be simplified with a tool.&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;m here to advocate another way: write your own installers, people.&lt;/p&gt;

	&lt;h2&gt;It&amp;#8217;s not that hard.&lt;/h2&gt;

	&lt;p&gt;As everyone else, I did my installers with a tool. &lt;a href="http://nsis.sourceforge.net"&gt;NSIS&lt;/a&gt; was my weapon of choice: it&amp;#8217;s free, (relatively) easy to learn, (relatively well) documented and since other people used it, there are examples to learn from. &lt;/p&gt;

	&lt;p&gt;I used it in &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf/free-pdf-reader.html"&gt;SumatraPDF&lt;/a&gt;, &lt;a href="https://github.com/opendns/dynamicipupdate"&gt;OpenDNS client&lt;/a&gt; and was reasonably happy with it. However, it wasn&amp;#8217;t all roses.&lt;/p&gt;

	&lt;p&gt;&lt;span class="caps"&gt;NSIS&lt;/span&gt; is great if you don&amp;#8217;t try to do anything that it doesn&amp;#8217;t support out of the box. Once you stray outside the box, it&amp;#8217;s hours spent trying to find an existing &lt;span class="caps"&gt;NSIS&lt;/span&gt; code to do what you want and if you&amp;#8217;re unsuccessful, learning how to write code in NSIS&amp;#8217; awful macro language or write extension dlls.&lt;/p&gt;

	&lt;p&gt;Two issues I ran into were:
	&lt;ul&gt;
		&lt;li&gt;since you can&amp;#8217;t overwrite an executable file of a running program, it&amp;#8217;s a good idea to kill running instance of the program in the installer, to avoid a failure in the middle of installation. There&amp;#8217;s no built-in functionality to kill processes in &lt;span class="caps"&gt;NSIS&lt;/span&gt;. After spending way too much time trying to find an existing solution, I ended up writing an extension dll with necessary support command.&lt;/li&gt;
		&lt;li&gt;for my .&lt;span class="caps"&gt;NET&lt;/span&gt; app I had to install .&lt;span class="caps"&gt;NET&lt;/span&gt; 4.0 runtime if it wasn&amp;#8217;t already installed. Doing that in C code is simple: check registry keys to determine if .&lt;span class="caps"&gt;NET&lt;/span&gt; runtime is installed and execute the installer if it isn&amp;#8217;t. This is a common problem and I found several solutions on the net but each one was slightly different, since I&amp;#8217;m not proficient in &lt;span class="caps"&gt;NSIS&lt;/span&gt; macro language they were not easy to tweak for my purpose and they were all outdated (e.g. showing how to install .&lt;span class="caps"&gt;NET&lt;/span&gt; 2.0 while I needed .&lt;span class="caps"&gt;NET&lt;/span&gt; 4.0).&lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;p&gt;I realized that an installer doesn&amp;#8217;t do anything complicated: it shows a window, writes a few registry keys a copies a few files. I figured that writing installer in C++ from scratch wouldn&amp;#8217;t take more time that I&amp;#8217;ve spent in total learning about &lt;span class="caps"&gt;NSIS&lt;/span&gt;.&lt;/p&gt;

	&lt;p&gt;I was right: it took me &lt;a href="http://code.google.com/p/sumatrapdf/source/list?path=/trunk/src/installer/Installer.cpp&amp;#38;start=2535"&gt;9 days&lt;/a&gt; to write shippable version of Sumatra&amp;#8217;s custom installer. Most of it was support code so writing future installers for my other software will be even faster since I&amp;#8217;ll reuse most of the code.&lt;/p&gt;

	&lt;h2&gt;Why write custom installer?&lt;/h2&gt;

	&lt;p&gt;I already had a functioning installer so why fix something that isn&amp;#8217;t broken? For me, the reasons where:
	&lt;ul&gt;
		&lt;li&gt;provide a better user experience&lt;/li&gt;
		&lt;li&gt;no frustration due to &lt;span class="caps"&gt;NSIS&lt;/span&gt; limitations&lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;p&gt;Installer is the first thing a potential user of your application sees. What will be his first experience with your app?&lt;/p&gt;

	&lt;p&gt;Will it be terrible, like those installers that take half an hour to unpack a few files? &lt;/p&gt;

	&lt;p&gt;Will it be &lt;a href="http://sethgodin.typepad.com/seths_blog/2009/01/youre-boring.html"&gt;boring&lt;/a&gt;, just like most other installers? &lt;/p&gt;

	&lt;p&gt;Or will it be &lt;a href="http://sethgodin.typepad.com/seths_blog/2003/06/remarkable_is_w.html"&gt;remarkable&lt;/a&gt;, unique, extra pleasant? An experience worth talking about to others?&lt;/p&gt;

	&lt;p&gt;Writer Joe Konrath &lt;a href="http://jakonrath.blogspot.com/2010/12/holiday-ebook-buying-guide.html"&gt;stress the importance&lt;/a&gt; of a good book cover. An installer is the equivalent of a great book cover.&lt;/p&gt;

	&lt;p&gt;Writing a custom installer doesn&amp;#8217;t guarantee it&amp;#8217;ll be exceptional, but using &lt;span class="caps"&gt;NSIS&lt;/span&gt; guarantees that it&amp;#8217;ll be boring, just like every other installer created with &lt;span class="caps"&gt;NSIS&lt;/span&gt;.&lt;/p&gt;

	&lt;p&gt;In SumatraPDF&amp;#8217;s case, I&amp;#8217;ve made an usability improvement: installation is a one-click affair (old installer required a few clicks).&lt;/p&gt;

	&lt;p&gt;On the whimsicality front, I&amp;#8217;ve added a small startup animation, which shows the program letters one by one. It&amp;#8217;s only a small thing, I haven&amp;#8217;t spent much time on it, but the possibilities for interesting animations are endless: scrolling text, 3d objects rotating, fireworks, star fields etc. Old school &lt;a href="http://www.pouet.net/"&gt;demos&lt;/a&gt; and &lt;a href="http://processing.org/"&gt;processing&lt;/a&gt; are a rich source of inspiration for possible effects.&lt;/p&gt;

	&lt;p&gt;If you want to learn how a custom installer is done, the &lt;a href="http://code.google.com/p/sumatrapdf/source/browse/#svn/trunk/src/installer"&gt;source is out there&amp;#8230;&lt;/a&gt;&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/uPLyb4U8-g0" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/8nqb/Writing-a-custom-installer-for-Windows-software.html</feedburner:origLink></entry><entry><title>Using Quora for customer support</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/FEEnEdWXHgs/Using-Quora-for-customer-support.html" rel="alternate" /><updated>2010-12-26T22:36:40Z</updated><id>tag:blog.kowalczyk.info,2010-12-26:/article/8g0h/Using-Quora-for-customer-support.html</id><summary type="html">	&lt;p&gt;I was reading Scoble&amp;#8217;s post about &lt;a href="http://scobleizer.com/2010/12/26/is-quora-the-biggest-blogging-innovation-in-10-years/"&gt;Quora being a blogging innovation&lt;/a&gt; and I got this idea: how about using &lt;a href="http://www.quora.com/"&gt;Quora&lt;/a&gt; for customer support?&lt;/p&gt;

	&lt;p&gt;If you sell software or give it away for free or provide a service, it&amp;#8217;s a good idea to have a way to communicate with your users, to get bug reports, ideas for new features, answer questions etc.&lt;/p&gt;

	&lt;p&gt;There are many ways of doing that: e-mail groups, forum software like phpBB or Vanilla or my own &lt;a href="http://blog.kowalczyk.info/software/fofou/index.html"&gt;fofou&lt;/a&gt;, bug trackers, UserVoice etc.&lt;/p&gt;

	&lt;p&gt;Creatively used Quora could fulfill this purpose as well. I envision creating a topic for your product e.g. since I work on SumatraPDF, the topic could be &amp;#8220;SumatraPDF official support forum&amp;#8221;.&lt;/p&gt;

	&lt;p&gt;People would have to tag their questions with this topic. Quora has pretty good capabilities for browsing/monitoring e.g. people could watch the forum to see all new questions.&lt;/p&gt;

	&lt;p&gt;Unsurprisingly, Quora uses itself as its &lt;a href="http://www.quora.com/Quora-User-Feedback"&gt;user feedback mechanism&lt;/a&gt; so it looks like it just might work.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/FEEnEdWXHgs" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/8g0h/Using-Quora-for-customer-support.html</feedburner:origLink></entry><entry><title>Which technology for writing desktop software?</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/zScCnA_wDM8/Which-technology-for-writing-desktop-software.html" rel="alternate" /><updated>2010-12-06T07:20:58Z</updated><id>tag:blog.kowalczyk.info,2010-12-06:/article/Which-technology-for-writing-desktop-software.html</id><summary type="html">	&lt;p&gt;This post is inspired by &lt;a href="http://discuss.joelonsoftware.com/default.asp?biz.5.829264.15"&gt;a question&lt;/a&gt; posted on JoelOnSoftware software business forum. &lt;/p&gt;

	&lt;p&gt;To paraphrase: &amp;#8220;I&amp;#8217;m a one person coding machine. I want to write small, consumer oriented desktop software. Which technology should I use? Should I write cross-platform code or stick with one platform?&amp;#8221;&lt;/p&gt;

	&lt;p&gt;It is a good question because the amount of available technologies is vast: C/C++, .&lt;span class="caps"&gt;NET&lt;/span&gt;, Java, Adobe Air, Cocoa with Objective-C, QT, wxWidgets and many more lesser known technologies. &lt;/p&gt;

	&lt;p&gt;I have an answer.&lt;/p&gt;

	&lt;h2&gt;Don&amp;#8217;t write cross-platform code&lt;/h2&gt;

	&lt;p&gt;The logic behind writing cross-platform code is deceptively attractive: if I target both Mac and Windows, I&amp;#8217;ll sell twice as many copies of my software.&lt;/p&gt;

	&lt;p&gt;However, at the beginning your biggest problem is that your idea hasn&amp;#8217;t been tested with the market. Writing for a single platform is faster so you&amp;#8217;ll find out sooner if your software is a hit or a flop.&lt;/p&gt;

	&lt;p&gt;If it&amp;#8217;s a flop, the effort of supporting two platforms was lot.&lt;/p&gt;

	&lt;p&gt;If it&amp;#8217;s a success: congratulation, you now have the money to invest in supporting the other platform and a much higher chance that the result will be successful as well.&lt;/p&gt;

	&lt;p&gt;Don&amp;#8217;t delude yourself that a cross-platform toolkit will allow you to ship a cross-platform as fast as shipping a single-platform code. Life is not as simple as that.&lt;/p&gt;

	&lt;p&gt;Today Qt is the best cross-platform toolkit, a truly impressive piece of work. It is, however, limited by its legacy. Qt requires you to use C++. You&amp;#8217;ll be much more productive using C# with &lt;span class="caps"&gt;WPF&lt;/span&gt; on Windows or Objective C with Coca on Mac.&lt;/p&gt;

	&lt;p&gt;Writing code takes only a fraction of time and effort needed to ship an application to end users. Other activities that you&amp;#8217;ll need to do that also require doubling the time and effort:
	&lt;ul&gt;
		&lt;li&gt;testing the code on both platforms&lt;/li&gt;
		&lt;li&gt;writing documentation and marketing materials for 2 platforms&lt;/li&gt;
		&lt;li&gt;learning how to market to both Windows and Mac users&lt;/li&gt;
		&lt;li&gt;learning to become an expert user of both OSes to help your users when inevitable support requests come in&lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;h2&gt;What you need from a platform&lt;/h2&gt;

	&lt;p&gt;Sometimes platform are chosen based on vague understanding of what they provide. I see no end of people who e.g. will blindly suggest Adobe Air just because it&amp;#8217;s marketed as allowing cross-platform development and happens to get lots of buzz recently, without considering if the technical limitations of Air would even make a given application possible to write.&lt;/p&gt;

	&lt;p&gt;Here are things to consider when choosing a platform for your software.&lt;/p&gt;

	&lt;h3&gt;Is it capable enough?&lt;/h3&gt;

	&lt;p&gt;Adobe Air might be a great technology for some applications. If you&amp;#8217;re building a Twitter client, it&amp;#8217;ll do just fine. If you&amp;#8217;re building a novel compression engine, it&amp;#8217;s not appropriate. &lt;/p&gt;

	&lt;p&gt;By their nature, cross platform toolkits tend to target the lowest common denominator and don&amp;#8217;t support important platform-specific features. Those fancy Core Animation transitions in your Mac app? You probably won&amp;#8217;t get that from Java or Air or Qt. Support for Windows 7 task bar integration? Probably not there either.&lt;/p&gt;

	&lt;h3&gt;Is it documented well?&lt;/h3&gt;

	&lt;p&gt;This is not only about documentation that comes in the box but also about the availability of greater ecosystem. You&amp;#8217;ll run into problems, bugs, things you don&amp;#8217;t understand. It&amp;#8217;s important to resolve those issues quickly.&lt;/p&gt;

	&lt;p&gt;Mainstream technologies like Java or .&lt;span class="caps"&gt;NET&lt;/span&gt; are documented in books from respected publishers, numerous blog posts and have communities where you can show up, ask a question and get an answer quickly. There&amp;#8217;s much less of that for e.g Adobe Air or Clojure.&lt;/p&gt;

	&lt;h3&gt;Are there third-party libraries available?&lt;/h3&gt;

	&lt;p&gt;You don&amp;#8217;t want to write a zip compression or http client from scratch. Availability of 3rd party libraries that you can drop in your code and save tons of time is important. In that respect Java and .&lt;span class="caps"&gt;NET&lt;/span&gt; are unmatched. There&amp;#8217;s lots of C/C++ libraries out there, but integrating them in your project will be harder.&lt;/p&gt;

	&lt;h3&gt;Are other programs like the one you&amp;#8217;re thinking about implemented with that toolkit?&lt;/h3&gt;

	&lt;p&gt;Can you write a great text editor in Air? I don&amp;#8217;t know, I haven&amp;#8217;t seen one.&lt;/p&gt;

	&lt;p&gt;The fact that Microsoft used .NET/&lt;span class="caps"&gt;WPF&lt;/span&gt; for writing editor in Visual Studio or that Eclipse is written in Java is a proof that a complex text editor can be written in those technologies.&lt;/p&gt;

	&lt;h3&gt;Do you know it well?&lt;/h3&gt;

	&lt;p&gt;Learning a new technology is hard. Even switching to a similar platforms (e.g. from Java to C#) requires a large amount of effort and time. All else being equal, use the technology you already know.&lt;/p&gt;

	&lt;p&gt;Now for a final verdict.&lt;/p&gt;

	&lt;h2&gt;Cocoa is for Mac&lt;/h2&gt;

	&lt;p&gt;There really is no contest: for writing Mac software use Cocoa with Objective-C. While Java or C# are more productive than Objective-C, you can&amp;#8217;t beat the combination of tool support (XCode, especially in version 4, is doing a lot to help you program in Objective-C), documentation, community. It&amp;#8217;s also the most capable, being the native language of the platform.&lt;/p&gt;

	&lt;h2&gt;.&lt;span class="caps"&gt;NET&lt;/span&gt; and &lt;span class="caps"&gt;WPF&lt;/span&gt; is for Windows&lt;/h2&gt;

	&lt;p&gt;While Java is close to C# in productivity, documentation and availability of 3rd party libraries, .&lt;span class="caps"&gt;NET&lt;/span&gt; wins by having &lt;span class="caps"&gt;WPF&lt;/span&gt;, better integration with Windows and being better optimized for desktop apps.&lt;/p&gt;

	&lt;p&gt;&lt;span class="caps"&gt;WPF&lt;/span&gt; is what seals the deal: there&amp;#8217;s nothing even remotely as good in Java land for writing UI code.&lt;/p&gt;

	&lt;p&gt;Unsurprisingly, .&lt;span class="caps"&gt;NET&lt;/span&gt; is more capable than Java when it comes to all the little things you need to do to integrate with the OS really well. Things like support for Win 7 taskbar, reading/writing registry etc. I&amp;#8217;m sure all that can eventually be achieved with Java, but .&lt;span class="caps"&gt;NET&lt;/span&gt; already has everything you can possibly need to make your app a good citizen in Windows.&lt;/p&gt;

	&lt;p&gt;Finally, Java platform is mostly used on servers and optimized for that. In that context, it&amp;#8217;s much more important that an app runs fast in a stead state than to have short startup time.&lt;/p&gt;

	&lt;p&gt;On desktop, things like startup time matters and Microsoft cares about minimizing that, since their own apps are increasingly using .&lt;span class="caps"&gt;NET&lt;/span&gt;. Your apps get the benefit of Microsoft&amp;#8217;s work on optimizing startup time.&lt;/p&gt;

	&lt;h2&gt;What if you absolutely must target both platforms?&lt;/h2&gt;

	&lt;p&gt;What if your startup idea requires multi-platform support and you just got few millions in funding?&lt;/p&gt;

	&lt;p&gt;It&amp;#8217;s still better to hire two competent programmers, each an expert in writing software for one platform.&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve seen very few successful products that target both Windows and Mac. I exclude titans like Microsoft or Adobe, who have extremely complex application and infinite amounts of cash to pour into development.&lt;/p&gt;

	&lt;p&gt;Within the confines of small company, at best you might succeed despite sucking, like Libox (their Mac application doesn&amp;#8217;t even respect Cmd-Q). All the runaway successes that come to my mind, like Evernote or Dropbox, did invest in a native clients for each platform they support, because their apps are their core differentiator (there are tens of note-taking applications out there or apps that allow to backup or share files in some way).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/zScCnA_wDM8" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/Which-technology-for-writing-desktop-software.html</feedburner:origLink></entry><entry><title>SumatraPDF 1.2 released</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/JH4SUBTKlic/SumatraPDF-12-released.html" rel="alternate" /><updated>2010-12-04T07:04:17Z</updated><id>tag:blog.kowalczyk.info,2010-12-04:/article/SumatraPDF-12-released.html</id><summary type="html">	&lt;p&gt;SumatraPDF team is happy to announce 1.2 release. &lt;/p&gt;

	&lt;p&gt;Changes in this relase: 
	&lt;ul&gt;
		&lt;li&gt;improved printing: faster and uses less resources &lt;/li&gt;
		&lt;li&gt;add Ctrl-Y as a shortcut for Custom Zoom &lt;/li&gt;
		&lt;li&gt;add Ctrl-A as a shortcut for Select All Text &lt;/li&gt;
		&lt;li&gt;improved full screen mode &lt;/li&gt;
		&lt;li&gt;open embedded &lt;span class="caps"&gt;PDF&lt;/span&gt; documents &lt;/li&gt;
		&lt;li&gt;allow saving &lt;span class="caps"&gt;PDF&lt;/span&gt; document attachements to disk &lt;/li&gt;
		&lt;li&gt;latest fixes and improvements to &lt;span class="caps"&gt;PDF&lt;/span&gt; rendering from &lt;a href="http://mupdf.com/"&gt;mupdf&lt;/a&gt; project &lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;p&gt;Contributors to this release: 
	&lt;ul&gt;
		&lt;li&gt;Simon Bünzli (zeniko) &lt;/li&gt;
		&lt;li&gt;William Blum &lt;/li&gt;
		&lt;li&gt;Krzysztof Kowalczyk &lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;p&gt;As always, it&amp;#8217;s available &lt;a href="http://blog.kowalczyk.info/software/sumatrapdf/free-pdf-reader.html"&gt;from here&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/JH4SUBTKlic" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/SumatraPDF-12-released.html</feedburner:origLink></entry><entry><title>Using averages - a common performance measurement mistake</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/vqYwAEs5c_k/Using-averages-a-common-performance-measurement-.html" rel="alternate" /><updated>2010-11-25T06:06:05Z</updated><id>tag:blog.kowalczyk.info,2010-11-25:/article/Using-averages-a-common-performance-measurement-.html</id><summary type="html">	&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; when people want to get a more accurate result when benchmarking a performance of given piece of code they often run the same test multiple times and use an average as a final benchmark result. It&amp;#8217;s a mistake: using the time of the fastest run is more accurate.&lt;/p&gt;

	&lt;p&gt;By definition, a performance test must be deterministic: given the same inputs it&amp;#8217;ll execute exactly the same number of machine instructions, read and write the same amount of data to/from disk etc. If it isn&amp;#8217;t deterministic, benchmarking it is pointless.&lt;/p&gt;

	&lt;p&gt;We all know, however, that execution time is not deterministic. Why is that?&lt;/p&gt;

	&lt;p&gt;Multi-tasking nature of the operating system is to blame. Your code is only one of the many processes that compete for fixed resources like cpu time and i/o bandwidth. Operating system will interrupt your program and start executing some other code, at random times and for unpredictable amount of time.&lt;/p&gt;

	&lt;p&gt;If you measure just the time of execution, like most benchmarking methods do, it&amp;#8217;ll include not only the execution time of your code but also of other programs executed by operating system during that particular test run.&lt;/p&gt;

	&lt;p&gt;The same applies to other shared resources like a hard-drive: the benchmarked program asks the OS to read a piece of data from disk but so do other programs. The OS decides who gets to do I/O first in an unpredictable and unaccountable way.&lt;/p&gt;

	&lt;p&gt;You have little control over that behavior. You can think of execution time of your test as consisting of 2 components:
	&lt;ul&gt;
		&lt;li&gt;the deterministic execution time of only your code, which would happen if your process had exclusive access to all resources like cpu and hard-drive&lt;/li&gt;
		&lt;li&gt;random, unpredictable execution time of all other programs that OS decided to run during that particular test run&lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;p&gt;In other words, the benchmarked time is: the time your&amp;#8217;re interested in + a random overhead attributable to other processes.&lt;/p&gt;

	&lt;p&gt;This model explains why you should use the time of the fastest test run: it&amp;#8217;s the best approximation of the running time that is attributable only to your code (and with the smallest part attributable to other random processes).&lt;/p&gt;

	&lt;p&gt;Other coping mechanisms when doing performance tests involve trying to minimize the random component by shutting down as many processes as possible, so that less things will get in the way.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/vqYwAEs5c_k" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/Using-averages-a-common-performance-measurement-.html</feedburner:origLink></entry><entry><title>8 habits for becoming a better programmer</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/hTnAIFEFgtU/8-habits-for-becoming-a-better-programmer.html" rel="alternate" /><updated>2010-11-06T01:21:53Z</updated><id>tag:blog.kowalczyk.info,2010-11-06:/article/8-habits-for-becoming-a-better-programmer.html</id><summary type="html">	&lt;p&gt;This post is inspired by &lt;a href="http://news.ycombinator.cm/item?id=1674103"&gt;a question&lt;/a&gt; &amp;#8220;What habits made you a better programmer&amp;#8221;. &lt;/p&gt;

	&lt;p&gt;All the habits described below stem from one realization: I&amp;#8217;m too stupid to write bug free code so I need ways to compensate for my inevitable human fallibility.&lt;/p&gt;

	&lt;h2&gt;Code reviews&lt;/h2&gt;

	&lt;p&gt;I welcome code reviews because a second pair of eyes might spot mistakes I&amp;#8217;ve made.&lt;/p&gt;

	&lt;p&gt;Some people can&amp;#8217;t stand their code being criticized. I avoid bruised ego by assuming from the start that I&amp;#8217;m too stupid to write correct code.&lt;/p&gt;

	&lt;h2&gt;Using good tools&lt;/h2&gt;

	&lt;p&gt;I seek out and use tools that help me find bugs automatically and tools that help me understand my code better. Those tools include:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;static code checkers like &lt;a href="http://clang-analyzer.llvm.org/"&gt;clang analyzer&lt;/a&gt; or &lt;a href="http://sourceforge.net/apps/mediawiki/cppcheck/index.php?title=Main_Page"&gt;cppcheck&lt;/a&gt; or &lt;a href="http://pychecker.sourceforge.net/"&gt;pychecker&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.valgrind.org/"&gt;Valgrind&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;memory and cpu profilers&lt;/li&gt;
		&lt;li&gt;debuggers&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.sourceinsight.com/"&gt;Source Insight&lt;/a&gt; (a text editor)&lt;/li&gt;
	&lt;/ul&gt;

	&lt;h2&gt;Automated testing and continuous builds&lt;/h2&gt;

	&lt;p&gt;Continuous build quickly alerts to mistakes that break the build.&lt;/p&gt;

	&lt;p&gt;Automated tests (unit tests, system tests) increase my confidence in the correctness of the code and catch mistakes that cause regressions.&lt;/p&gt;

	&lt;h2&gt;Stepping through all new code in the debugger&lt;/h2&gt;

	&lt;p&gt;I see a lot of macho anti-debugger posturing. The reasoning is: good debuggers make it too easy to fix problems which makes you a sloppier programmer. But this reasoning applies to unit tests as well (although I don&amp;#8217;t see anyone criticizing unit tests for that reason).&lt;/p&gt;

	&lt;p&gt;Stepping through newly written code in the debugger to double-check that it behaves the way I expect is just another way to compensate for the inevitability of writing buggy code.&lt;/p&gt;

	&lt;h2&gt;Avoiding complexity&lt;/h2&gt;

	&lt;p&gt;Unnecessary, productivity sapping complexity is something that no one would defend but popularity of C++ or boost shows that a definition of unnecessary complexity is different for different people.&lt;/p&gt;

	&lt;p&gt;My bar for calling something complex is lower that many. I stay away from complexity, both self-inflicted (like trying to be too clever when implementing something, using multithreading when it&amp;#8217;s not absolutely necessary) or inflicted by the tool (e.g. advanced features of C++).&lt;/p&gt;

	&lt;h2&gt;Diagnostic code built into apps&lt;/h2&gt;

	&lt;p&gt;I add diagnostics to my code. Logging, asserts in debug builds, crash dump submission to my site for analyzing crashes that happen in the wild. They all help to figure out the inevitable problems that you don&amp;#8217;t see in testing on your machine but happen on user&amp;#8217;s computers due to different configurations.&lt;/p&gt;

	&lt;h2&gt;Writing readable code&lt;/h2&gt;

	&lt;p&gt;No one has writing unreadable code as a goal but it does happen because writing readable code is harder and requires more care and attention that just writing some code that works.&lt;/p&gt;

	&lt;p&gt;Readable code is important because I know that bugs will happen despite my best efforts to prevent it. To fix them I will have to read my own code long after I wrote it. Therefore I try to make my code as readable as possible for my future self. The specific techniques involve:
	&lt;ul&gt;
		&lt;li&gt;balanced commenting. Not too much (so that it doesn&amp;#8217;t detract from the code itself) but also not too little so that non-obvious decisions that are not captured in the code are explained.&lt;/li&gt;
		&lt;li&gt;no cryptic names for variables or functions&lt;/li&gt;
		&lt;li&gt;no long functions with complex logic&lt;/li&gt;
		&lt;li&gt;taking the time to make the code look consistent&lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;h2&gt;Re-use high-quality code&lt;/h2&gt;

	&lt;p&gt;It&amp;#8217;s much better if other people sweat writing code and fixing bugs. I look for high quality, reputable code and use it whenever I can e.g. I will use &lt;a href="http://www.sqlite.org/"&gt;SQLite&lt;/a&gt; rather than writing my own persistence layer. &lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/hTnAIFEFgtU" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/8-habits-for-becoming-a-better-programmer.html</feedburner:origLink></entry><entry><title>Simple duplicate post detection for your blog, forum or commenting software</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/XRfujS-RsEw/Simple-duplicate-post-detection-for-your-blog-fo.html" rel="alternate" /><updated>2010-10-27T04:25:39Z</updated><id>tag:blog.kowalczyk.info,2010-10-27:/article/Simple-duplicate-post-detection-for-your-blog-fo.html</id><summary type="html">	&lt;h2&gt;Mistakes happen&lt;/h2&gt;

	&lt;p&gt;I was reading &lt;a href="http://scripting.com" title="scripting.com"&gt;scripting.com&lt;/a&gt; the other day and some article had 3 identical comments from the same person.&lt;/p&gt;

	&lt;p&gt;A mistake, obviously. &lt;/p&gt;

	&lt;p&gt;What is less obvious, at least to the authors of that commenting system, is that such mistakes can be easily prevented with a bit of programming.&lt;/p&gt;

	&lt;p&gt;I know it&amp;#8217;s easy because I&amp;#8217;ve implemented it in a few lines of python in software running this blog and in my &lt;a href="http://blog.kowalczyk.info/software/fofou/index.html"&gt;forum software&lt;/a&gt;. They run on App Engine but the technique applies to any web development platform.&lt;/p&gt;

	&lt;h2&gt;Duplication detection, the easy way&lt;/h2&gt;

	&lt;p&gt;The idea is simple: before inserting an article/post/comment into a database, check if an entry with exactly the same content already exists. In most storage systems (like &lt;span class="caps"&gt;SQL&lt;/span&gt; database) doing this against large text column is difficult and slow. To make it easy and fast we can calculate SHA1 hash of the text, store it as part of the data describing the post and check for duplicate hash.&lt;/p&gt;

	&lt;p&gt;SHA1 keys are short. They are a perfect match for key-value stores. With a proper index they&amp;#8217;re also very fast to check for in a &lt;span class="caps"&gt;SQL&lt;/span&gt; database.&lt;/p&gt;

	&lt;p&gt;For added robustness you can trim whitespace from the beginning and end of text before calculating the hash.&lt;/p&gt;

	&lt;p&gt;This method doesn&amp;#8217;t prevent malicious people (it only takes changing one character to change the hash) but it does fix the common problem of people submitting the same content twice because due to network connection problems they were not properly notified that the post has been successfully submitted. It happens more often that you might think.&lt;/p&gt;

	&lt;p&gt;Using other hash function, like MD5, will work too. SHA1 has better properties but if your programming language provides MD5 but not SHA1, use MD5.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/XRfujS-RsEw" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/Simple-duplicate-post-detection-for-your-blog-fo.html</feedburner:origLink></entry><entry><title>Value your time</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/xftPIeB7RrI/Value-your-time.html" rel="alternate" /><updated>2010-10-24T23:40:38Z</updated><id>tag:blog.kowalczyk.info,2010-10-24:/article/Value-your-time.html</id><summary type="html">	&lt;p&gt;A common question on the internet: I want to host a website. Which low cost &lt;span class="caps"&gt;VPS&lt;/span&gt; should I use? &lt;a href="http://www.linode.com"&gt;Linode&lt;/a&gt; ($20/month for the cheapest plan)? &lt;a href="http://www.slicehost.com/"&gt;Slicehost&lt;/a&gt; (also $20/moth for the cheapest plan)? Something else?&lt;/p&gt;

	&lt;p&gt;A helpful, albeit misguided, answer would weight various pros and cons of many services, compare prices, do rigorous processor and I/O benchmarks etc.&lt;/p&gt;

	&lt;p&gt;A much better answer is: stop wasting your time (and money) trying to optimize inconsequential parts of your business.&lt;/p&gt;

	&lt;p&gt;Your time is worth a lot. For the purpose of this discussion let&amp;#8217;s say it&amp;#8217;s $50/hour (a not so great salary of a good software developer).&lt;/p&gt;

	&lt;p&gt;&lt;span class="caps"&gt;VPS&lt;/span&gt; hosting is a mature, competitive business. You can reject all plans that are too good to be true (e.g. unlimited bandwidth for $5/month) because they are scams. That leaves a number of roughly equivalent plans. Pick one and move on to more important things.&lt;/p&gt;

	&lt;p&gt;If a competitive plan costs $20/month, let&amp;#8217;s be unrealistic and assume you&amp;#8217;ll be able to find an equivalent service that is 25% ($5) cheaper. One hour spent trying to find such a plan would cost you 10 months of savings on such a hypothetical service.&lt;/p&gt;

	&lt;p&gt;Too many of us are obsessed with getting the best possible sticker price without considering the total cost, which includes additional time spent researching the options.&lt;/p&gt;

	&lt;p&gt;If you&amp;#8217;re Google or Amazon, running thousands of servers, squeezing the best possible value out of each server is worth the time because a minor saving gets multiplied. If you&amp;#8217;re choosing a single, low priced commodity among many similar options, you&amp;#8217;ll be better of just picking one with minimal amount of research (the good stuff comes at the top anyway) than spending unbound amount of time comparing options in hopes of finding the best possible value.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/xftPIeB7RrI" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/Value-your-time.html</feedburner:origLink></entry><entry><title>Startup management lessons from "The Social Network"</title><link href="http://feedproxy.google.com/~r/KrzysztofKowalczykBlog/~3/zsTGMELbu3w/Startup-management-lessons-from-The-Social-Netwo.html" rel="alternate" /><updated>2010-10-03T21:14:27Z</updated><id>tag:blog.kowalczyk.info,2010-10-03:/article/Startup-management-lessons-from-The-Social-Netwo.html</id><summary type="html">	&lt;p&gt;&lt;img src="http://www.google.com/movies/image?tbn=f6b490da50581e5b" style="float:right;padding:8px;" title="Social Network" alt="Social Network" /&gt;&lt;/p&gt;

	&lt;p&gt;The movie &lt;a href="http://www.rottentomatoes.com/m/the-social-network/"&gt;The Social Network&lt;/a&gt; is centered around a lawsuit that three founders of ConnectU, a social network in the making, mount against Mark Zuckerberg, the founder of competing social network, Facebook.&lt;/p&gt;

	&lt;p&gt;If you look at at the movie via proper lenses, it can be a lesson about software startup business mistakes. Mistakes that ConnectU founders made managing their project. Mistakes that you can avoid in your own startup.&lt;/p&gt;

	&lt;p&gt;The &lt;a href="http://en.wikipedia.org/wiki/ConnectU"&gt;relevant facts&lt;/a&gt; are:
	&lt;ul&gt;
		&lt;li&gt;three Harvard students start working on an idea for social networking website exclusive to Harvard students in December 2002&lt;/li&gt;
		&lt;li&gt;neither of them is a programmer, so they hire fellow Harvard student to work on it in January 2003. He leaves the project in spring 2003 after graduating and getting a job at Google&lt;/li&gt;
		&lt;li&gt;they hire another Harvard student to continue coding. He works during summer and fall, gets paid $400 for the work but leaves the project for personal reasons. He recommends Zuckerberg, also a Harvard student, for his replacement&lt;/li&gt;
		&lt;li&gt;they talk to Zuckerberg on November 30, 2003 and he agrees to continue the project for equity stake. No formal contract is signed&lt;/li&gt;
		&lt;li&gt;for the next 2 months (December 2003 and January 2004) Zuckerberg pretends to work on ConnectU website but in reality he&amp;#8217;s working on his own similar website instead. He registers the original thefacebook.com domain name on January 14 and launches the website on February 4th, 2004&lt;/li&gt;
		&lt;li&gt;ConnectU website finally launches 4 months later, on May 21, 2004&lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;p&gt;There are several mistakes that ConnectU founders made managing their startup.&lt;/p&gt;

	&lt;h2&gt;Not using written contracts when hiring people.&lt;/h2&gt;

	&lt;p&gt;The agreement between ConnectU founders and Zuckerberg was oral. If you hire people to work on your idea on a contract basis, write a contract. It should spell what the contractor is supposed to do and how much he will be paid for it. It&amp;#8217;s business 101.&lt;/p&gt;

	&lt;p&gt;You can even add a reasonable non-compete clause so that they can&amp;#8217;t just learn everything about your business and start a competing one, like Zuckerberg did.&lt;/p&gt;

	&lt;h2&gt;Underestimating the value of good programmers&lt;/h2&gt;

	&lt;p&gt;It took ConnectU 17 months to launch their website. At least 3 programmers worked on it (2 programmers before Zuckerberg and at least one after) and the 3 founders presumably did something productive as well.&lt;/p&gt;

	&lt;p&gt;Zuckerberg launched his website in 2 months, with code written all by himself (although he did have a non-technical co-founder). He was 8x as effective as ConnectU programmers.&lt;/p&gt;

	&lt;h2&gt;Not growing fast enough&lt;/h2&gt;

	&lt;p&gt;There are some businesses that can grow slowly and organically. There are some that have to &lt;a href="http://joelonsoftware.com/articles/fog0000000056.html"&gt;grow fast at any price&lt;/a&gt;. The wisdom is to know what kind of a business you&amp;#8217;re in.&lt;/p&gt;

	&lt;p&gt;Social networking websites are in the &amp;#8220;grow fast at any price&amp;#8221; category but ConnectU founders didn&amp;#8217;t act like they understood that. Facebook was launched in 2 months which demonstrates Zuckerberg&amp;#8217;s urgency and dedication to the idea at the exclusivity of other things. As soon as he secured funding, Zuckerberg started to aggressively hire more people to work on it, which is exactly what you need to do in such a situation.&lt;/p&gt;

	&lt;p&gt;ConnectU founders pursued other time-consuming activities during that time (they were training as rowers for Olympics) and dragged their feet hiring talent necessary to implement their idea.&lt;/p&gt;

	&lt;h2&gt;Not supervising the work and not firing ineffective employees&lt;/h2&gt;

	&lt;p&gt;Zuckerberg was able to string them along for 2 months by making excuses via e-mail. During that time he didn&amp;#8217;t deliver any code.&lt;/p&gt;

	&lt;p&gt;Sure, Zuckerberg won&amp;#8217;t win Gentlemen Of The Year award but if you&amp;#8217;re mis-managing your employees so badly, you only have yourself to blame. After a month of no results they should have just fired Zuckerberg and hire a more dependable programmer.&lt;/p&gt;

	&lt;h2&gt;Not paying your programmers well&lt;/h2&gt;

	&lt;p&gt;We don&amp;#8217;t have enough facts to say why ConnectU had such a hard time finding effective programmers for their project but it&amp;#8217;s telling that they paid the second programmer $400 for several months of work.&lt;/p&gt;

	&lt;p&gt;A fair market rate would be more like $5000 per month. If you&amp;#8217;re serious about your idea, you need to be realistic about how much you need to pay your crucial employees.&lt;/p&gt;

	&lt;h2&gt;Treating programmers as replaceable cogs&lt;/h2&gt;

	&lt;p&gt;In rare cases you can but programming is hard, good programmers are rare and good code is crucial element of software startups. The visible product might be a website, but what software startups really produce is code behind those html pages.&lt;/p&gt;

	&lt;p&gt;ConnectU founders seemingly treated programmers as hired guns that can be replaced at any time.&lt;/p&gt;

	&lt;p&gt;What Facebook and other technology companies do is hiring the best and retaining them for as long as they can.&lt;/p&gt;

	&lt;h2&gt;Paying in equity&lt;/h2&gt;

	&lt;p&gt;It&amp;#8217;s unclear if ConnectU founders had funds to pay in cash for programmers but from the point of view of the startup founder, paying in equity should be done only if you have no other options.&lt;/p&gt;

	&lt;p&gt;It didn&amp;#8217;t bite ConnectU founders because they failed but if they were successful, they would pay disproportional amount of money for the initial work.&lt;/p&gt;

	&lt;p&gt;In all fairness, this is one mistake that Zuckerberg also made. He founded Facebook with his friend Eduardo, with 70-30 split, with no vesting provision. &lt;/p&gt;

	&lt;p&gt;Eduardo put a minuscule amount of money ($1000 initially and later added $18000) but other than that he doesn&amp;#8217;t seem to have done much work on Facebook. The idea was Zuckerberg&amp;#8217;s. The code was Zuckerberg&amp;#8217;s. Eduardo was a business guy at a time when there was no business to do. He wasn&amp;#8217;t interested in the project enough to work on it during a crucial time after launch, in summer 2004, when he opted to do an internship in New York instead of working with Zuckerberg on Facebook in California.&lt;/p&gt;

	&lt;p&gt;Despite contributing very little, Eduardo ended up with 5% of Facebook (worth more than $billion). Good for Eduardo but sucks for Zuckerberg.&lt;/p&gt;

	&lt;p&gt;Zuckerberg could have done it all by himself but at the very least there should be a clause stipulating vesting schedule of, say, 4 years, saying that if a person stops working on the startup, like Eduardo did, he&amp;#8217;s only entitled to the vested part. Since Eduardo stopped working about 6 months in, he would only get 1/8 of 30% (3.75%) and the rest would go to other founders.&lt;/p&gt;

	&lt;h2&gt;What you don&amp;#8217;t know you don&amp;#8217;t know will hurt you&lt;/h2&gt;

	&lt;p&gt;It all shows that even Harvard hot-shots are not immune to youthful business naiveté. The above mistakes are pretty basic but they still might bite inexperienced people, regardless of how intelligent they are in general.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/KrzysztofKowalczykBlog/~4/zsTGMELbu3w" height="1" width="1"/&gt;</summary><feedburner:origLink>http://blog.kowalczyk.info/article/Startup-management-lessons-from-The-Social-Netwo.html</feedburner:origLink></entry></feed>

