{"id":1216,"date":"2014-09-17T08:46:06","date_gmt":"2014-09-17T15:46:06","guid":{"rendered":"http:\/\/10kdev.net\/?p=1216"},"modified":"2014-10-02T14:01:56","modified_gmt":"2014-10-02T21:01:56","slug":"making-asynchronous-release-schedules-easy-on-your-development-process","status":"publish","type":"post","link":"http:\/\/10kdev.net\/?p=1216","title":{"rendered":"Making Asynchronous Release Schedules Easy On Your Development Process"},"content":{"rendered":"<p>Once upon a nightmare a project manager said to me: &#8220;I would never let developers work on <em><strong>trunk<\/strong><\/em>.&#8221;<\/p>\n<p>Serious? \u00a0It turned out the organization had *redefined* from industry standards the definition of &#8220;trunk&#8221; &#8212; to them it meant &#8220;production release.&#8221; \u00a0Ummmm. \u00a0Ok.<\/p>\n<p>I explained why the concept of <em>trunk<\/em> is that it is the most advanced rendition of the code,\u00a0that development is always ahead of production and that production is just a release of developer code. \u00a0No matter how you look at it this is the truth, even if you do hot fixes or patches in production (which should be patched back to development or forgotten with production that becomes a dead end branch.)<\/p>\n<p>The repository is there to support development. \u00a0Part of development is release. \u00a0If the philosophy is the converse: \u00a0repositories are there for production release and developers-be-damned I can guarantee you rough seas.<\/p>\n<p>Two scenarios I have worked with that deal with extreme repository interesting situations:<\/p>\n<ul>\n<li><strong>Divergent Branch\u00a0Problem:<\/strong> A branch that diverged\u00a0with trunk so far that it went on its own release schedule and eventually became its own product. \u00a0You see this kind of branching in Github all the time. If this happens, and an organization is still under the delusion that they have one product its too bad &#8212; but the behavior of the team will be supporting two products. \u00a0<strong>Solution<\/strong>: \u00a0drop your delusion. You have two products.<\/li>\n<li><strong>Asynchronous Features Problem:<\/strong> In this case the teams have several features coming out but <em>no one knows which will be released first<\/em>. \u00a0<strong>Solution:<\/strong> \u00a0Make branches and merge back to trunk often. Have build servers on all branches . . . and read on.<\/li>\n<\/ul>\n<p><strong>The Asynchronous Cake Batter<\/strong><\/p>\n<p>We had two competing Features, A and B. \u00a0The features were to be released separately, the first one exclusive of the second feature&#8217;s code but no one knew which would be the first to be released. \u00a0Got it? Parallel timeline. <em><strong>\u00a0AND<\/strong><strong><em>. <\/em>. . they had all the developers on all features checking into the same common trunk.<\/strong><\/em> \u00a0Oh yes they did. \u00a0Eventually the &#8220;build master&#8221; would do a <strong>reverse merge<\/strong> in trunk when a build was needed. \u00a0using\u00a0check-in tags to\u00a0could identify what to pull out, and create a release from what was left. \u00a0That&#8217;s right &#8212; a reverse merge.<\/p>\n<p>Pause.<\/p>\n<blockquote><p><strong>A <em>&#8220;reverse merge&#8221;<\/em> is pulling code out to create a build with the intention of putting the code back again.<\/strong><\/p><\/blockquote>\n<p>OK, now that you&#8217;ve wiped the Dr. Pepper off your screen from your guffaw, and believe my I couldn&#8217;t believe it either, nothing would budge them. \u00a0They wouldn&#8217;t create dedicate branches &#8212; indeed, even using SVN they could have, and none of the teams were really sure what a build number meant out in QA. \u00a0You&#8217;d get build 456 and say &#8220;hey. . are you testing Feature A or B&#8221;? \u00a0Only the build master knew from the edict he received from management. \u00a0Yeah, our QA systems were testing both at the same time on the same systems. \u00a0And services were going out too &#8212; so sometimes a Feature A client would be operating on a Feature B service.<\/p>\n<p>And the worst part was the releases suffered from cake batter syndrome &#8212; that is, once you&#8217;ve put the eggs and sugar into the batter and its baked you can&#8217;t get them out again. \u00a0Reverse-merging suffered from this: the resultant code was nothing nobody had created. \u00a0And . . .the build masters didn&#8217;t work on the code at all but they had to do this complex merging.<\/p>\n<p><strong>My Solution<\/strong><\/p>\n<p>I was able to manage things my self locally with git and git-svn for our respective repositories. \u00a0After hands-on with this I came up with the solution in the following diagram.<\/p>\n<p><a href=\"http:\/\/10kdev.net\/wp-content\/uploads\/2014\/09\/Asynchronous-Release-Strategy1.png\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-1229 size-full\" src=\"http:\/\/10kdev.net\/wp-content\/uploads\/2014\/09\/Asynchronous-Release-Strategy1.png\" alt=\"Asynchronous Release Strategy\" width=\"566\" height=\"941\" srcset=\"http:\/\/10kdev.net\/wp-content\/uploads\/2014\/09\/Asynchronous-Release-Strategy1.png 566w, http:\/\/10kdev.net\/wp-content\/uploads\/2014\/09\/Asynchronous-Release-Strategy1-180x300.png 180w\" sizes=\"(max-width: 566px) 100vw, 566px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>The features are branches where the developers work. \u00a0The pain comes in merging back to trunk, but doing so ensures that a future branch gets all the previous features.<\/p>\n<p>Discussing this solution with a few outside that particular culture, this makes sense. \u00a0Hg or Git really go a long way to help this. \u00a0A developer can switch easily between them.<\/p>\n<p>Also &#8212; <em>very important<\/em> &#8212; is the <strong>merge back to trunk<\/strong> from the branches. \u00a0Now who does this is up for contention. \u00a0A merge requires builds and tests and can be time consuming. \u00a0My suggestion &#8212; automate the merge back to trunk on developer check-ins and run the builds with automated testing. \u00a0A breakage means a peal off.<\/p>\n<p>I really think you need three ingredients to\u00a0do this kind of development &#8212; or be ready to descend into the hell we experienced:<\/p>\n<ol>\n<li>A distributed repository that makes branch creating and switching a snap &#8212; like Git or Hg.<\/li>\n<li>A build server with a crew ready to clone build jobs for the necessary branches (minimally the mainline trunk and feature branches).<\/li>\n<li>Automated testing &#8212; to ensure that nothing breaks.<\/li>\n<li>Frequent and often merges<\/li>\n<\/ol>\n<p>I cannot suggest this kind of management paradigm that creates this scenario &#8212; even with the solution I put forth there is considerable pain in the merges no matter what a person can do. Double check-ins have to occur somewhere when an organization decides to do this, but its better than the dratted reverse-merge.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Once upon a nightmare a project manager said to me: &#8220;I would never let developers work on trunk.&#8221; Serious? \u00a0It turned out the organization had *redefined* from industry standards the definition of &#8220;trunk&#8221; &#8212; to them it meant &#8220;production release.&#8221; \u00a0Ummmm. \u00a0Ok. I explained why the concept of trunk is that it is the most [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[35,66,46,65],"_links":{"self":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts\/1216"}],"collection":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1216"}],"version-history":[{"count":7,"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts\/1216\/revisions"}],"predecessor-version":[{"id":1231,"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts\/1216\/revisions\/1231"}],"wp:attachment":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1216"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1216"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1216"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}