{"componentChunkName":"component---node-modules-gatsby-theme-medium-to-own-blog-src-templates-blog-post-js","path":"/promote-environments-not-artifacts/","result":{"data":{"site":{"siteMetadata":{"siteUrl":"https://javame.netlify.app","githubUrl":"https://github.com/aterreno/blog"}},"mdx":{"fields":{"slug":"/promote-environments-not-artifacts/"},"excerpt":"Lately I’ve been working quite a lot with environments and release issues. On my last project we had eight environments: development…","timeToRead":3,"frontmatter":{"title":"Promote environments not artifacts","description":"","categories":[],"date":"April 05, 2010","canonical_link":"https://javame.netlify.app//promote-environments-not-artifacts-3564d0a209ee"},"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"Promote environments not artifacts\",\n  \"description\": \"\",\n  \"date\": \"2010-04-05T00:00:00.000Z\",\n  \"categories\": [],\n  \"published\": true,\n  \"canonical_link\": \"https://javame.netlify.app//promote-environments-not-artifacts-3564d0a209ee\",\n  \"redirect_from\": [\"/promote-environments-not-artifacts-3564d0a209ee\"]\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"Lately I\\u2019ve been working quite a lot with environments and release issues.\"), mdx(\"p\", null, \"On my last project we had eight environments: development, continuous integration, test, performance, pre-live and live plus a couple of demo boxes.\"), mdx(\"p\", null, \"This over-engineered situation caused few issues but at the same time made me think and write this blog post\\xA0:-)\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"What we did to improve deployment\")), mdx(\"p\", null, \"Well, automation is the key, even if we are in a windows environment we wrote remote deployment scripts to do remote deploy in the machines using \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"psexec\"), \" and \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"http://technet.microsoft.com/en-us/library/cc733145%28WS.10%29.aspx\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"robocopy\"), \".\"), mdx(\"p\", null, \"We template our config files and we have one config per machine.\"), mdx(\"p\", null, \"So far so good, old school good practices.\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"What still doesn\\u2019t work\")), mdx(\"p\", null, \"Your software is done, finished, all the test are passing, unit and integration on the development boxes, acceptance on the CI box, the QA is happy in the testing environment and the product owners are happy on both of the demo boxes, the performance test team is happy on the performance box, the security team is happy with their tests executed on the pre live box.\"), mdx(\"p\", null, \"But still your sofware may not work on live. Or most likely in any of those environments.\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Configuration is vital\")), mdx(\"p\", null, \"Your application without configuration doesn\\u2019t neither start or with a wrong configuration won\\u2019t log or work properly. There\\u2019s test coverage on all the aspects of your application but not on environment configuration. You may misspell a name of a server or simply forget that something is different from environment to environment. Your application won\\u2019t work as expected.\"), mdx(\"p\", null, \"The configuration of the environment itself may cause serious problems. The most different your live boxes are from your test/integration/performance ones the higher is the risk that your software won\\u2019t perform as expected on the target servers.\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"So, my humble recommendations\")), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, \"Move fast\")), mdx(\"p\", null, \"Moving fast is essential in any aspect of software development, when talking about releasing software is essential that you should be able to continuously deploy and redeploy in a repeatable stable way your application as fast as possible. Use remote scripts, even if you are not working with the cool kids in the ruby world do something similar to what \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"http://www.capify.org/index.php/Capistrano\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"capistrano\"), \" does.\"), mdx(\"p\", null, \"Have a look on the \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"http://heroku.com/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"heroku\"), \" website for a good example of moving fast\\u2026\"), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, \"Reduce as much as possible the number of environments\")), mdx(\"p\", null, \"It\\u2019s clear that in the above example we have too many environments, if you have full control ask yourself why do you need them and just take them off. If an environment doesn\\u2019t produce any value it\\u2019s just a waste of time and resources. Environments can be recycled, most of the applications won\\u2019t need two demo environments and a performance environments available for the whole project life-cycle.\"), mdx(\"p\", null, \"How would I cut down the number of environments on my previous example?\"), mdx(\"p\", null, \"Development, continuous integration, test & performance, that\\u2019s it, four, it\\u2019s a 50% cut down!\"), mdx(\"p\", null, \"A good rule is that your environments should be the same number of your story wall lanes:\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Story in dev > development environment\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Story dev complete > CI environment\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Story in test > test environment\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Story ready to sign off > performance environment\")), mdx(\"p\", null, \"The performance environment can be used as stable build environment for showcases, demonstration of the software and indeed performance tests. But also for one last, more important thing, which is the whole point of this blog post:\"), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, \"Promote environments not artifacts\")), mdx(\"p\", null, \"Imagine that you\\u2019re happy with you software, it has been signed off by the product owner and it\\u2019s performing well.\"), mdx(\"p\", null, \"Probably you made some changes to the performance environment, maybe you started with a cluster of two machine and ended up with a cluster of four. Now you want to go live, but the live environment that you have is different, you may have some problems.\"), mdx(\"p\", null, \"My idea is to promote the whole environment. You are probably using cloud computing or virtualization, just move this stuff to the live environment, clone it and you are done.\"), mdx(\"p\", null, \"Promote the environment with the artifacts, all together.\"), mdx(\"p\", null, \"Try to define your environments as executable scripts (in the \", \"*\", \"nix world won\\u2019t be that hard) and version control these scripts with your environment configuration, the creation of the whole environment should be scriptable, repeatable and should evolve with your code.\"), mdx(\"p\", null, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"http://www.markhneedham.com/blog/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"Mark\"), \" told me that \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"http://blog.chris-read.net/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"Chris Read\"), \" has been talking about this stuff for years, you may want to check out his blog or his \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"http://www.slideshare.net/ChristopherRead/all-my-tests-are-passing-now-what\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"presentations\"), \", he\\u2019s anyway way much better than me explaining and making these things real.\"));\n}\n;\nMDXContent.isMDXComponent = true;"},"allWebMentionEntry":{"nodes":[]}},"pageContext":{"id":"7f6ba02b-4093-5b22-9d09-fc88b703e8dd","previous":{"id":"35b4f75c-8f20-5764-971d-0166d34625c0","fields":{"slug":"/practices-of-the-proper-christian-programmer/","published":true},"frontmatter":{"redirect_from":["/practices-of-the-proper-christian-programmer-e0eaaaefddd5"],"redirect_to":null,"title":"Practices of the Proper Christian Programmer"}},"next":{"id":"fc59916d-8696-5414-8f16-5ffcf5c31624","fields":{"slug":"/the-speckled-people/","published":true},"frontmatter":{"redirect_from":["/the-speckled-people-86b903d39522"],"redirect_to":null,"title":"The Speckled People"}},"permalink":"https://javame.netlify.app/promote-environments-not-artifacts/","themeOptions":{"plugins":[],"config":{"title":"Antonio Terreno","description":"Antonio Terreno's blog archive","shortBio":"","bio":"Principal Consultant at Equal Experts","author":"Antonio Terreno","githubUrl":"https://github.com/aterreno/blog","siteUrl":"https://javame.netlify.app/","social":{"twitter":"javame","medium":"","facebook":"","github":"aterreno","linkedin":"antonioterreno","instagram":"tritonitri"},"goatCounterCode":null}}}},"staticQueryHashes":["4131332129","645483741"]}