<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SteveStreeting.com &#187; Development</title>
	<atom:link href="http://www.stevestreeting.com/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.stevestreeting.com</link>
	<description>Man bites Ogre</description>
	<lastBuildDate>Sat, 24 Dec 2011 13:08:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.4</generator>
		<item>
		<title>Escalating privileges on Mac OS X securely, and without using deprecated methods</title>
		<link>http://www.stevestreeting.com/2011/11/25/escalating-privileges-on-mac-os-x-securely-and-without-using-deprecated-methods/</link>
		<comments>http://www.stevestreeting.com/2011/11/25/escalating-privileges-on-mac-os-x-securely-and-without-using-deprecated-methods/#comments</comments>
		<pubDate>Fri, 25 Nov 2011 17:04:09 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Objective C]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[AuthorizationExecuteWithPrivileges]]></category>
		<category><![CDATA[SMJobBless]]></category>

		<guid isPermaLink="false">http://www.stevestreeting.com/?p=3059</guid>
		<description><![CDATA[This week I implemented a much-requested feature in SourceTree for the upcoming 1.3 release (beta 1 went out on Monday, this will make it into beta 2) &#8211; a command-line tool so you can quickly pull up SourceTree for the repository you&#8217;re in from a terminal. Writing the command-line tool was trivial, but when I [...]]]></description>
			<content:encoded><![CDATA[<p>This week I implemented a much-requested feature in <a href="http://www.sourcetreeapp.com" target="_blank">SourceTree</a> for the upcoming 1.3 release (<a href="http://www.sourcetreeapp.com/2011/11/21/sourcetree-1-3-public-beta/" target="_blank">beta 1</a> went out on Monday, this will make it into beta 2) &#8211; a command-line tool so you can quickly pull up SourceTree for the repository you&#8217;re in from a terminal. Writing the command-line tool was trivial, but when I came to implement the menu item which would install it in /usr/local/bin, which inherently needs privilege escalation, it turned out to be a lot more complicated than I expected.</p>
<p>How so? Surely lots of people have done this sort of thing before? Well, that&#8217;s true, they have &#8211; but the problem is that just about all of the existing examples of this use the <a href="http://developer.apple.com/library/mac/#documentation/Security/Reference/authorization_ref/Reference/reference.html" target="_blank">Authorization Services</a> API call <a href="http://developer.apple.com/library/mac/#documentation/Security/Reference/authorization_ref/DeprecationAppendix/AppendixADeprecatedAPI.html#//apple_ref/doc/uid/TP30000826-AppendixA" target="_blank">AuthorizationExecuteWithPrivileges</a> &#8211; and this method is <strong>deprecated</strong> in OS X 10.7 (Lion). Now, of course that doesn&#8217;t stop you using it (yet), provided you&#8217;re willing to turn off the warning that building against the 10.7 SDK gives you, but any programmer worth his salt should take deprecation as a hint that they should be looking for another way.</p>
<p>There are basically 3 ways to escalate privileges on OS X, and only one of them is now recommended:</p>
<ol>
<li>Use a helper tool which has its setuid bit set so that it runs as root. Risky if that tool gets compromised, and the setuid bit can be lost, needing reinstatement by another privileged task.</li>
<li>Execute a command as root via <a href="http://developer.apple.com/library/mac/#documentation/Security/Reference/authorization_ref/DeprecationAppendix/AppendixADeprecatedAPI.html#//apple_ref/doc/uid/TP30000826-AppendixA" target="_blank">AuthorizationExecuteWithPrivileges</a>. As mentioned above, this is now deprecated, and again if a hacker compromises either the app or the tool being launched, bad things can happen.</li>
<li>Ask Launch Services to install a privileged helper tool via <a href="http://developer.apple.com/library/mac/#samplecode/SMJobBless/Listings/ReadMe_txt.html" target="_blank">SMJobBless</a>. This helper is subsequently run by launchd as root when invoked via a Unix socket, and can perform privileged tasks. Importantly, code signing is verified at both ends by Launch Services at install time to prevent tampering with either binary.</li>
</ol>
<p>Clearly option 3 was the way to go &#8211; the only &#8216;downside&#8217; about it is that is does require that you have the ability to sign your application and helper tool. I already have valid code signing certificates because I deploy on the App Store, so this isn&#8217;t an issue (even though this functionality won&#8217;t actually be in the App Store version of SourceTree because Apple disallow installer behaviour there, I still sign with the same certs). In fact, the fact that I know my app and helper tool can&#8217;t be interfered with without the code signatures becoming invalid is very reassuring. Given that it only costs $99 per year to be on the Mac Developer Programme which allows you to get certificates (even if you don&#8217;t deploy on the App Store), it&#8217;s something serious developers should consider strongly.</p>
<p>SMJobBless is ideally suited to installing daemons, but it&#8217;s perfectly acceptable to install tools which run simple one-off tasks too. When setting up the plist for the helper, you specify that it is &#8216;OnDemand&#8217;, with no &#8216;KeepAlive&#8217; which means it&#8217;s not started by Launch Services at startup, only when a Unix socket is opened, and shuts down very quickly if there&#8217;s no activity. Unfortunately the <a href="http://developer.apple.com/library/mac/#samplecode/SMJobBless/Listings/ReadMe_txt.html" target="_blank">SMJobBless example</a> doesn&#8217;t do anything except to show you how to install a tool, it doesn&#8217;t tell you how to implement that tool to do anything useful, or how to call it from your main application.</p>
<p>To see how to do that, you need to refer to <a href="http://developer.apple.com/library/mac/#samplecode/BetterAuthorizationSample/Introduction/Intro.html" target="_blank">BetterAuthorizationSample </a>, which includes a re-usable library for this. Ironically though, this example uses AuthorizationExecuteWithPrivileges to install its helper (this example pre-dated its deprecation in favour of SMJobBless). So you have to remove all the code associated with installation; you won&#8217;t need it anyway since SMJobBless does that function better. You keep the rest which gives you a framework for implementing and calling the helper. So here&#8217;s what I did:</p>
<ol>
<li>Implement the installation of a privileged helper, based directly on the SMJobBless example. I needed to change the bundle IDs and the certificate CN&#8217;s to match my setup of course.</li>
<li>Extend the plist files from SMJobBless to register the helper with a socket. This was basically a case of copying the settings from the BetterAuthorizationSample plists, which already does this.</li>
<li>Bring in BetterAuthorizationSampleLib.c/.h to assist with implementation of the helper, and the code for calling it in the app, but remove everything in the &#8216;Installation&#8217; section. This eliminates all the references to AuthorizationExecuteWithPrivileges &#8211; we&#8217;re doing the install with SMJobBless so don&#8217;t need that.</li>
<li>Follow the BetterAuthorizationSample for the implementation of the helper, and the bit in the application where you call the helper to perform privileged operations.</li>
</ol>
<p>So in my case, the following happens when you click &#8216;Install Command Line Tool&#8217; in SourceTree:</p>
<ol>
<li>A privileged helper is installed in Launch Services using SMJobBless. OS X checks the code signatures on both ends to ensure that the helper and the application asking to install it are valid (must be signed with my cert, and that cert must be issued by Apple).</li>
<li>A connection is opened to the privileged helper over a socket which causes launchd to start it up</li>
<li>I ask the helper via the BetterAuthorizationSampleLib to install the command-line tool in /usr/local/bin. As an additional check, the helper validates via &#8216;codesign -v  -R=&#8221;conditions&#8221;&#8216; that this tool is code signed with my cert (again, must be issued by Apple) &#8211; this is to prevent anyone else sniffing out this socket and trying to use it to install other things. If that passes, it installs the command.</li>
</ol>
<p>This is quite a long-winded process compared to just calling a &#8216;cp&#8217; command via AuthorizationExecuteWithPrivileges, but it&#8217;s also a lot more secure, since a malicious person can&#8217;t alter any of the moving parts without invalidating the code signatures. You&#8217;re also insulated from future changes when inevitably AuthorizationExecuteWithPrivileges is removed entirely.</p>
<p>I apologise for the lack of a pre-packaged example here &#8211; I haven&#8217;t had time to extract one from my own implementation yet. However, as described above if you start with the <a href="http://developer.apple.com/library/mac/#samplecode/SMJobBless/Listings/ReadMe_txt.html" target="_blank">SMJobBless</a> sample and add-in the <a href="http://developer.apple.com/library/mac/#samplecode/BetterAuthorizationSample/Introduction/Intro.html" target="_blank">BetterAuthorizationSample</a>, removing from the latter everything associated with installation, you&#8217;re basically there. If I get chance later I&#8217;ll post a shrink-wrapped example.</p>
<p>I hope that helps someone &#8211; I found there to be little information on this subject that was up-to-date, and lots of older information that was misleading so maybe this will save someone some time. Ideally, I hope Apple will combine the SMJobBless and BetterAuthorizationSample some time to produce a 10.7-compliant official example.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevestreeting.com/2011/11/25/escalating-privileges-on-mac-os-x-securely-and-without-using-deprecated-methods/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SSSelectableToolbar</title>
		<link>http://www.stevestreeting.com/2011/06/20/ssselectabletoolbar/</link>
		<comments>http://www.stevestreeting.com/2011/06/20/ssselectabletoolbar/#comments</comments>
		<pubDate>Mon, 20 Jun 2011 13:32:07 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Objective C]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[bwtoolkit]]></category>
		<category><![CDATA[preference pane]]></category>
		<category><![CDATA[ssselectabletoolbar]]></category>

		<guid isPermaLink="false">http://www.stevestreeting.com/?p=3002</guid>
		<description><![CDATA[A common requirement in any Cocoa application is a preference pane style window where each toolbar item switches to a different view in the main window, resizing as necessary. I&#8217;ve used BWToolkit to do this in the past, which provides BWSelectableToolbar. However, there are a few issues with using BWToolkit: If you want to deploy [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-3003" title="SelectableToolbarDemo001" src="http://www.stevestreeting.com/wp-content/uploads/2011/06/SelectableToolbarDemo001.png" alt="" width="239" height="254" align="right" />A common requirement in any Cocoa application is a preference pane style window where each toolbar item switches to a different view in the main window, resizing as necessary. I&#8217;ve used <a href="http://brandonwalkin.com/bwtoolkit/" target="_blank">BWToolkit</a> to do this in the past, which provides BWSelectableToolbar. However, there are a few issues with using BWToolkit:</p>
<ol>
<li>If you want to deploy on the Mac App Store, You have to customise it to remove all uses of private methods, since those are banned on the App Store.</li>
<li>It sometimes crashes Interface Builder &#8211; usually not fatally but it can get awkward</li>
<li>Sometimes it gets the window height slightly too tall when switching panes &#8211; I&#8217;ve patched it to try to cope with this but it still happens sometimes</li>
<li>It relies on using IB plugins. XCode 4 does not support IB plugins anymore &#8211; although you can still build the code, you can&#8217;t edit the nibs anymore</li>
</ol>
<p>I&#8217;ve just been coping with 1, 2 &amp; 3 so far, but 4 was the killer which made me come up with my own alternative: <a href="https://bitbucket.org/sinbad/ssselectabletoolbar" target="_blank">SSSelectableToolbar</a>.</p>
<p>With SSSelectableToolbar, you can still do the preference pane setup entirely within Interface Builder, but it doesn&#8217;t require any plugins. There are a couple of extra steps required because of this, but they&#8217;re not onerous and still better than setting it all up in code.</p>
<p>The license is permissive MIT, usage is in the README, and there&#8217;s an example demo to show how it works. I hope it&#8217;s useful to someone else too.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevestreeting.com/2011/06/20/ssselectabletoolbar/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Why &#8216;software engineering&#8217; is a misnomer</title>
		<link>http://www.stevestreeting.com/2011/06/16/why-software-engineering-is-a-misnomer/</link>
		<comments>http://www.stevestreeting.com/2011/06/16/why-software-engineering-is-a-misnomer/#comments</comments>
		<pubDate>Thu, 16 Jun 2011 18:07:36 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[software engineering]]></category>

		<guid isPermaLink="false">http://www.stevestreeting.com/?p=2970</guid>
		<description><![CDATA[These days I&#8217;m a free agent, and I&#8217;m lucky enough to be able to choose what projects I work on, but in a past life, I was what I suppose is properly referred to as an &#8216;enterprise software developer&#8217;. Yes, I once functioned in an environment where terms like &#8216;mission-critical&#8217;, &#8216;project life-cycle&#8217;, &#8216;stakeholders&#8217; and &#8216;change [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-3000" title="bridge" src="http://www.stevestreeting.com/wp-content/uploads/2011/06/bridge.jpg" alt="" width="150" height="113" align="right" />These days I&#8217;m a free agent, and I&#8217;m lucky enough to be able to choose what projects I work on, but in a past life, I was what I suppose is properly referred to as an &#8216;enterprise software developer&#8217;. Yes, I once functioned in an environment where terms like &#8216;mission-critical&#8217;, &#8216;project life-cycle&#8217;, &#8216;stakeholders&#8217; and &#8216;change management&#8217; came up quite a lot. I&#8217;m grateful for the experience I gained over 12 years of doing that, but I&#8217;m also very glad to be free of it now.</p>
<p>One term which was bandied around a lot in this environment was &#8216;<strong>software engineering</strong>&#8216;. The implication of this term, and the expectation of many people using it, is that designing and creating software is very much like physical engineering disciplines, such as erecting a bridge or building a block of flats. When a software project starts to go off the rails, and fingers are starting to be pointed, a common question is why large physical engineering projects can come in on time an budget, when most software projects beyond a certain size don&#8217;t? Surely if the people who create software claim to be &#8216;engineers&#8217;, they should be able to adhere to the same standards of other engineering professions?</p>
<p>At face value it sounds like a fair argument, and I&#8217;ll be the first one to admit that software engineers are very often not as rigorous as others bearing the title. But there&#8217;s a good reason &#8211; the belief that software projects are akin to building bridges is completely misplaced, and it is a belief which too often leads people to think that software projects should be run using techniques such as fixed prices, up-front design, and waterfall life-cycles. This is despite decades of case studies indicating that such techniques rarely work, and are more often a collective delusion adopted because the reality &#8211; that you&#8217;re never going to be able to predict a large software project accurately up-front &#8211; is too terrifying to be contemplated. The term &#8216;software engineering&#8217;, while indicating some of the responsibilities of such a person, is an incomplete definition of what building software actually entails, and just reinforces these misconceptions.</p>
<p>So, why is making software so different to building a bridge?</p>
<ol>
<li><strong>Software is intangible</strong>.<br />
You can see and touch a bridge, it has a physical presence you can measure and its purpose is absolutely obvious to any observer, as are its success and failure conditions (getting people across a gap without falling down). Even though there are parts of the bridge the user will never see, their purpose can be easily unambiguously defined &#8211; carrying utility cables/pipes, providing maintenance access, etc. Software is intangible, and even the part that is seen by those defining its purpose is often hard to evaluate until it can be seen and used directly, never mind the internal working processes. Evaluating and defining software ahead of time is like trying to describe a dream seen through a keyhole &#8211; incomplete and everyone has a slightly different impression, and regardless of how much you try to write it down, you can&#8217;t capture or communicate its essence completely to others, or guarantee that they interpreted it the same way.<br />
People are just naturally very bad at defining and evaluating intangible things. There&#8217;s no point pretending they can with 300-page requirements documents, you&#8217;re just wasting everyone&#8217;s time &#8211; accept that people won&#8217;t know what they like until they can play with it &#8211; iterate!</li>
<li><strong>Interaction complexity</strong><br />
There&#8217;s only a small number of ways to use a bridge, and they&#8217;re each quite straight forward. Yes, there&#8217;s much complexity to the structure of the bridge itself, but that really doesn&#8217;t matter to a person driving or walking across it &#8211; that doesn&#8217;t need input or feedback from people except for whether they like the look of it.<br />
Software is basically defined by complex interaction, which is often context- and data-sensitive. The number of variations mean that even if every one is bug free (yeah, right), there&#8217;s the question of whether it&#8217;s solving the correct problem, which is a function of people and their interpretation / opinion. While building projects can be complex, those complexities are most often a function of the engineering challenge, whilst most complexity in a software project is a function of the involvement of people, which are far more difficult to pin down.</li>
<li><strong>Change is a constant factor<br />
</strong>Change happens everywhere of course &#8211; maybe the bridge builder discovers that the ground isn&#8217;t as firm as they thought, or suddenly someone wants to make an extra deck available for trains. Big disruption, and an effect on time and budget &#8211; all understandable. The problem when it comes to software is that the perception of change is very different. If suddenly you have to sink massive extra foundations or double the amount of steel you need to use, people understand the magnitude of that intuitively and accept the effect on the schedule. Changes in a software project tend to be perceived as &#8216;just a little tweak&#8217; by those requesting it, which tends to mean tolerance for schedule impact is lower, and indeed the potential for interaction between changes in unexpected ways is often overlooked. Now, I&#8217;m not for a second advocating that change should not be allowed, but often the mechanisms that have been established for managing a project &#8211; up-front estimation, fixed feature sets and so on &#8211; prevent the efficient integration of change, or at least obscure its impact to a point where things become critical. It&#8217;s important to appreciate that change is more common and expected in software projects, by nature of the issues raised in the previous points, and therefore setting your expectations based on a discipline where change is less common is not a smart move.</li>
<li><strong>Lack of hard limits<br />
</strong>Building  a bridge involves respecting some hard, unchallengeable limits. As a wise man once said &#8220;You canna change the laws of physics, Cap&#8217;n!&#8221;. When you&#8217;re building software, however, there are very rarely any unbreakable limits, and even the soft limits that there are tend to be invalidated very regularly as new technology comes on stream. No-one can realistically stand up and say &#8216;this is impossible&#8217; when faced with a request, because almost nothing is impossible. Hard limits in physical projects make all stakeholders &#8216;get real&#8217; &#8211; you can&#8217;t use more land than you have, you can&#8217;t build a skyscraper out of paper, there are non-negotiable rules for safe load-bearing and so on. Barring some really crazy and ground-breaking structures (which BTW, rarely come in on time &amp; budget), these limits ground everyone involved in the project to realistic expectations. In a software project, reining in those feature requests, or those ideas that the implementors have for a new tech they could use, is much more abstract affair, and everything is up for debate.</li>
</ol>
<p>All these things put together mean that if you think you can use the same kinds of techniques to run a software project as you would use for a building project, you&#8217;re kidding yourself. They&#8217;re so very different in fundamental ways, it&#8217;s like trying to catch a shark with a shrimping net (because it&#8217;s just a fish, right?).</p>
<p>So please, stop with these delusions:</p>
<ol>
<li>that estimating the cost of any non-trivial software project (that isn&#8217;t just a carbon copy of something else) is any more sophisticated than mildly informed guesswork.</li>
<li>that it&#8217;s reasonable to think that a fixed-price can be realistic for any software project longer than a couple of weeks</li>
<li>that &#8216;change control&#8217; is the about exceptions, rather than the norm</li>
</ol>
<p>Of course, agile approaches attack these particular delusions rather well. But try to get those adopted in very large organisations where the &#8216;software is like a bridge&#8217; mentality still thrives <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevestreeting.com/2011/06/16/why-software-engineering-is-a-misnomer/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Sales work &#8211; who knew?</title>
		<link>http://www.stevestreeting.com/2011/05/26/sales-work-who-knew/</link>
		<comments>http://www.stevestreeting.com/2011/05/26/sales-work-who-knew/#comments</comments>
		<pubDate>Thu, 26 May 2011 17:00:10 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[sales]]></category>
		<category><![CDATA[sourcetree]]></category>

		<guid isPermaLink="false">http://www.stevestreeting.com/?p=2987</guid>
		<description><![CDATA[The SourceTree 1.2 launch sale is now over, and I thought I&#8217;d post some indicative results. I went for a fairly large discount of 40% over a full week, and some people I know commented to me along the lines of &#8216;what about all that money you&#8217;ll be losing on each sale?&#8217;. I decided on [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-2988 alignright" style="margin-left: 5px; margin-right: 5px; border: 1px solid black;" title="SourceTreeSaleInfographic" src="http://www.stevestreeting.com/wp-content/uploads/2011/05/SourceTreeSaleInfographic.png" alt="" width="205" height="573" align="right" /></p>
<p>The <a href="http://www.sourcetreeapp.com" target="_blank">SourceTree</a> 1.2 launch sale is now over, and I thought I&#8217;d post some indicative results. I went for a fairly large discount of 40% over a full week, and some people I know commented to me along the lines of &#8216;what about all that money you&#8217;ll be losing on each sale?&#8217;.</p>
<p>I decided on a large discount because SourceTree 1.2 was a major update that I was actually quite proud of, so I wanted to get it in front of as many people as I could. I was also aware that there might be people who tried SourceTree before, but who decided it wasn&#8217;t for them, and I wanted to encourage these people to try it again, since I&#8217;d made pretty big strides in this version on the overall appearance of the app and the smoothness of the workflow, in addition to all the normal new features. The way to do this of course is to make it worth their while to do so, by offering a discount that really grabs their attention. A 20% discount probably wasn&#8217;t going to do that effectively, but 40%? That&#8217;s almost half price! It&#8217;s this sort of gut reaction I was looking to promote.</p>
<p>The other thing I was acutely aware of is that you have to be careful not to have too many sales. If you go on sale too often, people are going to start assuming that there&#8217;s a sale coming almost any time of year, so will avoid buying unless there&#8217;s a sale on. In my opinion, sales need to be infrequent, but big and attention-grabbing when they do happen.</p>
<p>So actually my goal for the sale wasn&#8217;t necessarily to make more money than usual, but to get more eyeballs on the new version, and more active users, which I hoped would then translate to more awareness and more sales further down the line, because satisfied customers are the best marketing resources you can ever have. Solid reasoning, but as it turned out, things went <em>much</em> better than I could have hoped, so in the end I actually achieved both at once. <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>So for those people who were wondering whether having a sale is worth it, my results are on the right, in fashionable infographic form <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>As I said above, what I was really looking for was to reach more people, and I certainly did that &#8211; with a 793% increase in units sold in the sale week, that&#8217;s about 2 months&#8217; worth of new users in one week. And as you can see, in value terms it also ended up a considerable net positive even with the 40% discount &#8211; now of course I&#8217;m expecting sales to be more sluggish immediately following since the sale will have caused people to bring forward their purchase, but I&#8217;m pretty confident it&#8217;ll remain positive even with that compensating effect.</p>
<p>So why am I writing about this? Am I doing it to strut around flashing my &#8216;wad&#8217; at people? No, and if I&#8217;d included the actual $ values you wouldn&#8217;t think that anyway &#8211; they&#8217;re fantastic news to me but they&#8217;re in the &#8216;I can keep doing this sort of thing for a living!&#8217; range rather than the &#8216;I can buy a Ferrari tomorrow!&#8217; range <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  I&#8217;m writing it to hopefully provide a data point to other developers who, like me, are still learning about selling their wares online, and are wondering about what kind of affect a sale might have. I don&#8217;t know whether it will be exactly the same for you, and there are no doubt a number of variables involved, but this was my experience, and I&#8217;ve been very happy with it. Maybe it will help someone else pondering a similar decision&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevestreeting.com/2011/05/26/sales-work-who-knew/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SourceTree, your Mac Git &amp; Mercurial GUI, is 40% off this week</title>
		<link>http://www.stevestreeting.com/2011/05/19/sourcetree-your-mac-git-mercurial-gui-is-40-off-this-week/</link>
		<comments>http://www.stevestreeting.com/2011/05/19/sourcetree-your-mac-git-mercurial-gui-is-40-off-this-week/#comments</comments>
		<pubDate>Thu, 19 May 2011 17:13:40 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Objective C]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[1.2]]></category>
		<category><![CDATA[releases]]></category>
		<category><![CDATA[sourcetree]]></category>

		<guid isPermaLink="false">http://www.stevestreeting.com/?p=2982</guid>
		<description><![CDATA[Since I&#8217;m trying to spread this news as far and wide as I can, I might as well say it here too Since the approval light just went green on the Mac App Store, I&#8217;m happy to announce the launch of SourceTree 1.2! In celebration, I&#8217;m having a crazy-bonkers 40% off sale just for one week, so [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-2846" title="SourceTree icon" src="http://www.stevestreeting.com/wp-content/uploads/2010/10/icon.png" alt="" width="154" height="154" /></p>
<p>Since I&#8217;m trying to spread this news as far and wide as I can, I might as well say it here too <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Since the approval light just went green on the Mac App Store, I&#8217;m happy to announce the launch of <a href="http://www.sourcetreeapp.com" target="_blank">SourceTree</a> 1.2! In celebration, I&#8217;m having a crazy-bonkers <strong>40% off sale</strong> just for one week, so get it while it&#8217;s hot!</p>
<p>There&#8217;s <em>loads</em> of things that are new or improved in this release, but here are the headlines:</p>
<ul>
<li><strong>Support for GitHub, Bitbucket and Kiln APIs</strong>, so you can see your hosted projects inside SourceTree, clone from them, link them as remotes, and even create new projects if you want.</li>
<li><strong>Streamlined and polished user interface</strong> &#8211; I specifically dedicated a lot of extra time in this release on making SourceTree easier on the eyes, and to streamline the layout and workflows better.</li>
<li><strong>Performance -</strong> I thought SourceTree was already pretty fast, but I managed to find quite a few more places to trim the fat, and also parallelised more activities to make things feel more responsive. Everything feels snappier, and complex repositories benefit especially.</li>
<li><strong>New Sidebar </strong>- I had previously resisted the need to emulate iTunes here, but once I had implemented it, I had to admit that I was wrong, and in fact this worked great. Provides lots of shortcuts to navigating and operating on branches, tags and remotes.</li>
<li><strong>Stashing and Shelving </strong>- oft requested, now delivered <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li><strong>Customise Git and Mercurial</strong> &#8211; you can now use your system Git / Mercurial instead of SourceTree&#8217;s standard versions (which have been updated), and enable additional Mercurial extensions (at your own risk).</li>
<li><strong>French and Japanese translations</strong> &#8211; local versions for our friends in far away (and not so far away) places, likely to be more to come in future. Big thanks to tuan_kuranes and mzch for their help with these two!</li>
<li><strong>And the rest</strong> &#8211; just lots of little refinements too numerous to list. Examples: copying text from the diff panel, &#8216;git commit &#8211;amend&#8217; support, close branches in Mercurial, switch tracking branches in Git</li>
</ul>
<p>It&#8217;s quite a big update &#8211; one user remarked to me that they&#8217;d normally expect developers to charge an upgrade fee for something like this, but like all other SourceTree updates this is free to existing customers. I have no plans for any paid upgrades for some time yet, I just want to keep making SourceTree better, and hope that more people come onboard. Maybe it&#8217;s my open source background, but I like to keep iterating and continually improving things, based on what I want to do (I&#8217;m a daily SourceTree user myself), and on what people tell me they&#8217;d like to see. SourceTree 1.2 certainly won&#8217;t be the last update by far <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>When I look back 6 months at SourceTree 1.0, it&#8217;s incredible how much better it is as a product now, both visually and functionally. I&#8217;ve learned a ton of things while I&#8217;ve been developing it, and I continue to learn more all the time, and I can&#8217;t think of anything I&#8217;d rather be doing right now. Also, my wife Marie re-designed many of the icons for 1.2 (and I think you&#8217;ll agree they&#8217;re a lot nicer) &#8211; that was fun to do as a joint project, even if I am a picky &#8216;customer&#8217; <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>I hope you enjoy the new release!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevestreeting.com/2011/05/19/sourcetree-your-mac-git-mercurial-gui-is-40-off-this-week/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Automatically get latest download link from Sparkle in PHP</title>
		<link>http://www.stevestreeting.com/2011/05/19/automatically-get-latest-download-link-from-sparkle-in-php/</link>
		<comments>http://www.stevestreeting.com/2011/05/19/automatically-get-latest-download-link-from-sparkle-in-php/#comments</comments>
		<pubDate>Thu, 19 May 2011 14:48:07 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Objective C]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[sparkle]]></category>
		<category><![CDATA[webdev]]></category>

		<guid isPermaLink="false">http://www.stevestreeting.com/?p=2973</guid>
		<description><![CDATA[This is just a quick post to help someone out on Twitter, and the blog seemed the best place to post it. If you make Mac apps, you probably use Sparkle to manage your auto-update process, outside the Mac App Store anyway. And so you should, it&#8217;s awesome, and makes keeping software up to date [...]]]></description>
			<content:encoded><![CDATA[<p>This is just a quick post to help someone out on Twitter, and the blog seemed the best place to post it.</p>
<p>If you make Mac apps, you probably use <a href="http://sparkle.andymatuschak.org/" target="_blank">Sparkle</a> to manage your auto-update process, outside the Mac App Store anyway. And so you should, it&#8217;s awesome, and makes keeping software up to date much easier. But what about the download link on your website for new users? Wouldn&#8217;t it be nice not to have to manually update that every time?</p>
<p>For <a href="http://www.sourcetreeapp.com">SourceTree</a>, I use a PHP script which just parses my Sparkle appcast and reads the latest release from there, generating a download link automatically. So whenever I update the Sparkle appcast (and I have scripts to do this from XCode, which I may share in a subsequent post if there&#8217;s interest), the download link for new users is always up to date immediately.</p>
<p>The full code is after the jump if you want it. As usual, feel free to use this for whatever you want, but there are no warranties for anything whatsoever; don&#8217;t blame me if it doesn&#8217;t work, or dissolves your website into a pool of steaming alien slime.</p>
<p><span id="more-2973"></span></p>
<pre class="brush: php;">
&lt;?php

// We're looking for the latest link link this:
// 			&lt;pubDate&gt;Thu, 14 Oct 2010 10:34:03 +0100&lt;/pubDate&gt;
//			&lt;enclosure url=&quot;http://downloads.whatever.com/MyDownload.dmg&quot; sparkle:version=&quot;1.0.0.5&quot;

class AppCastXMLParser
{
   var $tag_name;
   var $tag_data;
   var $tag_prev_name;
   var $tag_parent_name;
   var $latest_date;
   var $use_next_url;
   var $download_url;
   function AppCastXMLParser ()
   {
	   $tag_name = NULL;
	   $tag_data = array ();
	   $tag_prev_name = NULL;
	   $tag_parent_name = NULL;

	   $latest_date = NULL;
	   $use_next_url = true;
	   $download_url = NULL;
   }
   function startElement ($parser, $name, $attrs)
   {
	  if ($this-&gt;tag_name != NULL)
	  {
		 $this-&gt;tag_parent_name = $this-&gt;tag_name;
	  }
	  $this-&gt;tag_name = $name;

	  if ($name == &quot;enclosure&quot; &amp;&amp; $this-&gt;use_next_url)
	  {
	  	$this-&gt;download_url = $attrs['url'];
	  	$this-&gt;use_next_url = false;
	  }

   }
   function endElement ($parser, $name)
   {
	  if ($this-&gt;tag_name == NULL)
	  {
		 $this-&gt;tag_parent_name = NULL;
	  }
	  $this-&gt;tag_name = NULL;
	  $this-&gt;tag_prev_name = NULL;
   }
   function characterData ($parser, $data)
   {
	  if ($this-&gt;tag_name == $this-&gt;tag_prev_name)
	  {
		 $data = $this-&gt;tag_data[$this-&gt;tag_name] . $data;
	  }
	  $this-&gt;tag_data[$this-&gt;tag_name] = $data;
	  if ($this-&gt;tag_parent_name != NULL)
	  {
		 $this-&gt;tag_data[$this-&gt;tag_parent_name . &quot;.&quot; . $this-&gt;tag_name] = $data;
	  }
	  $this-&gt;tag_prev_name = $this-&gt;tag_name;

	  if ($this-&gt;tag_name == &quot;pubDate&quot;)
	  {
		if ($thisdate = strtotime($this-&gt;tag_data[$this-&gt;tag_name]))
		{
			if ($this-&gt;latest_date == NULL || $this-&gt;latest_date &lt; $thisdate)
			{
				$this-&gt;use_next_url = true;
				$this-&gt;latest_date = $thisdate;
			}
		}
	  }

   }
   function parse ($data)
   {
	  $xml_parser = xml_parser_create ();
	  xml_set_object ($xml_parser, $this);
	  xml_parser_set_option ($xml_parser, XML_OPTION_CASE_FOLDING, false);
	  xml_set_element_handler ($xml_parser, &quot;startElement&quot;, &quot;endElement&quot;);
	  xml_set_character_data_handler ($xml_parser, &quot;characterData&quot;);
	  $success = xml_parse ($xml_parser, $data, true);
	  if (!$success)
	  {
		  $this-&gt;tag_data['error'] =  sprintf (&quot;XML error: %s at line %d&quot;, xml_error_string(xml_get_error_code ($xml_parser)), xml_get_current_line_number ($xml_parser));
	  }
	  xml_parser_free ($xml_parser);
	  return ($success);
   }
   function getElement ($tag)
   {
	  return ($this-&gt;tag_data[$tag]);
   }
}

function getLatestDownloadURL()
{

	$appcastparser = new AppCastXMLParser ();

	$appcast = $contents=file_get_contents(&quot;http://www.myapp.com/path/to/SparkleAppcast.xml&quot;);

	if ($appcastparser-&gt;parse ($appcast))
	{
		return $appcastparser-&gt;download_url;
	}
	else
	{
		return NULL;
	}
}

$url = getLatestDownloadURL();

if ($url)
{
	echo &quot;&lt;p&gt;Thank you for downloading MyRandomApp, your download should start automatically.&lt;/p&gt;&quot;;
	echo &quot;&lt;p&gt;If your download doesn't start within 5 seconds, you can use this &lt;a href=\&quot;$url\&quot;&gt;direct link&lt;/a&gt;.&lt;/p&gt;\n&quot;;

	echo &lt;&lt;&lt;EXCERPT
	&lt;script type=&quot;text/javascript&quot;&gt;
	&lt;!--
	function godownload()
	{
		window.location = &quot;$url&quot;
	}
	setTimeout(&quot;godownload()&quot;, 2000)
	//--&gt;
	&lt;/script&gt;
EXCERPT;

}

?&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.stevestreeting.com/2011/05/19/automatically-get-latest-download-link-from-sparkle-in-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mac user base by country: my figures so far</title>
		<link>http://www.stevestreeting.com/2011/04/07/mac-user-base-by-country-my-figures-so-far/</link>
		<comments>http://www.stevestreeting.com/2011/04/07/mac-user-base-by-country-my-figures-so-far/#comments</comments>
		<pubDate>Thu, 07 Apr 2011 12:09:29 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[sales]]></category>
		<category><![CDATA[sourcetree]]></category>

		<guid isPermaLink="false">http://www.stevestreeting.com/?p=2935</guid>
		<description><![CDATA[As many of you probably know, almost a year ago now I decided to take the plunge and move my primary development activities to the Mac. I taught myself Objective-C, got properly to grips with Cocoa at last, and started a new Mac OS X-specific project which would eventually become SourceTree, learning a ton along [...]]]></description>
			<content:encoded><![CDATA[<p>As many of you probably know, <a href="http://www.stevestreeting.com/2010/05/16/takinga-bite-of-the-apple/">almost a year ago now</a> I decided to take the plunge and move my primary development activities to the Mac. I taught myself Objective-C, got properly to grips with Cocoa at last, and started a new Mac OS X-specific project which would eventually become <a href="http://www.sourcetreeapp.com" target="_blank">SourceTree</a>, learning a ton along the way (a process which is by no means complete!).</p>
<p>Happily, things have turned out very well &#8211; SourceTree continues to sell, reassuring me that there&#8217;s enough interest out there for me to keep expanding and improving it (I&#8217;m looking forward to getting the next major release in people&#8217;s hands soon), and I&#8217;ve also been getting some Mac/<a href="http://www.ogre3d.org" target="_blank">Ogre</a>-based contract work which I&#8217;ve enjoyed a great deal. In short, my Macbook Pro and I are now pretty inseparable, Windows 7 is powered off 99% of the time, and I saved hundreds of pounds by not upgrading to Visual Studio 2010 <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Out of interest, I thought I&#8217;d share some of my <a href="http://www.sourcetreeapp.com" target="_blank">SourceTree</a> sales information, in terms of the country distribution. Mac use is typically associated primarily with the USA, and while that&#8217;s certainly reflected in my absolute numbers, there&#8217;s some quite interesting figures revealed when you take into account population size. SourceTree is aimed at developers of course, so all numbers reflect this audience alone (and of course those that chose to buy it) but in practice I suspect that the proportions of developers to non-developers is fairly uniform in most developed countries.</p>
<p>So, firstly the absolute distribution:</p>
<p><img class="alignnone size-full wp-image-2938" title="SourceTree_Country_Absolute" src="http://www.stevestreeting.com/wp-content/uploads/2011/04/SourceTree_Country_Absolute.png" alt="" width="611" height="400" /></p>
<p>No surprises there, the USA is the single largest source, followed by Germany and the UK (who are constantly scrapping over second place!). To me though, Switzerland stuck out as the most interesting, because it&#8217;s up there in 4th place yet has a relatively small population (under 8m). So I wondered &#8211; what would the chart look like if I scaled it by the population size? Here&#8217;s the result:</p>
<p><img class="alignnone size-full wp-image-2941" title="SourceTree_Country_PerCapita2" src="http://www.stevestreeting.com/wp-content/uploads/2011/04/SourceTree_Country_PerCapita2.png" alt="" width="611" height="400" /></p>
<p>And there you go &#8211; as expected Switzerland jumps right to the top, and to my surprise Luxembourg and Denmark are up there too, beating the UK which I expected to come in second. Quite a lot of European countries are punching above their weight in per-capita Mac development, if SourceTree sales are any indication. In fact, on a per-capita basis, the USA is only just sneaking into the top 10, despite it being by far my best overall customer in sheer sales volume.</p>
<p>I&#8217;m aware that scaling by population isn&#8217;t all that scientific, since it is sensitive to the proportion of non-developers (and even non-computer users), but as I say, I think in developed countries at least, the comparisons are reasonably valid.</p>
<p>So the perception that Mac development is more popular in the USA than elsewhere may be inaccurate, based on my numbers at least (which of course are not massive in the grand scheme of things, but still a statistically relevant sample I think). Sure, simply because of the sheer population size of the USA it&#8217;s bound to dominate anyone&#8217;s sales numbers, but if you asked the question &#8216;of 1000 randomly selected developers in a country, what percentage are using a Mac?&#8217;, the result may not be skewed in the way you might expect. It was surprising to me, anyway.</p>
<p>I wonder if anyone else who has been doing this for longer has had similar results?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevestreeting.com/2011/04/07/mac-user-base-by-country-my-figures-so-far/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Automating Incremental Nib Localisation in Cocoa</title>
		<link>http://www.stevestreeting.com/2011/02/25/automating-incremental-nib-localisation-in-cocoa/</link>
		<comments>http://www.stevestreeting.com/2011/02/25/automating-incremental-nib-localisation-in-cocoa/#comments</comments>
		<pubDate>Fri, 25 Feb 2011 17:47:35 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[OS X]]></category>

		<guid isPermaLink="false">http://www.stevestreeting.com/?p=2901</guid>
		<description><![CDATA[Cocoa is already quite good at handling localisation &#8211; you have a folder per language where all your resources are loaded from, and you get tools for exporting your strings from your code (genstrings which exports NSLocalizedString macros) and from your user interface components (ibtool which can process nib files to export &#38; import strings). [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://developer.apple.com/technologies/mac/cocoa.html" target="_blank">Cocoa</a> is already quite good at <a href="http://developer.apple.com/internationalization/localization/" target="_blank">handling localisation</a> &#8211; you have a folder per language where all your resources are loaded from, and you get tools for exporting your strings from your code (genstrings which exports NSLocalizedString macros) and from your user interface components (ibtool which can process nib files to export &amp; import strings).</p>
<p>What isn&#8217;t covered very well in the docs though is how you might automate all this so that it&#8217;s efficient, incremental, and idiot-proof. And by idiot, I mean me after more than 7 days since reading the docs.</p>
<p>There are tools out there that purport to make this easier, such as AppleGlot and iLocalize, but to be honest I found they just made things more complicated. All I really wanted was an efficient way to batch export and import localised strings, to know what changed between versions, and to keep my previously localised strings automatically without overwriting them. Translators should need nothing more than a Unicode-capable text editor &#8211; no complex tools, no training, just their natural ability to turn English into a different language and type it into a text file.</p>
<p>I ended up with two Python scripts to handle this &#8211; one to handle the genstrings/NSLocalizedString route, which I wrote a while back and covered <a href="http://www.stevestreeting.com/2010/05/18/os-x-localisation-incremental-genstrings-and-utf-8-files/" target="_blank">in a previous blog post</a>. The second I wrote today to handle nibs, and also to build the individual language folders. I needed it to do this:</p>
<ol>
<li>Export strings from nibs for each language, merge with strings already translated, or</li>
<li>Import strings for each language and create localised nibs based on the master English versions</li>
</ol>
<p>Here&#8217;s my Python script to do this: <a href="https://bitbucket.org/sinbad/cocoalocalisationtools/src/6a79754c6887/localize_nibs.py" target="_blank">localise_nibs.py</a></p>
<pre class="brush: plain;">
Usage:
  localize_nibs.py --basedir=&lt;base&gt; --stringsdir=&lt;strdir&gt;
    [--langdir=&lt;langdir&gt;] export|import

  export: Reads all the xib files in &lt;base&gt; and generates .strings files
        for every 2-char country code directory under &lt;strdir&gt;
        New strings will be added to existing files.
  import: Reads all the xib files in &lt;base&gt; and looks for .strings files
        in &lt;strdir&gt;/&lt;lang&gt; with the same name. Replaces strings in xib and
        writes the output to &lt;langdir&gt;/&lt;lang&gt;.lproj</pre>
<p>So basically, you start with a base folder full of nib files (in English in my case), and point &#8211;stringsdir at a folder which contains (empty to begin with) subfolders corresponding to languages (like &#8216;fr&#8217;, &#8216;de&#8217;, &#8216;ja&#8217; etc). When using the &#8216;export&#8217; option, it will go through all your .xib files and generate strings from them using ibtool, once for each language. It will also turn these files into UTF-8 rather than UTF-16 (as ibtool exports them), so that you can put the files in hg/git without losing text diff support. You can give all these files to your translators.</p>
<p>The nice thing is that if you add a new control to your user interface, and you&#8217;ve already got translations in the &#8211;stringsdir folder, the script will <strong>merge</strong> the output from ibtool and the existing translation, only adding the new strings. You can then simply give the files to your translator with a &#8216;diff&#8217; report (this is why you want UTF-8) to show them what they need to look at. The Apple localisation docs talk about &#8216;incremental&#8217; localisation, but they totally miss this part &#8211; by &#8216;incremental&#8217; they just mean taking a localised nib that you&#8217;ve manually changed and merging geometry settings, not generating a new strings file which doesn&#8217;t lose the previous translation.</p>
<p>The &#8216;import&#8217; option does the reverse, it takes the translated strings and the base nibs, and creates localised nibs in the &#8211;langdir folder. Mostly the script just automates everything so it finds the files on its own, processes all languages, and highlights when there&#8217;s a missing translation (and uses the base version temporarily so the app still works). Note that I assume that you only manually author one nib (the base version) &#8211; personally I don&#8217;t have the resources to tweak geometry in every language so if you do, you&#8217;ll need to alter the script to cope with the &#8216;incremental&#8217; localisation as Apple presents it in the docs. </p>
<p>Anyway, I just thought I&#8217;d post this in case it helps someone else &#8211; I experimented with a few different options and I found this one to be the best &#8211; it&#8217;s simple, uses tools you already have, and plays nice with source control. Result?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevestreeting.com/2011/02/25/automating-incremental-nib-localisation-in-cocoa/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>My Version Control System History</title>
		<link>http://www.stevestreeting.com/2011/02/19/my-version-control-system-history/</link>
		<comments>http://www.stevestreeting.com/2011/02/19/my-version-control-system-history/#comments</comments>
		<pubDate>Sat, 19 Feb 2011 13:05:19 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[CVS]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[sourcetree]]></category>
		<category><![CDATA[svn]]></category>
		<category><![CDATA[vcs]]></category>
		<category><![CDATA[version control]]></category>

		<guid isPermaLink="false">http://www.stevestreeting.com/?p=2893</guid>
		<description><![CDATA[I was thinking the other day about how many version control systems I&#8217;ve made my way through over the years of being a professional developer, and I figured it would be fun to put it in graph form. Of course, this is entirely from memory and gives the illusion of being more empirical than it [...]]]></description>
			<content:encoded><![CDATA[<p>I was thinking the other day about how many version control systems I&#8217;ve made my way through over the years of being a professional developer, and I figured it would be fun to put it in graph form. Of course, this is entirely from memory and gives the illusion of being more empirical than it actually is, but hey, everyone loves graphs, right?</p>
<p><a href="http://www.stevestreeting.com/wp-content/uploads/2011/02/vcs_history.png"><img class="alignnone size-full wp-image-2894" title="vcs_history" src="http://www.stevestreeting.com/wp-content/uploads/2011/02/vcs_history.png" alt="" width="918" height="350" /></a></p>
<p>Yes, I really didn&#8217;t use any source control back in 1994, barring backing up to 3.5&#8243; floppies. &#8216;Custom&#8217; refers to a system I wrote myself in 1995 to do version control on a mainframe system I was working on at the time; really it wasn&#8217;t a proper VCS system as you would think of it now, but it did the very basics to make sure we knew what was being developed and deployed at any point in time. You could think of it as a VCS system that only had history at the tags <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>As you can also see, Visual SourceSafe was the first packaged system I used &#8211; you can pity me now &#8211; as more of my work started to involve PCs instead of &#8216;big iron&#8217;. At that stage, the concept of &#8216;checking out&#8217; and &#8216;checking in&#8217; was normal. Oh, how naïve we were.</p>
<p>I discovered <a href="http://www.nongnu.org/cvs/" target="_blank">CVS</a> at the turn of the millennium, at the same time I started <a href="http://www.ogre3d.org" target="_blank">Ogre</a>. The ability to work without checking anything out was a revelation! I went on to use that on all my projects for quite a few years, at least until I considered <a href="http://subversion.tigris.org/" target="_blank">Subversion</a> stable enough to base production work on. Even then, I only moved new projects to Subversion mostly (Ogre eventually moved in 2008 &#8211; was it really that recent?), and kept CVS for many existing projects.</p>
<p>I first encountered <a href="http://en.wikipedia.org/wiki/Distributed_revision_control" target="_blank">Distributed Version Control</a> at a <a href="http://git-scm.com/" target="_blank">Git</a> presentation at the Summer of Code mentor summit at Google HQ in late 2007. I have to admit, I didn&#8217;t really &#8216;get it&#8217; at first &#8211; it just seemed to make things more complicated and most of those promoting it were mostly die-hard Linux fans and wide-eyed early adopters that didn&#8217;t make you want to put your production code on it yet. There was also no <a href="http://www.github.com" target="_blank">GitHub</a> at this time so the benefits weren&#8217;t really very visible. It took me until 2009 to really start evaluating DVCS in earnest, and decided that I liked <a href="http://mercurial.selenic.com/" target="_blank">Mercurial</a> best, due to its equal treatment of all platforms, good diagnostic reporting, easy extensibility and intuitive interface that gave power without over-complexity. Today, all my own projects are in Mercurial, but I use Git a lot too, not least because I support it in <a href="http://www.sourcetreeapp.com" target="_blank">SourceTree</a>, and get involved in other projects which use Git.</p>
<p>There are a couple of randoms thrown in there &#8211; I used <a href="http://www.alienbrain.com/" target="_blank">Alienbrain</a> for a few months on a client project and totally hated it (think Visual SourceSafe with a few bells &#8211; it may be useful for artists but for coders it was horrid), and I did play with <a href="http://bazaar.canonical.com/" target="_blank">Bazaar</a> for a bit but didn&#8217;t really warm to it, even though it had some quite nice ideas.</p>
<p>So there you are &#8211; my VCS experience over ~17 years in professional development. It kinda makes me want to do a language / platform graph now <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevestreeting.com/2011/02/19/my-version-control-system-history/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Introducing: SourceTree</title>
		<link>http://www.stevestreeting.com/2010/10/26/introducing-sourcetree/</link>
		<comments>http://www.stevestreeting.com/2010/10/26/introducing-sourcetree/#comments</comments>
		<pubDate>Tue, 26 Oct 2010 16:24:20 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Objective C]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DVCS]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[sourcetree]]></category>
		<category><![CDATA[vcs]]></category>
		<category><![CDATA[version control]]></category>

		<guid isPermaLink="false">http://www.stevestreeting.com/?p=2845</guid>
		<description><![CDATA[I&#8217;m pleased to announce that I&#8217;m finally ready to make my first fully-fledged commercial Mac OS X application available to the world! SourceTree is a user-friendly Mac OS X front-end for Mercurial and Git, the two most popular distributed version control systems used today. The goal was to create a single tool which could deal [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.sourcetreeapp.com" target="_blank"><img class="alignright size-thumbnail wp-image-2846" title="icon" src="http://www.stevestreeting.com/wp-content/uploads/2010/10/icon-150x150.png" alt="" width="150" height="150" align="right" /></a>I&#8217;m pleased to announce that I&#8217;m finally ready to make my first fully-fledged commercial Mac OS X application available to the world!</p>
<p><strong><a href="http://www.sourcetreeapp.com" target="_blank">SourceTree</a></strong> is a user-friendly Mac OS X front-end for <a href="http://mercurial.selenic.com/" target="_blank">Mercurial</a> and <a href="http://git-scm.com/" target="_blank">Git</a>, the two most popular distributed version control systems used today. The goal was to create a single tool which could deal with both systems efficiently, and to give a developer quick and intuitive access to the things (s)he needs to just get on with building software.</p>
<p>I thought I&#8217;d answer a few background questions on this that I get asked on occasion:</p>
<p><strong>Why Mercurial AND Git?</strong></p>
<p>Other apps tend to concentrate on just one version control system, so why am I supporting two? Well, as a developer I&#8217;m regularly coming across projects from both sides of the fence, and in practice I find I need to use both fairly regularly. I personally chose Mercurial for my own projects (and discussed why <a href="http://www.stevestreeting.com/2009/11/06/dvcs-score-card/">here</a>), but I still use Git when dealing with other projects, and spend a fair amount of time hopping between the two. It struck me that even though they have their differences, they are both based on the same <a href="http://en.wikipedia.org/wiki/Distributed_Version_Control_System" target="_blank">distributed principles</a>, so having to use two separate tools was just unnecessary. I wanted a single tool which provided a common interface where that made sense, while still exposing the things they do differently where that was useful too. <a href="http://www.sourcetreeapp.com" target="_blank">SourceTree 1.0</a> is my first attempt at that.</p>
<p><strong>Why only Mac OS X?</strong></p>
<p>There were actually multiple reasons for this choice:</p>
<ol>
<li>I wanted to learn Objective-C and Cocoa on a real project</li>
<li>I know from experience that designing for multiple platforms can be a distraction, with more time spent on compatibility issues, and less on functionality &#8211; and that&#8217;s before you even consider the compromises  you have to make, particularly on UI conventions which are far from uniform across platforms. I&#8217;ve been a multi-platform developer for more than 10 years, and for a change I just wanted to focus on the end user results and nothing else. I&#8217;m aware that schedules slip very easily when you overcomplicate, and I&#8217;m already supporting multiple DVCS systems (something I consider to be an important feature point), so I deliberately chose to keep this element simple.</li>
<li>Mac OS X has become my own platform of choice for most things now. The combination of stability, user-friendliness, Unix underpinnings and well designed hardware match my current needs perfectly. I&#8217;m done with the &#8216;some assembly required&#8217; PCs that I loved tinkering with over the past 15 years</li>
</ol>
<p><strong>What about Subversion?</strong></p>
<p>A few people have asked me if I plan to add Subversion support too. I actually did intend to originally, until I realised how much time it was going to take to just do a decent job on Mercurial and Git. Within the time constraints, I focussed on the subject areas that I felt I could contribute most to &#8211; there are already quite a few Subversion tools out there for Mac OS X, but Mercurial and Git are much less well served, so that&#8217;s where I focussed my efforts.</p>
<p>I still have Subversion support tentatively on my work plan, but it&#8217;s not top of the list. I think it&#8217;s better to do your most important features well before diversifying. Plus, there are problems with Subversion &#8211; it&#8217;s very, very slow compared to Mercurial and Git, so to match the performance in SourceTree of things like the interactive searches and dynamic refreshing / log population I&#8217;d probably have to do a ton of extra caching just so the user wasn&#8217;t sat tapping their fingers.</p>
<p><strong>Edit:</strong> I made my decision on this: I don&#8217;t plan to support local Subversion, but to support operating with Subversion servers with Mercurial and Git locally via hgsvn and git-svn.</p>
<p><strong>Why didn&#8217;t you make it open source?</strong></p>
<p>Sorry folks, while I love contributing to open source (I&#8217;ve done a bit on SourceTree too, sending a patch back to BWToolkit), making it work as a business is very hard indeed. I half-killed myself trying to combine being an open source project leader and doing other commercial activities at the same time, so now I&#8217;m trying a more traditional approach. One thing I learned in the last few years is that there are some sectors &amp; application types where being an open source maintainer is very compatible with also running a business based on that project, and there are others where you can really only do one or the other simultaneously without flaming out. Sucks, but there it is <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>What&#8217;s Next?</strong></p>
<p>I have a <a href="http://www.sourcetreeapp.com/roadmap/" target="_blank">public, official roadmap</a> for SourceTree and encourage users to suggest things they think should be on there, via the <a href="http://www.sourcetreeapp.com/support/" target="_blank">support system</a>. I learned from running an open source project for 10 years that being open about your plans can be a big benefit &#8211; users like to know where things are likely to be going, and often have better ideas than the developer on what could do with a bit more spit and polish. They can also tell you what&#8217;s important to them, which is crucial for prioritising &#8211; as developers we tend to get carried away with things we want to work on, but in the end, it&#8217;s scratching the customer&#8217;s itch that matters most.</p>
<p>And while I&#8217;m really quite proud of SourceTree 1.0, there are plenty of features I&#8217;d like to continue to add, and definitely more room for some totally unnecessary beautification which I didn&#8217;t have time for in the first release. Hey, this <em>is</em> OS X <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>SourceTree is available now on a 21-day trial license. <a href="http://www.sourcetreeapp.com" target="_blank">Go get it already</a> <img src='http://www.stevestreeting.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevestreeting.com/2010/10/26/introducing-sourcetree/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>

